diff options
author | David S. Miller <davem@davemloft.net> | 2009-11-06 08:01:54 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-06 08:01:54 -0500 |
commit | 62d83681e53fd87c91927018cfe5ba9f9e8109a3 (patch) | |
tree | 3dc4d99c1d9e782de6fb56b61369aee8f4291a5e | |
parent | 230f9bb701d37ae9b48e96456689452978f5c439 (diff) | |
parent | e7fec0bbf13b9bc2869a18e66f0cda7bb7f559f0 (diff) |
Merge branch 'linux-2.6.33.y' of git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
26 files changed, 2104 insertions, 618 deletions
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index 07308686dbcf..944945540391 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c | |||
@@ -54,7 +54,7 @@ | |||
54 | * i2400m_set_init_config() | 54 | * i2400m_set_init_config() |
55 | * i2400m_cmd_get_state() | 55 | * i2400m_cmd_get_state() |
56 | * i2400m_dev_shutdown() Called by i2400m_dev_stop() | 56 | * i2400m_dev_shutdown() Called by i2400m_dev_stop() |
57 | * i2400m->bus_reset() | 57 | * i2400m_reset() |
58 | * | 58 | * |
59 | * i2400m_{cmd,get,set}_*() | 59 | * i2400m_{cmd,get,set}_*() |
60 | * i2400m_msg_to_dev() | 60 | * i2400m_msg_to_dev() |
@@ -82,6 +82,13 @@ | |||
82 | #define D_SUBMODULE control | 82 | #define D_SUBMODULE control |
83 | #include "debug-levels.h" | 83 | #include "debug-levels.h" |
84 | 84 | ||
85 | int i2400m_passive_mode; /* 0 (passive mode disabled) by default */ | ||
86 | module_param_named(passive_mode, i2400m_passive_mode, int, 0644); | ||
87 | MODULE_PARM_DESC(passive_mode, | ||
88 | "If true, the driver will not do any device setup " | ||
89 | "and leave it up to user space, who must be properly " | ||
90 | "setup."); | ||
91 | |||
85 | 92 | ||
86 | /* | 93 | /* |
87 | * Return if a TLV is of a give type and size | 94 | * Return if a TLV is of a give type and size |
@@ -263,7 +270,7 @@ int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *l3l4_hdr, | |||
263 | 270 | ||
264 | if (status == 0) | 271 | if (status == 0) |
265 | return 0; | 272 | return 0; |
266 | if (status > ARRAY_SIZE(ms_to_errno)) { | 273 | if (status >= ARRAY_SIZE(ms_to_errno)) { |
267 | str = "unknown status code"; | 274 | str = "unknown status code"; |
268 | result = -EBADR; | 275 | result = -EBADR; |
269 | } else { | 276 | } else { |
@@ -336,7 +343,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, | |||
336 | /* Huh? just in case, shut it down */ | 343 | /* Huh? just in case, shut it down */ |
337 | dev_err(dev, "HW BUG? unknown state %u: shutting down\n", | 344 | dev_err(dev, "HW BUG? unknown state %u: shutting down\n", |
338 | i2400m_state); | 345 | i2400m_state); |
339 | i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 346 | i2400m_reset(i2400m, I2400M_RT_WARM); |
340 | break; | 347 | break; |
341 | }; | 348 | }; |
342 | d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", | 349 | d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", |
@@ -1335,6 +1342,8 @@ int i2400m_dev_initialize(struct i2400m *i2400m) | |||
1335 | unsigned argc = 0; | 1342 | unsigned argc = 0; |
1336 | 1343 | ||
1337 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 1344 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
1345 | if (i2400m_passive_mode) | ||
1346 | goto out_passive; | ||
1338 | /* Disable idle mode? (enabled by default) */ | 1347 | /* Disable idle mode? (enabled by default) */ |
1339 | if (i2400m_idle_mode_disabled) { | 1348 | if (i2400m_idle_mode_disabled) { |
1340 | if (i2400m_le_v1_3(i2400m)) { | 1349 | if (i2400m_le_v1_3(i2400m)) { |
@@ -1377,6 +1386,7 @@ int i2400m_dev_initialize(struct i2400m *i2400m) | |||
1377 | result = i2400m_set_init_config(i2400m, args, argc); | 1386 | result = i2400m_set_init_config(i2400m, args, argc); |
1378 | if (result < 0) | 1387 | if (result < 0) |
1379 | goto error; | 1388 | goto error; |
1389 | out_passive: | ||
1380 | /* | 1390 | /* |
1381 | * Update state: Here it just calls a get state; parsing the | 1391 | * Update state: Here it just calls a get state; parsing the |
1382 | * result (System State TLV and RF Status TLV [done in the rx | 1392 | * result (System State TLV and RF Status TLV [done in the rx |
diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c index 9b81af3f80a9..b1aec3e1892f 100644 --- a/drivers/net/wimax/i2400m/debugfs.c +++ b/drivers/net/wimax/i2400m/debugfs.c | |||
@@ -214,7 +214,7 @@ int debugfs_i2400m_reset_set(void *data, u64 val) | |||
214 | case I2400M_RT_WARM: | 214 | case I2400M_RT_WARM: |
215 | case I2400M_RT_COLD: | 215 | case I2400M_RT_COLD: |
216 | case I2400M_RT_BUS: | 216 | case I2400M_RT_BUS: |
217 | result = i2400m->bus_reset(i2400m, rt); | 217 | result = i2400m_reset(i2400m, rt); |
218 | if (result >= 0) | 218 | if (result >= 0) |
219 | result = 0; | 219 | result = 0; |
220 | default: | 220 | default: |
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 304f0443ca4b..96a615fe09de 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c | |||
@@ -41,8 +41,10 @@ | |||
41 | * __i2400m_dev_start() | 41 | * __i2400m_dev_start() |
42 | * | 42 | * |
43 | * i2400m_setup() | 43 | * i2400m_setup() |
44 | * i2400m->bus_setup() | ||
44 | * i2400m_bootrom_init() | 45 | * i2400m_bootrom_init() |
45 | * register_netdev() | 46 | * register_netdev() |
47 | * wimax_dev_add() | ||
46 | * i2400m_dev_start() | 48 | * i2400m_dev_start() |
47 | * __i2400m_dev_start() | 49 | * __i2400m_dev_start() |
48 | * i2400m_dev_bootstrap() | 50 | * i2400m_dev_bootstrap() |
@@ -50,15 +52,15 @@ | |||
50 | * i2400m->bus_dev_start() | 52 | * i2400m->bus_dev_start() |
51 | * i2400m_firmware_check() | 53 | * i2400m_firmware_check() |
52 | * i2400m_check_mac_addr() | 54 | * i2400m_check_mac_addr() |
53 | * wimax_dev_add() | ||
54 | * | 55 | * |
55 | * i2400m_release() | 56 | * i2400m_release() |
56 | * wimax_dev_rm() | ||
57 | * i2400m_dev_stop() | 57 | * i2400m_dev_stop() |
58 | * __i2400m_dev_stop() | 58 | * __i2400m_dev_stop() |
59 | * i2400m_dev_shutdown() | 59 | * i2400m_dev_shutdown() |
60 | * i2400m->bus_dev_stop() | 60 | * i2400m->bus_dev_stop() |
61 | * i2400m_tx_release() | 61 | * i2400m_tx_release() |
62 | * i2400m->bus_release() | ||
63 | * wimax_dev_rm() | ||
62 | * unregister_netdev() | 64 | * unregister_netdev() |
63 | */ | 65 | */ |
64 | #include "i2400m.h" | 66 | #include "i2400m.h" |
@@ -66,6 +68,7 @@ | |||
66 | #include <linux/wimax/i2400m.h> | 68 | #include <linux/wimax/i2400m.h> |
67 | #include <linux/module.h> | 69 | #include <linux/module.h> |
68 | #include <linux/moduleparam.h> | 70 | #include <linux/moduleparam.h> |
71 | #include <linux/suspend.h> | ||
69 | 72 | ||
70 | #define D_SUBMODULE driver | 73 | #define D_SUBMODULE driver |
71 | #include "debug-levels.h" | 74 | #include "debug-levels.h" |
@@ -90,76 +93,39 @@ MODULE_PARM_DESC(power_save_disabled, | |||
90 | "False by default (so the device is told to do power " | 93 | "False by default (so the device is told to do power " |
91 | "saving)."); | 94 | "saving)."); |
92 | 95 | ||
93 | /** | 96 | static char i2400m_debug_params[128]; |
94 | * i2400m_queue_work - schedule work on a i2400m's queue | 97 | module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params), |
95 | * | 98 | 0644); |
96 | * @i2400m: device descriptor | 99 | MODULE_PARM_DESC(debug, |
97 | * | 100 | "String of space-separated NAME:VALUE pairs, where NAMEs " |
98 | * @fn: function to run to execute work. It gets passed a 'struct | 101 | "are the different debug submodules and VALUE are the " |
99 | * work_struct' that is wrapped in a 'struct i2400m_work'. Once | 102 | "initial debug value to set."); |
100 | * done, you have to (1) i2400m_put(i2400m_work->i2400m) and then | 103 | |
101 | * (2) kfree(i2400m_work). | 104 | static char i2400m_barkers_params[128]; |
102 | * | 105 | module_param_string(barkers, i2400m_barkers_params, |
103 | * @gfp_flags: GFP flags for memory allocation. | 106 | sizeof(i2400m_barkers_params), 0644); |
104 | * | 107 | MODULE_PARM_DESC(barkers, |
105 | * @pl: pointer to a payload buffer that you want to pass to the _work | 108 | "String of comma-separated 32-bit values; each is " |
106 | * function. Use this to pack (for example) a struct with extra | 109 | "recognized as the value the device sends as a reboot " |
107 | * arguments. | 110 | "signal; values are appended to a list--setting one value " |
108 | * | 111 | "as zero cleans the existing list and starts a new one."); |
109 | * @pl_size: size of the payload buffer. | 112 | |
110 | * | 113 | static |
111 | * We do this quite often, so this just saves typing; allocate a | 114 | struct i2400m_work *__i2400m_work_setup( |
112 | * wrapper for a i2400m, get a ref to it, pack arguments and launch | 115 | struct i2400m *i2400m, void (*fn)(struct work_struct *), |
113 | * the work. | 116 | gfp_t gfp_flags, const void *pl, size_t pl_size) |
114 | * | ||
115 | * A usual workflow is: | ||
116 | * | ||
117 | * struct my_work_args { | ||
118 | * void *something; | ||
119 | * int whatever; | ||
120 | * }; | ||
121 | * ... | ||
122 | * | ||
123 | * struct my_work_args my_args = { | ||
124 | * .something = FOO, | ||
125 | * .whaetever = BLAH | ||
126 | * }; | ||
127 | * i2400m_queue_work(i2400m, 1, my_work_function, GFP_KERNEL, | ||
128 | * &args, sizeof(args)) | ||
129 | * | ||
130 | * And now the work function can unpack the arguments and call the | ||
131 | * real function (or do the job itself): | ||
132 | * | ||
133 | * static | ||
134 | * void my_work_fn((struct work_struct *ws) | ||
135 | * { | ||
136 | * struct i2400m_work *iw = | ||
137 | * container_of(ws, struct i2400m_work, ws); | ||
138 | * struct my_work_args *my_args = (void *) iw->pl; | ||
139 | * | ||
140 | * my_work(iw->i2400m, my_args->something, my_args->whatevert); | ||
141 | * } | ||
142 | */ | ||
143 | int i2400m_queue_work(struct i2400m *i2400m, | ||
144 | void (*fn)(struct work_struct *), gfp_t gfp_flags, | ||
145 | const void *pl, size_t pl_size) | ||
146 | { | 117 | { |
147 | int result; | ||
148 | struct i2400m_work *iw; | 118 | struct i2400m_work *iw; |
149 | 119 | ||
150 | BUG_ON(i2400m->work_queue == NULL); | ||
151 | result = -ENOMEM; | ||
152 | iw = kzalloc(sizeof(*iw) + pl_size, gfp_flags); | 120 | iw = kzalloc(sizeof(*iw) + pl_size, gfp_flags); |
153 | if (iw == NULL) | 121 | if (iw == NULL) |
154 | goto error_kzalloc; | 122 | return NULL; |
155 | iw->i2400m = i2400m_get(i2400m); | 123 | iw->i2400m = i2400m_get(i2400m); |
124 | iw->pl_size = pl_size; | ||
156 | memcpy(iw->pl, pl, pl_size); | 125 | memcpy(iw->pl, pl, pl_size); |
157 | INIT_WORK(&iw->ws, fn); | 126 | INIT_WORK(&iw->ws, fn); |
158 | result = queue_work(i2400m->work_queue, &iw->ws); | 127 | return iw; |
159 | error_kzalloc: | ||
160 | return result; | ||
161 | } | 128 | } |
162 | EXPORT_SYMBOL_GPL(i2400m_queue_work); | ||
163 | 129 | ||
164 | 130 | ||
165 | /* | 131 | /* |
@@ -175,21 +141,19 @@ EXPORT_SYMBOL_GPL(i2400m_queue_work); | |||
175 | * it should not happen. | 141 | * it should not happen. |
176 | */ | 142 | */ |
177 | int i2400m_schedule_work(struct i2400m *i2400m, | 143 | int i2400m_schedule_work(struct i2400m *i2400m, |
178 | void (*fn)(struct work_struct *), gfp_t gfp_flags) | 144 | void (*fn)(struct work_struct *), gfp_t gfp_flags, |
145 | const void *pl, size_t pl_size) | ||
179 | { | 146 | { |
180 | int result; | 147 | int result; |
181 | struct i2400m_work *iw; | 148 | struct i2400m_work *iw; |
182 | 149 | ||
183 | result = -ENOMEM; | 150 | result = -ENOMEM; |
184 | iw = kzalloc(sizeof(*iw), gfp_flags); | 151 | iw = __i2400m_work_setup(i2400m, fn, gfp_flags, pl, pl_size); |
185 | if (iw == NULL) | 152 | if (iw != NULL) { |
186 | goto error_kzalloc; | 153 | result = schedule_work(&iw->ws); |
187 | iw->i2400m = i2400m_get(i2400m); | 154 | if (WARN_ON(result == 0)) |
188 | INIT_WORK(&iw->ws, fn); | 155 | result = -ENXIO; |
189 | result = schedule_work(&iw->ws); | 156 | } |
190 | if (result == 0) | ||
191 | result = -ENXIO; | ||
192 | error_kzalloc: | ||
193 | return result; | 157 | return result; |
194 | } | 158 | } |
195 | 159 | ||
@@ -291,7 +255,7 @@ int i2400m_op_reset(struct wimax_dev *wimax_dev) | |||
291 | mutex_lock(&i2400m->init_mutex); | 255 | mutex_lock(&i2400m->init_mutex); |
292 | i2400m->reset_ctx = &ctx; | 256 | i2400m->reset_ctx = &ctx; |
293 | mutex_unlock(&i2400m->init_mutex); | 257 | mutex_unlock(&i2400m->init_mutex); |
294 | result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 258 | result = i2400m_reset(i2400m, I2400M_RT_WARM); |
295 | if (result < 0) | 259 | if (result < 0) |
296 | goto out; | 260 | goto out; |
297 | result = wait_for_completion_timeout(&ctx.completion, 4*HZ); | 261 | result = wait_for_completion_timeout(&ctx.completion, 4*HZ); |
@@ -420,9 +384,15 @@ retry: | |||
420 | dev_err(dev, "cannot create workqueue\n"); | 384 | dev_err(dev, "cannot create workqueue\n"); |
421 | goto error_create_workqueue; | 385 | goto error_create_workqueue; |
422 | } | 386 | } |
423 | result = i2400m->bus_dev_start(i2400m); | 387 | if (i2400m->bus_dev_start) { |
424 | if (result < 0) | 388 | result = i2400m->bus_dev_start(i2400m); |
425 | goto error_bus_dev_start; | 389 | if (result < 0) |
390 | goto error_bus_dev_start; | ||
391 | } | ||
392 | i2400m->ready = 1; | ||
393 | wmb(); /* see i2400m->ready's documentation */ | ||
394 | /* process pending reports from the device */ | ||
395 | queue_work(i2400m->work_queue, &i2400m->rx_report_ws); | ||
426 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ | 396 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ |
427 | if (result < 0) | 397 | if (result < 0) |
428 | goto error_fw_check; | 398 | goto error_fw_check; |
@@ -430,8 +400,6 @@ retry: | |||
430 | result = i2400m_check_mac_addr(i2400m); | 400 | result = i2400m_check_mac_addr(i2400m); |
431 | if (result < 0) | 401 | if (result < 0) |
432 | goto error_check_mac_addr; | 402 | goto error_check_mac_addr; |
433 | i2400m->ready = 1; | ||
434 | wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED); | ||
435 | result = i2400m_dev_initialize(i2400m); | 403 | result = i2400m_dev_initialize(i2400m); |
436 | if (result < 0) | 404 | if (result < 0) |
437 | goto error_dev_initialize; | 405 | goto error_dev_initialize; |
@@ -443,8 +411,12 @@ retry: | |||
443 | 411 | ||
444 | error_dev_initialize: | 412 | error_dev_initialize: |
445 | error_check_mac_addr: | 413 | error_check_mac_addr: |
414 | i2400m->ready = 0; | ||
415 | wmb(); /* see i2400m->ready's documentation */ | ||
416 | flush_workqueue(i2400m->work_queue); | ||
446 | error_fw_check: | 417 | error_fw_check: |
447 | i2400m->bus_dev_stop(i2400m); | 418 | if (i2400m->bus_dev_stop) |
419 | i2400m->bus_dev_stop(i2400m); | ||
448 | error_bus_dev_start: | 420 | error_bus_dev_start: |
449 | destroy_workqueue(i2400m->work_queue); | 421 | destroy_workqueue(i2400m->work_queue); |
450 | error_create_workqueue: | 422 | error_create_workqueue: |
@@ -466,11 +438,15 @@ error_bootstrap: | |||
466 | static | 438 | static |
467 | int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) | 439 | int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) |
468 | { | 440 | { |
469 | int result; | 441 | int result = 0; |
470 | mutex_lock(&i2400m->init_mutex); /* Well, start the device */ | 442 | mutex_lock(&i2400m->init_mutex); /* Well, start the device */ |
471 | result = __i2400m_dev_start(i2400m, bm_flags); | 443 | if (i2400m->updown == 0) { |
472 | if (result >= 0) | 444 | result = __i2400m_dev_start(i2400m, bm_flags); |
473 | i2400m->updown = 1; | 445 | if (result >= 0) { |
446 | i2400m->updown = 1; | ||
447 | wmb(); /* see i2400m->updown's documentation */ | ||
448 | } | ||
449 | } | ||
474 | mutex_unlock(&i2400m->init_mutex); | 450 | mutex_unlock(&i2400m->init_mutex); |
475 | return result; | 451 | return result; |
476 | } | 452 | } |
@@ -495,9 +471,20 @@ void __i2400m_dev_stop(struct i2400m *i2400m) | |||
495 | 471 | ||
496 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 472 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
497 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); | 473 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); |
474 | i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); | ||
475 | complete(&i2400m->msg_completion); | ||
476 | i2400m_net_wake_stop(i2400m); | ||
498 | i2400m_dev_shutdown(i2400m); | 477 | i2400m_dev_shutdown(i2400m); |
499 | i2400m->ready = 0; | 478 | /* |
500 | i2400m->bus_dev_stop(i2400m); | 479 | * Make sure no report hooks are running *before* we stop the |
480 | * communication infrastructure with the device. | ||
481 | */ | ||
482 | i2400m->ready = 0; /* nobody can queue work anymore */ | ||
483 | wmb(); /* see i2400m->ready's documentation */ | ||
484 | flush_workqueue(i2400m->work_queue); | ||
485 | |||
486 | if (i2400m->bus_dev_stop) | ||
487 | i2400m->bus_dev_stop(i2400m); | ||
501 | destroy_workqueue(i2400m->work_queue); | 488 | destroy_workqueue(i2400m->work_queue); |
502 | i2400m_rx_release(i2400m); | 489 | i2400m_rx_release(i2400m); |
503 | i2400m_tx_release(i2400m); | 490 | i2400m_tx_release(i2400m); |
@@ -518,12 +505,139 @@ void i2400m_dev_stop(struct i2400m *i2400m) | |||
518 | if (i2400m->updown) { | 505 | if (i2400m->updown) { |
519 | __i2400m_dev_stop(i2400m); | 506 | __i2400m_dev_stop(i2400m); |
520 | i2400m->updown = 0; | 507 | i2400m->updown = 0; |
508 | wmb(); /* see i2400m->updown's documentation */ | ||
521 | } | 509 | } |
522 | mutex_unlock(&i2400m->init_mutex); | 510 | mutex_unlock(&i2400m->init_mutex); |
523 | } | 511 | } |
524 | 512 | ||
525 | 513 | ||
526 | /* | 514 | /* |
515 | * Listen to PM events to cache the firmware before suspend/hibernation | ||
516 | * | ||
517 | * When the device comes out of suspend, it might go into reset and | ||
518 | * firmware has to be uploaded again. At resume, most of the times, we | ||
519 | * can't load firmware images from disk, so we need to cache it. | ||
520 | * | ||
521 | * i2400m_fw_cache() will allocate a kobject and attach the firmware | ||
522 | * to it; that way we don't have to worry too much about the fw loader | ||
523 | * hitting a race condition. | ||
524 | * | ||
525 | * Note: modus operandi stolen from the Orinoco driver; thx. | ||
526 | */ | ||
527 | static | ||
528 | int i2400m_pm_notifier(struct notifier_block *notifier, | ||
529 | unsigned long pm_event, | ||
530 | void *unused) | ||
531 | { | ||
532 | struct i2400m *i2400m = | ||
533 | container_of(notifier, struct i2400m, pm_notifier); | ||
534 | struct device *dev = i2400m_dev(i2400m); | ||
535 | |||
536 | d_fnstart(3, dev, "(i2400m %p pm_event %lx)\n", i2400m, pm_event); | ||
537 | switch (pm_event) { | ||
538 | case PM_HIBERNATION_PREPARE: | ||
539 | case PM_SUSPEND_PREPARE: | ||
540 | i2400m_fw_cache(i2400m); | ||
541 | break; | ||
542 | case PM_POST_RESTORE: | ||
543 | /* Restore from hibernation failed. We need to clean | ||
544 | * up in exactly the same way, so fall through. */ | ||
545 | case PM_POST_HIBERNATION: | ||
546 | case PM_POST_SUSPEND: | ||
547 | i2400m_fw_uncache(i2400m); | ||
548 | break; | ||
549 | |||
550 | case PM_RESTORE_PREPARE: | ||
551 | default: | ||
552 | break; | ||
553 | } | ||
554 | d_fnend(3, dev, "(i2400m %p pm_event %lx) = void\n", i2400m, pm_event); | ||
555 | return NOTIFY_DONE; | ||
556 | } | ||
557 | |||
558 | |||
559 | /* | ||
560 | * pre-reset is called before a device is going on reset | ||
561 | * | ||
562 | * This has to be followed by a call to i2400m_post_reset(), otherwise | ||
563 | * bad things might happen. | ||
564 | */ | ||
565 | int i2400m_pre_reset(struct i2400m *i2400m) | ||
566 | { | ||
567 | int result; | ||
568 | struct device *dev = i2400m_dev(i2400m); | ||
569 | |||
570 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | ||
571 | d_printf(1, dev, "pre-reset shut down\n"); | ||
572 | |||
573 | result = 0; | ||
574 | mutex_lock(&i2400m->init_mutex); | ||
575 | if (i2400m->updown) { | ||
576 | netif_tx_disable(i2400m->wimax_dev.net_dev); | ||
577 | __i2400m_dev_stop(i2400m); | ||
578 | result = 0; | ||
579 | /* down't set updown to zero -- this way | ||
580 | * post_reset can restore properly */ | ||
581 | } | ||
582 | mutex_unlock(&i2400m->init_mutex); | ||
583 | if (i2400m->bus_release) | ||
584 | i2400m->bus_release(i2400m); | ||
585 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | ||
586 | return result; | ||
587 | } | ||
588 | EXPORT_SYMBOL_GPL(i2400m_pre_reset); | ||
589 | |||
590 | |||
591 | /* | ||
592 | * Restore device state after a reset | ||
593 | * | ||
594 | * Do the work needed after a device reset to bring it up to the same | ||
595 | * state as it was before the reset. | ||
596 | * | ||
597 | * NOTE: this requires i2400m->init_mutex taken | ||
598 | */ | ||
599 | int i2400m_post_reset(struct i2400m *i2400m) | ||
600 | { | ||
601 | int result = 0; | ||
602 | struct device *dev = i2400m_dev(i2400m); | ||
603 | |||
604 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | ||
605 | d_printf(1, dev, "post-reset start\n"); | ||
606 | if (i2400m->bus_setup) { | ||
607 | result = i2400m->bus_setup(i2400m); | ||
608 | if (result < 0) { | ||
609 | dev_err(dev, "bus-specific setup failed: %d\n", | ||
610 | result); | ||
611 | goto error_bus_setup; | ||
612 | } | ||
613 | } | ||
614 | mutex_lock(&i2400m->init_mutex); | ||
615 | if (i2400m->updown) { | ||
616 | result = __i2400m_dev_start( | ||
617 | i2400m, I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); | ||
618 | if (result < 0) | ||
619 | goto error_dev_start; | ||
620 | } | ||
621 | mutex_unlock(&i2400m->init_mutex); | ||
622 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | ||
623 | return result; | ||
624 | |||
625 | error_dev_start: | ||
626 | if (i2400m->bus_release) | ||
627 | i2400m->bus_release(i2400m); | ||
628 | error_bus_setup: | ||
629 | /* even if the device was up, it could not be recovered, so we | ||
630 | * mark it as down. */ | ||
631 | i2400m->updown = 0; | ||
632 | wmb(); /* see i2400m->updown's documentation */ | ||
633 | mutex_unlock(&i2400m->init_mutex); | ||
634 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | ||
635 | return result; | ||
636 | } | ||
637 | EXPORT_SYMBOL_GPL(i2400m_post_reset); | ||
638 | |||
639 | |||
640 | /* | ||
527 | * The device has rebooted; fix up the device and the driver | 641 | * The device has rebooted; fix up the device and the driver |
528 | * | 642 | * |
529 | * Tear down the driver communication with the device, reload the | 643 | * Tear down the driver communication with the device, reload the |
@@ -542,56 +656,69 @@ void i2400m_dev_stop(struct i2400m *i2400m) | |||
542 | * _stop()], don't do anything, let it fail and handle it. | 656 | * _stop()], don't do anything, let it fail and handle it. |
543 | * | 657 | * |
544 | * This function is ran always in a thread context | 658 | * This function is ran always in a thread context |
659 | * | ||
660 | * This function gets passed, as payload to i2400m_work() a 'const | ||
661 | * char *' ptr with a "reason" why the reset happened (for messages). | ||
545 | */ | 662 | */ |
546 | static | 663 | static |
547 | void __i2400m_dev_reset_handle(struct work_struct *ws) | 664 | void __i2400m_dev_reset_handle(struct work_struct *ws) |
548 | { | 665 | { |
549 | int result; | 666 | int result; |
550 | struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); | 667 | struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); |
668 | const char *reason; | ||
551 | struct i2400m *i2400m = iw->i2400m; | 669 | struct i2400m *i2400m = iw->i2400m; |
552 | struct device *dev = i2400m_dev(i2400m); | 670 | struct device *dev = i2400m_dev(i2400m); |
553 | enum wimax_st wimax_state; | ||
554 | struct i2400m_reset_ctx *ctx = i2400m->reset_ctx; | 671 | struct i2400m_reset_ctx *ctx = i2400m->reset_ctx; |
555 | 672 | ||
556 | d_fnstart(3, dev, "(ws %p i2400m %p)\n", ws, i2400m); | 673 | if (WARN_ON(iw->pl_size != sizeof(reason))) |
674 | reason = "SW BUG: reason n/a"; | ||
675 | else | ||
676 | memcpy(&reason, iw->pl, sizeof(reason)); | ||
677 | |||
678 | d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason); | ||
679 | |||
557 | result = 0; | 680 | result = 0; |
558 | if (mutex_trylock(&i2400m->init_mutex) == 0) { | 681 | if (mutex_trylock(&i2400m->init_mutex) == 0) { |
559 | /* We are still in i2400m_dev_start() [let it fail] or | 682 | /* We are still in i2400m_dev_start() [let it fail] or |
560 | * i2400m_dev_stop() [we are shutting down anyway, so | 683 | * i2400m_dev_stop() [we are shutting down anyway, so |
561 | * ignore it] or we are resetting somewhere else. */ | 684 | * ignore it] or we are resetting somewhere else. */ |
562 | dev_err(dev, "device rebooted\n"); | 685 | dev_err(dev, "device rebooted somewhere else?\n"); |
563 | i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); | 686 | i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); |
564 | complete(&i2400m->msg_completion); | 687 | complete(&i2400m->msg_completion); |
565 | goto out; | 688 | goto out; |
566 | } | 689 | } |
567 | wimax_state = wimax_state_get(&i2400m->wimax_dev); | 690 | if (i2400m->updown == 0) { |
568 | if (wimax_state < WIMAX_ST_UNINITIALIZED) { | 691 | dev_info(dev, "%s: device is down, doing nothing\n", reason); |
569 | dev_info(dev, "device rebooted: it is down, ignoring\n"); | 692 | goto out_unlock; |
570 | goto out_unlock; /* ifconfig up/down wasn't called */ | ||
571 | } | 693 | } |
572 | dev_err(dev, "device rebooted: reinitializing driver\n"); | 694 | dev_err(dev, "%s: reinitializing driver\n", reason); |
573 | __i2400m_dev_stop(i2400m); | 695 | __i2400m_dev_stop(i2400m); |
574 | i2400m->updown = 0; | ||
575 | result = __i2400m_dev_start(i2400m, | 696 | result = __i2400m_dev_start(i2400m, |
576 | I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); | 697 | I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); |
577 | if (result < 0) { | 698 | if (result < 0) { |
578 | dev_err(dev, "device reboot: cannot start the device: %d\n", | 699 | i2400m->updown = 0; |
579 | result); | 700 | wmb(); /* see i2400m->updown's documentation */ |
580 | result = i2400m->bus_reset(i2400m, I2400M_RT_BUS); | 701 | dev_err(dev, "%s: cannot start the device: %d\n", |
581 | if (result >= 0) | 702 | reason, result); |
582 | result = -ENODEV; | 703 | result = -EUCLEAN; |
583 | } else | 704 | } |
584 | i2400m->updown = 1; | ||
585 | out_unlock: | 705 | out_unlock: |
586 | if (i2400m->reset_ctx) { | 706 | if (i2400m->reset_ctx) { |
587 | ctx->result = result; | 707 | ctx->result = result; |
588 | complete(&ctx->completion); | 708 | complete(&ctx->completion); |
589 | } | 709 | } |
590 | mutex_unlock(&i2400m->init_mutex); | 710 | mutex_unlock(&i2400m->init_mutex); |
711 | if (result == -EUCLEAN) { | ||
712 | /* ops, need to clean up [w/ init_mutex not held] */ | ||
713 | result = i2400m_reset(i2400m, I2400M_RT_BUS); | ||
714 | if (result >= 0) | ||
715 | result = -ENODEV; | ||
716 | } | ||
591 | out: | 717 | out: |
592 | i2400m_put(i2400m); | 718 | i2400m_put(i2400m); |
593 | kfree(iw); | 719 | kfree(iw); |
594 | d_fnend(3, dev, "(ws %p i2400m %p) = void\n", ws, i2400m); | 720 | d_fnend(3, dev, "(ws %p i2400m %p reason %s) = void\n", |
721 | ws, i2400m, reason); | ||
595 | return; | 722 | return; |
596 | } | 723 | } |
597 | 724 | ||
@@ -608,16 +735,104 @@ out: | |||
608 | * reinitializing the driver to handle the reset, calling into the | 735 | * reinitializing the driver to handle the reset, calling into the |
609 | * bus-specific functions ops as needed. | 736 | * bus-specific functions ops as needed. |
610 | */ | 737 | */ |
611 | int i2400m_dev_reset_handle(struct i2400m *i2400m) | 738 | int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason) |
612 | { | 739 | { |
613 | i2400m->boot_mode = 1; | 740 | i2400m->boot_mode = 1; |
614 | wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ | 741 | wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ |
615 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, | 742 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, |
616 | GFP_ATOMIC); | 743 | GFP_ATOMIC, &reason, sizeof(reason)); |
617 | } | 744 | } |
618 | EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); | 745 | EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); |
619 | 746 | ||
620 | 747 | ||
748 | /* | ||
749 | * Alloc the command and ack buffers for boot mode | ||
750 | * | ||
751 | * Get the buffers needed to deal with boot mode messages. These | ||
752 | * buffers need to be allocated before the sdio recieve irq is setup. | ||
753 | */ | ||
754 | static | ||
755 | int i2400m_bm_buf_alloc(struct i2400m *i2400m) | ||
756 | { | ||
757 | int result; | ||
758 | |||
759 | result = -ENOMEM; | ||
760 | i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL); | ||
761 | if (i2400m->bm_cmd_buf == NULL) | ||
762 | goto error_bm_cmd_kzalloc; | ||
763 | i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL); | ||
764 | if (i2400m->bm_ack_buf == NULL) | ||
765 | goto error_bm_ack_buf_kzalloc; | ||
766 | return 0; | ||
767 | |||
768 | error_bm_ack_buf_kzalloc: | ||
769 | kfree(i2400m->bm_cmd_buf); | ||
770 | error_bm_cmd_kzalloc: | ||
771 | return result; | ||
772 | } | ||
773 | |||
774 | |||
775 | /* | ||
776 | * Free boot mode command and ack buffers. | ||
777 | */ | ||
778 | static | ||
779 | void i2400m_bm_buf_free(struct i2400m *i2400m) | ||
780 | { | ||
781 | kfree(i2400m->bm_ack_buf); | ||
782 | kfree(i2400m->bm_cmd_buf); | ||
783 | } | ||
784 | |||
785 | |||
786 | /** | ||
787 | * i2400m_init - Initialize a 'struct i2400m' from all zeroes | ||
788 | * | ||
789 | * This is a bus-generic API call. | ||
790 | */ | ||
791 | void i2400m_init(struct i2400m *i2400m) | ||
792 | { | ||
793 | wimax_dev_init(&i2400m->wimax_dev); | ||
794 | |||
795 | i2400m->boot_mode = 1; | ||
796 | i2400m->rx_reorder = 1; | ||
797 | init_waitqueue_head(&i2400m->state_wq); | ||
798 | |||
799 | spin_lock_init(&i2400m->tx_lock); | ||
800 | i2400m->tx_pl_min = UINT_MAX; | ||
801 | i2400m->tx_size_min = UINT_MAX; | ||
802 | |||
803 | spin_lock_init(&i2400m->rx_lock); | ||
804 | i2400m->rx_pl_min = UINT_MAX; | ||
805 | i2400m->rx_size_min = UINT_MAX; | ||
806 | INIT_LIST_HEAD(&i2400m->rx_reports); | ||
807 | INIT_WORK(&i2400m->rx_report_ws, i2400m_report_hook_work); | ||
808 | |||
809 | mutex_init(&i2400m->msg_mutex); | ||
810 | init_completion(&i2400m->msg_completion); | ||
811 | |||
812 | mutex_init(&i2400m->init_mutex); | ||
813 | /* wake_tx_ws is initialized in i2400m_tx_setup() */ | ||
814 | } | ||
815 | EXPORT_SYMBOL_GPL(i2400m_init); | ||
816 | |||
817 | |||
818 | int i2400m_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) | ||
819 | { | ||
820 | struct net_device *net_dev = i2400m->wimax_dev.net_dev; | ||
821 | |||
822 | /* | ||
823 | * Make sure we stop TXs and down the carrier before | ||
824 | * resetting; this is needed to avoid things like | ||
825 | * i2400m_wake_tx() scheduling stuff in parallel. | ||
826 | */ | ||
827 | if (net_dev->reg_state == NETREG_REGISTERED) { | ||
828 | netif_tx_disable(net_dev); | ||
829 | netif_carrier_off(net_dev); | ||
830 | } | ||
831 | return i2400m->bus_reset(i2400m, rt); | ||
832 | } | ||
833 | EXPORT_SYMBOL_GPL(i2400m_reset); | ||
834 | |||
835 | |||
621 | /** | 836 | /** |
622 | * i2400m_setup - bus-generic setup function for the i2400m device | 837 | * i2400m_setup - bus-generic setup function for the i2400m device |
623 | * | 838 | * |
@@ -625,13 +840,9 @@ EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); | |||
625 | * | 840 | * |
626 | * Returns: 0 if ok, < 0 errno code on error. | 841 | * Returns: 0 if ok, < 0 errno code on error. |
627 | * | 842 | * |
628 | * Initializes the bus-generic parts of the i2400m driver; the | 843 | * Sets up basic device comunication infrastructure, boots the ROM to |
629 | * bus-specific parts have been initialized, function pointers filled | 844 | * read the MAC address, registers with the WiMAX and network stacks |
630 | * out by the bus-specific probe function. | 845 | * and then brings up the device. |
631 | * | ||
632 | * As well, this registers the WiMAX and net device nodes. Once this | ||
633 | * function returns, the device is operative and has to be ready to | ||
634 | * receive and send network traffic and WiMAX control operations. | ||
635 | */ | 846 | */ |
636 | int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | 847 | int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) |
637 | { | 848 | { |
@@ -645,16 +856,21 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
645 | snprintf(wimax_dev->name, sizeof(wimax_dev->name), | 856 | snprintf(wimax_dev->name, sizeof(wimax_dev->name), |
646 | "i2400m-%s:%s", dev->bus->name, dev_name(dev)); | 857 | "i2400m-%s:%s", dev->bus->name, dev_name(dev)); |
647 | 858 | ||
648 | i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL); | 859 | result = i2400m_bm_buf_alloc(i2400m); |
649 | if (i2400m->bm_cmd_buf == NULL) { | 860 | if (result < 0) { |
650 | dev_err(dev, "cannot allocate USB command buffer\n"); | 861 | dev_err(dev, "cannot allocate bootmode scratch buffers\n"); |
651 | goto error_bm_cmd_kzalloc; | 862 | goto error_bm_buf_alloc; |
652 | } | 863 | } |
653 | i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL); | 864 | |
654 | if (i2400m->bm_ack_buf == NULL) { | 865 | if (i2400m->bus_setup) { |
655 | dev_err(dev, "cannot allocate USB ack buffer\n"); | 866 | result = i2400m->bus_setup(i2400m); |
656 | goto error_bm_ack_buf_kzalloc; | 867 | if (result < 0) { |
868 | dev_err(dev, "bus-specific setup failed: %d\n", | ||
869 | result); | ||
870 | goto error_bus_setup; | ||
871 | } | ||
657 | } | 872 | } |
873 | |||
658 | result = i2400m_bootrom_init(i2400m, bm_flags); | 874 | result = i2400m_bootrom_init(i2400m, bm_flags); |
659 | if (result < 0) { | 875 | if (result < 0) { |
660 | dev_err(dev, "read mac addr: bootrom init " | 876 | dev_err(dev, "read mac addr: bootrom init " |
@@ -666,6 +882,9 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
666 | goto error_read_mac_addr; | 882 | goto error_read_mac_addr; |
667 | random_ether_addr(i2400m->src_mac_addr); | 883 | random_ether_addr(i2400m->src_mac_addr); |
668 | 884 | ||
885 | i2400m->pm_notifier.notifier_call = i2400m_pm_notifier; | ||
886 | register_pm_notifier(&i2400m->pm_notifier); | ||
887 | |||
669 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | 888 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ |
670 | if (result < 0) { | 889 | if (result < 0) { |
671 | dev_err(dev, "cannot register i2400m network device: %d\n", | 890 | dev_err(dev, "cannot register i2400m network device: %d\n", |
@@ -674,18 +893,13 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
674 | } | 893 | } |
675 | netif_carrier_off(net_dev); | 894 | netif_carrier_off(net_dev); |
676 | 895 | ||
677 | result = i2400m_dev_start(i2400m, bm_flags); | ||
678 | if (result < 0) | ||
679 | goto error_dev_start; | ||
680 | |||
681 | i2400m->wimax_dev.op_msg_from_user = i2400m_op_msg_from_user; | 896 | i2400m->wimax_dev.op_msg_from_user = i2400m_op_msg_from_user; |
682 | i2400m->wimax_dev.op_rfkill_sw_toggle = i2400m_op_rfkill_sw_toggle; | 897 | i2400m->wimax_dev.op_rfkill_sw_toggle = i2400m_op_rfkill_sw_toggle; |
683 | i2400m->wimax_dev.op_reset = i2400m_op_reset; | 898 | i2400m->wimax_dev.op_reset = i2400m_op_reset; |
899 | |||
684 | result = wimax_dev_add(&i2400m->wimax_dev, net_dev); | 900 | result = wimax_dev_add(&i2400m->wimax_dev, net_dev); |
685 | if (result < 0) | 901 | if (result < 0) |
686 | goto error_wimax_dev_add; | 902 | goto error_wimax_dev_add; |
687 | /* User space needs to do some init stuff */ | ||
688 | wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED); | ||
689 | 903 | ||
690 | /* Now setup all that requires a registered net and wimax device. */ | 904 | /* Now setup all that requires a registered net and wimax device. */ |
691 | result = sysfs_create_group(&net_dev->dev.kobj, &i2400m_dev_attr_group); | 905 | result = sysfs_create_group(&net_dev->dev.kobj, &i2400m_dev_attr_group); |
@@ -693,30 +907,37 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
693 | dev_err(dev, "cannot setup i2400m's sysfs: %d\n", result); | 907 | dev_err(dev, "cannot setup i2400m's sysfs: %d\n", result); |
694 | goto error_sysfs_setup; | 908 | goto error_sysfs_setup; |
695 | } | 909 | } |
910 | |||
696 | result = i2400m_debugfs_add(i2400m); | 911 | result = i2400m_debugfs_add(i2400m); |
697 | if (result < 0) { | 912 | if (result < 0) { |
698 | dev_err(dev, "cannot setup i2400m's debugfs: %d\n", result); | 913 | dev_err(dev, "cannot setup i2400m's debugfs: %d\n", result); |
699 | goto error_debugfs_setup; | 914 | goto error_debugfs_setup; |
700 | } | 915 | } |
916 | |||
917 | result = i2400m_dev_start(i2400m, bm_flags); | ||
918 | if (result < 0) | ||
919 | goto error_dev_start; | ||
701 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | 920 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); |
702 | return result; | 921 | return result; |
703 | 922 | ||
923 | error_dev_start: | ||
924 | i2400m_debugfs_rm(i2400m); | ||
704 | error_debugfs_setup: | 925 | error_debugfs_setup: |
705 | sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, | 926 | sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, |
706 | &i2400m_dev_attr_group); | 927 | &i2400m_dev_attr_group); |
707 | error_sysfs_setup: | 928 | error_sysfs_setup: |
708 | wimax_dev_rm(&i2400m->wimax_dev); | 929 | wimax_dev_rm(&i2400m->wimax_dev); |
709 | error_wimax_dev_add: | 930 | error_wimax_dev_add: |
710 | i2400m_dev_stop(i2400m); | ||
711 | error_dev_start: | ||
712 | unregister_netdev(net_dev); | 931 | unregister_netdev(net_dev); |
713 | error_register_netdev: | 932 | error_register_netdev: |
933 | unregister_pm_notifier(&i2400m->pm_notifier); | ||
714 | error_read_mac_addr: | 934 | error_read_mac_addr: |
715 | error_bootrom_init: | 935 | error_bootrom_init: |
716 | kfree(i2400m->bm_ack_buf); | 936 | if (i2400m->bus_release) |
717 | error_bm_ack_buf_kzalloc: | 937 | i2400m->bus_release(i2400m); |
718 | kfree(i2400m->bm_cmd_buf); | 938 | error_bus_setup: |
719 | error_bm_cmd_kzalloc: | 939 | i2400m_bm_buf_free(i2400m); |
940 | error_bm_buf_alloc: | ||
720 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | 941 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); |
721 | return result; | 942 | return result; |
722 | } | 943 | } |
@@ -735,14 +956,17 @@ void i2400m_release(struct i2400m *i2400m) | |||
735 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 956 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
736 | netif_stop_queue(i2400m->wimax_dev.net_dev); | 957 | netif_stop_queue(i2400m->wimax_dev.net_dev); |
737 | 958 | ||
959 | i2400m_dev_stop(i2400m); | ||
960 | |||
738 | i2400m_debugfs_rm(i2400m); | 961 | i2400m_debugfs_rm(i2400m); |
739 | sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, | 962 | sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, |
740 | &i2400m_dev_attr_group); | 963 | &i2400m_dev_attr_group); |
741 | wimax_dev_rm(&i2400m->wimax_dev); | 964 | wimax_dev_rm(&i2400m->wimax_dev); |
742 | i2400m_dev_stop(i2400m); | ||
743 | unregister_netdev(i2400m->wimax_dev.net_dev); | 965 | unregister_netdev(i2400m->wimax_dev.net_dev); |
744 | kfree(i2400m->bm_ack_buf); | 966 | unregister_pm_notifier(&i2400m->pm_notifier); |
745 | kfree(i2400m->bm_cmd_buf); | 967 | if (i2400m->bus_release) |
968 | i2400m->bus_release(i2400m); | ||
969 | i2400m_bm_buf_free(i2400m); | ||
746 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 970 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
747 | } | 971 | } |
748 | EXPORT_SYMBOL_GPL(i2400m_release); | 972 | EXPORT_SYMBOL_GPL(i2400m_release); |
@@ -759,6 +983,7 @@ struct d_level D_LEVEL[] = { | |||
759 | D_SUBMODULE_DEFINE(netdev), | 983 | D_SUBMODULE_DEFINE(netdev), |
760 | D_SUBMODULE_DEFINE(rfkill), | 984 | D_SUBMODULE_DEFINE(rfkill), |
761 | D_SUBMODULE_DEFINE(rx), | 985 | D_SUBMODULE_DEFINE(rx), |
986 | D_SUBMODULE_DEFINE(sysfs), | ||
762 | D_SUBMODULE_DEFINE(tx), | 987 | D_SUBMODULE_DEFINE(tx), |
763 | }; | 988 | }; |
764 | size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); | 989 | size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); |
@@ -767,7 +992,9 @@ size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); | |||
767 | static | 992 | static |
768 | int __init i2400m_driver_init(void) | 993 | int __init i2400m_driver_init(void) |
769 | { | 994 | { |
770 | return 0; | 995 | d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400m_debug_params, |
996 | "i2400m.debug"); | ||
997 | return i2400m_barker_db_init(i2400m_barkers_params); | ||
771 | } | 998 | } |
772 | module_init(i2400m_driver_init); | 999 | module_init(i2400m_driver_init); |
773 | 1000 | ||
@@ -776,6 +1003,7 @@ void __exit i2400m_driver_exit(void) | |||
776 | { | 1003 | { |
777 | /* for scheds i2400m_dev_reset_handle() */ | 1004 | /* for scheds i2400m_dev_reset_handle() */ |
778 | flush_scheduled_work(); | 1005 | flush_scheduled_work(); |
1006 | i2400m_barker_db_exit(); | ||
779 | return; | 1007 | return; |
780 | } | 1008 | } |
781 | module_exit(i2400m_driver_exit); | 1009 | module_exit(i2400m_driver_exit); |
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index e81750e54452..64cdfeb299ca 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c | |||
@@ -40,11 +40,9 @@ | |||
40 | * | 40 | * |
41 | * THE PROCEDURE | 41 | * THE PROCEDURE |
42 | * | 42 | * |
43 | * (this is decribed for USB, but for SDIO is similar) | 43 | * The 2400m and derived devices work in two modes: boot-mode or |
44 | * | 44 | * normal mode. In boot mode we can execute only a handful of commands |
45 | * The 2400m works in two modes: boot-mode or normal mode. In boot | 45 | * targeted at uploading the firmware and launching it. |
46 | * mode we can execute only a handful of commands targeted at | ||
47 | * uploading the firmware and launching it. | ||
48 | * | 46 | * |
49 | * The 2400m enters boot mode when it is first connected to the | 47 | * The 2400m enters boot mode when it is first connected to the |
50 | * system, when it crashes and when you ask it to reboot. There are | 48 | * system, when it crashes and when you ask it to reboot. There are |
@@ -52,18 +50,26 @@ | |||
52 | * firmwares signed with a certain private key, non-signed takes any | 50 | * firmwares signed with a certain private key, non-signed takes any |
53 | * firmware. Normal hardware takes only signed firmware. | 51 | * firmware. Normal hardware takes only signed firmware. |
54 | * | 52 | * |
55 | * Upon entrance to boot mode, the device sends a few zero length | 53 | * On boot mode, in USB, we write to the device using the bulk out |
56 | * packets (ZLPs) on the notification endpoint, then a reboot barker | 54 | * endpoint and read from it in the notification endpoint. In SDIO we |
57 | * (4 le32 words with value I2400M_{S,N}BOOT_BARKER). We ack it by | 55 | * talk to it via the write address and read from the read address. |
58 | * sending the same barker on the bulk out endpoint. The device acks | 56 | * |
59 | * with a reboot ack barker (4 le32 words with value 0xfeedbabe) and | 57 | * Upon entrance to boot mode, the device sends (preceeded with a few |
60 | * then the device is fully rebooted. At this point we can upload the | 58 | * zero length packets (ZLPs) on the notification endpoint in USB) a |
61 | * firmware. | 59 | * reboot barker (4 le32 words with the same value). We ack it by |
60 | * sending the same barker to the device. The device acks with a | ||
61 | * reboot ack barker (4 le32 words with value I2400M_ACK_BARKER) and | ||
62 | * then is fully booted. At this point we can upload the firmware. | ||
63 | * | ||
64 | * Note that different iterations of the device and EEPROM | ||
65 | * configurations will send different [re]boot barkers; these are | ||
66 | * collected in i2400m_barker_db along with the firmware | ||
67 | * characteristics they require. | ||
62 | * | 68 | * |
63 | * This process is accomplished by the i2400m_bootrom_init() | 69 | * This process is accomplished by the i2400m_bootrom_init() |
64 | * function. All the device interaction happens through the | 70 | * function. All the device interaction happens through the |
65 | * i2400m_bm_cmd() [boot mode command]. Special return values will | 71 | * i2400m_bm_cmd() [boot mode command]. Special return values will |
66 | * indicate if the device resets. | 72 | * indicate if the device did reset during the process. |
67 | * | 73 | * |
68 | * After this, we read the MAC address and then (if needed) | 74 | * After this, we read the MAC address and then (if needed) |
69 | * reinitialize the device. We need to read it ahead of time because | 75 | * reinitialize the device. We need to read it ahead of time because |
@@ -72,11 +78,11 @@ | |||
72 | * | 78 | * |
73 | * We can then upload the firmware file. The file is composed of a BCF | 79 | * We can then upload the firmware file. The file is composed of a BCF |
74 | * header (basic data, keys and signatures) and a list of write | 80 | * header (basic data, keys and signatures) and a list of write |
75 | * commands and payloads. We first upload the header | 81 | * commands and payloads. Optionally more BCF headers might follow the |
76 | * [i2400m_dnload_init()] and then pass the commands and payloads | 82 | * main payload. We first upload the header [i2400m_dnload_init()] and |
77 | * verbatim to the i2400m_bm_cmd() function | 83 | * then pass the commands and payloads verbatim to the i2400m_bm_cmd() |
78 | * [i2400m_dnload_bcf()]. Then we tell the device to jump to the new | 84 | * function [i2400m_dnload_bcf()]. Then we tell the device to jump to |
79 | * firmware [i2400m_dnload_finalize()]. | 85 | * the new firmware [i2400m_dnload_finalize()]. |
80 | * | 86 | * |
81 | * Once firmware is uploaded, we are good to go :) | 87 | * Once firmware is uploaded, we are good to go :) |
82 | * | 88 | * |
@@ -99,18 +105,32 @@ | |||
99 | * read an acknolwedgement from it (or an asynchronous notification) | 105 | * read an acknolwedgement from it (or an asynchronous notification) |
100 | * from it. | 106 | * from it. |
101 | * | 107 | * |
108 | * FIRMWARE LOADING | ||
109 | * | ||
110 | * Note that in some cases, we can't just load a firmware file (for | ||
111 | * example, when resuming). For that, we might cache the firmware | ||
112 | * file. Thus, when doing the bootstrap, if there is a cache firmware | ||
113 | * file, it is used; if not, loading from disk is attempted. | ||
114 | * | ||
102 | * ROADMAP | 115 | * ROADMAP |
103 | * | 116 | * |
117 | * i2400m_barker_db_init Called by i2400m_driver_init() | ||
118 | * i2400m_barker_db_add | ||
119 | * | ||
120 | * i2400m_barker_db_exit Called by i2400m_driver_exit() | ||
121 | * | ||
104 | * i2400m_dev_bootstrap Called by __i2400m_dev_start() | 122 | * i2400m_dev_bootstrap Called by __i2400m_dev_start() |
105 | * request_firmware | 123 | * request_firmware |
106 | * i2400m_fw_check | 124 | * i2400m_fw_bootstrap |
107 | * i2400m_fw_dnload | 125 | * i2400m_fw_check |
126 | * i2400m_fw_hdr_check | ||
127 | * i2400m_fw_dnload | ||
108 | * release_firmware | 128 | * release_firmware |
109 | * | 129 | * |
110 | * i2400m_fw_dnload | 130 | * i2400m_fw_dnload |
111 | * i2400m_bootrom_init | 131 | * i2400m_bootrom_init |
112 | * i2400m_bm_cmd | 132 | * i2400m_bm_cmd |
113 | * i2400m->bus_reset | 133 | * i2400m_reset |
114 | * i2400m_dnload_init | 134 | * i2400m_dnload_init |
115 | * i2400m_dnload_init_signed | 135 | * i2400m_dnload_init_signed |
116 | * i2400m_dnload_init_nonsigned | 136 | * i2400m_dnload_init_nonsigned |
@@ -125,9 +145,14 @@ | |||
125 | * i2400m->bus_bm_cmd_send() | 145 | * i2400m->bus_bm_cmd_send() |
126 | * i2400m->bus_bm_wait_for_ack | 146 | * i2400m->bus_bm_wait_for_ack |
127 | * __i2400m_bm_ack_verify | 147 | * __i2400m_bm_ack_verify |
148 | * i2400m_is_boot_barker | ||
128 | * | 149 | * |
129 | * i2400m_bm_cmd_prepare Used by bus-drivers to prep | 150 | * i2400m_bm_cmd_prepare Used by bus-drivers to prep |
130 | * commands before sending | 151 | * commands before sending |
152 | * | ||
153 | * i2400m_pm_notifier Called on Power Management events | ||
154 | * i2400m_fw_cache | ||
155 | * i2400m_fw_uncache | ||
131 | */ | 156 | */ |
132 | #include <linux/firmware.h> | 157 | #include <linux/firmware.h> |
133 | #include <linux/sched.h> | 158 | #include <linux/sched.h> |
@@ -175,6 +200,240 @@ EXPORT_SYMBOL_GPL(i2400m_bm_cmd_prepare); | |||
175 | 200 | ||
176 | 201 | ||
177 | /* | 202 | /* |
203 | * Database of known barkers. | ||
204 | * | ||
205 | * A barker is what the device sends indicating he is ready to be | ||
206 | * bootloaded. Different versions of the device will send different | ||
207 | * barkers. Depending on the barker, it might mean the device wants | ||
208 | * some kind of firmware or the other. | ||
209 | */ | ||
210 | static struct i2400m_barker_db { | ||
211 | __le32 data[4]; | ||
212 | } *i2400m_barker_db; | ||
213 | static size_t i2400m_barker_db_used, i2400m_barker_db_size; | ||
214 | |||
215 | |||
216 | static | ||
217 | int i2400m_zrealloc_2x(void **ptr, size_t *_count, size_t el_size, | ||
218 | gfp_t gfp_flags) | ||
219 | { | ||
220 | size_t old_count = *_count, | ||
221 | new_count = old_count ? 2 * old_count : 2, | ||
222 | old_size = el_size * old_count, | ||
223 | new_size = el_size * new_count; | ||
224 | void *nptr = krealloc(*ptr, new_size, gfp_flags); | ||
225 | if (nptr) { | ||
226 | /* zero the other half or the whole thing if old_count | ||
227 | * was zero */ | ||
228 | if (old_size == 0) | ||
229 | memset(nptr, 0, new_size); | ||
230 | else | ||
231 | memset(nptr + old_size, 0, old_size); | ||
232 | *_count = new_count; | ||
233 | *ptr = nptr; | ||
234 | return 0; | ||
235 | } else | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | |||
239 | |||
240 | /* | ||
241 | * Add a barker to the database | ||
242 | * | ||
243 | * This cannot used outside of this module and only at at module_init | ||
244 | * time. This is to avoid the need to do locking. | ||
245 | */ | ||
246 | static | ||
247 | int i2400m_barker_db_add(u32 barker_id) | ||
248 | { | ||
249 | int result; | ||
250 | |||
251 | struct i2400m_barker_db *barker; | ||
252 | if (i2400m_barker_db_used >= i2400m_barker_db_size) { | ||
253 | result = i2400m_zrealloc_2x( | ||
254 | (void **) &i2400m_barker_db, &i2400m_barker_db_size, | ||
255 | sizeof(i2400m_barker_db[0]), GFP_KERNEL); | ||
256 | if (result < 0) | ||
257 | return result; | ||
258 | } | ||
259 | barker = i2400m_barker_db + i2400m_barker_db_used++; | ||
260 | barker->data[0] = le32_to_cpu(barker_id); | ||
261 | barker->data[1] = le32_to_cpu(barker_id); | ||
262 | barker->data[2] = le32_to_cpu(barker_id); | ||
263 | barker->data[3] = le32_to_cpu(barker_id); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | |||
268 | void i2400m_barker_db_exit(void) | ||
269 | { | ||
270 | kfree(i2400m_barker_db); | ||
271 | i2400m_barker_db = NULL; | ||
272 | i2400m_barker_db_size = 0; | ||
273 | i2400m_barker_db_used = 0; | ||
274 | } | ||
275 | |||
276 | |||
277 | /* | ||
278 | * Helper function to add all the known stable barkers to the barker | ||
279 | * database. | ||
280 | */ | ||
281 | static | ||
282 | int i2400m_barker_db_known_barkers(void) | ||
283 | { | ||
284 | int result; | ||
285 | |||
286 | result = i2400m_barker_db_add(I2400M_NBOOT_BARKER); | ||
287 | if (result < 0) | ||
288 | goto error_add; | ||
289 | result = i2400m_barker_db_add(I2400M_SBOOT_BARKER); | ||
290 | if (result < 0) | ||
291 | goto error_add; | ||
292 | result = i2400m_barker_db_add(I2400M_SBOOT_BARKER_6050); | ||
293 | if (result < 0) | ||
294 | goto error_add; | ||
295 | error_add: | ||
296 | return result; | ||
297 | } | ||
298 | |||
299 | |||
300 | /* | ||
301 | * Initialize the barker database | ||
302 | * | ||
303 | * This can only be used from the module_init function for this | ||
304 | * module; this is to avoid the need to do locking. | ||
305 | * | ||
306 | * @options: command line argument with extra barkers to | ||
307 | * recognize. This is a comma-separated list of 32-bit hex | ||
308 | * numbers. They are appended to the existing list. Setting 0 | ||
309 | * cleans the existing list and starts a new one. | ||
310 | */ | ||
311 | int i2400m_barker_db_init(const char *_options) | ||
312 | { | ||
313 | int result; | ||
314 | char *options = NULL, *options_orig, *token; | ||
315 | |||
316 | i2400m_barker_db = NULL; | ||
317 | i2400m_barker_db_size = 0; | ||
318 | i2400m_barker_db_used = 0; | ||
319 | |||
320 | result = i2400m_barker_db_known_barkers(); | ||
321 | if (result < 0) | ||
322 | goto error_add; | ||
323 | /* parse command line options from i2400m.barkers */ | ||
324 | if (_options != NULL) { | ||
325 | unsigned barker; | ||
326 | |||
327 | options_orig = kstrdup(_options, GFP_KERNEL); | ||
328 | if (options_orig == NULL) | ||
329 | goto error_parse; | ||
330 | options = options_orig; | ||
331 | |||
332 | while ((token = strsep(&options, ",")) != NULL) { | ||
333 | if (*token == '\0') /* eat joint commas */ | ||
334 | continue; | ||
335 | if (sscanf(token, "%x", &barker) != 1 | ||
336 | || barker > 0xffffffff) { | ||
337 | printk(KERN_ERR "%s: can't recognize " | ||
338 | "i2400m.barkers value '%s' as " | ||
339 | "a 32-bit number\n", | ||
340 | __func__, token); | ||
341 | result = -EINVAL; | ||
342 | goto error_parse; | ||
343 | } | ||
344 | if (barker == 0) { | ||
345 | /* clean list and start new */ | ||
346 | i2400m_barker_db_exit(); | ||
347 | continue; | ||
348 | } | ||
349 | result = i2400m_barker_db_add(barker); | ||
350 | if (result < 0) | ||
351 | goto error_add; | ||
352 | } | ||
353 | kfree(options_orig); | ||
354 | } | ||
355 | return 0; | ||
356 | |||
357 | error_parse: | ||
358 | error_add: | ||
359 | kfree(i2400m_barker_db); | ||
360 | return result; | ||
361 | } | ||
362 | |||
363 | |||
364 | /* | ||
365 | * Recognize a boot barker | ||
366 | * | ||
367 | * @buf: buffer where the boot barker. | ||
368 | * @buf_size: size of the buffer (has to be 16 bytes). It is passed | ||
369 | * here so the function can check it for the caller. | ||
370 | * | ||
371 | * Note that as a side effect, upon identifying the obtained boot | ||
372 | * barker, this function will set i2400m->barker to point to the right | ||
373 | * barker database entry. Subsequent calls to the function will result | ||
374 | * in verifying that the same type of boot barker is returned when the | ||
375 | * device [re]boots (as long as the same device instance is used). | ||
376 | * | ||
377 | * Return: 0 if @buf matches a known boot barker. -ENOENT if the | ||
378 | * buffer in @buf doesn't match any boot barker in the database or | ||
379 | * -EILSEQ if the buffer doesn't have the right size. | ||
380 | */ | ||
381 | int i2400m_is_boot_barker(struct i2400m *i2400m, | ||
382 | const void *buf, size_t buf_size) | ||
383 | { | ||
384 | int result; | ||
385 | struct device *dev = i2400m_dev(i2400m); | ||
386 | struct i2400m_barker_db *barker; | ||
387 | int i; | ||
388 | |||
389 | result = -ENOENT; | ||
390 | if (buf_size != sizeof(i2400m_barker_db[i].data)) | ||
391 | return result; | ||
392 | |||
393 | /* Short circuit if we have already discovered the barker | ||
394 | * associated with the device. */ | ||
395 | if (i2400m->barker | ||
396 | && !memcmp(buf, i2400m->barker, sizeof(i2400m->barker->data))) { | ||
397 | unsigned index = (i2400m->barker - i2400m_barker_db) | ||
398 | / sizeof(*i2400m->barker); | ||
399 | d_printf(2, dev, "boot barker cache-confirmed #%u/%08x\n", | ||
400 | index, le32_to_cpu(i2400m->barker->data[0])); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | for (i = 0; i < i2400m_barker_db_used; i++) { | ||
405 | barker = &i2400m_barker_db[i]; | ||
406 | BUILD_BUG_ON(sizeof(barker->data) != 16); | ||
407 | if (memcmp(buf, barker->data, sizeof(barker->data))) | ||
408 | continue; | ||
409 | |||
410 | if (i2400m->barker == NULL) { | ||
411 | i2400m->barker = barker; | ||
412 | d_printf(1, dev, "boot barker set to #%u/%08x\n", | ||
413 | i, le32_to_cpu(barker->data[0])); | ||
414 | if (barker->data[0] == le32_to_cpu(I2400M_NBOOT_BARKER)) | ||
415 | i2400m->sboot = 0; | ||
416 | else | ||
417 | i2400m->sboot = 1; | ||
418 | } else if (i2400m->barker != barker) { | ||
419 | dev_err(dev, "HW inconsistency: device " | ||
420 | "reports a different boot barker " | ||
421 | "than set (from %08x to %08x)\n", | ||
422 | le32_to_cpu(i2400m->barker->data[0]), | ||
423 | le32_to_cpu(barker->data[0])); | ||
424 | result = -EIO; | ||
425 | } else | ||
426 | d_printf(2, dev, "boot barker confirmed #%u/%08x\n", | ||
427 | i, le32_to_cpu(barker->data[0])); | ||
428 | result = 0; | ||
429 | break; | ||
430 | } | ||
431 | return result; | ||
432 | } | ||
433 | EXPORT_SYMBOL_GPL(i2400m_is_boot_barker); | ||
434 | |||
435 | |||
436 | /* | ||
178 | * Verify the ack data received | 437 | * Verify the ack data received |
179 | * | 438 | * |
180 | * Given a reply to a boot mode command, chew it and verify everything | 439 | * Given a reply to a boot mode command, chew it and verify everything |
@@ -204,20 +463,10 @@ ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode, | |||
204 | opcode, ack_size, sizeof(*ack)); | 463 | opcode, ack_size, sizeof(*ack)); |
205 | goto error_ack_short; | 464 | goto error_ack_short; |
206 | } | 465 | } |
207 | if (ack_size == sizeof(i2400m_NBOOT_BARKER) | 466 | result = i2400m_is_boot_barker(i2400m, ack, ack_size); |
208 | && memcmp(ack, i2400m_NBOOT_BARKER, sizeof(*ack)) == 0) { | 467 | if (result >= 0) { |
209 | result = -ERESTARTSYS; | 468 | result = -ERESTARTSYS; |
210 | i2400m->sboot = 0; | 469 | d_printf(6, dev, "boot-mode cmd %d: HW boot barker\n", opcode); |
211 | d_printf(6, dev, "boot-mode cmd %d: " | ||
212 | "HW non-signed boot barker\n", opcode); | ||
213 | goto error_reboot; | ||
214 | } | ||
215 | if (ack_size == sizeof(i2400m_SBOOT_BARKER) | ||
216 | && memcmp(ack, i2400m_SBOOT_BARKER, sizeof(*ack)) == 0) { | ||
217 | result = -ERESTARTSYS; | ||
218 | i2400m->sboot = 1; | ||
219 | d_printf(6, dev, "boot-mode cmd %d: HW signed reboot barker\n", | ||
220 | opcode); | ||
221 | goto error_reboot; | 470 | goto error_reboot; |
222 | } | 471 | } |
223 | if (ack_size == sizeof(i2400m_ACK_BARKER) | 472 | if (ack_size == sizeof(i2400m_ACK_BARKER) |
@@ -343,7 +592,6 @@ ssize_t i2400m_bm_cmd(struct i2400m *i2400m, | |||
343 | BUG_ON(i2400m->boot_mode == 0); | 592 | BUG_ON(i2400m->boot_mode == 0); |
344 | 593 | ||
345 | if (cmd != NULL) { /* send the command */ | 594 | if (cmd != NULL) { /* send the command */ |
346 | memcpy(i2400m->bm_cmd_buf, cmd, cmd_size); | ||
347 | result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags); | 595 | result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags); |
348 | if (result < 0) | 596 | if (result < 0) |
349 | goto error_cmd_send; | 597 | goto error_cmd_send; |
@@ -432,8 +680,8 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, | |||
432 | * Download a BCF file's sections to the device | 680 | * Download a BCF file's sections to the device |
433 | * | 681 | * |
434 | * @i2400m: device descriptor | 682 | * @i2400m: device descriptor |
435 | * @bcf: pointer to firmware data (followed by the payloads). Assumed | 683 | * @bcf: pointer to firmware data (first header followed by the |
436 | * verified and consistent. | 684 | * payloads). Assumed verified and consistent. |
437 | * @bcf_len: length (in bytes) of the @bcf buffer. | 685 | * @bcf_len: length (in bytes) of the @bcf buffer. |
438 | * | 686 | * |
439 | * Returns: < 0 errno code on error or the offset to the jump instruction. | 687 | * Returns: < 0 errno code on error or the offset to the jump instruction. |
@@ -472,14 +720,17 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m, | |||
472 | "downloading section #%zu (@%zu %zu B) to 0x%08x\n", | 720 | "downloading section #%zu (@%zu %zu B) to 0x%08x\n", |
473 | section, offset, sizeof(*bh) + data_size, | 721 | section, offset, sizeof(*bh) + data_size, |
474 | le32_to_cpu(bh->target_addr)); | 722 | le32_to_cpu(bh->target_addr)); |
475 | if (i2400m_brh_get_opcode(bh) == I2400M_BRH_SIGNED_JUMP) { | 723 | /* |
476 | /* Secure boot needs to stop here */ | 724 | * We look for JUMP cmd from the bootmode header, |
477 | d_printf(5, dev, "signed jump found @%zu\n", offset); | 725 | * either I2400M_BRH_SIGNED_JUMP for secure boot |
726 | * or I2400M_BRH_JUMP for unsecure boot, the last chunk | ||
727 | * should be the bootmode header with JUMP cmd. | ||
728 | */ | ||
729 | if (i2400m_brh_get_opcode(bh) == I2400M_BRH_SIGNED_JUMP || | ||
730 | i2400m_brh_get_opcode(bh) == I2400M_BRH_JUMP) { | ||
731 | d_printf(5, dev, "jump found @%zu\n", offset); | ||
478 | break; | 732 | break; |
479 | } | 733 | } |
480 | if (offset + section_size == bcf_len) | ||
481 | /* Non-secure boot stops here */ | ||
482 | break; | ||
483 | if (offset + section_size > bcf_len) { | 734 | if (offset + section_size > bcf_len) { |
484 | dev_err(dev, "fw %s: bad section #%zu, " | 735 | dev_err(dev, "fw %s: bad section #%zu, " |
485 | "end (@%zu) beyond EOF (@%zu)\n", | 736 | "end (@%zu) beyond EOF (@%zu)\n", |
@@ -510,13 +761,30 @@ error_send: | |||
510 | 761 | ||
511 | 762 | ||
512 | /* | 763 | /* |
764 | * Indicate if the device emitted a reboot barker that indicates | ||
765 | * "signed boot" | ||
766 | */ | ||
767 | static | ||
768 | unsigned i2400m_boot_is_signed(struct i2400m *i2400m) | ||
769 | { | ||
770 | return likely(i2400m->sboot); | ||
771 | } | ||
772 | |||
773 | |||
774 | /* | ||
513 | * Do the final steps of uploading firmware | 775 | * Do the final steps of uploading firmware |
514 | * | 776 | * |
777 | * @bcf_hdr: BCF header we are actually using | ||
778 | * @bcf: pointer to the firmware image (which matches the first header | ||
779 | * that is followed by the actual payloads). | ||
780 | * @offset: [byte] offset into @bcf for the command we need to send. | ||
781 | * | ||
515 | * Depending on the boot mode (signed vs non-signed), different | 782 | * Depending on the boot mode (signed vs non-signed), different |
516 | * actions need to be taken. | 783 | * actions need to be taken. |
517 | */ | 784 | */ |
518 | static | 785 | static |
519 | int i2400m_dnload_finalize(struct i2400m *i2400m, | 786 | int i2400m_dnload_finalize(struct i2400m *i2400m, |
787 | const struct i2400m_bcf_hdr *bcf_hdr, | ||
520 | const struct i2400m_bcf_hdr *bcf, size_t offset) | 788 | const struct i2400m_bcf_hdr *bcf, size_t offset) |
521 | { | 789 | { |
522 | int ret = 0; | 790 | int ret = 0; |
@@ -530,10 +798,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, | |||
530 | 798 | ||
531 | d_fnstart(3, dev, "offset %zu\n", offset); | 799 | d_fnstart(3, dev, "offset %zu\n", offset); |
532 | cmd = (void *) bcf + offset; | 800 | cmd = (void *) bcf + offset; |
533 | if (i2400m->sboot == 0) { | 801 | if (i2400m_boot_is_signed(i2400m) == 0) { |
534 | struct i2400m_bootrom_header jump_ack; | 802 | struct i2400m_bootrom_header jump_ack; |
535 | d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", | 803 | d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", |
536 | le32_to_cpu(cmd->target_addr)); | 804 | le32_to_cpu(cmd->target_addr)); |
805 | cmd_buf = i2400m->bm_cmd_buf; | ||
806 | memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); | ||
807 | cmd = &cmd_buf->cmd; | ||
808 | /* now cmd points to the actual bootrom_header in cmd_buf */ | ||
537 | i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); | 809 | i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); |
538 | cmd->data_size = 0; | 810 | cmd->data_size = 0; |
539 | ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), | 811 | ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), |
@@ -544,12 +816,13 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, | |||
544 | cmd_buf = i2400m->bm_cmd_buf; | 816 | cmd_buf = i2400m->bm_cmd_buf; |
545 | memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); | 817 | memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); |
546 | signature_block_offset = | 818 | signature_block_offset = |
547 | sizeof(*bcf) | 819 | sizeof(*bcf_hdr) |
548 | + le32_to_cpu(bcf->key_size) * sizeof(u32) | 820 | + le32_to_cpu(bcf_hdr->key_size) * sizeof(u32) |
549 | + le32_to_cpu(bcf->exponent_size) * sizeof(u32); | 821 | + le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32); |
550 | signature_block_size = | 822 | signature_block_size = |
551 | le32_to_cpu(bcf->modulus_size) * sizeof(u32); | 823 | le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32); |
552 | memcpy(cmd_buf->cmd_pl, (void *) bcf + signature_block_offset, | 824 | memcpy(cmd_buf->cmd_pl, |
825 | (void *) bcf_hdr + signature_block_offset, | ||
553 | signature_block_size); | 826 | signature_block_size); |
554 | ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, | 827 | ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, |
555 | sizeof(cmd_buf->cmd) + signature_block_size, | 828 | sizeof(cmd_buf->cmd) + signature_block_size, |
@@ -565,7 +838,7 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, | |||
565 | * | 838 | * |
566 | * @i2400m: device descriptor | 839 | * @i2400m: device descriptor |
567 | * @flags: | 840 | * @flags: |
568 | * I2400M_BRI_SOFT: a reboot notification has been seen | 841 | * I2400M_BRI_SOFT: a reboot barker has been seen |
569 | * already, so don't wait for it. | 842 | * already, so don't wait for it. |
570 | * | 843 | * |
571 | * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait | 844 | * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait |
@@ -576,17 +849,15 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, | |||
576 | * | 849 | * |
577 | * < 0 errno code on error, 0 if ok. | 850 | * < 0 errno code on error, 0 if ok. |
578 | * | 851 | * |
579 | * i2400m->sboot set to 0 for unsecure boot process, 1 for secure | ||
580 | * boot process. | ||
581 | * | ||
582 | * Description: | 852 | * Description: |
583 | * | 853 | * |
584 | * Tries hard enough to put the device in boot-mode. There are two | 854 | * Tries hard enough to put the device in boot-mode. There are two |
585 | * main phases to this: | 855 | * main phases to this: |
586 | * | 856 | * |
587 | * a. (1) send a reboot command and (2) get a reboot barker | 857 | * a. (1) send a reboot command and (2) get a reboot barker |
588 | * b. (1) ack the reboot sending a reboot barker and (2) getting an | 858 | * |
589 | * ack barker in return | 859 | * b. (1) echo/ack the reboot sending the reboot barker back and (2) |
860 | * getting an ack barker in return | ||
590 | * | 861 | * |
591 | * We want to skip (a) in some cases [soft]. The state machine is | 862 | * We want to skip (a) in some cases [soft]. The state machine is |
592 | * horrible, but it is basically: on each phase, send what has to be | 863 | * horrible, but it is basically: on each phase, send what has to be |
@@ -594,6 +865,16 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, | |||
594 | * have to backtrack and retry, so we keep a max tries counter for | 865 | * have to backtrack and retry, so we keep a max tries counter for |
595 | * that. | 866 | * that. |
596 | * | 867 | * |
868 | * It sucks because we don't know ahead of time which is going to be | ||
869 | * the reboot barker (the device might send different ones depending | ||
870 | * on its EEPROM config) and once the device reboots and waits for the | ||
871 | * echo/ack reboot barker being sent back, it doesn't understand | ||
872 | * anything else. So we can be left at the point where we don't know | ||
873 | * what to send to it -- cold reset and bus reset seem to have little | ||
874 | * effect. So the function iterates (in this case) through all the | ||
875 | * known barkers and tries them all until an ACK is | ||
876 | * received. Otherwise, it gives up. | ||
877 | * | ||
597 | * If we get a timeout after sending a warm reset, we do it again. | 878 | * If we get a timeout after sending a warm reset, we do it again. |
598 | */ | 879 | */ |
599 | int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags) | 880 | int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags) |
@@ -602,10 +883,11 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags) | |||
602 | struct device *dev = i2400m_dev(i2400m); | 883 | struct device *dev = i2400m_dev(i2400m); |
603 | struct i2400m_bootrom_header *cmd; | 884 | struct i2400m_bootrom_header *cmd; |
604 | struct i2400m_bootrom_header ack; | 885 | struct i2400m_bootrom_header ack; |
605 | int count = I2400M_BOOT_RETRIES; | 886 | int count = i2400m->bus_bm_retries; |
606 | int ack_timeout_cnt = 1; | 887 | int ack_timeout_cnt = 1; |
888 | unsigned i; | ||
607 | 889 | ||
608 | BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_NBOOT_BARKER)); | 890 | BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data)); |
609 | BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER)); | 891 | BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER)); |
610 | 892 | ||
611 | d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags); | 893 | d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags); |
@@ -614,27 +896,59 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags) | |||
614 | if (flags & I2400M_BRI_SOFT) | 896 | if (flags & I2400M_BRI_SOFT) |
615 | goto do_reboot_ack; | 897 | goto do_reboot_ack; |
616 | do_reboot: | 898 | do_reboot: |
899 | ack_timeout_cnt = 1; | ||
617 | if (--count < 0) | 900 | if (--count < 0) |
618 | goto error_timeout; | 901 | goto error_timeout; |
619 | d_printf(4, dev, "device reboot: reboot command [%d # left]\n", | 902 | d_printf(4, dev, "device reboot: reboot command [%d # left]\n", |
620 | count); | 903 | count); |
621 | if ((flags & I2400M_BRI_NO_REBOOT) == 0) | 904 | if ((flags & I2400M_BRI_NO_REBOOT) == 0) |
622 | i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 905 | i2400m_reset(i2400m, I2400M_RT_WARM); |
623 | result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack), | 906 | result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack), |
624 | I2400M_BM_CMD_RAW); | 907 | I2400M_BM_CMD_RAW); |
625 | flags &= ~I2400M_BRI_NO_REBOOT; | 908 | flags &= ~I2400M_BRI_NO_REBOOT; |
626 | switch (result) { | 909 | switch (result) { |
627 | case -ERESTARTSYS: | 910 | case -ERESTARTSYS: |
911 | /* | ||
912 | * at this point, i2400m_bm_cmd(), through | ||
913 | * __i2400m_bm_ack_process(), has updated | ||
914 | * i2400m->barker and we are good to go. | ||
915 | */ | ||
628 | d_printf(4, dev, "device reboot: got reboot barker\n"); | 916 | d_printf(4, dev, "device reboot: got reboot barker\n"); |
629 | break; | 917 | break; |
630 | case -EISCONN: /* we don't know how it got here...but we follow it */ | 918 | case -EISCONN: /* we don't know how it got here...but we follow it */ |
631 | d_printf(4, dev, "device reboot: got ack barker - whatever\n"); | 919 | d_printf(4, dev, "device reboot: got ack barker - whatever\n"); |
632 | goto do_reboot; | 920 | goto do_reboot; |
633 | case -ETIMEDOUT: /* device has timed out, we might be in boot | 921 | case -ETIMEDOUT: |
634 | * mode already and expecting an ack, let's try | 922 | /* |
635 | * that */ | 923 | * Device has timed out, we might be in boot mode |
636 | dev_info(dev, "warm reset timed out, trying an ack\n"); | 924 | * already and expecting an ack; if we don't know what |
637 | goto do_reboot_ack; | 925 | * the barker is, we just send them all. Cold reset |
926 | * and bus reset don't work. Beats me. | ||
927 | */ | ||
928 | if (i2400m->barker != NULL) { | ||
929 | dev_err(dev, "device boot: reboot barker timed out, " | ||
930 | "trying (set) %08x echo/ack\n", | ||
931 | le32_to_cpu(i2400m->barker->data[0])); | ||
932 | goto do_reboot_ack; | ||
933 | } | ||
934 | for (i = 0; i < i2400m_barker_db_used; i++) { | ||
935 | struct i2400m_barker_db *barker = &i2400m_barker_db[i]; | ||
936 | memcpy(cmd, barker->data, sizeof(barker->data)); | ||
937 | result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), | ||
938 | &ack, sizeof(ack), | ||
939 | I2400M_BM_CMD_RAW); | ||
940 | if (result == -EISCONN) { | ||
941 | dev_warn(dev, "device boot: got ack barker " | ||
942 | "after sending echo/ack barker " | ||
943 | "#%d/%08x; rebooting j.i.c.\n", | ||
944 | i, le32_to_cpu(barker->data[0])); | ||
945 | flags &= ~I2400M_BRI_NO_REBOOT; | ||
946 | goto do_reboot; | ||
947 | } | ||
948 | } | ||
949 | dev_err(dev, "device boot: tried all the echo/acks, could " | ||
950 | "not get device to respond; giving up"); | ||
951 | result = -ESHUTDOWN; | ||
638 | case -EPROTO: | 952 | case -EPROTO: |
639 | case -ESHUTDOWN: /* dev is gone */ | 953 | case -ESHUTDOWN: /* dev is gone */ |
640 | case -EINTR: /* user cancelled */ | 954 | case -EINTR: /* user cancelled */ |
@@ -642,6 +956,7 @@ do_reboot: | |||
642 | default: | 956 | default: |
643 | dev_err(dev, "device reboot: error %d while waiting " | 957 | dev_err(dev, "device reboot: error %d while waiting " |
644 | "for reboot barker - rebooting\n", result); | 958 | "for reboot barker - rebooting\n", result); |
959 | d_dump(1, dev, &ack, result); | ||
645 | goto do_reboot; | 960 | goto do_reboot; |
646 | } | 961 | } |
647 | /* At this point we ack back with 4 REBOOT barkers and expect | 962 | /* At this point we ack back with 4 REBOOT barkers and expect |
@@ -650,12 +965,7 @@ do_reboot: | |||
650 | * notification and report it as -EISCONN. */ | 965 | * notification and report it as -EISCONN. */ |
651 | do_reboot_ack: | 966 | do_reboot_ack: |
652 | d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count); | 967 | d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count); |
653 | if (i2400m->sboot == 0) | 968 | memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data)); |
654 | memcpy(cmd, i2400m_NBOOT_BARKER, | ||
655 | sizeof(i2400m_NBOOT_BARKER)); | ||
656 | else | ||
657 | memcpy(cmd, i2400m_SBOOT_BARKER, | ||
658 | sizeof(i2400m_SBOOT_BARKER)); | ||
659 | result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), | 969 | result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), |
660 | &ack, sizeof(ack), I2400M_BM_CMD_RAW); | 970 | &ack, sizeof(ack), I2400M_BM_CMD_RAW); |
661 | switch (result) { | 971 | switch (result) { |
@@ -668,10 +978,8 @@ do_reboot_ack: | |||
668 | d_printf(4, dev, "reboot ack: got ack barker - good\n"); | 978 | d_printf(4, dev, "reboot ack: got ack barker - good\n"); |
669 | break; | 979 | break; |
670 | case -ETIMEDOUT: /* no response, maybe it is the other type? */ | 980 | case -ETIMEDOUT: /* no response, maybe it is the other type? */ |
671 | if (ack_timeout_cnt-- >= 0) { | 981 | if (ack_timeout_cnt-- < 0) { |
672 | d_printf(4, dev, "reboot ack timedout: " | 982 | d_printf(4, dev, "reboot ack timedout: retrying\n"); |
673 | "trying the other type?\n"); | ||
674 | i2400m->sboot = !i2400m->sboot; | ||
675 | goto do_reboot_ack; | 983 | goto do_reboot_ack; |
676 | } else { | 984 | } else { |
677 | dev_err(dev, "reboot ack timedout too long: " | 985 | dev_err(dev, "reboot ack timedout too long: " |
@@ -839,32 +1147,29 @@ int i2400m_dnload_init_signed(struct i2400m *i2400m, | |||
839 | * (signed or non-signed). | 1147 | * (signed or non-signed). |
840 | */ | 1148 | */ |
841 | static | 1149 | static |
842 | int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf) | 1150 | int i2400m_dnload_init(struct i2400m *i2400m, |
1151 | const struct i2400m_bcf_hdr *bcf_hdr) | ||
843 | { | 1152 | { |
844 | int result; | 1153 | int result; |
845 | struct device *dev = i2400m_dev(i2400m); | 1154 | struct device *dev = i2400m_dev(i2400m); |
846 | u32 module_id = le32_to_cpu(bcf->module_id); | ||
847 | 1155 | ||
848 | if (i2400m->sboot == 0 | 1156 | if (i2400m_boot_is_signed(i2400m)) { |
849 | && (module_id & I2400M_BCF_MOD_ID_POKES) == 0) { | 1157 | d_printf(1, dev, "signed boot\n"); |
850 | /* non-signed boot process without pokes */ | 1158 | result = i2400m_dnload_init_signed(i2400m, bcf_hdr); |
851 | result = i2400m_dnload_init_nonsigned(i2400m); | ||
852 | if (result == -ERESTARTSYS) | 1159 | if (result == -ERESTARTSYS) |
853 | return result; | 1160 | return result; |
854 | if (result < 0) | 1161 | if (result < 0) |
855 | dev_err(dev, "fw %s: non-signed download " | 1162 | dev_err(dev, "firmware %s: signed boot download " |
856 | "initialization failed: %d\n", | 1163 | "initialization failed: %d\n", |
857 | i2400m->fw_name, result); | 1164 | i2400m->fw_name, result); |
858 | } else if (i2400m->sboot == 0 | 1165 | } else { |
859 | && (module_id & I2400M_BCF_MOD_ID_POKES)) { | 1166 | /* non-signed boot process without pokes */ |
860 | /* non-signed boot process with pokes, nothing to do */ | 1167 | d_printf(1, dev, "non-signed boot\n"); |
861 | result = 0; | 1168 | result = i2400m_dnload_init_nonsigned(i2400m); |
862 | } else { /* signed boot process */ | ||
863 | result = i2400m_dnload_init_signed(i2400m, bcf); | ||
864 | if (result == -ERESTARTSYS) | 1169 | if (result == -ERESTARTSYS) |
865 | return result; | 1170 | return result; |
866 | if (result < 0) | 1171 | if (result < 0) |
867 | dev_err(dev, "fw %s: signed boot download " | 1172 | dev_err(dev, "firmware %s: non-signed download " |
868 | "initialization failed: %d\n", | 1173 | "initialization failed: %d\n", |
869 | i2400m->fw_name, result); | 1174 | i2400m->fw_name, result); |
870 | } | 1175 | } |
@@ -873,74 +1178,201 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf) | |||
873 | 1178 | ||
874 | 1179 | ||
875 | /* | 1180 | /* |
876 | * Run quick consistency tests on the firmware file | 1181 | * Run consistency tests on the firmware file and load up headers |
877 | * | 1182 | * |
878 | * Check for the firmware being made for the i2400m device, | 1183 | * Check for the firmware being made for the i2400m device, |
879 | * etc...These checks are mostly informative, as the device will make | 1184 | * etc...These checks are mostly informative, as the device will make |
880 | * them too; but the driver's response is more informative on what | 1185 | * them too; but the driver's response is more informative on what |
881 | * went wrong. | 1186 | * went wrong. |
1187 | * | ||
1188 | * This will also look at all the headers present on the firmware | ||
1189 | * file, and update i2400m->fw_bcf_hdr to point to them. | ||
882 | */ | 1190 | */ |
883 | static | 1191 | static |
884 | int i2400m_fw_check(struct i2400m *i2400m, | 1192 | int i2400m_fw_hdr_check(struct i2400m *i2400m, |
885 | const struct i2400m_bcf_hdr *bcf, | 1193 | const struct i2400m_bcf_hdr *bcf_hdr, |
886 | size_t bcf_size) | 1194 | size_t index, size_t offset) |
887 | { | 1195 | { |
888 | int result; | ||
889 | struct device *dev = i2400m_dev(i2400m); | 1196 | struct device *dev = i2400m_dev(i2400m); |
1197 | |||
890 | unsigned module_type, header_len, major_version, minor_version, | 1198 | unsigned module_type, header_len, major_version, minor_version, |
891 | module_id, module_vendor, date, size; | 1199 | module_id, module_vendor, date, size; |
892 | 1200 | ||
893 | /* Check hard errors */ | 1201 | module_type = bcf_hdr->module_type; |
894 | result = -EINVAL; | 1202 | header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len); |
895 | if (bcf_size < sizeof(*bcf)) { /* big enough header? */ | 1203 | major_version = (le32_to_cpu(bcf_hdr->header_version) & 0xffff0000) |
896 | dev_err(dev, "firmware %s too short: " | 1204 | >> 16; |
897 | "%zu B vs %zu (at least) expected\n", | 1205 | minor_version = le32_to_cpu(bcf_hdr->header_version) & 0x0000ffff; |
898 | i2400m->fw_name, bcf_size, sizeof(*bcf)); | 1206 | module_id = le32_to_cpu(bcf_hdr->module_id); |
899 | goto error; | 1207 | module_vendor = le32_to_cpu(bcf_hdr->module_vendor); |
900 | } | 1208 | date = le32_to_cpu(bcf_hdr->date); |
1209 | size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); | ||
901 | 1210 | ||
902 | module_type = bcf->module_type; | 1211 | d_printf(1, dev, "firmware %s #%zd@%08zx: BCF header " |
903 | header_len = sizeof(u32) * le32_to_cpu(bcf->header_len); | 1212 | "type:vendor:id 0x%x:%x:%x v%u.%u (%u/%u B) built %08x\n", |
904 | major_version = le32_to_cpu(bcf->header_version) & 0xffff0000 >> 16; | 1213 | i2400m->fw_name, index, offset, |
905 | minor_version = le32_to_cpu(bcf->header_version) & 0x0000ffff; | 1214 | module_type, module_vendor, module_id, |
906 | module_id = le32_to_cpu(bcf->module_id); | 1215 | major_version, minor_version, header_len, size, date); |
907 | module_vendor = le32_to_cpu(bcf->module_vendor); | ||
908 | date = le32_to_cpu(bcf->date); | ||
909 | size = sizeof(u32) * le32_to_cpu(bcf->size); | ||
910 | |||
911 | if (bcf_size != size) { /* annoyingly paranoid */ | ||
912 | dev_err(dev, "firmware %s: bad size, got " | ||
913 | "%zu B vs %u expected\n", | ||
914 | i2400m->fw_name, bcf_size, size); | ||
915 | goto error; | ||
916 | } | ||
917 | 1216 | ||
918 | d_printf(2, dev, "type 0x%x id 0x%x vendor 0x%x; header v%u.%u (%zu B) " | 1217 | /* Hard errors */ |
919 | "date %08x (%zu B)\n", | 1218 | if (major_version != 1) { |
920 | module_type, module_id, module_vendor, | 1219 | dev_err(dev, "firmware %s #%zd@%08zx: major header version " |
921 | major_version, minor_version, (size_t) header_len, | 1220 | "v%u.%u not supported\n", |
922 | date, (size_t) size); | 1221 | i2400m->fw_name, index, offset, |
1222 | major_version, minor_version); | ||
1223 | return -EBADF; | ||
1224 | } | ||
923 | 1225 | ||
924 | if (module_type != 6) { /* built for the right hardware? */ | 1226 | if (module_type != 6) { /* built for the right hardware? */ |
925 | dev_err(dev, "bad fw %s: unexpected module type 0x%x; " | 1227 | dev_err(dev, "firmware %s #%zd@%08zx: unexpected module " |
926 | "aborting\n", i2400m->fw_name, module_type); | 1228 | "type 0x%x; aborting\n", |
927 | goto error; | 1229 | i2400m->fw_name, index, offset, |
1230 | module_type); | ||
1231 | return -EBADF; | ||
1232 | } | ||
1233 | |||
1234 | if (module_vendor != 0x8086) { | ||
1235 | dev_err(dev, "firmware %s #%zd@%08zx: unexpected module " | ||
1236 | "vendor 0x%x; aborting\n", | ||
1237 | i2400m->fw_name, index, offset, module_vendor); | ||
1238 | return -EBADF; | ||
928 | } | 1239 | } |
929 | 1240 | ||
930 | /* Check soft-er errors */ | ||
931 | result = 0; | ||
932 | if (module_vendor != 0x8086) | ||
933 | dev_err(dev, "bad fw %s? unexpected vendor 0x%04x\n", | ||
934 | i2400m->fw_name, module_vendor); | ||
935 | if (date < 0x20080300) | 1241 | if (date < 0x20080300) |
936 | dev_err(dev, "bad fw %s? build date too old %08x\n", | 1242 | dev_warn(dev, "firmware %s #%zd@%08zx: build date %08x " |
937 | i2400m->fw_name, date); | 1243 | "too old; unsupported\n", |
938 | error: | 1244 | i2400m->fw_name, index, offset, date); |
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | |||
1249 | /* | ||
1250 | * Run consistency tests on the firmware file and load up headers | ||
1251 | * | ||
1252 | * Check for the firmware being made for the i2400m device, | ||
1253 | * etc...These checks are mostly informative, as the device will make | ||
1254 | * them too; but the driver's response is more informative on what | ||
1255 | * went wrong. | ||
1256 | * | ||
1257 | * This will also look at all the headers present on the firmware | ||
1258 | * file, and update i2400m->fw_hdrs to point to them. | ||
1259 | */ | ||
1260 | static | ||
1261 | int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size) | ||
1262 | { | ||
1263 | int result; | ||
1264 | struct device *dev = i2400m_dev(i2400m); | ||
1265 | size_t headers = 0; | ||
1266 | const struct i2400m_bcf_hdr *bcf_hdr; | ||
1267 | const void *itr, *next, *top; | ||
1268 | size_t slots = 0, used_slots = 0; | ||
1269 | |||
1270 | for (itr = bcf, top = itr + bcf_size; | ||
1271 | itr < top; | ||
1272 | headers++, itr = next) { | ||
1273 | size_t leftover, offset, header_len, size; | ||
1274 | |||
1275 | leftover = top - itr; | ||
1276 | offset = itr - (const void *) bcf; | ||
1277 | if (leftover <= sizeof(*bcf_hdr)) { | ||
1278 | dev_err(dev, "firmware %s: %zu B left at @%zx, " | ||
1279 | "not enough for BCF header\n", | ||
1280 | i2400m->fw_name, leftover, offset); | ||
1281 | break; | ||
1282 | } | ||
1283 | bcf_hdr = itr; | ||
1284 | /* Only the first header is supposed to be followed by | ||
1285 | * payload */ | ||
1286 | header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len); | ||
1287 | size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); | ||
1288 | if (headers == 0) | ||
1289 | next = itr + size; | ||
1290 | else | ||
1291 | next = itr + header_len; | ||
1292 | |||
1293 | result = i2400m_fw_hdr_check(i2400m, bcf_hdr, headers, offset); | ||
1294 | if (result < 0) | ||
1295 | continue; | ||
1296 | if (used_slots + 1 >= slots) { | ||
1297 | /* +1 -> we need to account for the one we'll | ||
1298 | * occupy and at least an extra one for | ||
1299 | * always being NULL */ | ||
1300 | result = i2400m_zrealloc_2x( | ||
1301 | (void **) &i2400m->fw_hdrs, &slots, | ||
1302 | sizeof(i2400m->fw_hdrs[0]), | ||
1303 | GFP_KERNEL); | ||
1304 | if (result < 0) | ||
1305 | goto error_zrealloc; | ||
1306 | } | ||
1307 | i2400m->fw_hdrs[used_slots] = bcf_hdr; | ||
1308 | used_slots++; | ||
1309 | } | ||
1310 | if (headers == 0) { | ||
1311 | dev_err(dev, "firmware %s: no usable headers found\n", | ||
1312 | i2400m->fw_name); | ||
1313 | result = -EBADF; | ||
1314 | } else | ||
1315 | result = 0; | ||
1316 | error_zrealloc: | ||
939 | return result; | 1317 | return result; |
940 | } | 1318 | } |
941 | 1319 | ||
942 | 1320 | ||
943 | /* | 1321 | /* |
1322 | * Match a barker to a BCF header module ID | ||
1323 | * | ||
1324 | * The device sends a barker which tells the firmware loader which | ||
1325 | * header in the BCF file has to be used. This does the matching. | ||
1326 | */ | ||
1327 | static | ||
1328 | unsigned i2400m_bcf_hdr_match(struct i2400m *i2400m, | ||
1329 | const struct i2400m_bcf_hdr *bcf_hdr) | ||
1330 | { | ||
1331 | u32 barker = le32_to_cpu(i2400m->barker->data[0]) | ||
1332 | & 0x7fffffff; | ||
1333 | u32 module_id = le32_to_cpu(bcf_hdr->module_id) | ||
1334 | & 0x7fffffff; /* high bit used for something else */ | ||
1335 | |||
1336 | /* special case for 5x50 */ | ||
1337 | if (barker == I2400M_SBOOT_BARKER && module_id == 0) | ||
1338 | return 1; | ||
1339 | if (module_id == barker) | ||
1340 | return 1; | ||
1341 | return 0; | ||
1342 | } | ||
1343 | |||
1344 | static | ||
1345 | const struct i2400m_bcf_hdr *i2400m_bcf_hdr_find(struct i2400m *i2400m) | ||
1346 | { | ||
1347 | struct device *dev = i2400m_dev(i2400m); | ||
1348 | const struct i2400m_bcf_hdr **bcf_itr, *bcf_hdr; | ||
1349 | unsigned i = 0; | ||
1350 | u32 barker = le32_to_cpu(i2400m->barker->data[0]); | ||
1351 | |||
1352 | d_printf(2, dev, "finding BCF header for barker %08x\n", barker); | ||
1353 | if (barker == I2400M_NBOOT_BARKER) { | ||
1354 | bcf_hdr = i2400m->fw_hdrs[0]; | ||
1355 | d_printf(1, dev, "using BCF header #%u/%08x for non-signed " | ||
1356 | "barker\n", 0, le32_to_cpu(bcf_hdr->module_id)); | ||
1357 | return bcf_hdr; | ||
1358 | } | ||
1359 | for (bcf_itr = i2400m->fw_hdrs; *bcf_itr != NULL; bcf_itr++, i++) { | ||
1360 | bcf_hdr = *bcf_itr; | ||
1361 | if (i2400m_bcf_hdr_match(i2400m, bcf_hdr)) { | ||
1362 | d_printf(1, dev, "hit on BCF hdr #%u/%08x\n", | ||
1363 | i, le32_to_cpu(bcf_hdr->module_id)); | ||
1364 | return bcf_hdr; | ||
1365 | } else | ||
1366 | d_printf(1, dev, "miss on BCF hdr #%u/%08x\n", | ||
1367 | i, le32_to_cpu(bcf_hdr->module_id)); | ||
1368 | } | ||
1369 | dev_err(dev, "cannot find a matching BCF header for barker %08x\n", | ||
1370 | barker); | ||
1371 | return NULL; | ||
1372 | } | ||
1373 | |||
1374 | |||
1375 | /* | ||
944 | * Download the firmware to the device | 1376 | * Download the firmware to the device |
945 | * | 1377 | * |
946 | * @i2400m: device descriptor | 1378 | * @i2400m: device descriptor |
@@ -956,14 +1388,16 @@ error: | |||
956 | */ | 1388 | */ |
957 | static | 1389 | static |
958 | int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, | 1390 | int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, |
959 | size_t bcf_size, enum i2400m_bri flags) | 1391 | size_t fw_size, enum i2400m_bri flags) |
960 | { | 1392 | { |
961 | int ret = 0; | 1393 | int ret = 0; |
962 | struct device *dev = i2400m_dev(i2400m); | 1394 | struct device *dev = i2400m_dev(i2400m); |
963 | int count = i2400m->bus_bm_retries; | 1395 | int count = i2400m->bus_bm_retries; |
1396 | const struct i2400m_bcf_hdr *bcf_hdr; | ||
1397 | size_t bcf_size; | ||
964 | 1398 | ||
965 | d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", | 1399 | d_fnstart(5, dev, "(i2400m %p bcf %p fw size %zu)\n", |
966 | i2400m, bcf, bcf_size); | 1400 | i2400m, bcf, fw_size); |
967 | i2400m->boot_mode = 1; | 1401 | i2400m->boot_mode = 1; |
968 | wmb(); /* Make sure other readers see it */ | 1402 | wmb(); /* Make sure other readers see it */ |
969 | hw_reboot: | 1403 | hw_reboot: |
@@ -985,13 +1419,28 @@ hw_reboot: | |||
985 | * Initialize the download, push the bytes to the device and | 1419 | * Initialize the download, push the bytes to the device and |
986 | * then jump to the new firmware. Note @ret is passed with the | 1420 | * then jump to the new firmware. Note @ret is passed with the |
987 | * offset of the jump instruction to _dnload_finalize() | 1421 | * offset of the jump instruction to _dnload_finalize() |
1422 | * | ||
1423 | * Note we need to use the BCF header in the firmware image | ||
1424 | * that matches the barker that the device sent when it | ||
1425 | * rebooted, so it has to be passed along. | ||
988 | */ | 1426 | */ |
989 | ret = i2400m_dnload_init(i2400m, bcf); /* Init device's dnload */ | 1427 | ret = -EBADF; |
1428 | bcf_hdr = i2400m_bcf_hdr_find(i2400m); | ||
1429 | if (bcf_hdr == NULL) | ||
1430 | goto error_bcf_hdr_find; | ||
1431 | |||
1432 | ret = i2400m_dnload_init(i2400m, bcf_hdr); | ||
990 | if (ret == -ERESTARTSYS) | 1433 | if (ret == -ERESTARTSYS) |
991 | goto error_dev_rebooted; | 1434 | goto error_dev_rebooted; |
992 | if (ret < 0) | 1435 | if (ret < 0) |
993 | goto error_dnload_init; | 1436 | goto error_dnload_init; |
994 | 1437 | ||
1438 | /* | ||
1439 | * bcf_size refers to one header size plus the fw sections size | ||
1440 | * indicated by the header,ie. if there are other extended headers | ||
1441 | * at the tail, they are not counted | ||
1442 | */ | ||
1443 | bcf_size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); | ||
995 | ret = i2400m_dnload_bcf(i2400m, bcf, bcf_size); | 1444 | ret = i2400m_dnload_bcf(i2400m, bcf, bcf_size); |
996 | if (ret == -ERESTARTSYS) | 1445 | if (ret == -ERESTARTSYS) |
997 | goto error_dev_rebooted; | 1446 | goto error_dev_rebooted; |
@@ -1001,7 +1450,7 @@ hw_reboot: | |||
1001 | goto error_dnload_bcf; | 1450 | goto error_dnload_bcf; |
1002 | } | 1451 | } |
1003 | 1452 | ||
1004 | ret = i2400m_dnload_finalize(i2400m, bcf, ret); | 1453 | ret = i2400m_dnload_finalize(i2400m, bcf_hdr, bcf, ret); |
1005 | if (ret == -ERESTARTSYS) | 1454 | if (ret == -ERESTARTSYS) |
1006 | goto error_dev_rebooted; | 1455 | goto error_dev_rebooted; |
1007 | if (ret < 0) { | 1456 | if (ret < 0) { |
@@ -1018,10 +1467,11 @@ hw_reboot: | |||
1018 | error_dnload_finalize: | 1467 | error_dnload_finalize: |
1019 | error_dnload_bcf: | 1468 | error_dnload_bcf: |
1020 | error_dnload_init: | 1469 | error_dnload_init: |
1470 | error_bcf_hdr_find: | ||
1021 | error_bootrom_init: | 1471 | error_bootrom_init: |
1022 | error_too_many_reboots: | 1472 | error_too_many_reboots: |
1023 | d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n", | 1473 | d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n", |
1024 | i2400m, bcf, bcf_size, ret); | 1474 | i2400m, bcf, fw_size, ret); |
1025 | return ret; | 1475 | return ret; |
1026 | 1476 | ||
1027 | error_dev_rebooted: | 1477 | error_dev_rebooted: |
@@ -1031,6 +1481,61 @@ error_dev_rebooted: | |||
1031 | goto hw_reboot; | 1481 | goto hw_reboot; |
1032 | } | 1482 | } |
1033 | 1483 | ||
1484 | static | ||
1485 | int i2400m_fw_bootstrap(struct i2400m *i2400m, const struct firmware *fw, | ||
1486 | enum i2400m_bri flags) | ||
1487 | { | ||
1488 | int ret; | ||
1489 | struct device *dev = i2400m_dev(i2400m); | ||
1490 | const struct i2400m_bcf_hdr *bcf; /* Firmware data */ | ||
1491 | |||
1492 | d_fnstart(5, dev, "(i2400m %p)\n", i2400m); | ||
1493 | bcf = (void *) fw->data; | ||
1494 | ret = i2400m_fw_check(i2400m, bcf, fw->size); | ||
1495 | if (ret >= 0) | ||
1496 | ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags); | ||
1497 | if (ret < 0) | ||
1498 | dev_err(dev, "%s: cannot use: %d, skipping\n", | ||
1499 | i2400m->fw_name, ret); | ||
1500 | kfree(i2400m->fw_hdrs); | ||
1501 | i2400m->fw_hdrs = NULL; | ||
1502 | d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); | ||
1503 | return ret; | ||
1504 | } | ||
1505 | |||
1506 | |||
1507 | /* Refcounted container for firmware data */ | ||
1508 | struct i2400m_fw { | ||
1509 | struct kref kref; | ||
1510 | const struct firmware *fw; | ||
1511 | }; | ||
1512 | |||
1513 | |||
1514 | static | ||
1515 | void i2400m_fw_destroy(struct kref *kref) | ||
1516 | { | ||
1517 | struct i2400m_fw *i2400m_fw = | ||
1518 | container_of(kref, struct i2400m_fw, kref); | ||
1519 | release_firmware(i2400m_fw->fw); | ||
1520 | kfree(i2400m_fw); | ||
1521 | } | ||
1522 | |||
1523 | |||
1524 | static | ||
1525 | struct i2400m_fw *i2400m_fw_get(struct i2400m_fw *i2400m_fw) | ||
1526 | { | ||
1527 | if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) | ||
1528 | kref_get(&i2400m_fw->kref); | ||
1529 | return i2400m_fw; | ||
1530 | } | ||
1531 | |||
1532 | |||
1533 | static | ||
1534 | void i2400m_fw_put(struct i2400m_fw *i2400m_fw) | ||
1535 | { | ||
1536 | kref_put(&i2400m_fw->kref, i2400m_fw_destroy); | ||
1537 | } | ||
1538 | |||
1034 | 1539 | ||
1035 | /** | 1540 | /** |
1036 | * i2400m_dev_bootstrap - Bring the device to a known state and upload firmware | 1541 | * i2400m_dev_bootstrap - Bring the device to a known state and upload firmware |
@@ -1049,42 +1554,109 @@ error_dev_rebooted: | |||
1049 | */ | 1554 | */ |
1050 | int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags) | 1555 | int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags) |
1051 | { | 1556 | { |
1052 | int ret = 0, itr = 0; | 1557 | int ret, itr; |
1053 | struct device *dev = i2400m_dev(i2400m); | 1558 | struct device *dev = i2400m_dev(i2400m); |
1054 | const struct firmware *fw; | 1559 | struct i2400m_fw *i2400m_fw; |
1055 | const struct i2400m_bcf_hdr *bcf; /* Firmware data */ | 1560 | const struct i2400m_bcf_hdr *bcf; /* Firmware data */ |
1561 | const struct firmware *fw; | ||
1056 | const char *fw_name; | 1562 | const char *fw_name; |
1057 | 1563 | ||
1058 | d_fnstart(5, dev, "(i2400m %p)\n", i2400m); | 1564 | d_fnstart(5, dev, "(i2400m %p)\n", i2400m); |
1059 | 1565 | ||
1566 | ret = -ENODEV; | ||
1567 | spin_lock(&i2400m->rx_lock); | ||
1568 | i2400m_fw = i2400m_fw_get(i2400m->fw_cached); | ||
1569 | spin_unlock(&i2400m->rx_lock); | ||
1570 | if (i2400m_fw == (void *) ~0) { | ||
1571 | dev_err(dev, "can't load firmware now!"); | ||
1572 | goto out; | ||
1573 | } else if (i2400m_fw != NULL) { | ||
1574 | dev_info(dev, "firmware %s: loading from cache\n", | ||
1575 | i2400m->fw_name); | ||
1576 | ret = i2400m_fw_bootstrap(i2400m, i2400m_fw->fw, flags); | ||
1577 | i2400m_fw_put(i2400m_fw); | ||
1578 | goto out; | ||
1579 | } | ||
1580 | |||
1060 | /* Load firmware files to memory. */ | 1581 | /* Load firmware files to memory. */ |
1061 | itr = 0; | 1582 | for (itr = 0, bcf = NULL, ret = -ENOENT; ; itr++) { |
1062 | while(1) { | ||
1063 | fw_name = i2400m->bus_fw_names[itr]; | 1583 | fw_name = i2400m->bus_fw_names[itr]; |
1064 | if (fw_name == NULL) { | 1584 | if (fw_name == NULL) { |
1065 | dev_err(dev, "Could not find a usable firmware image\n"); | 1585 | dev_err(dev, "Could not find a usable firmware image\n"); |
1066 | ret = -ENOENT; | 1586 | break; |
1067 | goto error_no_fw; | ||
1068 | } | 1587 | } |
1588 | d_printf(1, dev, "trying firmware %s (%d)\n", fw_name, itr); | ||
1069 | ret = request_firmware(&fw, fw_name, dev); | 1589 | ret = request_firmware(&fw, fw_name, dev); |
1070 | if (ret == 0) | 1590 | if (ret < 0) { |
1071 | break; /* got it */ | ||
1072 | if (ret < 0) | ||
1073 | dev_err(dev, "fw %s: cannot load file: %d\n", | 1591 | dev_err(dev, "fw %s: cannot load file: %d\n", |
1074 | fw_name, ret); | 1592 | fw_name, ret); |
1075 | itr++; | 1593 | continue; |
1594 | } | ||
1595 | i2400m->fw_name = fw_name; | ||
1596 | ret = i2400m_fw_bootstrap(i2400m, fw, flags); | ||
1597 | release_firmware(fw); | ||
1598 | if (ret >= 0) /* firmware loaded succesfully */ | ||
1599 | break; | ||
1600 | i2400m->fw_name = NULL; | ||
1076 | } | 1601 | } |
1077 | 1602 | out: | |
1078 | bcf = (void *) fw->data; | ||
1079 | i2400m->fw_name = fw_name; | ||
1080 | ret = i2400m_fw_check(i2400m, bcf, fw->size); | ||
1081 | if (ret < 0) | ||
1082 | goto error_fw_bad; | ||
1083 | ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags); | ||
1084 | error_fw_bad: | ||
1085 | release_firmware(fw); | ||
1086 | error_no_fw: | ||
1087 | d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); | 1603 | d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); |
1088 | return ret; | 1604 | return ret; |
1089 | } | 1605 | } |
1090 | EXPORT_SYMBOL_GPL(i2400m_dev_bootstrap); | 1606 | EXPORT_SYMBOL_GPL(i2400m_dev_bootstrap); |
1607 | |||
1608 | |||
1609 | void i2400m_fw_cache(struct i2400m *i2400m) | ||
1610 | { | ||
1611 | int result; | ||
1612 | struct i2400m_fw *i2400m_fw; | ||
1613 | struct device *dev = i2400m_dev(i2400m); | ||
1614 | |||
1615 | /* if there is anything there, free it -- now, this'd be weird */ | ||
1616 | spin_lock(&i2400m->rx_lock); | ||
1617 | i2400m_fw = i2400m->fw_cached; | ||
1618 | spin_unlock(&i2400m->rx_lock); | ||
1619 | if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) { | ||
1620 | i2400m_fw_put(i2400m_fw); | ||
1621 | WARN(1, "%s:%u: still cached fw still present?\n", | ||
1622 | __func__, __LINE__); | ||
1623 | } | ||
1624 | |||
1625 | if (i2400m->fw_name == NULL) { | ||
1626 | dev_err(dev, "firmware n/a: can't cache\n"); | ||
1627 | i2400m_fw = (void *) ~0; | ||
1628 | goto out; | ||
1629 | } | ||
1630 | |||
1631 | i2400m_fw = kzalloc(sizeof(*i2400m_fw), GFP_ATOMIC); | ||
1632 | if (i2400m_fw == NULL) | ||
1633 | goto out; | ||
1634 | kref_init(&i2400m_fw->kref); | ||
1635 | result = request_firmware(&i2400m_fw->fw, i2400m->fw_name, dev); | ||
1636 | if (result < 0) { | ||
1637 | dev_err(dev, "firmware %s: failed to cache: %d\n", | ||
1638 | i2400m->fw_name, result); | ||
1639 | kfree(i2400m_fw); | ||
1640 | i2400m_fw = (void *) ~0; | ||
1641 | } else | ||
1642 | dev_info(dev, "firmware %s: cached\n", i2400m->fw_name); | ||
1643 | out: | ||
1644 | spin_lock(&i2400m->rx_lock); | ||
1645 | i2400m->fw_cached = i2400m_fw; | ||
1646 | spin_unlock(&i2400m->rx_lock); | ||
1647 | } | ||
1648 | |||
1649 | |||
1650 | void i2400m_fw_uncache(struct i2400m *i2400m) | ||
1651 | { | ||
1652 | struct i2400m_fw *i2400m_fw; | ||
1653 | |||
1654 | spin_lock(&i2400m->rx_lock); | ||
1655 | i2400m_fw = i2400m->fw_cached; | ||
1656 | i2400m->fw_cached = NULL; | ||
1657 | spin_unlock(&i2400m->rx_lock); | ||
1658 | |||
1659 | if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) | ||
1660 | i2400m_fw_put(i2400m_fw); | ||
1661 | } | ||
1662 | |||
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index 9c4e3189f7b5..b9c4bed3b457 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h | |||
@@ -67,6 +67,7 @@ | |||
67 | 67 | ||
68 | /* Host-Device interface for SDIO */ | 68 | /* Host-Device interface for SDIO */ |
69 | enum { | 69 | enum { |
70 | I2400M_SDIO_BOOT_RETRIES = 3, | ||
70 | I2400MS_BLK_SIZE = 256, | 71 | I2400MS_BLK_SIZE = 256, |
71 | I2400MS_PL_SIZE_MAX = 0x3E00, | 72 | I2400MS_PL_SIZE_MAX = 0x3E00, |
72 | 73 | ||
@@ -77,9 +78,11 @@ enum { | |||
77 | I2400MS_INTR_GET_SIZE_ADDR = 0x2C, | 78 | I2400MS_INTR_GET_SIZE_ADDR = 0x2C, |
78 | /* The number of ticks to wait for the device to signal that | 79 | /* The number of ticks to wait for the device to signal that |
79 | * it is ready */ | 80 | * it is ready */ |
80 | I2400MS_INIT_SLEEP_INTERVAL = 10, | 81 | I2400MS_INIT_SLEEP_INTERVAL = 100, |
81 | /* How long to wait for the device to settle after reset */ | 82 | /* How long to wait for the device to settle after reset */ |
82 | I2400MS_SETTLE_TIME = 40, | 83 | I2400MS_SETTLE_TIME = 40, |
84 | /* The number of msec to wait for IOR after sending IOE */ | ||
85 | IWMC3200_IOR_TIMEOUT = 10, | ||
83 | }; | 86 | }; |
84 | 87 | ||
85 | 88 | ||
@@ -97,6 +100,14 @@ enum { | |||
97 | * @tx_workqueue: workqeueue used for data TX; we don't use the | 100 | * @tx_workqueue: workqeueue used for data TX; we don't use the |
98 | * system's workqueue as that might cause deadlocks with code in | 101 | * system's workqueue as that might cause deadlocks with code in |
99 | * the bus-generic driver. | 102 | * the bus-generic driver. |
103 | * | ||
104 | * @debugfs_dentry: dentry for the SDIO specific debugfs files | ||
105 | * | ||
106 | * Note this value is set to NULL upon destruction; this is | ||
107 | * because some routinges use it to determine if we are inside the | ||
108 | * probe() path or some other path. When debugfs is disabled, | ||
109 | * creation sets the dentry to '(void*) -ENODEV', which is valid | ||
110 | * for the test. | ||
100 | */ | 111 | */ |
101 | struct i2400ms { | 112 | struct i2400ms { |
102 | struct i2400m i2400m; /* FIRST! See doc */ | 113 | struct i2400m i2400m; /* FIRST! See doc */ |
@@ -111,6 +122,9 @@ struct i2400ms { | |||
111 | wait_queue_head_t bm_wfa_wq; | 122 | wait_queue_head_t bm_wfa_wq; |
112 | int bm_wait_result; | 123 | int bm_wait_result; |
113 | size_t bm_ack_size; | 124 | size_t bm_ack_size; |
125 | |||
126 | /* Device is any of the iwmc3200 SKUs */ | ||
127 | unsigned iwmc3200:1; | ||
114 | }; | 128 | }; |
115 | 129 | ||
116 | 130 | ||
diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h index 6f76558b170f..5cc0f279417e 100644 --- a/drivers/net/wimax/i2400m/i2400m-usb.h +++ b/drivers/net/wimax/i2400m/i2400m-usb.h | |||
@@ -88,6 +88,13 @@ struct edc { | |||
88 | u16 errorcount; | 88 | u16 errorcount; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | struct i2400m_endpoint_cfg { | ||
92 | unsigned char bulk_out; | ||
93 | unsigned char notification; | ||
94 | unsigned char reset_cold; | ||
95 | unsigned char bulk_in; | ||
96 | }; | ||
97 | |||
91 | static inline void edc_init(struct edc *edc) | 98 | static inline void edc_init(struct edc *edc) |
92 | { | 99 | { |
93 | edc->timestart = jiffies; | 100 | edc->timestart = jiffies; |
@@ -137,15 +144,13 @@ static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe) | |||
137 | 144 | ||
138 | /* Host-Device interface for USB */ | 145 | /* Host-Device interface for USB */ |
139 | enum { | 146 | enum { |
147 | I2400M_USB_BOOT_RETRIES = 3, | ||
140 | I2400MU_MAX_NOTIFICATION_LEN = 256, | 148 | I2400MU_MAX_NOTIFICATION_LEN = 256, |
141 | I2400MU_BLK_SIZE = 16, | 149 | I2400MU_BLK_SIZE = 16, |
142 | I2400MU_PL_SIZE_MAX = 0x3EFF, | 150 | I2400MU_PL_SIZE_MAX = 0x3EFF, |
143 | 151 | ||
144 | /* Endpoints */ | 152 | /* Device IDs */ |
145 | I2400MU_EP_BULK_OUT = 0, | 153 | USB_DEVICE_ID_I6050 = 0x0186, |
146 | I2400MU_EP_NOTIFICATION, | ||
147 | I2400MU_EP_RESET_COLD, | ||
148 | I2400MU_EP_BULK_IN, | ||
149 | }; | 154 | }; |
150 | 155 | ||
151 | 156 | ||
@@ -215,6 +220,7 @@ struct i2400mu { | |||
215 | struct usb_device *usb_dev; | 220 | struct usb_device *usb_dev; |
216 | struct usb_interface *usb_iface; | 221 | struct usb_interface *usb_iface; |
217 | struct edc urb_edc; /* Error density counter */ | 222 | struct edc urb_edc; /* Error density counter */ |
223 | struct i2400m_endpoint_cfg endpoint_cfg; | ||
218 | 224 | ||
219 | struct urb *notif_urb; | 225 | struct urb *notif_urb; |
220 | struct task_struct *tx_kthread; | 226 | struct task_struct *tx_kthread; |
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 60330f313f27..04df9bbe340f 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h | |||
@@ -117,16 +117,30 @@ | |||
117 | * well as i2400m->wimax_dev.net_dev and call i2400m_setup(). The | 117 | * well as i2400m->wimax_dev.net_dev and call i2400m_setup(). The |
118 | * i2400m driver will only register with the WiMAX and network stacks; | 118 | * i2400m driver will only register with the WiMAX and network stacks; |
119 | * the only access done to the device is to read the MAC address so we | 119 | * the only access done to the device is to read the MAC address so we |
120 | * can register a network device. This calls i2400m_dev_start() to | 120 | * can register a network device. |
121 | * load firmware, setup communication with the device and configure it | ||
122 | * for operation. | ||
123 | * | 121 | * |
124 | * At this point, control and data communications are possible. | 122 | * The high-level call flow is: |
123 | * | ||
124 | * bus_probe() | ||
125 | * i2400m_setup() | ||
126 | * i2400m->bus_setup() | ||
127 | * boot rom initialization / read mac addr | ||
128 | * network / WiMAX stacks registration | ||
129 | * i2400m_dev_start() | ||
130 | * i2400m->bus_dev_start() | ||
131 | * i2400m_dev_initialize() | ||
125 | * | 132 | * |
126 | * On disconnect/driver unload, the bus-specific disconnect function | 133 | * The reverse applies for a disconnect() call: |
127 | * calls i2400m_release() to undo i2400m_setup(). i2400m_dev_stop() | 134 | * |
128 | * shuts the firmware down and releases resources uses to communicate | 135 | * bus_disconnect() |
129 | * with the device. | 136 | * i2400m_release() |
137 | * i2400m_dev_stop() | ||
138 | * i2400m_dev_shutdown() | ||
139 | * i2400m->bus_dev_stop() | ||
140 | * network / WiMAX stack unregistration | ||
141 | * i2400m->bus_release() | ||
142 | * | ||
143 | * At this point, control and data communications are possible. | ||
130 | * | 144 | * |
131 | * While the device is up, it might reset. The bus-specific driver has | 145 | * While the device is up, it might reset. The bus-specific driver has |
132 | * to catch that situation and call i2400m_dev_reset_handle() to deal | 146 | * to catch that situation and call i2400m_dev_reset_handle() to deal |
@@ -148,9 +162,6 @@ | |||
148 | 162 | ||
149 | /* Misc constants */ | 163 | /* Misc constants */ |
150 | enum { | 164 | enum { |
151 | /* Firmware uploading */ | ||
152 | I2400M_BOOT_RETRIES = 3, | ||
153 | I3200_BOOT_RETRIES = 3, | ||
154 | /* Size of the Boot Mode Command buffer */ | 165 | /* Size of the Boot Mode Command buffer */ |
155 | I2400M_BM_CMD_BUF_SIZE = 16 * 1024, | 166 | I2400M_BM_CMD_BUF_SIZE = 16 * 1024, |
156 | I2400M_BM_ACK_BUF_SIZE = 256, | 167 | I2400M_BM_ACK_BUF_SIZE = 256, |
@@ -197,6 +208,7 @@ enum i2400m_reset_type { | |||
197 | 208 | ||
198 | struct i2400m_reset_ctx; | 209 | struct i2400m_reset_ctx; |
199 | struct i2400m_roq; | 210 | struct i2400m_roq; |
211 | struct i2400m_barker_db; | ||
200 | 212 | ||
201 | /** | 213 | /** |
202 | * struct i2400m - descriptor for an Intel 2400m | 214 | * struct i2400m - descriptor for an Intel 2400m |
@@ -204,27 +216,50 @@ struct i2400m_roq; | |||
204 | * Members marked with [fill] must be filled out/initialized before | 216 | * Members marked with [fill] must be filled out/initialized before |
205 | * calling i2400m_setup(). | 217 | * calling i2400m_setup(). |
206 | * | 218 | * |
219 | * Note the @bus_setup/@bus_release, @bus_dev_start/@bus_dev_release | ||
220 | * call pairs are very much doing almost the same, and depending on | ||
221 | * the underlying bus, some stuff has to be put in one or the | ||
222 | * other. The idea of setup/release is that they setup the minimal | ||
223 | * amount needed for loading firmware, where us dev_start/stop setup | ||
224 | * the rest needed to do full data/control traffic. | ||
225 | * | ||
207 | * @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16, | 226 | * @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16, |
208 | * so we have a tx_blk_size variable that the bus layer sets to | 227 | * so we have a tx_blk_size variable that the bus layer sets to |
209 | * tell the engine how much of that we need. | 228 | * tell the engine how much of that we need. |
210 | * | 229 | * |
211 | * @bus_pl_size_max: [fill] Maximum payload size. | 230 | * @bus_pl_size_max: [fill] Maximum payload size. |
212 | * | 231 | * |
213 | * @bus_dev_start: [fill] Function called by the bus-generic code | 232 | * @bus_setup: [optional fill] Function called by the bus-generic code |
214 | * [i2400m_dev_start()] to setup the bus-specific communications | 233 | * [i2400m_setup()] to setup the basic bus-specific communications |
215 | * to the the device. See LIFE CYCLE above. | 234 | * to the the device needed to load firmware. See LIFE CYCLE above. |
216 | * | 235 | * |
217 | * NOTE: Doesn't need to upload the firmware, as that is taken | 236 | * NOTE: Doesn't need to upload the firmware, as that is taken |
218 | * care of by the bus-generic code. | 237 | * care of by the bus-generic code. |
219 | * | 238 | * |
220 | * @bus_dev_stop: [fill] Function called by the bus-generic code | 239 | * @bus_release: [optional fill] Function called by the bus-generic |
221 | * [i2400m_dev_stop()] to shutdown the bus-specific communications | 240 | * code [i2400m_release()] to shutdown the basic bus-specific |
222 | * to the the device. See LIFE CYCLE above. | 241 | * communications to the the device needed to load firmware. See |
242 | * LIFE CYCLE above. | ||
223 | * | 243 | * |
224 | * This function does not need to reset the device, just tear down | 244 | * This function does not need to reset the device, just tear down |
225 | * all the host resources created to handle communication with | 245 | * all the host resources created to handle communication with |
226 | * the device. | 246 | * the device. |
227 | * | 247 | * |
248 | * @bus_dev_start: [optional fill] Function called by the bus-generic | ||
249 | * code [i2400m_dev_start()] to do things needed to start the | ||
250 | * device. See LIFE CYCLE above. | ||
251 | * | ||
252 | * NOTE: Doesn't need to upload the firmware, as that is taken | ||
253 | * care of by the bus-generic code. | ||
254 | * | ||
255 | * @bus_dev_stop: [optional fill] Function called by the bus-generic | ||
256 | * code [i2400m_dev_stop()] to do things needed for stopping the | ||
257 | * device. See LIFE CYCLE above. | ||
258 | * | ||
259 | * This function does not need to reset the device, just tear down | ||
260 | * all the host resources created to handle communication with | ||
261 | * the device. | ||
262 | * | ||
228 | * @bus_tx_kick: [fill] Function called by the bus-generic code to let | 263 | * @bus_tx_kick: [fill] Function called by the bus-generic code to let |
229 | * the bus-specific code know that there is data available in the | 264 | * the bus-specific code know that there is data available in the |
230 | * TX FIFO for transmission to the device. | 265 | * TX FIFO for transmission to the device. |
@@ -246,6 +281,9 @@ struct i2400m_roq; | |||
246 | * process, so it cannot rely on common infrastructure being laid | 281 | * process, so it cannot rely on common infrastructure being laid |
247 | * out. | 282 | * out. |
248 | * | 283 | * |
284 | * IMPORTANT: don't call reset on RT_BUS with i2400m->init_mutex | ||
285 | * held, as the .pre/.post reset handlers will deadlock. | ||
286 | * | ||
249 | * @bus_bm_retries: [fill] How many times shall a firmware upload / | 287 | * @bus_bm_retries: [fill] How many times shall a firmware upload / |
250 | * device initialization be retried? Different models of the same | 288 | * device initialization be retried? Different models of the same |
251 | * device might need different values, hence it is set by the | 289 | * device might need different values, hence it is set by the |
@@ -297,6 +335,27 @@ struct i2400m_roq; | |||
297 | * force this to be the first field so that we can get from | 335 | * force this to be the first field so that we can get from |
298 | * netdev_priv() the right pointer. | 336 | * netdev_priv() the right pointer. |
299 | * | 337 | * |
338 | * @updown: the device is up and ready for transmitting control and | ||
339 | * data packets. This implies @ready (communication infrastructure | ||
340 | * with the device is ready) and the device's firmware has been | ||
341 | * loaded and the device initialized. | ||
342 | * | ||
343 | * Write to it only inside a i2400m->init_mutex protected area | ||
344 | * followed with a wmb(); rmb() before accesing (unless locked | ||
345 | * inside i2400m->init_mutex). Read access can be loose like that | ||
346 | * [just using rmb()] because the paths that use this also do | ||
347 | * other error checks later on. | ||
348 | * | ||
349 | * @ready: Communication infrastructure with the device is ready, data | ||
350 | * frames can start to be passed around (this is lighter than | ||
351 | * using the WiMAX state for certain hot paths). | ||
352 | * | ||
353 | * Write to it only inside a i2400m->init_mutex protected area | ||
354 | * followed with a wmb(); rmb() before accesing (unless locked | ||
355 | * inside i2400m->init_mutex). Read access can be loose like that | ||
356 | * [just using rmb()] because the paths that use this also do | ||
357 | * other error checks later on. | ||
358 | * | ||
300 | * @rx_reorder: 1 if RX reordering is enabled; this can only be | 359 | * @rx_reorder: 1 if RX reordering is enabled; this can only be |
301 | * set at probe time. | 360 | * set at probe time. |
302 | * | 361 | * |
@@ -362,6 +421,13 @@ struct i2400m_roq; | |||
362 | * delivered. Then the driver can release them to the host. See | 421 | * delivered. Then the driver can release them to the host. See |
363 | * drivers/net/i2400m/rx.c for details. | 422 | * drivers/net/i2400m/rx.c for details. |
364 | * | 423 | * |
424 | * @rx_reports: reports received from the device that couldn't be | ||
425 | * processed because the driver wasn't still ready; when ready, | ||
426 | * they are pulled from here and chewed. | ||
427 | * | ||
428 | * @rx_reports_ws: Work struct used to kick a scan of the RX reports | ||
429 | * list and to process each. | ||
430 | * | ||
365 | * @src_mac_addr: MAC address used to make ethernet packets be coming | 431 | * @src_mac_addr: MAC address used to make ethernet packets be coming |
366 | * from. This is generated at i2400m_setup() time and used during | 432 | * from. This is generated at i2400m_setup() time and used during |
367 | * the life cycle of the instance. See i2400m_fake_eth_header(). | 433 | * the life cycle of the instance. See i2400m_fake_eth_header(). |
@@ -422,6 +488,25 @@ struct i2400m_roq; | |||
422 | * | 488 | * |
423 | * @fw_version: version of the firmware interface, Major.minor, | 489 | * @fw_version: version of the firmware interface, Major.minor, |
424 | * encoded in the high word and low word (major << 16 | minor). | 490 | * encoded in the high word and low word (major << 16 | minor). |
491 | * | ||
492 | * @fw_hdrs: NULL terminated array of pointers to the firmware | ||
493 | * headers. This is only available during firmware load time. | ||
494 | * | ||
495 | * @fw_cached: Used to cache firmware when the system goes to | ||
496 | * suspend/standby/hibernation (as on resume we can't read it). If | ||
497 | * NULL, no firmware was cached, read it. If ~0, you can't read | ||
498 | * any firmware files (the system still didn't come out of suspend | ||
499 | * and failed to cache one), so abort; otherwise, a valid cached | ||
500 | * firmware to be used. Access to this variable is protected by | ||
501 | * the spinlock i2400m->rx_lock. | ||
502 | * | ||
503 | * @barker: barker type that the device uses; this is initialized by | ||
504 | * i2400m_is_boot_barker() the first time it is called. Then it | ||
505 | * won't change during the life cycle of the device and everytime | ||
506 | * a boot barker is received, it is just verified for it being the | ||
507 | * same. | ||
508 | * | ||
509 | * @pm_notifier: used to register for PM events | ||
425 | */ | 510 | */ |
426 | struct i2400m { | 511 | struct i2400m { |
427 | struct wimax_dev wimax_dev; /* FIRST! See doc */ | 512 | struct wimax_dev wimax_dev; /* FIRST! See doc */ |
@@ -429,7 +514,7 @@ struct i2400m { | |||
429 | unsigned updown:1; /* Network device is up or down */ | 514 | unsigned updown:1; /* Network device is up or down */ |
430 | unsigned boot_mode:1; /* is the device in boot mode? */ | 515 | unsigned boot_mode:1; /* is the device in boot mode? */ |
431 | unsigned sboot:1; /* signed or unsigned fw boot */ | 516 | unsigned sboot:1; /* signed or unsigned fw boot */ |
432 | unsigned ready:1; /* all probing steps done */ | 517 | unsigned ready:1; /* Device comm infrastructure ready */ |
433 | unsigned rx_reorder:1; /* RX reorder is enabled */ | 518 | unsigned rx_reorder:1; /* RX reorder is enabled */ |
434 | u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */ | 519 | u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */ |
435 | /* typed u8 so /sys/kernel/debug/u8 can tweak */ | 520 | /* typed u8 so /sys/kernel/debug/u8 can tweak */ |
@@ -440,8 +525,10 @@ struct i2400m { | |||
440 | size_t bus_pl_size_max; | 525 | size_t bus_pl_size_max; |
441 | unsigned bus_bm_retries; | 526 | unsigned bus_bm_retries; |
442 | 527 | ||
528 | int (*bus_setup)(struct i2400m *); | ||
443 | int (*bus_dev_start)(struct i2400m *); | 529 | int (*bus_dev_start)(struct i2400m *); |
444 | void (*bus_dev_stop)(struct i2400m *); | 530 | void (*bus_dev_stop)(struct i2400m *); |
531 | void (*bus_release)(struct i2400m *); | ||
445 | void (*bus_tx_kick)(struct i2400m *); | 532 | void (*bus_tx_kick)(struct i2400m *); |
446 | int (*bus_reset)(struct i2400m *, enum i2400m_reset_type); | 533 | int (*bus_reset)(struct i2400m *, enum i2400m_reset_type); |
447 | ssize_t (*bus_bm_cmd_send)(struct i2400m *, | 534 | ssize_t (*bus_bm_cmd_send)(struct i2400m *, |
@@ -468,6 +555,8 @@ struct i2400m { | |||
468 | rx_num, rx_size_acc, rx_size_min, rx_size_max; | 555 | rx_num, rx_size_acc, rx_size_min, rx_size_max; |
469 | struct i2400m_roq *rx_roq; /* not under rx_lock! */ | 556 | struct i2400m_roq *rx_roq; /* not under rx_lock! */ |
470 | u8 src_mac_addr[ETH_HLEN]; | 557 | u8 src_mac_addr[ETH_HLEN]; |
558 | struct list_head rx_reports; /* under rx_lock! */ | ||
559 | struct work_struct rx_report_ws; | ||
471 | 560 | ||
472 | struct mutex msg_mutex; /* serialize command execution */ | 561 | struct mutex msg_mutex; /* serialize command execution */ |
473 | struct completion msg_completion; | 562 | struct completion msg_completion; |
@@ -487,37 +576,12 @@ struct i2400m { | |||
487 | struct dentry *debugfs_dentry; | 576 | struct dentry *debugfs_dentry; |
488 | const char *fw_name; /* name of the current firmware image */ | 577 | const char *fw_name; /* name of the current firmware image */ |
489 | unsigned long fw_version; /* version of the firmware interface */ | 578 | unsigned long fw_version; /* version of the firmware interface */ |
490 | }; | 579 | const struct i2400m_bcf_hdr **fw_hdrs; |
491 | 580 | struct i2400m_fw *fw_cached; /* protected by rx_lock */ | |
581 | struct i2400m_barker_db *barker; | ||
492 | 582 | ||
493 | /* | 583 | struct notifier_block pm_notifier; |
494 | * Initialize a 'struct i2400m' from all zeroes | 584 | }; |
495 | * | ||
496 | * This is a bus-generic API call. | ||
497 | */ | ||
498 | static inline | ||
499 | void i2400m_init(struct i2400m *i2400m) | ||
500 | { | ||
501 | wimax_dev_init(&i2400m->wimax_dev); | ||
502 | |||
503 | i2400m->boot_mode = 1; | ||
504 | i2400m->rx_reorder = 1; | ||
505 | init_waitqueue_head(&i2400m->state_wq); | ||
506 | |||
507 | spin_lock_init(&i2400m->tx_lock); | ||
508 | i2400m->tx_pl_min = UINT_MAX; | ||
509 | i2400m->tx_size_min = UINT_MAX; | ||
510 | |||
511 | spin_lock_init(&i2400m->rx_lock); | ||
512 | i2400m->rx_pl_min = UINT_MAX; | ||
513 | i2400m->rx_size_min = UINT_MAX; | ||
514 | |||
515 | mutex_init(&i2400m->msg_mutex); | ||
516 | init_completion(&i2400m->msg_completion); | ||
517 | |||
518 | mutex_init(&i2400m->init_mutex); | ||
519 | /* wake_tx_ws is initialized in i2400m_tx_setup() */ | ||
520 | } | ||
521 | 585 | ||
522 | 586 | ||
523 | /* | 587 | /* |
@@ -577,6 +641,14 @@ extern void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *); | |||
577 | extern int i2400m_dev_bootstrap(struct i2400m *, enum i2400m_bri); | 641 | extern int i2400m_dev_bootstrap(struct i2400m *, enum i2400m_bri); |
578 | extern int i2400m_read_mac_addr(struct i2400m *); | 642 | extern int i2400m_read_mac_addr(struct i2400m *); |
579 | extern int i2400m_bootrom_init(struct i2400m *, enum i2400m_bri); | 643 | extern int i2400m_bootrom_init(struct i2400m *, enum i2400m_bri); |
644 | extern int i2400m_is_boot_barker(struct i2400m *, const void *, size_t); | ||
645 | static inline | ||
646 | int i2400m_is_d2h_barker(const void *buf) | ||
647 | { | ||
648 | const __le32 *barker = buf; | ||
649 | return le32_to_cpu(*barker) == I2400M_D2H_MSG_BARKER; | ||
650 | } | ||
651 | extern void i2400m_unknown_barker(struct i2400m *, const void *, size_t); | ||
580 | 652 | ||
581 | /* Make/grok boot-rom header commands */ | 653 | /* Make/grok boot-rom header commands */ |
582 | 654 | ||
@@ -644,6 +716,8 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr) | |||
644 | /* | 716 | /* |
645 | * Driver / device setup and internal functions | 717 | * Driver / device setup and internal functions |
646 | */ | 718 | */ |
719 | extern void i2400m_init(struct i2400m *); | ||
720 | extern int i2400m_reset(struct i2400m *, enum i2400m_reset_type); | ||
647 | extern void i2400m_netdev_setup(struct net_device *net_dev); | 721 | extern void i2400m_netdev_setup(struct net_device *net_dev); |
648 | extern int i2400m_sysfs_setup(struct device_driver *); | 722 | extern int i2400m_sysfs_setup(struct device_driver *); |
649 | extern void i2400m_sysfs_release(struct device_driver *); | 723 | extern void i2400m_sysfs_release(struct device_driver *); |
@@ -654,10 +728,14 @@ extern void i2400m_tx_release(struct i2400m *); | |||
654 | extern int i2400m_rx_setup(struct i2400m *); | 728 | extern int i2400m_rx_setup(struct i2400m *); |
655 | extern void i2400m_rx_release(struct i2400m *); | 729 | extern void i2400m_rx_release(struct i2400m *); |
656 | 730 | ||
731 | extern void i2400m_fw_cache(struct i2400m *); | ||
732 | extern void i2400m_fw_uncache(struct i2400m *); | ||
733 | |||
657 | extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned, | 734 | extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned, |
658 | const void *, int); | 735 | const void *, int); |
659 | extern void i2400m_net_erx(struct i2400m *, struct sk_buff *, | 736 | extern void i2400m_net_erx(struct i2400m *, struct sk_buff *, |
660 | enum i2400m_cs); | 737 | enum i2400m_cs); |
738 | extern void i2400m_net_wake_stop(struct i2400m *); | ||
661 | enum i2400m_pt; | 739 | enum i2400m_pt; |
662 | extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt); | 740 | extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt); |
663 | 741 | ||
@@ -672,14 +750,12 @@ static inline int i2400m_debugfs_add(struct i2400m *i2400m) | |||
672 | static inline void i2400m_debugfs_rm(struct i2400m *i2400m) {} | 750 | static inline void i2400m_debugfs_rm(struct i2400m *i2400m) {} |
673 | #endif | 751 | #endif |
674 | 752 | ||
675 | /* Called by _dev_start()/_dev_stop() to initialize the device itself */ | 753 | /* Initialize/shutdown the device */ |
676 | extern int i2400m_dev_initialize(struct i2400m *); | 754 | extern int i2400m_dev_initialize(struct i2400m *); |
677 | extern void i2400m_dev_shutdown(struct i2400m *); | 755 | extern void i2400m_dev_shutdown(struct i2400m *); |
678 | 756 | ||
679 | extern struct attribute_group i2400m_dev_attr_group; | 757 | extern struct attribute_group i2400m_dev_attr_group; |
680 | 758 | ||
681 | extern int i2400m_schedule_work(struct i2400m *, | ||
682 | void (*)(struct work_struct *), gfp_t); | ||
683 | 759 | ||
684 | /* HDI message's payload description handling */ | 760 | /* HDI message's payload description handling */ |
685 | 761 | ||
@@ -724,7 +800,9 @@ void i2400m_put(struct i2400m *i2400m) | |||
724 | dev_put(i2400m->wimax_dev.net_dev); | 800 | dev_put(i2400m->wimax_dev.net_dev); |
725 | } | 801 | } |
726 | 802 | ||
727 | extern int i2400m_dev_reset_handle(struct i2400m *); | 803 | extern int i2400m_dev_reset_handle(struct i2400m *, const char *); |
804 | extern int i2400m_pre_reset(struct i2400m *); | ||
805 | extern int i2400m_post_reset(struct i2400m *); | ||
728 | 806 | ||
729 | /* | 807 | /* |
730 | * _setup()/_release() are called by the probe/disconnect functions of | 808 | * _setup()/_release() are called by the probe/disconnect functions of |
@@ -737,20 +815,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *); | |||
737 | extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *); | 815 | extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *); |
738 | extern void i2400m_tx_msg_sent(struct i2400m *); | 816 | extern void i2400m_tx_msg_sent(struct i2400m *); |
739 | 817 | ||
740 | static const __le32 i2400m_NBOOT_BARKER[4] = { | ||
741 | cpu_to_le32(I2400M_NBOOT_BARKER), | ||
742 | cpu_to_le32(I2400M_NBOOT_BARKER), | ||
743 | cpu_to_le32(I2400M_NBOOT_BARKER), | ||
744 | cpu_to_le32(I2400M_NBOOT_BARKER) | ||
745 | }; | ||
746 | |||
747 | static const __le32 i2400m_SBOOT_BARKER[4] = { | ||
748 | cpu_to_le32(I2400M_SBOOT_BARKER), | ||
749 | cpu_to_le32(I2400M_SBOOT_BARKER), | ||
750 | cpu_to_le32(I2400M_SBOOT_BARKER), | ||
751 | cpu_to_le32(I2400M_SBOOT_BARKER) | ||
752 | }; | ||
753 | |||
754 | extern int i2400m_power_save_disabled; | 818 | extern int i2400m_power_save_disabled; |
755 | 819 | ||
756 | /* | 820 | /* |
@@ -773,10 +837,12 @@ struct device *i2400m_dev(struct i2400m *i2400m) | |||
773 | struct i2400m_work { | 837 | struct i2400m_work { |
774 | struct work_struct ws; | 838 | struct work_struct ws; |
775 | struct i2400m *i2400m; | 839 | struct i2400m *i2400m; |
840 | size_t pl_size; | ||
776 | u8 pl[0]; | 841 | u8 pl[0]; |
777 | }; | 842 | }; |
778 | extern int i2400m_queue_work(struct i2400m *, | 843 | |
779 | void (*)(struct work_struct *), gfp_t, | 844 | extern int i2400m_schedule_work(struct i2400m *, |
845 | void (*)(struct work_struct *), gfp_t, | ||
780 | const void *, size_t); | 846 | const void *, size_t); |
781 | 847 | ||
782 | extern int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *, | 848 | extern int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *, |
@@ -789,6 +855,7 @@ extern void i2400m_msg_ack_hook(struct i2400m *, | |||
789 | const struct i2400m_l3l4_hdr *, size_t); | 855 | const struct i2400m_l3l4_hdr *, size_t); |
790 | extern void i2400m_report_hook(struct i2400m *, | 856 | extern void i2400m_report_hook(struct i2400m *, |
791 | const struct i2400m_l3l4_hdr *, size_t); | 857 | const struct i2400m_l3l4_hdr *, size_t); |
858 | extern void i2400m_report_hook_work(struct work_struct *); | ||
792 | extern int i2400m_cmd_enter_powersave(struct i2400m *); | 859 | extern int i2400m_cmd_enter_powersave(struct i2400m *); |
793 | extern int i2400m_cmd_get_state(struct i2400m *); | 860 | extern int i2400m_cmd_get_state(struct i2400m *); |
794 | extern int i2400m_cmd_exit_idle(struct i2400m *); | 861 | extern int i2400m_cmd_exit_idle(struct i2400m *); |
@@ -849,6 +916,12 @@ void __i2400m_msleep(unsigned ms) | |||
849 | #endif | 916 | #endif |
850 | } | 917 | } |
851 | 918 | ||
919 | |||
920 | /* module initialization helpers */ | ||
921 | extern int i2400m_barker_db_init(const char *); | ||
922 | extern void i2400m_barker_db_exit(void); | ||
923 | |||
924 | |||
852 | /* Module parameters */ | 925 | /* Module parameters */ |
853 | 926 | ||
854 | extern int i2400m_idle_mode_disabled; | 927 | extern int i2400m_idle_mode_disabled; |
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 796396cb4c82..599aa4eb9baa 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c | |||
@@ -74,6 +74,7 @@ | |||
74 | */ | 74 | */ |
75 | #include <linux/if_arp.h> | 75 | #include <linux/if_arp.h> |
76 | #include <linux/netdevice.h> | 76 | #include <linux/netdevice.h> |
77 | #include <linux/ethtool.h> | ||
77 | #include "i2400m.h" | 78 | #include "i2400m.h" |
78 | 79 | ||
79 | 80 | ||
@@ -88,7 +89,10 @@ enum { | |||
88 | * The MTU is 1400 or less | 89 | * The MTU is 1400 or less |
89 | */ | 90 | */ |
90 | I2400M_MAX_MTU = 1400, | 91 | I2400M_MAX_MTU = 1400, |
91 | I2400M_TX_TIMEOUT = HZ, | 92 | /* 20 secs? yep, this is the maximum timeout that the device |
93 | * might take to get out of IDLE / negotiate it with the base | ||
94 | * station. We add 1sec for good measure. */ | ||
95 | I2400M_TX_TIMEOUT = 21 * HZ, | ||
92 | I2400M_TX_QLEN = 5, | 96 | I2400M_TX_QLEN = 5, |
93 | }; | 97 | }; |
94 | 98 | ||
@@ -101,22 +105,19 @@ int i2400m_open(struct net_device *net_dev) | |||
101 | struct device *dev = i2400m_dev(i2400m); | 105 | struct device *dev = i2400m_dev(i2400m); |
102 | 106 | ||
103 | d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); | 107 | d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); |
104 | if (i2400m->ready == 0) { | 108 | /* Make sure we wait until init is complete... */ |
105 | dev_err(dev, "Device is still initializing\n"); | 109 | mutex_lock(&i2400m->init_mutex); |
106 | result = -EBUSY; | 110 | if (i2400m->updown) |
107 | } else | ||
108 | result = 0; | 111 | result = 0; |
112 | else | ||
113 | result = -EBUSY; | ||
114 | mutex_unlock(&i2400m->init_mutex); | ||
109 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", | 115 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", |
110 | net_dev, i2400m, result); | 116 | net_dev, i2400m, result); |
111 | return result; | 117 | return result; |
112 | } | 118 | } |
113 | 119 | ||
114 | 120 | ||
115 | /* | ||
116 | * | ||
117 | * On kernel versions where cancel_work_sync() didn't return anything, | ||
118 | * we rely on wake_tx_skb() being non-NULL. | ||
119 | */ | ||
120 | static | 121 | static |
121 | int i2400m_stop(struct net_device *net_dev) | 122 | int i2400m_stop(struct net_device *net_dev) |
122 | { | 123 | { |
@@ -124,21 +125,7 @@ int i2400m_stop(struct net_device *net_dev) | |||
124 | struct device *dev = i2400m_dev(i2400m); | 125 | struct device *dev = i2400m_dev(i2400m); |
125 | 126 | ||
126 | d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); | 127 | d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); |
127 | /* See i2400m_hard_start_xmit(), references are taken there | 128 | i2400m_net_wake_stop(i2400m); |
128 | * and here we release them if the work was still | ||
129 | * pending. Note we can't differentiate work not pending vs | ||
130 | * never scheduled, so the NULL check does that. */ | ||
131 | if (cancel_work_sync(&i2400m->wake_tx_ws) == 0 | ||
132 | && i2400m->wake_tx_skb != NULL) { | ||
133 | unsigned long flags; | ||
134 | struct sk_buff *wake_tx_skb; | ||
135 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
136 | wake_tx_skb = i2400m->wake_tx_skb; /* compat help */ | ||
137 | i2400m->wake_tx_skb = NULL; /* compat help */ | ||
138 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
139 | i2400m_put(i2400m); | ||
140 | kfree_skb(wake_tx_skb); | ||
141 | } | ||
142 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m); | 129 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m); |
143 | return 0; | 130 | return 0; |
144 | } | 131 | } |
@@ -167,6 +154,7 @@ void i2400m_wake_tx_work(struct work_struct *ws) | |||
167 | { | 154 | { |
168 | int result; | 155 | int result; |
169 | struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); | 156 | struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); |
157 | struct net_device *net_dev = i2400m->wimax_dev.net_dev; | ||
170 | struct device *dev = i2400m_dev(i2400m); | 158 | struct device *dev = i2400m_dev(i2400m); |
171 | struct sk_buff *skb = i2400m->wake_tx_skb; | 159 | struct sk_buff *skb = i2400m->wake_tx_skb; |
172 | unsigned long flags; | 160 | unsigned long flags; |
@@ -182,27 +170,36 @@ void i2400m_wake_tx_work(struct work_struct *ws) | |||
182 | dev_err(dev, "WAKE&TX: skb dissapeared!\n"); | 170 | dev_err(dev, "WAKE&TX: skb dissapeared!\n"); |
183 | goto out_put; | 171 | goto out_put; |
184 | } | 172 | } |
173 | /* If we have, somehow, lost the connection after this was | ||
174 | * queued, don't do anything; this might be the device got | ||
175 | * reset or just disconnected. */ | ||
176 | if (unlikely(!netif_carrier_ok(net_dev))) | ||
177 | goto out_kfree; | ||
185 | result = i2400m_cmd_exit_idle(i2400m); | 178 | result = i2400m_cmd_exit_idle(i2400m); |
186 | if (result == -EILSEQ) | 179 | if (result == -EILSEQ) |
187 | result = 0; | 180 | result = 0; |
188 | if (result < 0) { | 181 | if (result < 0) { |
189 | dev_err(dev, "WAKE&TX: device didn't get out of idle: " | 182 | dev_err(dev, "WAKE&TX: device didn't get out of idle: " |
190 | "%d\n", result); | 183 | "%d - resetting\n", result); |
191 | goto error; | 184 | i2400m_reset(i2400m, I2400M_RT_BUS); |
185 | goto error; | ||
192 | } | 186 | } |
193 | result = wait_event_timeout(i2400m->state_wq, | 187 | result = wait_event_timeout(i2400m->state_wq, |
194 | i2400m->state != I2400M_SS_IDLE, 5 * HZ); | 188 | i2400m->state != I2400M_SS_IDLE, |
189 | net_dev->watchdog_timeo - HZ/2); | ||
195 | if (result == 0) | 190 | if (result == 0) |
196 | result = -ETIMEDOUT; | 191 | result = -ETIMEDOUT; |
197 | if (result < 0) { | 192 | if (result < 0) { |
198 | dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: " | 193 | dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: " |
199 | "%d\n", result); | 194 | "%d - resetting\n", result); |
195 | i2400m_reset(i2400m, I2400M_RT_BUS); | ||
200 | goto error; | 196 | goto error; |
201 | } | 197 | } |
202 | msleep(20); /* device still needs some time or it drops it */ | 198 | msleep(20); /* device still needs some time or it drops it */ |
203 | result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); | 199 | result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); |
204 | netif_wake_queue(i2400m->wimax_dev.net_dev); | ||
205 | error: | 200 | error: |
201 | netif_wake_queue(net_dev); | ||
202 | out_kfree: | ||
206 | kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */ | 203 | kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */ |
207 | out_put: | 204 | out_put: |
208 | i2400m_put(i2400m); | 205 | i2400m_put(i2400m); |
@@ -229,6 +226,38 @@ void i2400m_tx_prep_header(struct sk_buff *skb) | |||
229 | } | 226 | } |
230 | 227 | ||
231 | 228 | ||
229 | |||
230 | /* | ||
231 | * Cleanup resources acquired during i2400m_net_wake_tx() | ||
232 | * | ||
233 | * This is called by __i2400m_dev_stop and means we have to make sure | ||
234 | * the workqueue is flushed from any pending work. | ||
235 | */ | ||
236 | void i2400m_net_wake_stop(struct i2400m *i2400m) | ||
237 | { | ||
238 | struct device *dev = i2400m_dev(i2400m); | ||
239 | |||
240 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | ||
241 | /* See i2400m_hard_start_xmit(), references are taken there | ||
242 | * and here we release them if the work was still | ||
243 | * pending. Note we can't differentiate work not pending vs | ||
244 | * never scheduled, so the NULL check does that. */ | ||
245 | if (cancel_work_sync(&i2400m->wake_tx_ws) == 0 | ||
246 | && i2400m->wake_tx_skb != NULL) { | ||
247 | unsigned long flags; | ||
248 | struct sk_buff *wake_tx_skb; | ||
249 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
250 | wake_tx_skb = i2400m->wake_tx_skb; /* compat help */ | ||
251 | i2400m->wake_tx_skb = NULL; /* compat help */ | ||
252 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
253 | i2400m_put(i2400m); | ||
254 | kfree_skb(wake_tx_skb); | ||
255 | } | ||
256 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | |||
232 | /* | 261 | /* |
233 | * TX an skb to an idle device | 262 | * TX an skb to an idle device |
234 | * | 263 | * |
@@ -342,6 +371,20 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, | |||
342 | int result; | 371 | int result; |
343 | 372 | ||
344 | d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); | 373 | d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); |
374 | if (skb_header_cloned(skb)) { | ||
375 | /* | ||
376 | * Make tcpdump/wireshark happy -- if they are | ||
377 | * running, the skb is cloned and we will overwrite | ||
378 | * the mac fields in i2400m_tx_prep_header. Expand | ||
379 | * seems to fix this... | ||
380 | */ | ||
381 | result = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); | ||
382 | if (result) { | ||
383 | result = NETDEV_TX_BUSY; | ||
384 | goto error_expand; | ||
385 | } | ||
386 | } | ||
387 | |||
345 | if (i2400m->state == I2400M_SS_IDLE) | 388 | if (i2400m->state == I2400M_SS_IDLE) |
346 | result = i2400m_net_wake_tx(i2400m, net_dev, skb); | 389 | result = i2400m_net_wake_tx(i2400m, net_dev, skb); |
347 | else | 390 | else |
@@ -352,10 +395,11 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, | |||
352 | net_dev->stats.tx_packets++; | 395 | net_dev->stats.tx_packets++; |
353 | net_dev->stats.tx_bytes += skb->len; | 396 | net_dev->stats.tx_bytes += skb->len; |
354 | } | 397 | } |
398 | result = NETDEV_TX_OK; | ||
399 | error_expand: | ||
355 | kfree_skb(skb); | 400 | kfree_skb(skb); |
356 | 401 | d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); | |
357 | d_fnend(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); | 402 | return result; |
358 | return NETDEV_TX_OK; | ||
359 | } | 403 | } |
360 | 404 | ||
361 | 405 | ||
@@ -559,6 +603,22 @@ static const struct net_device_ops i2400m_netdev_ops = { | |||
559 | .ndo_change_mtu = i2400m_change_mtu, | 603 | .ndo_change_mtu = i2400m_change_mtu, |
560 | }; | 604 | }; |
561 | 605 | ||
606 | static void i2400m_get_drvinfo(struct net_device *net_dev, | ||
607 | struct ethtool_drvinfo *info) | ||
608 | { | ||
609 | struct i2400m *i2400m = net_dev_to_i2400m(net_dev); | ||
610 | |||
611 | strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1); | ||
612 | strncpy(info->fw_version, i2400m->fw_name, sizeof(info->fw_version) - 1); | ||
613 | if (net_dev->dev.parent) | ||
614 | strncpy(info->bus_info, dev_name(net_dev->dev.parent), | ||
615 | sizeof(info->bus_info) - 1); | ||
616 | } | ||
617 | |||
618 | static const struct ethtool_ops i2400m_ethtool_ops = { | ||
619 | .get_drvinfo = i2400m_get_drvinfo, | ||
620 | .get_link = ethtool_op_get_link, | ||
621 | }; | ||
562 | 622 | ||
563 | /** | 623 | /** |
564 | * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data | 624 | * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data |
@@ -580,6 +640,7 @@ void i2400m_netdev_setup(struct net_device *net_dev) | |||
580 | & ~IFF_MULTICAST); | 640 | & ~IFF_MULTICAST); |
581 | net_dev->watchdog_timeo = I2400M_TX_TIMEOUT; | 641 | net_dev->watchdog_timeo = I2400M_TX_TIMEOUT; |
582 | net_dev->netdev_ops = &i2400m_netdev_ops; | 642 | net_dev->netdev_ops = &i2400m_netdev_ops; |
643 | net_dev->ethtool_ops = &i2400m_ethtool_ops; | ||
583 | d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev); | 644 | d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev); |
584 | } | 645 | } |
585 | EXPORT_SYMBOL_GPL(i2400m_netdev_setup); | 646 | EXPORT_SYMBOL_GPL(i2400m_netdev_setup); |
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 07c32e68909f..e3d2a9de023c 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c | |||
@@ -158,30 +158,104 @@ struct i2400m_report_hook_args { | |||
158 | struct sk_buff *skb_rx; | 158 | struct sk_buff *skb_rx; |
159 | const struct i2400m_l3l4_hdr *l3l4_hdr; | 159 | const struct i2400m_l3l4_hdr *l3l4_hdr; |
160 | size_t size; | 160 | size_t size; |
161 | struct list_head list_node; | ||
161 | }; | 162 | }; |
162 | 163 | ||
163 | 164 | ||
164 | /* | 165 | /* |
165 | * Execute i2400m_report_hook in a workqueue | 166 | * Execute i2400m_report_hook in a workqueue |
166 | * | 167 | * |
167 | * Unpacks arguments from the deferred call, executes it and then | 168 | * Goes over the list of queued reports in i2400m->rx_reports and |
168 | * drops the references. | 169 | * processes them. |
169 | * | 170 | * |
170 | * Obvious NOTE: References are needed because we are a separate | 171 | * NOTE: refcounts on i2400m are not needed because we flush the |
171 | * thread; otherwise the buffer changes under us because it is | 172 | * workqueue this runs on (i2400m->work_queue) before destroying |
172 | * released by the original caller. | 173 | * i2400m. |
173 | */ | 174 | */ |
174 | static | ||
175 | void i2400m_report_hook_work(struct work_struct *ws) | 175 | void i2400m_report_hook_work(struct work_struct *ws) |
176 | { | 176 | { |
177 | struct i2400m_work *iw = | 177 | struct i2400m *i2400m = container_of(ws, struct i2400m, rx_report_ws); |
178 | container_of(ws, struct i2400m_work, ws); | 178 | struct device *dev = i2400m_dev(i2400m); |
179 | struct i2400m_report_hook_args *args = (void *) iw->pl; | 179 | struct i2400m_report_hook_args *args, *args_next; |
180 | if (iw->i2400m->ready) | 180 | LIST_HEAD(list); |
181 | i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); | 181 | unsigned long flags; |
182 | kfree_skb(args->skb_rx); | 182 | |
183 | i2400m_put(iw->i2400m); | 183 | while (1) { |
184 | kfree(iw); | 184 | spin_lock_irqsave(&i2400m->rx_lock, flags); |
185 | list_splice_init(&i2400m->rx_reports, &list); | ||
186 | spin_unlock_irqrestore(&i2400m->rx_lock, flags); | ||
187 | if (list_empty(&list)) | ||
188 | break; | ||
189 | else | ||
190 | d_printf(1, dev, "processing queued reports\n"); | ||
191 | list_for_each_entry_safe(args, args_next, &list, list_node) { | ||
192 | d_printf(2, dev, "processing queued report %p\n", args); | ||
193 | i2400m_report_hook(i2400m, args->l3l4_hdr, args->size); | ||
194 | kfree_skb(args->skb_rx); | ||
195 | list_del(&args->list_node); | ||
196 | kfree(args); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | |||
202 | /* | ||
203 | * Flush the list of queued reports | ||
204 | */ | ||
205 | static | ||
206 | void i2400m_report_hook_flush(struct i2400m *i2400m) | ||
207 | { | ||
208 | struct device *dev = i2400m_dev(i2400m); | ||
209 | struct i2400m_report_hook_args *args, *args_next; | ||
210 | LIST_HEAD(list); | ||
211 | unsigned long flags; | ||
212 | |||
213 | d_printf(1, dev, "flushing queued reports\n"); | ||
214 | spin_lock_irqsave(&i2400m->rx_lock, flags); | ||
215 | list_splice_init(&i2400m->rx_reports, &list); | ||
216 | spin_unlock_irqrestore(&i2400m->rx_lock, flags); | ||
217 | list_for_each_entry_safe(args, args_next, &list, list_node) { | ||
218 | d_printf(2, dev, "flushing queued report %p\n", args); | ||
219 | kfree_skb(args->skb_rx); | ||
220 | list_del(&args->list_node); | ||
221 | kfree(args); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | |||
226 | /* | ||
227 | * Queue a report for later processing | ||
228 | * | ||
229 | * @i2400m: device descriptor | ||
230 | * @skb_rx: skb that contains the payload (for reference counting) | ||
231 | * @l3l4_hdr: pointer to the control | ||
232 | * @size: size of the message | ||
233 | */ | ||
234 | static | ||
235 | void i2400m_report_hook_queue(struct i2400m *i2400m, struct sk_buff *skb_rx, | ||
236 | const void *l3l4_hdr, size_t size) | ||
237 | { | ||
238 | struct device *dev = i2400m_dev(i2400m); | ||
239 | unsigned long flags; | ||
240 | struct i2400m_report_hook_args *args; | ||
241 | |||
242 | args = kzalloc(sizeof(*args), GFP_NOIO); | ||
243 | if (args) { | ||
244 | args->skb_rx = skb_get(skb_rx); | ||
245 | args->l3l4_hdr = l3l4_hdr; | ||
246 | args->size = size; | ||
247 | spin_lock_irqsave(&i2400m->rx_lock, flags); | ||
248 | list_add_tail(&args->list_node, &i2400m->rx_reports); | ||
249 | spin_unlock_irqrestore(&i2400m->rx_lock, flags); | ||
250 | d_printf(2, dev, "queued report %p\n", args); | ||
251 | rmb(); /* see i2400m->ready's documentation */ | ||
252 | if (likely(i2400m->ready)) /* only send if up */ | ||
253 | queue_work(i2400m->work_queue, &i2400m->rx_report_ws); | ||
254 | } else { | ||
255 | if (printk_ratelimit()) | ||
256 | dev_err(dev, "%s:%u: Can't allocate %zu B\n", | ||
257 | __func__, __LINE__, sizeof(*args)); | ||
258 | } | ||
185 | } | 259 | } |
186 | 260 | ||
187 | 261 | ||
@@ -295,21 +369,29 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, | |||
295 | msg_type, size); | 369 | msg_type, size); |
296 | d_dump(2, dev, l3l4_hdr, size); | 370 | d_dump(2, dev, l3l4_hdr, size); |
297 | if (msg_type & I2400M_MT_REPORT_MASK) { | 371 | if (msg_type & I2400M_MT_REPORT_MASK) { |
298 | /* These hooks have to be ran serialized; as well, the | 372 | /* |
299 | * handling might force the execution of commands, and | 373 | * Process each report |
300 | * that might cause reentrancy issues with | 374 | * |
301 | * bus-specific subdrivers and workqueues. So we run | 375 | * - has to be ran serialized as well |
302 | * it in a separate workqueue. */ | 376 | * |
303 | struct i2400m_report_hook_args args = { | 377 | * - the handling might force the execution of |
304 | .skb_rx = skb_rx, | 378 | * commands. That might cause reentrancy issues with |
305 | .l3l4_hdr = l3l4_hdr, | 379 | * bus-specific subdrivers and workqueues, so the we |
306 | .size = size | 380 | * run it in a separate workqueue. |
307 | }; | 381 | * |
308 | if (unlikely(i2400m->ready == 0)) /* only send if up */ | 382 | * - when the driver is not yet ready to handle them, |
309 | return; | 383 | * they are queued and at some point the queue is |
310 | skb_get(skb_rx); | 384 | * restarted [NOTE: we can't queue SKBs directly, as |
311 | i2400m_queue_work(i2400m, i2400m_report_hook_work, | 385 | * this might be a piece of a SKB, not the whole |
312 | GFP_KERNEL, &args, sizeof(args)); | 386 | * thing, and this is cheaper than cloning the |
387 | * SKB]. | ||
388 | * | ||
389 | * Note we don't do refcounting for the device | ||
390 | * structure; this is because before destroying | ||
391 | * 'i2400m', we make sure to flush the | ||
392 | * i2400m->work_queue, so there are no issues. | ||
393 | */ | ||
394 | i2400m_report_hook_queue(i2400m, skb_rx, l3l4_hdr, size); | ||
313 | if (unlikely(i2400m->trace_msg_from_user)) | 395 | if (unlikely(i2400m->trace_msg_from_user)) |
314 | wimax_msg(&i2400m->wimax_dev, "echo", | 396 | wimax_msg(&i2400m->wimax_dev, "echo", |
315 | l3l4_hdr, size, GFP_KERNEL); | 397 | l3l4_hdr, size, GFP_KERNEL); |
@@ -363,8 +445,6 @@ void i2400m_rx_trace(struct i2400m *i2400m, | |||
363 | msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET", | 445 | msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET", |
364 | msg_type, size); | 446 | msg_type, size); |
365 | d_dump(2, dev, l3l4_hdr, size); | 447 | d_dump(2, dev, l3l4_hdr, size); |
366 | if (unlikely(i2400m->ready == 0)) /* only send if up */ | ||
367 | return; | ||
368 | result = wimax_msg(wimax_dev, "trace", l3l4_hdr, size, GFP_KERNEL); | 448 | result = wimax_msg(wimax_dev, "trace", l3l4_hdr, size, GFP_KERNEL); |
369 | if (result < 0) | 449 | if (result < 0) |
370 | dev_err(dev, "error sending trace to userspace: %d\n", | 450 | dev_err(dev, "error sending trace to userspace: %d\n", |
@@ -748,7 +828,7 @@ void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq, | |||
748 | dev_err(dev, "SW BUG? queue nsn %d (lbn %u ws %u)\n", | 828 | dev_err(dev, "SW BUG? queue nsn %d (lbn %u ws %u)\n", |
749 | nsn, lbn, roq->ws); | 829 | nsn, lbn, roq->ws); |
750 | i2400m_roq_log_dump(i2400m, roq); | 830 | i2400m_roq_log_dump(i2400m, roq); |
751 | i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 831 | i2400m_reset(i2400m, I2400M_RT_WARM); |
752 | } else { | 832 | } else { |
753 | __i2400m_roq_queue(i2400m, roq, skb, lbn, nsn); | 833 | __i2400m_roq_queue(i2400m, roq, skb, lbn, nsn); |
754 | i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET, | 834 | i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET, |
@@ -814,7 +894,7 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq, | |||
814 | dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n", | 894 | dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n", |
815 | nsn, sn, roq->ws); | 895 | nsn, sn, roq->ws); |
816 | i2400m_roq_log_dump(i2400m, roq); | 896 | i2400m_roq_log_dump(i2400m, roq); |
817 | i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 897 | i2400m_reset(i2400m, I2400M_RT_WARM); |
818 | } else { | 898 | } else { |
819 | /* if the queue is empty, don't bother as we'd queue | 899 | /* if the queue is empty, don't bother as we'd queue |
820 | * it and inmediately unqueue it -- just deliver it */ | 900 | * it and inmediately unqueue it -- just deliver it */ |
@@ -1194,6 +1274,28 @@ error_msg_hdr_check: | |||
1194 | EXPORT_SYMBOL_GPL(i2400m_rx); | 1274 | EXPORT_SYMBOL_GPL(i2400m_rx); |
1195 | 1275 | ||
1196 | 1276 | ||
1277 | void i2400m_unknown_barker(struct i2400m *i2400m, | ||
1278 | const void *buf, size_t size) | ||
1279 | { | ||
1280 | struct device *dev = i2400m_dev(i2400m); | ||
1281 | char prefix[64]; | ||
1282 | const __le32 *barker = buf; | ||
1283 | dev_err(dev, "RX: HW BUG? unknown barker %08x, " | ||
1284 | "dropping %zu bytes\n", le32_to_cpu(*barker), size); | ||
1285 | snprintf(prefix, sizeof(prefix), "%s %s: ", | ||
1286 | dev_driver_string(dev), dev_name(dev)); | ||
1287 | if (size > 64) { | ||
1288 | print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, | ||
1289 | 8, 4, buf, 64, 0); | ||
1290 | printk(KERN_ERR "%s... (only first 64 bytes " | ||
1291 | "dumped)\n", prefix); | ||
1292 | } else | ||
1293 | print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, | ||
1294 | 8, 4, buf, size, 0); | ||
1295 | } | ||
1296 | EXPORT_SYMBOL(i2400m_unknown_barker); | ||
1297 | |||
1298 | |||
1197 | /* | 1299 | /* |
1198 | * Initialize the RX queue and infrastructure | 1300 | * Initialize the RX queue and infrastructure |
1199 | * | 1301 | * |
@@ -1261,4 +1363,6 @@ void i2400m_rx_release(struct i2400m *i2400m) | |||
1261 | kfree(i2400m->rx_roq[0].log); | 1363 | kfree(i2400m->rx_roq[0].log); |
1262 | kfree(i2400m->rx_roq); | 1364 | kfree(i2400m->rx_roq); |
1263 | } | 1365 | } |
1366 | /* at this point, nothing can be received... */ | ||
1367 | i2400m_report_hook_flush(i2400m); | ||
1264 | } | 1368 | } |
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c index 7d6ec0f475f8..8e025418f5be 100644 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ b/drivers/net/wimax/i2400m/sdio-fw.c | |||
@@ -118,7 +118,8 @@ ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m, | |||
118 | if (cmd_size > I2400M_BM_CMD_BUF_SIZE) | 118 | if (cmd_size > I2400M_BM_CMD_BUF_SIZE) |
119 | goto error_too_big; | 119 | goto error_too_big; |
120 | 120 | ||
121 | memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size); /* Prep command */ | 121 | if (_cmd != i2400m->bm_cmd_buf) |
122 | memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); | ||
122 | cmd = i2400m->bm_cmd_buf; | 123 | cmd = i2400m->bm_cmd_buf; |
123 | if (cmd_size_a > cmd_size) /* Zero pad space */ | 124 | if (cmd_size_a > cmd_size) /* Zero pad space */ |
124 | memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); | 125 | memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); |
@@ -177,10 +178,6 @@ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, | |||
177 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", | 178 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", |
178 | i2400m, ack, ack_size); | 179 | i2400m, ack, ack_size); |
179 | 180 | ||
180 | spin_lock(&i2400m->rx_lock); | ||
181 | i2400ms->bm_ack_size = -EINPROGRESS; | ||
182 | spin_unlock(&i2400m->rx_lock); | ||
183 | |||
184 | result = wait_event_timeout(i2400ms->bm_wfa_wq, | 181 | result = wait_event_timeout(i2400ms->bm_wfa_wq, |
185 | i2400ms->bm_ack_size != -EINPROGRESS, | 182 | i2400ms->bm_ack_size != -EINPROGRESS, |
186 | 2 * HZ); | 183 | 2 * HZ); |
@@ -199,6 +196,10 @@ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, | |||
199 | size = min(ack_size, i2400ms->bm_ack_size); | 196 | size = min(ack_size, i2400ms->bm_ack_size); |
200 | memcpy(ack, i2400m->bm_ack_buf, size); | 197 | memcpy(ack, i2400m->bm_ack_buf, size); |
201 | } | 198 | } |
199 | /* | ||
200 | * Remember always to clear the bm_ack_size to -EINPROGRESS | ||
201 | * after the RX data is processed | ||
202 | */ | ||
202 | i2400ms->bm_ack_size = -EINPROGRESS; | 203 | i2400ms->bm_ack_size = -EINPROGRESS; |
203 | spin_unlock(&i2400m->rx_lock); | 204 | spin_unlock(&i2400m->rx_lock); |
204 | 205 | ||
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c index 321beadf6e47..8adf6c9b6f8f 100644 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ b/drivers/net/wimax/i2400m/sdio-rx.c | |||
@@ -53,6 +53,7 @@ | |||
53 | * i2400ms_irq() | 53 | * i2400ms_irq() |
54 | * i2400ms_rx() | 54 | * i2400ms_rx() |
55 | * __i2400ms_rx_get_size() | 55 | * __i2400ms_rx_get_size() |
56 | * i2400m_is_boot_barker() | ||
56 | * i2400m_rx() | 57 | * i2400m_rx() |
57 | * | 58 | * |
58 | * i2400ms_rx_setup() | 59 | * i2400ms_rx_setup() |
@@ -138,6 +139,11 @@ void i2400ms_rx(struct i2400ms *i2400ms) | |||
138 | ret = rx_size; | 139 | ret = rx_size; |
139 | goto error_get_size; | 140 | goto error_get_size; |
140 | } | 141 | } |
142 | /* | ||
143 | * Hardware quirk: make sure to clear the INTR status register | ||
144 | * AFTER getting the data transfer size. | ||
145 | */ | ||
146 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); | ||
141 | 147 | ||
142 | ret = -ENOMEM; | 148 | ret = -ENOMEM; |
143 | skb = alloc_skb(rx_size, GFP_ATOMIC); | 149 | skb = alloc_skb(rx_size, GFP_ATOMIC); |
@@ -153,25 +159,34 @@ void i2400ms_rx(struct i2400ms *i2400ms) | |||
153 | } | 159 | } |
154 | 160 | ||
155 | rmb(); /* make sure we get boot_mode from dev_reset_handle */ | 161 | rmb(); /* make sure we get boot_mode from dev_reset_handle */ |
156 | if (i2400m->boot_mode == 1) { | 162 | if (unlikely(i2400m->boot_mode == 1)) { |
157 | spin_lock(&i2400m->rx_lock); | 163 | spin_lock(&i2400m->rx_lock); |
158 | i2400ms->bm_ack_size = rx_size; | 164 | i2400ms->bm_ack_size = rx_size; |
159 | spin_unlock(&i2400m->rx_lock); | 165 | spin_unlock(&i2400m->rx_lock); |
160 | memcpy(i2400m->bm_ack_buf, skb->data, rx_size); | 166 | memcpy(i2400m->bm_ack_buf, skb->data, rx_size); |
161 | wake_up(&i2400ms->bm_wfa_wq); | 167 | wake_up(&i2400ms->bm_wfa_wq); |
162 | dev_err(dev, "RX: SDIO boot mode message\n"); | 168 | d_printf(5, dev, "RX: SDIO boot mode message\n"); |
163 | kfree_skb(skb); | 169 | kfree_skb(skb); |
164 | } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER, | 170 | goto out; |
165 | sizeof(i2400m_NBOOT_BARKER)) | 171 | } |
166 | || !memcmp(skb->data, i2400m_SBOOT_BARKER, | 172 | ret = -EIO; |
167 | sizeof(i2400m_SBOOT_BARKER)))) { | 173 | if (unlikely(rx_size < sizeof(__le32))) { |
168 | ret = i2400m_dev_reset_handle(i2400m); | 174 | dev_err(dev, "HW BUG? only %zu bytes received\n", rx_size); |
175 | goto error_bad_size; | ||
176 | } | ||
177 | if (likely(i2400m_is_d2h_barker(skb->data))) { | ||
178 | skb_put(skb, rx_size); | ||
179 | i2400m_rx(i2400m, skb); | ||
180 | } else if (unlikely(i2400m_is_boot_barker(i2400m, | ||
181 | skb->data, rx_size))) { | ||
182 | ret = i2400m_dev_reset_handle(i2400m, "device rebooted"); | ||
169 | dev_err(dev, "RX: SDIO reboot barker\n"); | 183 | dev_err(dev, "RX: SDIO reboot barker\n"); |
170 | kfree_skb(skb); | 184 | kfree_skb(skb); |
171 | } else { | 185 | } else { |
172 | skb_put(skb, rx_size); | 186 | i2400m_unknown_barker(i2400m, skb->data, rx_size); |
173 | i2400m_rx(i2400m, skb); | 187 | kfree_skb(skb); |
174 | } | 188 | } |
189 | out: | ||
175 | d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms); | 190 | d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms); |
176 | return; | 191 | return; |
177 | 192 | ||
@@ -179,6 +194,7 @@ error_memcpy_fromio: | |||
179 | kfree_skb(skb); | 194 | kfree_skb(skb); |
180 | error_alloc_skb: | 195 | error_alloc_skb: |
181 | error_get_size: | 196 | error_get_size: |
197 | error_bad_size: | ||
182 | d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret); | 198 | d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret); |
183 | return; | 199 | return; |
184 | } | 200 | } |
@@ -209,7 +225,6 @@ void i2400ms_irq(struct sdio_func *func) | |||
209 | dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n"); | 225 | dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n"); |
210 | goto error_no_irq; | 226 | goto error_no_irq; |
211 | } | 227 | } |
212 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); | ||
213 | i2400ms_rx(i2400ms); | 228 | i2400ms_rx(i2400ms); |
214 | error_no_irq: | 229 | error_no_irq: |
215 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); | 230 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); |
@@ -234,6 +249,13 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms) | |||
234 | init_waitqueue_head(&i2400ms->bm_wfa_wq); | 249 | init_waitqueue_head(&i2400ms->bm_wfa_wq); |
235 | spin_lock(&i2400m->rx_lock); | 250 | spin_lock(&i2400m->rx_lock); |
236 | i2400ms->bm_wait_result = -EINPROGRESS; | 251 | i2400ms->bm_wait_result = -EINPROGRESS; |
252 | /* | ||
253 | * Before we are about to enable the RX interrupt, make sure | ||
254 | * bm_ack_size is cleared to -EINPROGRESS which indicates | ||
255 | * no RX interrupt happened yet or the previous interrupt | ||
256 | * has been handled, we are ready to take the new interrupt | ||
257 | */ | ||
258 | i2400ms->bm_ack_size = -EINPROGRESS; | ||
237 | spin_unlock(&i2400m->rx_lock); | 259 | spin_unlock(&i2400m->rx_lock); |
238 | 260 | ||
239 | sdio_claim_host(func); | 261 | sdio_claim_host(func); |
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c index 5105a5ebc44f..de66d068c9cb 100644 --- a/drivers/net/wimax/i2400m/sdio-tx.c +++ b/drivers/net/wimax/i2400m/sdio-tx.c | |||
@@ -149,5 +149,8 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms) | |||
149 | 149 | ||
150 | void i2400ms_tx_release(struct i2400ms *i2400ms) | 150 | void i2400ms_tx_release(struct i2400ms *i2400ms) |
151 | { | 151 | { |
152 | destroy_workqueue(i2400ms->tx_workqueue); | 152 | if (i2400ms->tx_workqueue) { |
153 | destroy_workqueue(i2400ms->tx_workqueue); | ||
154 | i2400ms->tx_workqueue = NULL; | ||
155 | } | ||
153 | } | 156 | } |
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 2981e211e04f..76a50ac02ebb 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -43,18 +43,9 @@ | |||
43 | * i2400m_release() | 43 | * i2400m_release() |
44 | * free_netdev(net_dev) | 44 | * free_netdev(net_dev) |
45 | * | 45 | * |
46 | * i2400ms_bus_reset() Called by i2400m->bus_reset | 46 | * i2400ms_bus_reset() Called by i2400m_reset |
47 | * __i2400ms_reset() | 47 | * __i2400ms_reset() |
48 | * __i2400ms_send_barker() | 48 | * __i2400ms_send_barker() |
49 | * | ||
50 | * i2400ms_bus_dev_start() Called by i2400m_dev_start() [who is | ||
51 | * i2400ms_tx_setup() called by i2400m_setup()] | ||
52 | * i2400ms_rx_setup() | ||
53 | * | ||
54 | * i2400ms_bus_dev_stop() Called by i2400m_dev_stop() [who is | ||
55 | * i2400ms_rx_release() is called by i2400m_release()] | ||
56 | * i2400ms_tx_release() | ||
57 | * | ||
58 | */ | 49 | */ |
59 | 50 | ||
60 | #include <linux/debugfs.h> | 51 | #include <linux/debugfs.h> |
@@ -71,6 +62,14 @@ | |||
71 | static int ioe_timeout = 2; | 62 | static int ioe_timeout = 2; |
72 | module_param(ioe_timeout, int, 0); | 63 | module_param(ioe_timeout, int, 0); |
73 | 64 | ||
65 | static char i2400ms_debug_params[128]; | ||
66 | module_param_string(debug, i2400ms_debug_params, sizeof(i2400ms_debug_params), | ||
67 | 0644); | ||
68 | MODULE_PARM_DESC(debug, | ||
69 | "String of space-separated NAME:VALUE pairs, where NAMEs " | ||
70 | "are the different debug submodules and VALUE are the " | ||
71 | "initial debug value to set."); | ||
72 | |||
74 | /* Our firmware file name list */ | 73 | /* Our firmware file name list */ |
75 | static const char *i2400ms_bus_fw_names[] = { | 74 | static const char *i2400ms_bus_fw_names[] = { |
76 | #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf" | 75 | #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf" |
@@ -95,17 +94,24 @@ static const struct i2400m_poke_table i2400ms_pokes[] = { | |||
95 | * when we ask it to explicitly doing). Tries until a timeout is | 94 | * when we ask it to explicitly doing). Tries until a timeout is |
96 | * reached. | 95 | * reached. |
97 | * | 96 | * |
97 | * The @maxtries argument indicates how many times (at most) it should | ||
98 | * be tried to enable the function. 0 means forever. This acts along | ||
99 | * with the timeout (ie: it'll stop trying as soon as the maximum | ||
100 | * number of tries is reached _or_ as soon as the timeout is reached). | ||
101 | * | ||
98 | * The reverse of this is...sdio_disable_function() | 102 | * The reverse of this is...sdio_disable_function() |
99 | * | 103 | * |
100 | * Returns: 0 if the SDIO function was enabled, < 0 errno code on | 104 | * Returns: 0 if the SDIO function was enabled, < 0 errno code on |
101 | * error (-ENODEV when it was unable to enable the function). | 105 | * error (-ENODEV when it was unable to enable the function). |
102 | */ | 106 | */ |
103 | static | 107 | static |
104 | int i2400ms_enable_function(struct sdio_func *func) | 108 | int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries) |
105 | { | 109 | { |
110 | struct sdio_func *func = i2400ms->func; | ||
106 | u64 timeout; | 111 | u64 timeout; |
107 | int err; | 112 | int err; |
108 | struct device *dev = &func->dev; | 113 | struct device *dev = &func->dev; |
114 | unsigned tries = 0; | ||
109 | 115 | ||
110 | d_fnstart(3, dev, "(func %p)\n", func); | 116 | d_fnstart(3, dev, "(func %p)\n", func); |
111 | /* Setup timeout (FIXME: This needs to read the CIS table to | 117 | /* Setup timeout (FIXME: This needs to read the CIS table to |
@@ -115,6 +121,14 @@ int i2400ms_enable_function(struct sdio_func *func) | |||
115 | err = -ENODEV; | 121 | err = -ENODEV; |
116 | while (err != 0 && time_before64(get_jiffies_64(), timeout)) { | 122 | while (err != 0 && time_before64(get_jiffies_64(), timeout)) { |
117 | sdio_claim_host(func); | 123 | sdio_claim_host(func); |
124 | /* | ||
125 | * There is a sillicon bug on the IWMC3200, where the | ||
126 | * IOE timeout will cause problems on Moorestown | ||
127 | * platforms (system hang). We explicitly overwrite | ||
128 | * func->enable_timeout here to work around the issue. | ||
129 | */ | ||
130 | if (i2400ms->iwmc3200) | ||
131 | func->enable_timeout = IWMC3200_IOR_TIMEOUT; | ||
118 | err = sdio_enable_func(func); | 132 | err = sdio_enable_func(func); |
119 | if (0 == err) { | 133 | if (0 == err) { |
120 | sdio_release_host(func); | 134 | sdio_release_host(func); |
@@ -122,8 +136,11 @@ int i2400ms_enable_function(struct sdio_func *func) | |||
122 | goto function_enabled; | 136 | goto function_enabled; |
123 | } | 137 | } |
124 | d_printf(2, dev, "SDIO function failed to enable: %d\n", err); | 138 | d_printf(2, dev, "SDIO function failed to enable: %d\n", err); |
125 | sdio_disable_func(func); | ||
126 | sdio_release_host(func); | 139 | sdio_release_host(func); |
140 | if (maxtries > 0 && ++tries >= maxtries) { | ||
141 | err = -ETIME; | ||
142 | break; | ||
143 | } | ||
127 | msleep(I2400MS_INIT_SLEEP_INTERVAL); | 144 | msleep(I2400MS_INIT_SLEEP_INTERVAL); |
128 | } | 145 | } |
129 | /* If timed out, device is not there yet -- get -ENODEV so | 146 | /* If timed out, device is not there yet -- get -ENODEV so |
@@ -140,46 +157,99 @@ function_enabled: | |||
140 | 157 | ||
141 | 158 | ||
142 | /* | 159 | /* |
143 | * Setup driver resources needed to communicate with the device | 160 | * Setup minimal device communication infrastructure needed to at |
161 | * least be able to update the firmware. | ||
144 | * | 162 | * |
145 | * The fw needs some time to settle, and it was just uploaded, | 163 | * Note the ugly trick: if we are in the probe path |
146 | * so give it a break first. I'd prefer to just wait for the device to | 164 | * (i2400ms->debugfs_dentry == NULL), we only retry function |
147 | * send something, but seems the poking we do to enable SDIO stuff | 165 | * enablement one, to avoid racing with the iwmc3200 top controller. |
148 | * interferes with it, so just give it a break before starting... | ||
149 | */ | 166 | */ |
150 | static | 167 | static |
151 | int i2400ms_bus_dev_start(struct i2400m *i2400m) | 168 | int i2400ms_bus_setup(struct i2400m *i2400m) |
152 | { | 169 | { |
153 | int result; | 170 | int result; |
154 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | 171 | struct i2400ms *i2400ms = |
172 | container_of(i2400m, struct i2400ms, i2400m); | ||
173 | struct device *dev = i2400m_dev(i2400m); | ||
155 | struct sdio_func *func = i2400ms->func; | 174 | struct sdio_func *func = i2400ms->func; |
156 | struct device *dev = &func->dev; | 175 | int retries; |
176 | |||
177 | sdio_claim_host(func); | ||
178 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); | ||
179 | sdio_release_host(func); | ||
180 | if (result < 0) { | ||
181 | dev_err(dev, "Failed to set block size: %d\n", result); | ||
182 | goto error_set_blk_size; | ||
183 | } | ||
184 | |||
185 | if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL) | ||
186 | retries = 1; | ||
187 | else | ||
188 | retries = 0; | ||
189 | result = i2400ms_enable_function(i2400ms, retries); | ||
190 | if (result < 0) { | ||
191 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); | ||
192 | goto error_func_enable; | ||
193 | } | ||
157 | 194 | ||
158 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | ||
159 | msleep(200); | ||
160 | result = i2400ms_tx_setup(i2400ms); | 195 | result = i2400ms_tx_setup(i2400ms); |
161 | if (result < 0) | 196 | if (result < 0) |
162 | goto error_tx_setup; | 197 | goto error_tx_setup; |
163 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | 198 | result = i2400ms_rx_setup(i2400ms); |
164 | return result; | 199 | if (result < 0) |
200 | goto error_rx_setup; | ||
201 | return 0; | ||
165 | 202 | ||
166 | error_tx_setup: | 203 | error_rx_setup: |
167 | i2400ms_tx_release(i2400ms); | 204 | i2400ms_tx_release(i2400ms); |
168 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 205 | error_tx_setup: |
206 | sdio_claim_host(func); | ||
207 | sdio_disable_func(func); | ||
208 | sdio_release_host(func); | ||
209 | error_func_enable: | ||
210 | error_set_blk_size: | ||
169 | return result; | 211 | return result; |
170 | } | 212 | } |
171 | 213 | ||
172 | 214 | ||
215 | /* | ||
216 | * Tear down minimal device communication infrastructure needed to at | ||
217 | * least be able to update the firmware. | ||
218 | */ | ||
219 | static | ||
220 | void i2400ms_bus_release(struct i2400m *i2400m) | ||
221 | { | ||
222 | struct i2400ms *i2400ms = | ||
223 | container_of(i2400m, struct i2400ms, i2400m); | ||
224 | struct sdio_func *func = i2400ms->func; | ||
225 | |||
226 | i2400ms_rx_release(i2400ms); | ||
227 | i2400ms_tx_release(i2400ms); | ||
228 | sdio_claim_host(func); | ||
229 | sdio_disable_func(func); | ||
230 | sdio_release_host(func); | ||
231 | } | ||
232 | |||
233 | |||
234 | /* | ||
235 | * Setup driver resources needed to communicate with the device | ||
236 | * | ||
237 | * The fw needs some time to settle, and it was just uploaded, | ||
238 | * so give it a break first. I'd prefer to just wait for the device to | ||
239 | * send something, but seems the poking we do to enable SDIO stuff | ||
240 | * interferes with it, so just give it a break before starting... | ||
241 | */ | ||
173 | static | 242 | static |
174 | void i2400ms_bus_dev_stop(struct i2400m *i2400m) | 243 | int i2400ms_bus_dev_start(struct i2400m *i2400m) |
175 | { | 244 | { |
176 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | 245 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); |
177 | struct sdio_func *func = i2400ms->func; | 246 | struct sdio_func *func = i2400ms->func; |
178 | struct device *dev = &func->dev; | 247 | struct device *dev = &func->dev; |
179 | 248 | ||
180 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 249 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
181 | i2400ms_tx_release(i2400ms); | 250 | msleep(200); |
182 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 251 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, 0); |
252 | return 0; | ||
183 | } | 253 | } |
184 | 254 | ||
185 | 255 | ||
@@ -233,18 +303,17 @@ error_kzalloc: | |||
233 | * Warm reset: | 303 | * Warm reset: |
234 | * | 304 | * |
235 | * The device will be fully reset internally, but won't be | 305 | * The device will be fully reset internally, but won't be |
236 | * disconnected from the USB bus (so no reenumeration will | 306 | * disconnected from the bus (so no reenumeration will |
237 | * happen). Firmware upload will be neccessary. | 307 | * happen). Firmware upload will be neccessary. |
238 | * | 308 | * |
239 | * The device will send a reboot barker in the notification endpoint | 309 | * The device will send a reboot barker that will trigger the driver |
240 | * that will trigger the driver to reinitialize the state | 310 | * to reinitialize the state via __i2400m_dev_reset_handle. |
241 | * automatically from notif.c:i2400m_notification_grok() into | ||
242 | * i2400m_dev_bootstrap_delayed(). | ||
243 | * | 311 | * |
244 | * Cold and bus (USB) reset: | 312 | * |
313 | * Cold and bus reset: | ||
245 | * | 314 | * |
246 | * The device will be fully reset internally, disconnected from the | 315 | * The device will be fully reset internally, disconnected from the |
247 | * USB bus an a reenumeration will happen. Firmware upload will be | 316 | * bus an a reenumeration will happen. Firmware upload will be |
248 | * neccessary. Thus, we don't do any locking or struct | 317 | * neccessary. Thus, we don't do any locking or struct |
249 | * reinitialization, as we are going to be fully disconnected and | 318 | * reinitialization, as we are going to be fully disconnected and |
250 | * reenumerated. | 319 | * reenumerated. |
@@ -283,25 +352,13 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) | |||
283 | sizeof(i2400m_COLD_BOOT_BARKER)); | 352 | sizeof(i2400m_COLD_BOOT_BARKER)); |
284 | else if (rt == I2400M_RT_BUS) { | 353 | else if (rt == I2400M_RT_BUS) { |
285 | do_bus_reset: | 354 | do_bus_reset: |
286 | /* call netif_tx_disable() before sending IOE disable, | ||
287 | * so that all the tx from network layer are stopped | ||
288 | * while IOE is being reset. Make sure it is called | ||
289 | * only after register_netdev() was issued. | ||
290 | */ | ||
291 | if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) | ||
292 | netif_tx_disable(i2400m->wimax_dev.net_dev); | ||
293 | 355 | ||
294 | i2400ms_rx_release(i2400ms); | 356 | i2400ms_bus_release(i2400m); |
295 | sdio_claim_host(i2400ms->func); | ||
296 | sdio_disable_func(i2400ms->func); | ||
297 | sdio_release_host(i2400ms->func); | ||
298 | 357 | ||
299 | /* Wait for the device to settle */ | 358 | /* Wait for the device to settle */ |
300 | msleep(40); | 359 | msleep(40); |
301 | 360 | ||
302 | result = i2400ms_enable_function(i2400ms->func); | 361 | result = i2400ms_bus_setup(i2400m); |
303 | if (result >= 0) | ||
304 | i2400ms_rx_setup(i2400ms); | ||
305 | } else | 362 | } else |
306 | BUG(); | 363 | BUG(); |
307 | if (result < 0 && rt != I2400M_RT_BUS) { | 364 | if (result < 0 && rt != I2400M_RT_BUS) { |
@@ -350,7 +407,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms) | |||
350 | int result; | 407 | int result; |
351 | struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry; | 408 | struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry; |
352 | 409 | ||
353 | dentry = debugfs_create_dir("i2400m-usb", dentry); | 410 | dentry = debugfs_create_dir("i2400m-sdio", dentry); |
354 | result = PTR_ERR(dentry); | 411 | result = PTR_ERR(dentry); |
355 | if (IS_ERR(dentry)) { | 412 | if (IS_ERR(dentry)) { |
356 | if (result == -ENODEV) | 413 | if (result == -ENODEV) |
@@ -367,6 +424,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms) | |||
367 | 424 | ||
368 | error: | 425 | error: |
369 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | 426 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
427 | i2400ms->debugfs_dentry = NULL; | ||
370 | return result; | 428 | return result; |
371 | } | 429 | } |
372 | 430 | ||
@@ -425,37 +483,30 @@ int i2400ms_probe(struct sdio_func *func, | |||
425 | 483 | ||
426 | i2400m->bus_tx_block_size = I2400MS_BLK_SIZE; | 484 | i2400m->bus_tx_block_size = I2400MS_BLK_SIZE; |
427 | i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX; | 485 | i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX; |
486 | i2400m->bus_setup = i2400ms_bus_setup; | ||
428 | i2400m->bus_dev_start = i2400ms_bus_dev_start; | 487 | i2400m->bus_dev_start = i2400ms_bus_dev_start; |
429 | i2400m->bus_dev_stop = i2400ms_bus_dev_stop; | 488 | i2400m->bus_dev_stop = NULL; |
489 | i2400m->bus_release = i2400ms_bus_release; | ||
430 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; | 490 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; |
431 | i2400m->bus_reset = i2400ms_bus_reset; | 491 | i2400m->bus_reset = i2400ms_bus_reset; |
432 | /* The iwmc3200-wimax sometimes requires the driver to try | 492 | /* The iwmc3200-wimax sometimes requires the driver to try |
433 | * hard when we paint it into a corner. */ | 493 | * hard when we paint it into a corner. */ |
434 | i2400m->bus_bm_retries = I3200_BOOT_RETRIES; | 494 | i2400m->bus_bm_retries = I2400M_SDIO_BOOT_RETRIES; |
435 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; | 495 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; |
436 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; | 496 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; |
437 | i2400m->bus_fw_names = i2400ms_bus_fw_names; | 497 | i2400m->bus_fw_names = i2400ms_bus_fw_names; |
438 | i2400m->bus_bm_mac_addr_impaired = 1; | 498 | i2400m->bus_bm_mac_addr_impaired = 1; |
439 | i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; | 499 | i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; |
440 | 500 | ||
441 | sdio_claim_host(func); | 501 | switch (func->device) { |
442 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); | 502 | case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX: |
443 | sdio_release_host(func); | 503 | case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5: |
444 | if (result < 0) { | 504 | i2400ms->iwmc3200 = 1; |
445 | dev_err(dev, "Failed to set block size: %d\n", result); | 505 | break; |
446 | goto error_set_blk_size; | 506 | default: |
447 | } | 507 | i2400ms->iwmc3200 = 0; |
448 | |||
449 | result = i2400ms_enable_function(i2400ms->func); | ||
450 | if (result < 0) { | ||
451 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); | ||
452 | goto error_func_enable; | ||
453 | } | 508 | } |
454 | 509 | ||
455 | result = i2400ms_rx_setup(i2400ms); | ||
456 | if (result < 0) | ||
457 | goto error_rx_setup; | ||
458 | |||
459 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); | 510 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); |
460 | if (result < 0) { | 511 | if (result < 0) { |
461 | dev_err(dev, "cannot setup device: %d\n", result); | 512 | dev_err(dev, "cannot setup device: %d\n", result); |
@@ -473,13 +524,6 @@ int i2400ms_probe(struct sdio_func *func, | |||
473 | error_debugfs_add: | 524 | error_debugfs_add: |
474 | i2400m_release(i2400m); | 525 | i2400m_release(i2400m); |
475 | error_setup: | 526 | error_setup: |
476 | i2400ms_rx_release(i2400ms); | ||
477 | error_rx_setup: | ||
478 | sdio_claim_host(func); | ||
479 | sdio_disable_func(func); | ||
480 | sdio_release_host(func); | ||
481 | error_func_enable: | ||
482 | error_set_blk_size: | ||
483 | sdio_set_drvdata(func, NULL); | 527 | sdio_set_drvdata(func, NULL); |
484 | free_netdev(net_dev); | 528 | free_netdev(net_dev); |
485 | error_alloc_netdev: | 529 | error_alloc_netdev: |
@@ -497,12 +541,9 @@ void i2400ms_remove(struct sdio_func *func) | |||
497 | 541 | ||
498 | d_fnstart(3, dev, "SDIO func %p\n", func); | 542 | d_fnstart(3, dev, "SDIO func %p\n", func); |
499 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | 543 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
500 | i2400ms_rx_release(i2400ms); | 544 | i2400ms->debugfs_dentry = NULL; |
501 | i2400m_release(i2400m); | 545 | i2400m_release(i2400m); |
502 | sdio_set_drvdata(func, NULL); | 546 | sdio_set_drvdata(func, NULL); |
503 | sdio_claim_host(func); | ||
504 | sdio_disable_func(func); | ||
505 | sdio_release_host(func); | ||
506 | free_netdev(net_dev); | 547 | free_netdev(net_dev); |
507 | d_fnend(3, dev, "SDIO func %p\n", func); | 548 | d_fnend(3, dev, "SDIO func %p\n", func); |
508 | } | 549 | } |
@@ -512,6 +553,8 @@ const struct sdio_device_id i2400ms_sdio_ids[] = { | |||
512 | /* Intel: i2400m WiMAX (iwmc3200) over SDIO */ | 553 | /* Intel: i2400m WiMAX (iwmc3200) over SDIO */ |
513 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, | 554 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, |
514 | SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) }, | 555 | SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) }, |
556 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, | ||
557 | SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5) }, | ||
515 | { /* end: all zeroes */ }, | 558 | { /* end: all zeroes */ }, |
516 | }; | 559 | }; |
517 | MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids); | 560 | MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids); |
@@ -529,6 +572,8 @@ struct sdio_driver i2400m_sdio_driver = { | |||
529 | static | 572 | static |
530 | int __init i2400ms_driver_init(void) | 573 | int __init i2400ms_driver_init(void) |
531 | { | 574 | { |
575 | d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400ms_debug_params, | ||
576 | "i2400m_sdio.debug"); | ||
532 | return sdio_register_driver(&i2400m_sdio_driver); | 577 | return sdio_register_driver(&i2400m_sdio_driver); |
533 | } | 578 | } |
534 | module_init(i2400ms_driver_init); | 579 | module_init(i2400ms_driver_init); |
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index fa16ccf8e26a..54480e8947f1 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c | |||
@@ -310,7 +310,7 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m) | |||
310 | size_t tail_room; | 310 | size_t tail_room; |
311 | size_t tx_in; | 311 | size_t tx_in; |
312 | 312 | ||
313 | if (unlikely(i2400m->tx_in) == 0) | 313 | if (unlikely(i2400m->tx_in == 0)) |
314 | return I2400M_TX_BUF_SIZE; | 314 | return I2400M_TX_BUF_SIZE; |
315 | tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; | 315 | tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; |
316 | tail_room = I2400M_TX_BUF_SIZE - tx_in; | 316 | tail_room = I2400M_TX_BUF_SIZE - tx_in; |
@@ -642,6 +642,9 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, | |||
642 | * current one is out of payload slots or we have a singleton, | 642 | * current one is out of payload slots or we have a singleton, |
643 | * close it and start a new one */ | 643 | * close it and start a new one */ |
644 | spin_lock_irqsave(&i2400m->tx_lock, flags); | 644 | spin_lock_irqsave(&i2400m->tx_lock, flags); |
645 | result = -ESHUTDOWN; | ||
646 | if (i2400m->tx_buf == NULL) | ||
647 | goto error_tx_new; | ||
645 | try_new: | 648 | try_new: |
646 | if (unlikely(i2400m->tx_msg == NULL)) | 649 | if (unlikely(i2400m->tx_msg == NULL)) |
647 | i2400m_tx_new(i2400m); | 650 | i2400m_tx_new(i2400m); |
@@ -697,7 +700,10 @@ try_new: | |||
697 | } | 700 | } |
698 | error_tx_new: | 701 | error_tx_new: |
699 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | 702 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); |
700 | i2400m->bus_tx_kick(i2400m); /* always kick, might free up space */ | 703 | /* kick in most cases, except when the TX subsys is down, as |
704 | * it might free space */ | ||
705 | if (likely(result != -ESHUTDOWN)) | ||
706 | i2400m->bus_tx_kick(i2400m); | ||
701 | d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n", | 707 | d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n", |
702 | i2400m, buf, buf_len, pl_type, result); | 708 | i2400m, buf, buf_len, pl_type, result); |
703 | return result; | 709 | return result; |
@@ -740,6 +746,9 @@ struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m, | |||
740 | 746 | ||
741 | d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size); | 747 | d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size); |
742 | spin_lock_irqsave(&i2400m->tx_lock, flags); | 748 | spin_lock_irqsave(&i2400m->tx_lock, flags); |
749 | tx_msg_moved = NULL; | ||
750 | if (i2400m->tx_buf == NULL) | ||
751 | goto out_unlock; | ||
743 | skip: | 752 | skip: |
744 | tx_msg_moved = NULL; | 753 | tx_msg_moved = NULL; |
745 | if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */ | 754 | if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */ |
@@ -829,6 +838,8 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m) | |||
829 | 838 | ||
830 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 839 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
831 | spin_lock_irqsave(&i2400m->tx_lock, flags); | 840 | spin_lock_irqsave(&i2400m->tx_lock, flags); |
841 | if (i2400m->tx_buf == NULL) | ||
842 | goto out_unlock; | ||
832 | i2400m->tx_out += i2400m->tx_msg_size; | 843 | i2400m->tx_out += i2400m->tx_msg_size; |
833 | d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size); | 844 | d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size); |
834 | i2400m->tx_msg_size = 0; | 845 | i2400m->tx_msg_size = 0; |
@@ -837,6 +848,7 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m) | |||
837 | n = i2400m->tx_out / I2400M_TX_BUF_SIZE; | 848 | n = i2400m->tx_out / I2400M_TX_BUF_SIZE; |
838 | i2400m->tx_out %= I2400M_TX_BUF_SIZE; | 849 | i2400m->tx_out %= I2400M_TX_BUF_SIZE; |
839 | i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; | 850 | i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; |
851 | out_unlock: | ||
840 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | 852 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); |
841 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 853 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
842 | } | 854 | } |
@@ -876,5 +888,9 @@ int i2400m_tx_setup(struct i2400m *i2400m) | |||
876 | */ | 888 | */ |
877 | void i2400m_tx_release(struct i2400m *i2400m) | 889 | void i2400m_tx_release(struct i2400m *i2400m) |
878 | { | 890 | { |
891 | unsigned long flags; | ||
892 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
879 | kfree(i2400m->tx_buf); | 893 | kfree(i2400m->tx_buf); |
894 | i2400m->tx_buf = NULL; | ||
895 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
880 | } | 896 | } |
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c index 5ad287c228b8..ce6b9938fde0 100644 --- a/drivers/net/wimax/i2400m/usb-fw.c +++ b/drivers/net/wimax/i2400m/usb-fw.c | |||
@@ -99,10 +99,10 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size) | |||
99 | dev_err(dev, "BM-CMD: can't get autopm: %d\n", result); | 99 | dev_err(dev, "BM-CMD: can't get autopm: %d\n", result); |
100 | do_autopm = 0; | 100 | do_autopm = 0; |
101 | } | 101 | } |
102 | epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_OUT); | 102 | epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out); |
103 | pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); | 103 | pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); |
104 | retry: | 104 | retry: |
105 | result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, HZ); | 105 | result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, 200); |
106 | switch (result) { | 106 | switch (result) { |
107 | case 0: | 107 | case 0: |
108 | if (len != buf_size) { | 108 | if (len != buf_size) { |
@@ -113,6 +113,28 @@ retry: | |||
113 | } | 113 | } |
114 | result = len; | 114 | result = len; |
115 | break; | 115 | break; |
116 | case -EPIPE: | ||
117 | /* | ||
118 | * Stall -- maybe the device is choking with our | ||
119 | * requests. Clear it and give it some time. If they | ||
120 | * happen to often, it might be another symptom, so we | ||
121 | * reset. | ||
122 | * | ||
123 | * No error handling for usb_clear_halt(0; if it | ||
124 | * works, the retry works; if it fails, this switch | ||
125 | * does the error handling for us. | ||
126 | */ | ||
127 | if (edc_inc(&i2400mu->urb_edc, | ||
128 | 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
129 | dev_err(dev, "BM-CMD: too many stalls in " | ||
130 | "URB; resetting device\n"); | ||
131 | usb_queue_reset_device(i2400mu->usb_iface); | ||
132 | /* fallthrough */ | ||
133 | } else { | ||
134 | usb_clear_halt(i2400mu->usb_dev, pipe); | ||
135 | msleep(10); /* give the device some time */ | ||
136 | goto retry; | ||
137 | } | ||
116 | case -EINVAL: /* while removing driver */ | 138 | case -EINVAL: /* while removing driver */ |
117 | case -ENODEV: /* dev disconnect ... */ | 139 | case -ENODEV: /* dev disconnect ... */ |
118 | case -ENOENT: /* just ignore it */ | 140 | case -ENOENT: /* just ignore it */ |
@@ -135,7 +157,6 @@ retry: | |||
135 | result); | 157 | result); |
136 | goto retry; | 158 | goto retry; |
137 | } | 159 | } |
138 | result = len; | ||
139 | if (do_autopm) | 160 | if (do_autopm) |
140 | usb_autopm_put_interface(i2400mu->usb_iface); | 161 | usb_autopm_put_interface(i2400mu->usb_iface); |
141 | return result; | 162 | return result; |
@@ -172,7 +193,8 @@ ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m, | |||
172 | result = -E2BIG; | 193 | result = -E2BIG; |
173 | if (cmd_size > I2400M_BM_CMD_BUF_SIZE) | 194 | if (cmd_size > I2400M_BM_CMD_BUF_SIZE) |
174 | goto error_too_big; | 195 | goto error_too_big; |
175 | memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size); | 196 | if (_cmd != i2400m->bm_cmd_buf) |
197 | memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); | ||
176 | cmd = i2400m->bm_cmd_buf; | 198 | cmd = i2400m->bm_cmd_buf; |
177 | if (cmd_size_a > cmd_size) /* Zero pad space */ | 199 | if (cmd_size_a > cmd_size) /* Zero pad space */ |
178 | memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); | 200 | memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); |
@@ -226,7 +248,8 @@ int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb, | |||
226 | struct usb_endpoint_descriptor *epd; | 248 | struct usb_endpoint_descriptor *epd; |
227 | int pipe; | 249 | int pipe; |
228 | 250 | ||
229 | epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_NOTIFICATION); | 251 | epd = usb_get_epd(i2400mu->usb_iface, |
252 | i2400mu->endpoint_cfg.notification); | ||
230 | pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); | 253 | pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); |
231 | usb_fill_int_urb(urb, i2400mu->usb_dev, pipe, | 254 | usb_fill_int_urb(urb, i2400mu->usb_dev, pipe, |
232 | i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE, | 255 | i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE, |
@@ -328,8 +351,8 @@ error_dev_gone: | |||
328 | out: | 351 | out: |
329 | if (do_autopm) | 352 | if (do_autopm) |
330 | usb_autopm_put_interface(i2400mu->usb_iface); | 353 | usb_autopm_put_interface(i2400mu->usb_iface); |
331 | d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %zd\n", | 354 | d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n", |
332 | i2400m, ack, ack_size, result); | 355 | i2400m, ack, ack_size, (long) result); |
333 | return result; | 356 | return result; |
334 | 357 | ||
335 | error_exceeded: | 358 | error_exceeded: |
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c index 6add27c3f35c..f88d1c6e35cb 100644 --- a/drivers/net/wimax/i2400m/usb-notif.c +++ b/drivers/net/wimax/i2400m/usb-notif.c | |||
@@ -51,6 +51,7 @@ | |||
51 | * | 51 | * |
52 | * i2400mu_usb_notification_cb() Called when a URB is ready | 52 | * i2400mu_usb_notification_cb() Called when a URB is ready |
53 | * i2400mu_notif_grok() | 53 | * i2400mu_notif_grok() |
54 | * i2400m_is_boot_barker() | ||
54 | * i2400m_dev_reset_handle() | 55 | * i2400m_dev_reset_handle() |
55 | * i2400mu_rx_kick() | 56 | * i2400mu_rx_kick() |
56 | */ | 57 | */ |
@@ -87,32 +88,21 @@ int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf, | |||
87 | d_fnstart(4, dev, "(i2400m %p buf %p buf_len %zu)\n", | 88 | d_fnstart(4, dev, "(i2400m %p buf %p buf_len %zu)\n", |
88 | i2400mu, buf, buf_len); | 89 | i2400mu, buf, buf_len); |
89 | ret = -EIO; | 90 | ret = -EIO; |
90 | if (buf_len < sizeof(i2400m_NBOOT_BARKER)) | 91 | if (buf_len < sizeof(i2400m_ZERO_BARKER)) |
91 | /* Not a bug, just ignore */ | 92 | /* Not a bug, just ignore */ |
92 | goto error_bad_size; | 93 | goto error_bad_size; |
93 | if (!memcmp(i2400m_NBOOT_BARKER, buf, sizeof(i2400m_NBOOT_BARKER)) | 94 | ret = 0; |
94 | || !memcmp(i2400m_SBOOT_BARKER, buf, sizeof(i2400m_SBOOT_BARKER))) | 95 | if (!memcmp(i2400m_ZERO_BARKER, buf, sizeof(i2400m_ZERO_BARKER))) { |
95 | ret = i2400m_dev_reset_handle(i2400m); | ||
96 | else if (!memcmp(i2400m_ZERO_BARKER, buf, sizeof(i2400m_ZERO_BARKER))) { | ||
97 | i2400mu_rx_kick(i2400mu); | 96 | i2400mu_rx_kick(i2400mu); |
98 | ret = 0; | 97 | goto out; |
99 | } else { /* Unknown or unexpected data in the notif message */ | ||
100 | char prefix[64]; | ||
101 | ret = -EIO; | ||
102 | dev_err(dev, "HW BUG? Unknown/unexpected data in notification " | ||
103 | "message (%zu bytes)\n", buf_len); | ||
104 | snprintf(prefix, sizeof(prefix), "%s %s: ", | ||
105 | dev_driver_string(dev), dev_name(dev)); | ||
106 | if (buf_len > 64) { | ||
107 | print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, | ||
108 | 8, 4, buf, 64, 0); | ||
109 | printk(KERN_ERR "%s... (only first 64 bytes " | ||
110 | "dumped)\n", prefix); | ||
111 | } else | ||
112 | print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, | ||
113 | 8, 4, buf, buf_len, 0); | ||
114 | } | 98 | } |
99 | ret = i2400m_is_boot_barker(i2400m, buf, buf_len); | ||
100 | if (unlikely(ret >= 0)) | ||
101 | ret = i2400m_dev_reset_handle(i2400m, "device rebooted"); | ||
102 | else /* Unknown or unexpected data in the notif message */ | ||
103 | i2400m_unknown_barker(i2400m, buf, buf_len); | ||
115 | error_bad_size: | 104 | error_bad_size: |
105 | out: | ||
116 | d_fnend(4, dev, "(i2400m %p buf %p buf_len %zu) = %d\n", | 106 | d_fnend(4, dev, "(i2400m %p buf %p buf_len %zu) = %d\n", |
117 | i2400mu, buf, buf_len, ret); | 107 | i2400mu, buf, buf_len, ret); |
118 | return ret; | 108 | return ret; |
@@ -220,7 +210,8 @@ int i2400mu_notification_setup(struct i2400mu *i2400mu) | |||
220 | dev_err(dev, "notification: cannot allocate URB\n"); | 210 | dev_err(dev, "notification: cannot allocate URB\n"); |
221 | goto error_alloc_urb; | 211 | goto error_alloc_urb; |
222 | } | 212 | } |
223 | epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_NOTIFICATION); | 213 | epd = usb_get_epd(i2400mu->usb_iface, |
214 | i2400mu->endpoint_cfg.notification); | ||
224 | usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); | 215 | usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); |
225 | usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe, | 216 | usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe, |
226 | buf, I2400MU_MAX_NOTIFICATION_LEN, | 217 | buf, I2400MU_MAX_NOTIFICATION_LEN, |
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c index a314799967cf..ba1b02362dfc 100644 --- a/drivers/net/wimax/i2400m/usb-rx.c +++ b/drivers/net/wimax/i2400m/usb-rx.c | |||
@@ -204,7 +204,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb) | |||
204 | dev_err(dev, "RX: can't get autopm: %d\n", result); | 204 | dev_err(dev, "RX: can't get autopm: %d\n", result); |
205 | do_autopm = 0; | 205 | do_autopm = 0; |
206 | } | 206 | } |
207 | epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_IN); | 207 | epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_in); |
208 | usb_pipe = usb_rcvbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); | 208 | usb_pipe = usb_rcvbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); |
209 | retry: | 209 | retry: |
210 | rx_size = skb_end_pointer(rx_skb) - rx_skb->data - rx_skb->len; | 210 | rx_size = skb_end_pointer(rx_skb) - rx_skb->data - rx_skb->len; |
@@ -214,7 +214,7 @@ retry: | |||
214 | } | 214 | } |
215 | result = usb_bulk_msg( | 215 | result = usb_bulk_msg( |
216 | i2400mu->usb_dev, usb_pipe, rx_skb->data + rx_skb->len, | 216 | i2400mu->usb_dev, usb_pipe, rx_skb->data + rx_skb->len, |
217 | rx_size, &read_size, HZ); | 217 | rx_size, &read_size, 200); |
218 | usb_mark_last_busy(i2400mu->usb_dev); | 218 | usb_mark_last_busy(i2400mu->usb_dev); |
219 | switch (result) { | 219 | switch (result) { |
220 | case 0: | 220 | case 0: |
@@ -222,6 +222,26 @@ retry: | |||
222 | goto retry; /* ZLP, just resubmit */ | 222 | goto retry; /* ZLP, just resubmit */ |
223 | skb_put(rx_skb, read_size); | 223 | skb_put(rx_skb, read_size); |
224 | break; | 224 | break; |
225 | case -EPIPE: | ||
226 | /* | ||
227 | * Stall -- maybe the device is choking with our | ||
228 | * requests. Clear it and give it some time. If they | ||
229 | * happen to often, it might be another symptom, so we | ||
230 | * reset. | ||
231 | * | ||
232 | * No error handling for usb_clear_halt(0; if it | ||
233 | * works, the retry works; if it fails, this switch | ||
234 | * does the error handling for us. | ||
235 | */ | ||
236 | if (edc_inc(&i2400mu->urb_edc, | ||
237 | 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
238 | dev_err(dev, "BM-CMD: too many stalls in " | ||
239 | "URB; resetting device\n"); | ||
240 | goto do_reset; | ||
241 | } | ||
242 | usb_clear_halt(i2400mu->usb_dev, usb_pipe); | ||
243 | msleep(10); /* give the device some time */ | ||
244 | goto retry; | ||
225 | case -EINVAL: /* while removing driver */ | 245 | case -EINVAL: /* while removing driver */ |
226 | case -ENODEV: /* dev disconnect ... */ | 246 | case -ENODEV: /* dev disconnect ... */ |
227 | case -ENOENT: /* just ignore it */ | 247 | case -ENOENT: /* just ignore it */ |
@@ -283,6 +303,7 @@ out: | |||
283 | error_reset: | 303 | error_reset: |
284 | dev_err(dev, "RX: maximum errors in URB exceeded; " | 304 | dev_err(dev, "RX: maximum errors in URB exceeded; " |
285 | "resetting device\n"); | 305 | "resetting device\n"); |
306 | do_reset: | ||
286 | usb_queue_reset_device(i2400mu->usb_iface); | 307 | usb_queue_reset_device(i2400mu->usb_iface); |
287 | rx_skb = ERR_PTR(result); | 308 | rx_skb = ERR_PTR(result); |
288 | goto out; | 309 | goto out; |
@@ -316,10 +337,15 @@ int i2400mu_rxd(void *_i2400mu) | |||
316 | size_t pending; | 337 | size_t pending; |
317 | int rx_size; | 338 | int rx_size; |
318 | struct sk_buff *rx_skb; | 339 | struct sk_buff *rx_skb; |
340 | unsigned long flags; | ||
319 | 341 | ||
320 | d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); | 342 | d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); |
343 | spin_lock_irqsave(&i2400m->rx_lock, flags); | ||
344 | BUG_ON(i2400mu->rx_kthread != NULL); | ||
345 | i2400mu->rx_kthread = current; | ||
346 | spin_unlock_irqrestore(&i2400m->rx_lock, flags); | ||
321 | while (1) { | 347 | while (1) { |
322 | d_printf(2, dev, "TX: waiting for messages\n"); | 348 | d_printf(2, dev, "RX: waiting for messages\n"); |
323 | pending = 0; | 349 | pending = 0; |
324 | wait_event_interruptible( | 350 | wait_event_interruptible( |
325 | i2400mu->rx_wq, | 351 | i2400mu->rx_wq, |
@@ -367,6 +393,9 @@ int i2400mu_rxd(void *_i2400mu) | |||
367 | } | 393 | } |
368 | result = 0; | 394 | result = 0; |
369 | out: | 395 | out: |
396 | spin_lock_irqsave(&i2400m->rx_lock, flags); | ||
397 | i2400mu->rx_kthread = NULL; | ||
398 | spin_unlock_irqrestore(&i2400m->rx_lock, flags); | ||
370 | d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result); | 399 | d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result); |
371 | return result; | 400 | return result; |
372 | 401 | ||
@@ -403,18 +432,33 @@ int i2400mu_rx_setup(struct i2400mu *i2400mu) | |||
403 | struct i2400m *i2400m = &i2400mu->i2400m; | 432 | struct i2400m *i2400m = &i2400mu->i2400m; |
404 | struct device *dev = &i2400mu->usb_iface->dev; | 433 | struct device *dev = &i2400mu->usb_iface->dev; |
405 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; | 434 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; |
435 | struct task_struct *kthread; | ||
406 | 436 | ||
407 | i2400mu->rx_kthread = kthread_run(i2400mu_rxd, i2400mu, "%s-rx", | 437 | kthread = kthread_run(i2400mu_rxd, i2400mu, "%s-rx", |
408 | wimax_dev->name); | 438 | wimax_dev->name); |
409 | if (IS_ERR(i2400mu->rx_kthread)) { | 439 | /* the kthread function sets i2400mu->rx_thread */ |
410 | result = PTR_ERR(i2400mu->rx_kthread); | 440 | if (IS_ERR(kthread)) { |
441 | result = PTR_ERR(kthread); | ||
411 | dev_err(dev, "RX: cannot start thread: %d\n", result); | 442 | dev_err(dev, "RX: cannot start thread: %d\n", result); |
412 | } | 443 | } |
413 | return result; | 444 | return result; |
414 | } | 445 | } |
415 | 446 | ||
447 | |||
416 | void i2400mu_rx_release(struct i2400mu *i2400mu) | 448 | void i2400mu_rx_release(struct i2400mu *i2400mu) |
417 | { | 449 | { |
418 | kthread_stop(i2400mu->rx_kthread); | 450 | unsigned long flags; |
451 | struct i2400m *i2400m = &i2400mu->i2400m; | ||
452 | struct device *dev = i2400m_dev(i2400m); | ||
453 | struct task_struct *kthread; | ||
454 | |||
455 | spin_lock_irqsave(&i2400m->rx_lock, flags); | ||
456 | kthread = i2400mu->rx_kthread; | ||
457 | i2400mu->rx_kthread = NULL; | ||
458 | spin_unlock_irqrestore(&i2400m->rx_lock, flags); | ||
459 | if (kthread) | ||
460 | kthread_stop(kthread); | ||
461 | else | ||
462 | d_printf(1, dev, "RX: kthread had already exited\n"); | ||
419 | } | 463 | } |
420 | 464 | ||
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c index dfd893356f49..c65b9979f87e 100644 --- a/drivers/net/wimax/i2400m/usb-tx.c +++ b/drivers/net/wimax/i2400m/usb-tx.c | |||
@@ -101,11 +101,11 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg, | |||
101 | dev_err(dev, "TX: can't get autopm: %d\n", result); | 101 | dev_err(dev, "TX: can't get autopm: %d\n", result); |
102 | do_autopm = 0; | 102 | do_autopm = 0; |
103 | } | 103 | } |
104 | epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_OUT); | 104 | epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out); |
105 | usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); | 105 | usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); |
106 | retry: | 106 | retry: |
107 | result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe, | 107 | result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe, |
108 | tx_msg, tx_msg_size, &sent_size, HZ); | 108 | tx_msg, tx_msg_size, &sent_size, 200); |
109 | usb_mark_last_busy(i2400mu->usb_dev); | 109 | usb_mark_last_busy(i2400mu->usb_dev); |
110 | switch (result) { | 110 | switch (result) { |
111 | case 0: | 111 | case 0: |
@@ -115,6 +115,28 @@ retry: | |||
115 | result = -EIO; | 115 | result = -EIO; |
116 | } | 116 | } |
117 | break; | 117 | break; |
118 | case -EPIPE: | ||
119 | /* | ||
120 | * Stall -- maybe the device is choking with our | ||
121 | * requests. Clear it and give it some time. If they | ||
122 | * happen to often, it might be another symptom, so we | ||
123 | * reset. | ||
124 | * | ||
125 | * No error handling for usb_clear_halt(0; if it | ||
126 | * works, the retry works; if it fails, this switch | ||
127 | * does the error handling for us. | ||
128 | */ | ||
129 | if (edc_inc(&i2400mu->urb_edc, | ||
130 | 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
131 | dev_err(dev, "BM-CMD: too many stalls in " | ||
132 | "URB; resetting device\n"); | ||
133 | usb_queue_reset_device(i2400mu->usb_iface); | ||
134 | /* fallthrough */ | ||
135 | } else { | ||
136 | usb_clear_halt(i2400mu->usb_dev, usb_pipe); | ||
137 | msleep(10); /* give the device some time */ | ||
138 | goto retry; | ||
139 | } | ||
118 | case -EINVAL: /* while removing driver */ | 140 | case -EINVAL: /* while removing driver */ |
119 | case -ENODEV: /* dev disconnect ... */ | 141 | case -ENODEV: /* dev disconnect ... */ |
120 | case -ENOENT: /* just ignore it */ | 142 | case -ENOENT: /* just ignore it */ |
@@ -161,9 +183,15 @@ int i2400mu_txd(void *_i2400mu) | |||
161 | struct device *dev = &i2400mu->usb_iface->dev; | 183 | struct device *dev = &i2400mu->usb_iface->dev; |
162 | struct i2400m_msg_hdr *tx_msg; | 184 | struct i2400m_msg_hdr *tx_msg; |
163 | size_t tx_msg_size; | 185 | size_t tx_msg_size; |
186 | unsigned long flags; | ||
164 | 187 | ||
165 | d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); | 188 | d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); |
166 | 189 | ||
190 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
191 | BUG_ON(i2400mu->tx_kthread != NULL); | ||
192 | i2400mu->tx_kthread = current; | ||
193 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
194 | |||
167 | while (1) { | 195 | while (1) { |
168 | d_printf(2, dev, "TX: waiting for messages\n"); | 196 | d_printf(2, dev, "TX: waiting for messages\n"); |
169 | tx_msg = NULL; | 197 | tx_msg = NULL; |
@@ -183,6 +211,11 @@ int i2400mu_txd(void *_i2400mu) | |||
183 | if (result < 0) | 211 | if (result < 0) |
184 | break; | 212 | break; |
185 | } | 213 | } |
214 | |||
215 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
216 | i2400mu->tx_kthread = NULL; | ||
217 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
218 | |||
186 | d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result); | 219 | d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result); |
187 | return result; | 220 | return result; |
188 | } | 221 | } |
@@ -213,11 +246,13 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu) | |||
213 | struct i2400m *i2400m = &i2400mu->i2400m; | 246 | struct i2400m *i2400m = &i2400mu->i2400m; |
214 | struct device *dev = &i2400mu->usb_iface->dev; | 247 | struct device *dev = &i2400mu->usb_iface->dev; |
215 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; | 248 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; |
249 | struct task_struct *kthread; | ||
216 | 250 | ||
217 | i2400mu->tx_kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx", | 251 | kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx", |
218 | wimax_dev->name); | 252 | wimax_dev->name); |
219 | if (IS_ERR(i2400mu->tx_kthread)) { | 253 | /* the kthread function sets i2400mu->tx_thread */ |
220 | result = PTR_ERR(i2400mu->tx_kthread); | 254 | if (IS_ERR(kthread)) { |
255 | result = PTR_ERR(kthread); | ||
221 | dev_err(dev, "TX: cannot start thread: %d\n", result); | 256 | dev_err(dev, "TX: cannot start thread: %d\n", result); |
222 | } | 257 | } |
223 | return result; | 258 | return result; |
@@ -225,5 +260,17 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu) | |||
225 | 260 | ||
226 | void i2400mu_tx_release(struct i2400mu *i2400mu) | 261 | void i2400mu_tx_release(struct i2400mu *i2400mu) |
227 | { | 262 | { |
228 | kthread_stop(i2400mu->tx_kthread); | 263 | unsigned long flags; |
264 | struct i2400m *i2400m = &i2400mu->i2400m; | ||
265 | struct device *dev = i2400m_dev(i2400m); | ||
266 | struct task_struct *kthread; | ||
267 | |||
268 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
269 | kthread = i2400mu->tx_kthread; | ||
270 | i2400mu->tx_kthread = NULL; | ||
271 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
272 | if (kthread) | ||
273 | kthread_stop(kthread); | ||
274 | else | ||
275 | d_printf(1, dev, "TX: kthread had already exited\n"); | ||
229 | } | 276 | } |
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 7eadd11c815b..47e84ef355c5 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c | |||
@@ -58,7 +58,7 @@ | |||
58 | * i2400mu_rx_release() | 58 | * i2400mu_rx_release() |
59 | * i2400mu_tx_release() | 59 | * i2400mu_tx_release() |
60 | * | 60 | * |
61 | * i2400mu_bus_reset() Called by i2400m->bus_reset | 61 | * i2400mu_bus_reset() Called by i2400m_reset |
62 | * __i2400mu_reset() | 62 | * __i2400mu_reset() |
63 | * __i2400mu_send_barker() | 63 | * __i2400mu_send_barker() |
64 | * usb_reset_device() | 64 | * usb_reset_device() |
@@ -71,13 +71,25 @@ | |||
71 | #define D_SUBMODULE usb | 71 | #define D_SUBMODULE usb |
72 | #include "usb-debug-levels.h" | 72 | #include "usb-debug-levels.h" |
73 | 73 | ||
74 | static char i2400mu_debug_params[128]; | ||
75 | module_param_string(debug, i2400mu_debug_params, sizeof(i2400mu_debug_params), | ||
76 | 0644); | ||
77 | MODULE_PARM_DESC(debug, | ||
78 | "String of space-separated NAME:VALUE pairs, where NAMEs " | ||
79 | "are the different debug submodules and VALUE are the " | ||
80 | "initial debug value to set."); | ||
74 | 81 | ||
75 | /* Our firmware file name */ | 82 | /* Our firmware file name */ |
76 | static const char *i2400mu_bus_fw_names[] = { | 83 | static const char *i2400mu_bus_fw_names_5x50[] = { |
77 | #define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf" | 84 | #define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf" |
78 | I2400MU_FW_FILE_NAME_v1_4, | 85 | I2400MU_FW_FILE_NAME_v1_4, |
79 | #define I2400MU_FW_FILE_NAME_v1_3 "i2400m-fw-usb-1.3.sbcf" | 86 | NULL, |
80 | I2400MU_FW_FILE_NAME_v1_3, | 87 | }; |
88 | |||
89 | |||
90 | static const char *i2400mu_bus_fw_names_6050[] = { | ||
91 | #define I6050U_FW_FILE_NAME_v1_5 "i6050-fw-usb-1.5.sbcf" | ||
92 | I6050U_FW_FILE_NAME_v1_5, | ||
81 | NULL, | 93 | NULL, |
82 | }; | 94 | }; |
83 | 95 | ||
@@ -160,14 +172,59 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu, | |||
160 | epd = usb_get_epd(i2400mu->usb_iface, endpoint); | 172 | epd = usb_get_epd(i2400mu->usb_iface, endpoint); |
161 | pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); | 173 | pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); |
162 | memcpy(buffer, barker, barker_size); | 174 | memcpy(buffer, barker, barker_size); |
175 | retry: | ||
163 | ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size, | 176 | ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size, |
164 | &actual_len, HZ); | 177 | &actual_len, 200); |
165 | if (ret < 0) { | 178 | switch (ret) { |
166 | if (ret != -EINVAL) | 179 | case 0: |
167 | dev_err(dev, "E: barker error: %d\n", ret); | 180 | if (actual_len != barker_size) { /* Too short? drop it */ |
168 | } else if (actual_len != barker_size) { | 181 | dev_err(dev, "E: %s: short write (%d B vs %zu " |
169 | dev_err(dev, "E: only %d bytes transmitted\n", actual_len); | 182 | "expected)\n", |
170 | ret = -EIO; | 183 | __func__, actual_len, barker_size); |
184 | ret = -EIO; | ||
185 | } | ||
186 | break; | ||
187 | case -EPIPE: | ||
188 | /* | ||
189 | * Stall -- maybe the device is choking with our | ||
190 | * requests. Clear it and give it some time. If they | ||
191 | * happen to often, it might be another symptom, so we | ||
192 | * reset. | ||
193 | * | ||
194 | * No error handling for usb_clear_halt(0; if it | ||
195 | * works, the retry works; if it fails, this switch | ||
196 | * does the error handling for us. | ||
197 | */ | ||
198 | if (edc_inc(&i2400mu->urb_edc, | ||
199 | 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
200 | dev_err(dev, "E: %s: too many stalls in " | ||
201 | "URB; resetting device\n", __func__); | ||
202 | usb_queue_reset_device(i2400mu->usb_iface); | ||
203 | /* fallthrough */ | ||
204 | } else { | ||
205 | usb_clear_halt(i2400mu->usb_dev, pipe); | ||
206 | msleep(10); /* give the device some time */ | ||
207 | goto retry; | ||
208 | } | ||
209 | case -EINVAL: /* while removing driver */ | ||
210 | case -ENODEV: /* dev disconnect ... */ | ||
211 | case -ENOENT: /* just ignore it */ | ||
212 | case -ESHUTDOWN: /* and exit */ | ||
213 | case -ECONNRESET: | ||
214 | ret = -ESHUTDOWN; | ||
215 | break; | ||
216 | default: /* Some error? */ | ||
217 | if (edc_inc(&i2400mu->urb_edc, | ||
218 | EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
219 | dev_err(dev, "E: %s: maximum errors in URB " | ||
220 | "exceeded; resetting device\n", | ||
221 | __func__); | ||
222 | usb_queue_reset_device(i2400mu->usb_iface); | ||
223 | } else { | ||
224 | dev_warn(dev, "W: %s: cannot send URB: %d\n", | ||
225 | __func__, ret); | ||
226 | goto retry; | ||
227 | } | ||
171 | } | 228 | } |
172 | kfree(buffer); | 229 | kfree(buffer); |
173 | error_kzalloc: | 230 | error_kzalloc: |
@@ -232,15 +289,16 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) | |||
232 | 289 | ||
233 | d_fnstart(3, dev, "(i2400m %p rt %u)\n", i2400m, rt); | 290 | d_fnstart(3, dev, "(i2400m %p rt %u)\n", i2400m, rt); |
234 | if (rt == I2400M_RT_WARM) | 291 | if (rt == I2400M_RT_WARM) |
235 | result = __i2400mu_send_barker(i2400mu, i2400m_WARM_BOOT_BARKER, | 292 | result = __i2400mu_send_barker( |
236 | sizeof(i2400m_WARM_BOOT_BARKER), | 293 | i2400mu, i2400m_WARM_BOOT_BARKER, |
237 | I2400MU_EP_BULK_OUT); | 294 | sizeof(i2400m_WARM_BOOT_BARKER), |
295 | i2400mu->endpoint_cfg.bulk_out); | ||
238 | else if (rt == I2400M_RT_COLD) | 296 | else if (rt == I2400M_RT_COLD) |
239 | result = __i2400mu_send_barker(i2400mu, i2400m_COLD_BOOT_BARKER, | 297 | result = __i2400mu_send_barker( |
240 | sizeof(i2400m_COLD_BOOT_BARKER), | 298 | i2400mu, i2400m_COLD_BOOT_BARKER, |
241 | I2400MU_EP_RESET_COLD); | 299 | sizeof(i2400m_COLD_BOOT_BARKER), |
300 | i2400mu->endpoint_cfg.reset_cold); | ||
242 | else if (rt == I2400M_RT_BUS) { | 301 | else if (rt == I2400M_RT_BUS) { |
243 | do_bus_reset: | ||
244 | result = usb_reset_device(i2400mu->usb_dev); | 302 | result = usb_reset_device(i2400mu->usb_dev); |
245 | switch (result) { | 303 | switch (result) { |
246 | case 0: | 304 | case 0: |
@@ -248,7 +306,7 @@ do_bus_reset: | |||
248 | case -ENODEV: | 306 | case -ENODEV: |
249 | case -ENOENT: | 307 | case -ENOENT: |
250 | case -ESHUTDOWN: | 308 | case -ESHUTDOWN: |
251 | result = rt == I2400M_RT_WARM ? -ENODEV : 0; | 309 | result = 0; |
252 | break; /* We assume the device is disconnected */ | 310 | break; /* We assume the device is disconnected */ |
253 | default: | 311 | default: |
254 | dev_err(dev, "USB reset failed (%d), giving up!\n", | 312 | dev_err(dev, "USB reset failed (%d), giving up!\n", |
@@ -261,10 +319,17 @@ do_bus_reset: | |||
261 | if (result < 0 | 319 | if (result < 0 |
262 | && result != -EINVAL /* device is gone */ | 320 | && result != -EINVAL /* device is gone */ |
263 | && rt != I2400M_RT_BUS) { | 321 | && rt != I2400M_RT_BUS) { |
322 | /* | ||
323 | * Things failed -- resort to lower level reset, that | ||
324 | * we queue in another context; the reason for this is | ||
325 | * that the pre and post reset functionality requires | ||
326 | * the i2400m->init_mutex; RT_WARM and RT_COLD can | ||
327 | * come from areas where i2400m->init_mutex is taken. | ||
328 | */ | ||
264 | dev_err(dev, "%s reset failed (%d); trying USB reset\n", | 329 | dev_err(dev, "%s reset failed (%d); trying USB reset\n", |
265 | rt == I2400M_RT_WARM ? "warm" : "cold", result); | 330 | rt == I2400M_RT_WARM ? "warm" : "cold", result); |
266 | rt = I2400M_RT_BUS; | 331 | usb_queue_reset_device(i2400mu->usb_iface); |
267 | goto do_bus_reset; | 332 | result = -ENODEV; |
268 | } | 333 | } |
269 | d_fnend(3, dev, "(i2400m %p rt %u) = %d\n", i2400m, rt, result); | 334 | d_fnend(3, dev, "(i2400m %p rt %u) = %d\n", i2400m, rt, result); |
270 | return result; | 335 | return result; |
@@ -402,20 +467,33 @@ int i2400mu_probe(struct usb_interface *iface, | |||
402 | 467 | ||
403 | i2400m->bus_tx_block_size = I2400MU_BLK_SIZE; | 468 | i2400m->bus_tx_block_size = I2400MU_BLK_SIZE; |
404 | i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX; | 469 | i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX; |
470 | i2400m->bus_setup = NULL; | ||
405 | i2400m->bus_dev_start = i2400mu_bus_dev_start; | 471 | i2400m->bus_dev_start = i2400mu_bus_dev_start; |
406 | i2400m->bus_dev_stop = i2400mu_bus_dev_stop; | 472 | i2400m->bus_dev_stop = i2400mu_bus_dev_stop; |
473 | i2400m->bus_release = NULL; | ||
407 | i2400m->bus_tx_kick = i2400mu_bus_tx_kick; | 474 | i2400m->bus_tx_kick = i2400mu_bus_tx_kick; |
408 | i2400m->bus_reset = i2400mu_bus_reset; | 475 | i2400m->bus_reset = i2400mu_bus_reset; |
409 | i2400m->bus_bm_retries = I2400M_BOOT_RETRIES; | 476 | i2400m->bus_bm_retries = I2400M_USB_BOOT_RETRIES; |
410 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; | 477 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; |
411 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; | 478 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; |
412 | i2400m->bus_fw_names = i2400mu_bus_fw_names; | ||
413 | i2400m->bus_bm_mac_addr_impaired = 0; | 479 | i2400m->bus_bm_mac_addr_impaired = 0; |
414 | 480 | ||
481 | if (id->idProduct == USB_DEVICE_ID_I6050) { | ||
482 | i2400m->bus_fw_names = i2400mu_bus_fw_names_6050; | ||
483 | i2400mu->endpoint_cfg.bulk_out = 0; | ||
484 | i2400mu->endpoint_cfg.notification = 3; | ||
485 | i2400mu->endpoint_cfg.reset_cold = 2; | ||
486 | i2400mu->endpoint_cfg.bulk_in = 1; | ||
487 | } else { | ||
488 | i2400m->bus_fw_names = i2400mu_bus_fw_names_5x50; | ||
489 | i2400mu->endpoint_cfg.bulk_out = 0; | ||
490 | i2400mu->endpoint_cfg.notification = 1; | ||
491 | i2400mu->endpoint_cfg.reset_cold = 2; | ||
492 | i2400mu->endpoint_cfg.bulk_in = 3; | ||
493 | } | ||
415 | #ifdef CONFIG_PM | 494 | #ifdef CONFIG_PM |
416 | iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */ | 495 | iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */ |
417 | device_init_wakeup(dev, 1); | 496 | device_init_wakeup(dev, 1); |
418 | usb_autopm_enable(i2400mu->usb_iface); | ||
419 | usb_dev->autosuspend_delay = 15 * HZ; | 497 | usb_dev->autosuspend_delay = 15 * HZ; |
420 | usb_dev->autosuspend_disabled = 0; | 498 | usb_dev->autosuspend_disabled = 0; |
421 | #endif | 499 | #endif |
@@ -483,7 +561,10 @@ void i2400mu_disconnect(struct usb_interface *iface) | |||
483 | * So at the end, the three cases require common handling. | 561 | * So at the end, the three cases require common handling. |
484 | * | 562 | * |
485 | * If at the time of this call the device's firmware is not loaded, | 563 | * If at the time of this call the device's firmware is not loaded, |
486 | * nothing has to be done. | 564 | * nothing has to be done. Note we can be "loose" about not reading |
565 | * i2400m->updown under i2400m->init_mutex. If it happens to change | ||
566 | * inmediately, other parts of the call flow will fail and effectively | ||
567 | * catch it. | ||
487 | * | 568 | * |
488 | * If the firmware is loaded, we need to: | 569 | * If the firmware is loaded, we need to: |
489 | * | 570 | * |
@@ -522,6 +603,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) | |||
522 | #endif | 603 | #endif |
523 | 604 | ||
524 | d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); | 605 | d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); |
606 | rmb(); /* see i2400m->updown's documentation */ | ||
525 | if (i2400m->updown == 0) | 607 | if (i2400m->updown == 0) |
526 | goto no_firmware; | 608 | goto no_firmware; |
527 | if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { | 609 | if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { |
@@ -575,6 +657,7 @@ int i2400mu_resume(struct usb_interface *iface) | |||
575 | struct i2400m *i2400m = &i2400mu->i2400m; | 657 | struct i2400m *i2400m = &i2400mu->i2400m; |
576 | 658 | ||
577 | d_fnstart(3, dev, "(iface %p)\n", iface); | 659 | d_fnstart(3, dev, "(iface %p)\n", iface); |
660 | rmb(); /* see i2400m->updown's documentation */ | ||
578 | if (i2400m->updown == 0) { | 661 | if (i2400m->updown == 0) { |
579 | d_printf(1, dev, "fw was down, no resume neeed\n"); | 662 | d_printf(1, dev, "fw was down, no resume neeed\n"); |
580 | goto out; | 663 | goto out; |
@@ -591,7 +674,54 @@ out: | |||
591 | 674 | ||
592 | 675 | ||
593 | static | 676 | static |
677 | int i2400mu_reset_resume(struct usb_interface *iface) | ||
678 | { | ||
679 | int result; | ||
680 | struct device *dev = &iface->dev; | ||
681 | struct i2400mu *i2400mu = usb_get_intfdata(iface); | ||
682 | struct i2400m *i2400m = &i2400mu->i2400m; | ||
683 | |||
684 | d_fnstart(3, dev, "(iface %p)\n", iface); | ||
685 | result = i2400m_dev_reset_handle(i2400m, "device reset on resume"); | ||
686 | d_fnend(3, dev, "(iface %p) = %d\n", iface, result); | ||
687 | return result < 0 ? result : 0; | ||
688 | } | ||
689 | |||
690 | |||
691 | /* | ||
692 | * Another driver or user space is triggering a reset on the device | ||
693 | * which contains the interface passed as an argument. Cease IO and | ||
694 | * save any device state you need to restore. | ||
695 | * | ||
696 | * If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if | ||
697 | * you are in atomic context. | ||
698 | */ | ||
699 | static | ||
700 | int i2400mu_pre_reset(struct usb_interface *iface) | ||
701 | { | ||
702 | struct i2400mu *i2400mu = usb_get_intfdata(iface); | ||
703 | return i2400m_pre_reset(&i2400mu->i2400m); | ||
704 | } | ||
705 | |||
706 | |||
707 | /* | ||
708 | * The reset has completed. Restore any saved device state and begin | ||
709 | * using the device again. | ||
710 | * | ||
711 | * If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if | ||
712 | * you are in atomic context. | ||
713 | */ | ||
714 | static | ||
715 | int i2400mu_post_reset(struct usb_interface *iface) | ||
716 | { | ||
717 | struct i2400mu *i2400mu = usb_get_intfdata(iface); | ||
718 | return i2400m_post_reset(&i2400mu->i2400m); | ||
719 | } | ||
720 | |||
721 | |||
722 | static | ||
594 | struct usb_device_id i2400mu_id_table[] = { | 723 | struct usb_device_id i2400mu_id_table[] = { |
724 | { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) }, | ||
595 | { USB_DEVICE(0x8086, 0x0181) }, | 725 | { USB_DEVICE(0x8086, 0x0181) }, |
596 | { USB_DEVICE(0x8086, 0x1403) }, | 726 | { USB_DEVICE(0x8086, 0x1403) }, |
597 | { USB_DEVICE(0x8086, 0x1405) }, | 727 | { USB_DEVICE(0x8086, 0x1405) }, |
@@ -609,8 +739,11 @@ struct usb_driver i2400mu_driver = { | |||
609 | .name = KBUILD_MODNAME, | 739 | .name = KBUILD_MODNAME, |
610 | .suspend = i2400mu_suspend, | 740 | .suspend = i2400mu_suspend, |
611 | .resume = i2400mu_resume, | 741 | .resume = i2400mu_resume, |
742 | .reset_resume = i2400mu_reset_resume, | ||
612 | .probe = i2400mu_probe, | 743 | .probe = i2400mu_probe, |
613 | .disconnect = i2400mu_disconnect, | 744 | .disconnect = i2400mu_disconnect, |
745 | .pre_reset = i2400mu_pre_reset, | ||
746 | .post_reset = i2400mu_post_reset, | ||
614 | .id_table = i2400mu_id_table, | 747 | .id_table = i2400mu_id_table, |
615 | .supports_autosuspend = 1, | 748 | .supports_autosuspend = 1, |
616 | }; | 749 | }; |
@@ -618,6 +751,8 @@ struct usb_driver i2400mu_driver = { | |||
618 | static | 751 | static |
619 | int __init i2400mu_driver_init(void) | 752 | int __init i2400mu_driver_init(void) |
620 | { | 753 | { |
754 | d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400mu_debug_params, | ||
755 | "i2400m_usb.debug"); | ||
621 | return usb_register(&i2400mu_driver); | 756 | return usb_register(&i2400mu_driver); |
622 | } | 757 | } |
623 | module_init(i2400mu_driver_init); | 758 | module_init(i2400mu_driver_init); |
@@ -632,7 +767,7 @@ void __exit i2400mu_driver_exit(void) | |||
632 | module_exit(i2400mu_driver_exit); | 767 | module_exit(i2400mu_driver_exit); |
633 | 768 | ||
634 | MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); | 769 | MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); |
635 | MODULE_DESCRIPTION("Intel 2400M WiMAX networking for USB"); | 770 | MODULE_DESCRIPTION("Driver for USB based Intel Wireless WiMAX Connection 2400M " |
771 | "(5x50 & 6050)"); | ||
636 | MODULE_LICENSE("GPL"); | 772 | MODULE_LICENSE("GPL"); |
637 | MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4); | 773 | MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4); |
638 | MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_3); | ||
diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 2dbfb5a05994..33b2ea09a4ad 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 | 28 | #define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 |
29 | #define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 | 29 | #define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 |
30 | #define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 | 30 | #define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 |
31 | #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5 0x1407 | ||
31 | 32 | ||
32 | #define SDIO_VENDOR_ID_MARVELL 0x02df | 33 | #define SDIO_VENDOR_ID_MARVELL 0x02df |
33 | #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 | 34 | #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 |
diff --git a/include/linux/wimax/debug.h b/include/linux/wimax/debug.h index c703e0340423..db8096e88533 100644 --- a/include/linux/wimax/debug.h +++ b/include/linux/wimax/debug.h | |||
@@ -450,4 +450,76 @@ do { \ | |||
450 | }) | 450 | }) |
451 | 451 | ||
452 | 452 | ||
453 | static inline | ||
454 | void d_submodule_set(struct d_level *d_level, size_t d_level_size, | ||
455 | const char *submodule, u8 level, const char *tag) | ||
456 | { | ||
457 | struct d_level *itr, *top; | ||
458 | int index = -1; | ||
459 | |||
460 | for (itr = d_level, top = itr + d_level_size; itr < top; itr++) { | ||
461 | index++; | ||
462 | if (itr->name == NULL) { | ||
463 | printk(KERN_ERR "%s: itr->name NULL?? (%p, #%d)\n", | ||
464 | tag, itr, index); | ||
465 | continue; | ||
466 | } | ||
467 | if (!strcmp(itr->name, submodule)) { | ||
468 | itr->level = level; | ||
469 | return; | ||
470 | } | ||
471 | } | ||
472 | printk(KERN_ERR "%s: unknown submodule %s\n", tag, submodule); | ||
473 | } | ||
474 | |||
475 | |||
476 | /** | ||
477 | * d_parse_params - Parse a string with debug parameters from the | ||
478 | * command line | ||
479 | * | ||
480 | * @d_level: level structure (D_LEVEL) | ||
481 | * @d_level_size: number of items in the level structure | ||
482 | * (D_LEVEL_SIZE). | ||
483 | * @_params: string with the parameters; this is a space (not tab!) | ||
484 | * separated list of NAME:VALUE, where value is the debug level | ||
485 | * and NAME is the name of the submodule. | ||
486 | * @tag: string for error messages (example: MODULE.ARGNAME). | ||
487 | */ | ||
488 | static inline | ||
489 | void d_parse_params(struct d_level *d_level, size_t d_level_size, | ||
490 | const char *_params, const char *tag) | ||
491 | { | ||
492 | char submodule[130], *params, *params_orig, *token, *colon; | ||
493 | unsigned level, tokens; | ||
494 | |||
495 | if (_params == NULL) | ||
496 | return; | ||
497 | params_orig = kstrdup(_params, GFP_KERNEL); | ||
498 | params = params_orig; | ||
499 | while (1) { | ||
500 | token = strsep(¶ms, " "); | ||
501 | if (token == NULL) | ||
502 | break; | ||
503 | if (*token == '\0') /* eat joint spaces */ | ||
504 | continue; | ||
505 | /* kernel's sscanf %s eats until whitespace, so we | ||
506 | * replace : by \n so it doesn't get eaten later by | ||
507 | * strsep */ | ||
508 | colon = strchr(token, ':'); | ||
509 | if (colon != NULL) | ||
510 | *colon = '\n'; | ||
511 | tokens = sscanf(token, "%s\n%u", submodule, &level); | ||
512 | if (colon != NULL) | ||
513 | *colon = ':'; /* set back, for error messages */ | ||
514 | if (tokens == 2) | ||
515 | d_submodule_set(d_level, d_level_size, | ||
516 | submodule, level, tag); | ||
517 | else | ||
518 | printk(KERN_ERR "%s: can't parse '%s' as a " | ||
519 | "SUBMODULE:LEVEL (%d tokens)\n", | ||
520 | tag, token, tokens); | ||
521 | } | ||
522 | kfree(params_orig); | ||
523 | } | ||
524 | |||
453 | #endif /* #ifndef __debug__h__ */ | 525 | #endif /* #ifndef __debug__h__ */ |
diff --git a/include/linux/wimax/i2400m.h b/include/linux/wimax/i2400m.h index 433693ef2bb0..62d356153565 100644 --- a/include/linux/wimax/i2400m.h +++ b/include/linux/wimax/i2400m.h | |||
@@ -138,7 +138,7 @@ struct i2400m_bcf_hdr { | |||
138 | __le32 module_id; | 138 | __le32 module_id; |
139 | __le32 module_vendor; | 139 | __le32 module_vendor; |
140 | __le32 date; /* BCD YYYMMDD */ | 140 | __le32 date; /* BCD YYYMMDD */ |
141 | __le32 size; | 141 | __le32 size; /* in dwords */ |
142 | __le32 key_size; /* in dwords */ | 142 | __le32 key_size; /* in dwords */ |
143 | __le32 modulus_size; /* in dwords */ | 143 | __le32 modulus_size; /* in dwords */ |
144 | __le32 exponent_size; /* in dwords */ | 144 | __le32 exponent_size; /* in dwords */ |
@@ -168,16 +168,6 @@ enum i2400m_brh { | |||
168 | }; | 168 | }; |
169 | 169 | ||
170 | 170 | ||
171 | /* Constants for bcf->module_id */ | ||
172 | enum i2400m_bcf_mod_id { | ||
173 | /* Firmware file carries its own pokes -- pokes are a set of | ||
174 | * magical values that have to be written in certain memory | ||
175 | * addresses to get the device up and ready for firmware | ||
176 | * download when it is in non-signed boot mode. */ | ||
177 | I2400M_BCF_MOD_ID_POKES = 0x000000001, | ||
178 | }; | ||
179 | |||
180 | |||
181 | /** | 171 | /** |
182 | * i2400m_bootrom_header - Header for a boot-mode command | 172 | * i2400m_bootrom_header - Header for a boot-mode command |
183 | * | 173 | * |
@@ -276,6 +266,7 @@ enum { | |||
276 | I2400M_WARM_RESET_BARKER = 0x50f750f7, | 266 | I2400M_WARM_RESET_BARKER = 0x50f750f7, |
277 | I2400M_NBOOT_BARKER = 0xdeadbeef, | 267 | I2400M_NBOOT_BARKER = 0xdeadbeef, |
278 | I2400M_SBOOT_BARKER = 0x0ff1c1a1, | 268 | I2400M_SBOOT_BARKER = 0x0ff1c1a1, |
269 | I2400M_SBOOT_BARKER_6050 = 0x80000001, | ||
279 | I2400M_ACK_BARKER = 0xfeedbabe, | 270 | I2400M_ACK_BARKER = 0xfeedbabe, |
280 | I2400M_D2H_MSG_BARKER = 0xbeefbabe, | 271 | I2400M_D2H_MSG_BARKER = 0xbeefbabe, |
281 | }; | 272 | }; |
diff --git a/include/net/wimax.h b/include/net/wimax.h index 2af7bf839f23..d69c4a7a1267 100644 --- a/include/net/wimax.h +++ b/include/net/wimax.h | |||
@@ -195,6 +195,12 @@ | |||
195 | * defining the `struct nla_policy` for each message, it has to have | 195 | * defining the `struct nla_policy` for each message, it has to have |
196 | * an array size of WIMAX_GNL_ATTR_MAX+1. | 196 | * an array size of WIMAX_GNL_ATTR_MAX+1. |
197 | * | 197 | * |
198 | * The op_*() function pointers will not be called if the wimax_dev is | ||
199 | * in a state <= %WIMAX_ST_UNINITIALIZED. The exception is: | ||
200 | * | ||
201 | * - op_reset: can be called at any time after wimax_dev_add() has | ||
202 | * been called. | ||
203 | * | ||
198 | * THE PIPE INTERFACE: | 204 | * THE PIPE INTERFACE: |
199 | * | 205 | * |
200 | * This interface is kept intentionally simple. The driver can send | 206 | * This interface is kept intentionally simple. The driver can send |
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index d631a17186bc..d3bfb6ef13ae 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c | |||
@@ -388,6 +388,8 @@ int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info) | |||
388 | } | 388 | } |
389 | mutex_lock(&wimax_dev->mutex); | 389 | mutex_lock(&wimax_dev->mutex); |
390 | result = wimax_dev_is_ready(wimax_dev); | 390 | result = wimax_dev_is_ready(wimax_dev); |
391 | if (result == -ENOMEDIUM) | ||
392 | result = 0; | ||
391 | if (result < 0) | 393 | if (result < 0) |
392 | goto error_not_ready; | 394 | goto error_not_ready; |
393 | result = -ENOSYS; | 395 | result = -ENOSYS; |
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 70ef4df863b9..94d339c345d2 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c | |||
@@ -305,8 +305,15 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) | |||
305 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); | 305 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); |
306 | mutex_lock(&wimax_dev->mutex); | 306 | mutex_lock(&wimax_dev->mutex); |
307 | result = wimax_dev_is_ready(wimax_dev); | 307 | result = wimax_dev_is_ready(wimax_dev); |
308 | if (result < 0) | 308 | if (result < 0) { |
309 | /* While initializing, < 1.4.3 wimax-tools versions use | ||
310 | * this call to check if the device is a valid WiMAX | ||
311 | * device; so we allow it to proceed always, | ||
312 | * considering the radios are all off. */ | ||
313 | if (result == -ENOMEDIUM && state == WIMAX_RF_QUERY) | ||
314 | result = WIMAX_RF_OFF << 1 | WIMAX_RF_OFF; | ||
309 | goto error_not_ready; | 315 | goto error_not_ready; |
316 | } | ||
310 | switch (state) { | 317 | switch (state) { |
311 | case WIMAX_RF_ON: | 318 | case WIMAX_RF_ON: |
312 | case WIMAX_RF_OFF: | 319 | case WIMAX_RF_OFF: |
@@ -355,6 +362,7 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) | |||
355 | 362 | ||
356 | wimax_dev->rfkill = rfkill; | 363 | wimax_dev->rfkill = rfkill; |
357 | 364 | ||
365 | rfkill_init_sw_state(rfkill, 1); | ||
358 | result = rfkill_register(wimax_dev->rfkill); | 366 | result = rfkill_register(wimax_dev->rfkill); |
359 | if (result < 0) | 367 | if (result < 0) |
360 | goto error_rfkill_register; | 368 | goto error_rfkill_register; |
diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 79fb7d7c640f..c8866412f830 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c | |||
@@ -60,6 +60,14 @@ | |||
60 | #define D_SUBMODULE stack | 60 | #define D_SUBMODULE stack |
61 | #include "debug-levels.h" | 61 | #include "debug-levels.h" |
62 | 62 | ||
63 | static char wimax_debug_params[128]; | ||
64 | module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params), | ||
65 | 0644); | ||
66 | MODULE_PARM_DESC(debug, | ||
67 | "String of space-separated NAME:VALUE pairs, where NAMEs " | ||
68 | "are the different debug submodules and VALUE are the " | ||
69 | "initial debug value to set."); | ||
70 | |||
63 | /* | 71 | /* |
64 | * Authoritative source for the RE_STATE_CHANGE attribute policy | 72 | * Authoritative source for the RE_STATE_CHANGE attribute policy |
65 | * | 73 | * |
@@ -562,6 +570,9 @@ int __init wimax_subsys_init(void) | |||
562 | int result, cnt; | 570 | int result, cnt; |
563 | 571 | ||
564 | d_fnstart(4, NULL, "()\n"); | 572 | d_fnstart(4, NULL, "()\n"); |
573 | d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params, | ||
574 | "wimax.debug"); | ||
575 | |||
565 | snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), | 576 | snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), |
566 | "WiMAX"); | 577 | "WiMAX"); |
567 | result = genl_register_family(&wimax_gnl_family); | 578 | result = genl_register_family(&wimax_gnl_family); |