aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wimax/i2400m/driver.c12
-rw-r--r--drivers/net/wimax/i2400m/fw.c313
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h36
-rw-r--r--drivers/net/wimax/i2400m/rx.c22
-rw-r--r--drivers/net/wimax/i2400m/sdio-rx.c25
-rw-r--r--drivers/net/wimax/i2400m/usb-notif.c32
6 files changed, 355 insertions, 85 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index e3b2c246cad7..73f45ea010a7 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -98,6 +98,15 @@ MODULE_PARM_DESC(debug,
98 "are the different debug submodules and VALUE are the " 98 "are the different debug submodules and VALUE are the "
99 "initial debug value to set."); 99 "initial debug value to set.");
100 100
101static char i2400m_barkers_params[128];
102module_param_string(barkers, i2400m_barkers_params,
103 sizeof(i2400m_barkers_params), 0644);
104MODULE_PARM_DESC(barkers,
105 "String of comma-separated 32-bit values; each is "
106 "recognized as the value the device sends as a reboot "
107 "signal; values are appended to a list--setting one value "
108 "as zero cleans the existing list and starts a new one.");
109
101/** 110/**
102 * i2400m_queue_work - schedule work on a i2400m's queue 111 * i2400m_queue_work - schedule work on a i2400m's queue
103 * 112 *
@@ -804,7 +813,7 @@ int __init i2400m_driver_init(void)
804{ 813{
805 d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400m_debug_params, 814 d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400m_debug_params,
806 "i2400m.debug"); 815 "i2400m.debug");
807 return 0; 816 return i2400m_barker_db_init(i2400m_barkers_params);
808} 817}
809module_init(i2400m_driver_init); 818module_init(i2400m_driver_init);
810 819
@@ -813,6 +822,7 @@ void __exit i2400m_driver_exit(void)
813{ 822{
814 /* for scheds i2400m_dev_reset_handle() */ 823 /* for scheds i2400m_dev_reset_handle() */
815 flush_scheduled_work(); 824 flush_scheduled_work();
825 i2400m_barker_db_exit();
816 return; 826 return;
817} 827}
818module_exit(i2400m_driver_exit); 828module_exit(i2400m_driver_exit);
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index c962a8d8df7e..798564eb0e99 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
@@ -101,6 +107,11 @@
101 * 107 *
102 * ROADMAP 108 * ROADMAP
103 * 109 *
110 * i2400m_barker_db_init Called by i2400m_driver_init()
111 * i2400m_barker_db_add
112 *
113 * i2400m_barker_db_exit Called by i2400m_driver_exit()
114 *
104 * i2400m_dev_bootstrap Called by __i2400m_dev_start() 115 * i2400m_dev_bootstrap Called by __i2400m_dev_start()
105 * request_firmware 116 * request_firmware
106 * i2400m_fw_check 117 * i2400m_fw_check
@@ -125,6 +136,7 @@
125 * i2400m->bus_bm_cmd_send() 136 * i2400m->bus_bm_cmd_send()
126 * i2400m->bus_bm_wait_for_ack 137 * i2400m->bus_bm_wait_for_ack
127 * __i2400m_bm_ack_verify 138 * __i2400m_bm_ack_verify
139 * i2400m_is_boot_barker
128 * 140 *
129 * i2400m_bm_cmd_prepare Used by bus-drivers to prep 141 * i2400m_bm_cmd_prepare Used by bus-drivers to prep
130 * commands before sending 142 * commands before sending
@@ -175,6 +187,237 @@ EXPORT_SYMBOL_GPL(i2400m_bm_cmd_prepare);
175 187
176 188
177/* 189/*
190 * Database of known barkers.
191 *
192 * A barker is what the device sends indicating he is ready to be
193 * bootloaded. Different versions of the device will send different
194 * barkers. Depending on the barker, it might mean the device wants
195 * some kind of firmware or the other.
196 */
197static struct i2400m_barker_db {
198 __le32 data[4];
199} *i2400m_barker_db;
200static size_t i2400m_barker_db_used, i2400m_barker_db_size;
201
202
203static
204int i2400m_zrealloc_2x(void **ptr, size_t *_count, size_t el_size,
205 gfp_t gfp_flags)
206{
207 size_t old_count = *_count,
208 new_count = old_count ? 2 * old_count : 2,
209 old_size = el_size * old_count,
210 new_size = el_size * new_count;
211 void *nptr = krealloc(*ptr, new_size, gfp_flags);
212 if (nptr) {
213 /* zero the other half or the whole thing if old_count
214 * was zero */
215 if (old_size == 0)
216 memset(nptr, 0, new_size);
217 else
218 memset(nptr + old_size, 0, old_size);
219 *_count = new_count;
220 *ptr = nptr;
221 return 0;
222 } else
223 return -ENOMEM;
224}
225
226
227/*
228 * Add a barker to the database
229 *
230 * This cannot used outside of this module and only at at module_init
231 * time. This is to avoid the need to do locking.
232 */
233static
234int i2400m_barker_db_add(u32 barker_id)
235{
236 int result;
237
238 struct i2400m_barker_db *barker;
239 if (i2400m_barker_db_used >= i2400m_barker_db_size) {
240 result = i2400m_zrealloc_2x(
241 (void **) &i2400m_barker_db, &i2400m_barker_db_size,
242 sizeof(i2400m_barker_db[0]), GFP_KERNEL);
243 if (result < 0)
244 return result;
245 }
246 barker = i2400m_barker_db + i2400m_barker_db_used++;
247 barker->data[0] = le32_to_cpu(barker_id);
248 barker->data[1] = le32_to_cpu(barker_id);
249 barker->data[2] = le32_to_cpu(barker_id);
250 barker->data[3] = le32_to_cpu(barker_id);
251 return 0;
252}
253
254
255void i2400m_barker_db_exit(void)
256{
257 kfree(i2400m_barker_db);
258 i2400m_barker_db = NULL;
259 i2400m_barker_db_size = 0;
260 i2400m_barker_db_used = 0;
261}
262
263
264/*
265 * Helper function to add all the known stable barkers to the barker
266 * database.
267 */
268static
269int i2400m_barker_db_known_barkers(void)
270{
271 int result;
272
273 result = i2400m_barker_db_add(I2400M_NBOOT_BARKER);
274 if (result < 0)
275 goto error_add;
276 result = i2400m_barker_db_add(I2400M_SBOOT_BARKER);
277 if (result < 0)
278 goto error_add;
279error_add:
280 return result;
281}
282
283
284/*
285 * Initialize the barker database
286 *
287 * This can only be used from the module_init function for this
288 * module; this is to avoid the need to do locking.
289 *
290 * @options: command line argument with extra barkers to
291 * recognize. This is a comma-separated list of 32-bit hex
292 * numbers. They are appended to the existing list. Setting 0
293 * cleans the existing list and starts a new one.
294 */
295int i2400m_barker_db_init(const char *_options)
296{
297 int result;
298 char *options = NULL, *options_orig, *token;
299
300 i2400m_barker_db = NULL;
301 i2400m_barker_db_size = 0;
302 i2400m_barker_db_used = 0;
303
304 result = i2400m_barker_db_known_barkers();
305 if (result < 0)
306 goto error_add;
307 /* parse command line options from i2400m.barkers */
308 if (_options != NULL) {
309 unsigned barker;
310
311 options_orig = kstrdup(_options, GFP_KERNEL);
312 if (options_orig == NULL)
313 goto error_parse;
314 options = options_orig;
315
316 while ((token = strsep(&options, ",")) != NULL) {
317 if (*token == '\0') /* eat joint commas */
318 continue;
319 if (sscanf(token, "%x", &barker) != 1
320 || barker > 0xffffffff) {
321 printk(KERN_ERR "%s: can't recognize "
322 "i2400m.barkers value '%s' as "
323 "a 32-bit number\n",
324 __func__, token);
325 result = -EINVAL;
326 goto error_parse;
327 }
328 if (barker == 0) {
329 /* clean list and start new */
330 i2400m_barker_db_exit();
331 continue;
332 }
333 result = i2400m_barker_db_add(barker);
334 if (result < 0)
335 goto error_add;
336 }
337 kfree(options_orig);
338 }
339 return 0;
340
341error_parse:
342error_add:
343 kfree(i2400m_barker_db);
344 return result;
345}
346
347
348/*
349 * Recognize a boot barker
350 *
351 * @buf: buffer where the boot barker.
352 * @buf_size: size of the buffer (has to be 16 bytes). It is passed
353 * here so the function can check it for the caller.
354 *
355 * Note that as a side effect, upon identifying the obtained boot
356 * barker, this function will set i2400m->barker to point to the right
357 * barker database entry. Subsequent calls to the function will result
358 * in verifying that the same type of boot barker is returned when the
359 * device [re]boots (as long as the same device instance is used).
360 *
361 * Return: 0 if @buf matches a known boot barker. -ENOENT if the
362 * buffer in @buf doesn't match any boot barker in the database or
363 * -EILSEQ if the buffer doesn't have the right size.
364 */
365int i2400m_is_boot_barker(struct i2400m *i2400m,
366 const void *buf, size_t buf_size)
367{
368 int result;
369 struct device *dev = i2400m_dev(i2400m);
370 struct i2400m_barker_db *barker;
371 int i;
372
373 result = -ENOENT;
374 if (buf_size != sizeof(i2400m_barker_db[i].data))
375 return result;
376
377 /* Short circuit if we have already discovered the barker
378 * associated with the device. */
379 if (i2400m->barker
380 && !memcmp(buf, i2400m->barker, sizeof(i2400m->barker->data))) {
381 unsigned index = (i2400m->barker - i2400m_barker_db)
382 / sizeof(*i2400m->barker);
383 d_printf(2, dev, "boot barker cache-confirmed #%u/%08x\n",
384 index, le32_to_cpu(i2400m->barker->data[0]));
385 return 0;
386 }
387
388 for (i = 0; i < i2400m_barker_db_used; i++) {
389 barker = &i2400m_barker_db[i];
390 BUILD_BUG_ON(sizeof(barker->data) != 16);
391 if (memcmp(buf, barker->data, sizeof(barker->data)))
392 continue;
393
394 if (i2400m->barker == NULL) {
395 i2400m->barker = barker;
396 d_printf(1, dev, "boot barker set to #%u/%08x\n",
397 i, le32_to_cpu(barker->data[0]));
398 if (barker->data[0] == le32_to_cpu(I2400M_NBOOT_BARKER))
399 i2400m->sboot = 0;
400 else
401 i2400m->sboot = 1;
402 } else if (i2400m->barker != barker) {
403 dev_err(dev, "HW inconsistency: device "
404 "reports a different boot barker "
405 "than set (from %08x to %08x)\n",
406 le32_to_cpu(i2400m->barker->data[0]),
407 le32_to_cpu(barker->data[0]));
408 result = -EIO;
409 } else
410 d_printf(2, dev, "boot barker confirmed #%u/%08x\n",
411 i, le32_to_cpu(barker->data[0]));
412 result = 0;
413 break;
414 }
415 return result;
416}
417EXPORT_SYMBOL_GPL(i2400m_is_boot_barker);
418
419
420/*
178 * Verify the ack data received 421 * Verify the ack data received
179 * 422 *
180 * Given a reply to a boot mode command, chew it and verify everything 423 * Given a reply to a boot mode command, chew it and verify everything
@@ -204,20 +447,10 @@ ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode,
204 opcode, ack_size, sizeof(*ack)); 447 opcode, ack_size, sizeof(*ack));
205 goto error_ack_short; 448 goto error_ack_short;
206 } 449 }
207 if (ack_size == sizeof(i2400m_NBOOT_BARKER) 450 result = i2400m_is_boot_barker(i2400m, ack, ack_size);
208 && memcmp(ack, i2400m_NBOOT_BARKER, sizeof(*ack)) == 0) { 451 if (result >= 0) {
209 result = -ERESTARTSYS;
210 i2400m->sboot = 0;
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; 452 result = -ERESTARTSYS;
218 i2400m->sboot = 1; 453 d_printf(6, dev, "boot-mode cmd %d: HW boot barker\n", opcode);
219 d_printf(6, dev, "boot-mode cmd %d: HW signed reboot barker\n",
220 opcode);
221 goto error_reboot; 454 goto error_reboot;
222 } 455 }
223 if (ack_size == sizeof(i2400m_ACK_BARKER) 456 if (ack_size == sizeof(i2400m_ACK_BARKER)
@@ -590,9 +823,6 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
590 * 823 *
591 * < 0 errno code on error, 0 if ok. 824 * < 0 errno code on error, 0 if ok.
592 * 825 *
593 * i2400m->sboot set to 0 for unsecure boot process, 1 for secure
594 * boot process.
595 *
596 * Description: 826 * Description:
597 * 827 *
598 * Tries hard enough to put the device in boot-mode. There are two 828 * Tries hard enough to put the device in boot-mode. There are two
@@ -619,7 +849,7 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
619 int count = i2400m->bus_bm_retries; 849 int count = i2400m->bus_bm_retries;
620 int ack_timeout_cnt = 1; 850 int ack_timeout_cnt = 1;
621 851
622 BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_NBOOT_BARKER)); 852 BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data));
623 BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER)); 853 BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER));
624 854
625 d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags); 855 d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags);
@@ -647,8 +877,14 @@ do_reboot:
647 case -ETIMEDOUT: /* device has timed out, we might be in boot 877 case -ETIMEDOUT: /* device has timed out, we might be in boot
648 * mode already and expecting an ack, let's try 878 * mode already and expecting an ack, let's try
649 * that */ 879 * that */
650 dev_info(dev, "warm reset timed out, trying an ack\n"); 880 if (i2400m->barker == NULL) {
651 goto do_reboot_ack; 881 dev_info(dev, "warm reset timed out, unknown barker "
882 "type, rebooting\n");
883 goto do_reboot;
884 } else {
885 dev_info(dev, "warm reset timed out, trying an ack\n");
886 goto do_reboot_ack;
887 }
652 case -EPROTO: 888 case -EPROTO:
653 case -ESHUTDOWN: /* dev is gone */ 889 case -ESHUTDOWN: /* dev is gone */
654 case -EINTR: /* user cancelled */ 890 case -EINTR: /* user cancelled */
@@ -664,12 +900,7 @@ do_reboot:
664 * notification and report it as -EISCONN. */ 900 * notification and report it as -EISCONN. */
665do_reboot_ack: 901do_reboot_ack:
666 d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count); 902 d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count);
667 if (i2400m->sboot == 0) 903 memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data));
668 memcpy(cmd, i2400m_NBOOT_BARKER,
669 sizeof(i2400m_NBOOT_BARKER));
670 else
671 memcpy(cmd, i2400m_SBOOT_BARKER,
672 sizeof(i2400m_SBOOT_BARKER));
673 result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), 904 result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
674 &ack, sizeof(ack), I2400M_BM_CMD_RAW); 905 &ack, sizeof(ack), I2400M_BM_CMD_RAW);
675 switch (result) { 906 switch (result) {
@@ -682,10 +913,8 @@ do_reboot_ack:
682 d_printf(4, dev, "reboot ack: got ack barker - good\n"); 913 d_printf(4, dev, "reboot ack: got ack barker - good\n");
683 break; 914 break;
684 case -ETIMEDOUT: /* no response, maybe it is the other type? */ 915 case -ETIMEDOUT: /* no response, maybe it is the other type? */
685 if (ack_timeout_cnt-- >= 0) { 916 if (ack_timeout_cnt-- < 0) {
686 d_printf(4, dev, "reboot ack timedout: " 917 d_printf(4, dev, "reboot ack timedout: retrying\n");
687 "trying the other type?\n");
688 i2400m->sboot = !i2400m->sboot;
689 goto do_reboot_ack; 918 goto do_reboot_ack;
690 } else { 919 } else {
691 dev_err(dev, "reboot ack timedout too long: " 920 dev_err(dev, "reboot ack timedout too long: "
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 73b4e6a15135..bcb1882ed741 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -194,6 +194,7 @@ enum i2400m_reset_type {
194 194
195struct i2400m_reset_ctx; 195struct i2400m_reset_ctx;
196struct i2400m_roq; 196struct i2400m_roq;
197struct i2400m_barker_db;
197 198
198/** 199/**
199 * struct i2400m - descriptor for an Intel 2400m 200 * struct i2400m - descriptor for an Intel 2400m
@@ -419,6 +420,12 @@ struct i2400m_roq;
419 * 420 *
420 * @fw_version: version of the firmware interface, Major.minor, 421 * @fw_version: version of the firmware interface, Major.minor,
421 * encoded in the high word and low word (major << 16 | minor). 422 * encoded in the high word and low word (major << 16 | minor).
423 *
424 * @barker: barker type that the device uses; this is initialized by
425 * i2400m_is_boot_barker() the first time it is called. Then it
426 * won't change during the life cycle of the device and everytime
427 * a boot barker is received, it is just verified for it being the
428 * same.
422 */ 429 */
423struct i2400m { 430struct i2400m {
424 struct wimax_dev wimax_dev; /* FIRST! See doc */ 431 struct wimax_dev wimax_dev; /* FIRST! See doc */
@@ -484,6 +491,7 @@ struct i2400m {
484 struct dentry *debugfs_dentry; 491 struct dentry *debugfs_dentry;
485 const char *fw_name; /* name of the current firmware image */ 492 const char *fw_name; /* name of the current firmware image */
486 unsigned long fw_version; /* version of the firmware interface */ 493 unsigned long fw_version; /* version of the firmware interface */
494 struct i2400m_barker_db *barker;
487}; 495};
488 496
489 497
@@ -574,6 +582,14 @@ extern void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *);
574extern int i2400m_dev_bootstrap(struct i2400m *, enum i2400m_bri); 582extern int i2400m_dev_bootstrap(struct i2400m *, enum i2400m_bri);
575extern int i2400m_read_mac_addr(struct i2400m *); 583extern int i2400m_read_mac_addr(struct i2400m *);
576extern int i2400m_bootrom_init(struct i2400m *, enum i2400m_bri); 584extern int i2400m_bootrom_init(struct i2400m *, enum i2400m_bri);
585extern int i2400m_is_boot_barker(struct i2400m *, const void *, size_t);
586static inline
587int i2400m_is_d2h_barker(const void *buf)
588{
589 const __le32 *barker = buf;
590 return le32_to_cpu(*barker) == I2400M_D2H_MSG_BARKER;
591}
592extern void i2400m_unknown_barker(struct i2400m *, const void *, size_t);
577 593
578/* Make/grok boot-rom header commands */ 594/* Make/grok boot-rom header commands */
579 595
@@ -736,20 +752,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *);
736extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *); 752extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *);
737extern void i2400m_tx_msg_sent(struct i2400m *); 753extern void i2400m_tx_msg_sent(struct i2400m *);
738 754
739static const __le32 i2400m_NBOOT_BARKER[4] = {
740 cpu_to_le32(I2400M_NBOOT_BARKER),
741 cpu_to_le32(I2400M_NBOOT_BARKER),
742 cpu_to_le32(I2400M_NBOOT_BARKER),
743 cpu_to_le32(I2400M_NBOOT_BARKER)
744};
745
746static const __le32 i2400m_SBOOT_BARKER[4] = {
747 cpu_to_le32(I2400M_SBOOT_BARKER),
748 cpu_to_le32(I2400M_SBOOT_BARKER),
749 cpu_to_le32(I2400M_SBOOT_BARKER),
750 cpu_to_le32(I2400M_SBOOT_BARKER)
751};
752
753extern int i2400m_power_save_disabled; 755extern int i2400m_power_save_disabled;
754 756
755/* 757/*
@@ -848,6 +850,12 @@ void __i2400m_msleep(unsigned ms)
848#endif 850#endif
849} 851}
850 852
853
854/* module initialization helpers */
855extern int i2400m_barker_db_init(const char *);
856extern void i2400m_barker_db_exit(void);
857
858
851/* Module parameters */ 859/* Module parameters */
852 860
853extern int i2400m_idle_mode_disabled; 861extern int i2400m_idle_mode_disabled;
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 07c32e68909f..bcd411f1a854 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -1194,6 +1194,28 @@ error_msg_hdr_check:
1194EXPORT_SYMBOL_GPL(i2400m_rx); 1194EXPORT_SYMBOL_GPL(i2400m_rx);
1195 1195
1196 1196
1197void i2400m_unknown_barker(struct i2400m *i2400m,
1198 const void *buf, size_t size)
1199{
1200 struct device *dev = i2400m_dev(i2400m);
1201 char prefix[64];
1202 const __le32 *barker = buf;
1203 dev_err(dev, "RX: HW BUG? unknown barker %08x, "
1204 "dropping %zu bytes\n", le32_to_cpu(*barker), size);
1205 snprintf(prefix, sizeof(prefix), "%s %s: ",
1206 dev_driver_string(dev), dev_name(dev));
1207 if (size > 64) {
1208 print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
1209 8, 4, buf, 64, 0);
1210 printk(KERN_ERR "%s... (only first 64 bytes "
1211 "dumped)\n", prefix);
1212 } else
1213 print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
1214 8, 4, buf, size, 0);
1215}
1216EXPORT_SYMBOL(i2400m_unknown_barker);
1217
1218
1197/* 1219/*
1198 * Initialize the RX queue and infrastructure 1220 * Initialize the RX queue and infrastructure
1199 * 1221 *
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c
index 1c9046914bd1..87263be4eedb 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()
@@ -158,7 +159,7 @@ void i2400ms_rx(struct i2400ms *i2400ms)
158 } 159 }
159 160
160 rmb(); /* make sure we get boot_mode from dev_reset_handle */ 161 rmb(); /* make sure we get boot_mode from dev_reset_handle */
161 if (i2400m->boot_mode == 1) { 162 if (unlikely(i2400m->boot_mode == 1)) {
162 spin_lock(&i2400m->rx_lock); 163 spin_lock(&i2400m->rx_lock);
163 i2400ms->bm_ack_size = rx_size; 164 i2400ms->bm_ack_size = rx_size;
164 spin_unlock(&i2400m->rx_lock); 165 spin_unlock(&i2400m->rx_lock);
@@ -166,17 +167,26 @@ void i2400ms_rx(struct i2400ms *i2400ms)
166 wake_up(&i2400ms->bm_wfa_wq); 167 wake_up(&i2400ms->bm_wfa_wq);
167 dev_err(dev, "RX: SDIO boot mode message\n"); 168 dev_err(dev, "RX: SDIO boot mode message\n");
168 kfree_skb(skb); 169 kfree_skb(skb);
169 } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER, 170 goto out;
170 sizeof(i2400m_NBOOT_BARKER)) 171 }
171 || !memcmp(skb->data, i2400m_SBOOT_BARKER, 172 ret = -EIO;
172 sizeof(i2400m_SBOOT_BARKER)))) { 173 if (unlikely(rx_size < sizeof(__le32))) {
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))) {
173 ret = i2400m_dev_reset_handle(i2400m); 182 ret = i2400m_dev_reset_handle(i2400m);
174 dev_err(dev, "RX: SDIO reboot barker\n"); 183 dev_err(dev, "RX: SDIO reboot barker\n");
175 kfree_skb(skb); 184 kfree_skb(skb);
176 } else { 185 } else {
177 skb_put(skb, rx_size); 186 i2400m_unknown_barker(i2400m, skb->data, rx_size);
178 i2400m_rx(i2400m, skb); 187 kfree_skb(skb);
179 } 188 }
189out:
180 d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms); 190 d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms);
181 return; 191 return;
182 192
@@ -184,6 +194,7 @@ error_memcpy_fromio:
184 kfree_skb(skb); 194 kfree_skb(skb);
185error_alloc_skb: 195error_alloc_skb:
186error_get_size: 196error_get_size:
197error_bad_size:
187 d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret); 198 d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret);
188 return; 199 return;
189} 200}
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c
index 3e11e35cd696..a0751a347cdc 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);
102 else /* Unknown or unexpected data in the notif message */
103 i2400m_unknown_barker(i2400m, buf, buf_len);
115error_bad_size: 104error_bad_size:
105out:
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;