aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-09-03 18:14:29 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 02:55:53 -0400
commitaba3792ac2d7c808a2d2fd2adf89531e083bdb90 (patch)
treefdf901fe2d666805ad27a421b076cce2bfed7352 /drivers/net
parent32742e6158657f19ad31653705bef56d983508e7 (diff)
wimax/i2400m: rework bootrom initialization to be more flexible
This modifies the bootrom initialization code of the i2400m driver so it can more easily support upcoming hardware. Currently, the code detects two types of barkers (magic numbers) sent by the device to indicate the types of firmware it would take (signed vs non-signed). This schema is extended so that multiple reboot barkers are recognized; upcoming hw will expose more types barkers which will have to match a header in the firmware image before we can load it. For that, a barker database is introduced; the first time the device sends a barker, it is matched in the database. That gives the driver the information needed to decide how to upload the firmware and which types of firmware to use. The database can be populated from module parameters. The execution flow is not altered; a new function (i2400m_is_boot_barker) is introduced to determine in the RX path if the device has sent a boot barker. This function is becoming heavier, so it is put away from the hot reception path [this is why there is some reorganization in sdio-rx.c:i2400ms_rx and usb-notifc.c:i2400mu_notification_grok()]. The documentation on the process has also been updated. All these modifications are heavily based on previous work by Dirk Brandewie <dirk.brandewie@intel.com>. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net')
-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;