aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wimax/i2400m/usb.c')
-rw-r--r--drivers/net/wimax/i2400m/usb.c189
1 files changed, 162 insertions, 27 deletions
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
74static char i2400mu_debug_params[128];
75module_param_string(debug, i2400mu_debug_params, sizeof(i2400mu_debug_params),
76 0644);
77MODULE_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 */
76static const char *i2400mu_bus_fw_names[] = { 83static 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
90static 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);
175retry:
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);
173error_kzalloc: 230error_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) {
243do_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
593static 676static
677int 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 */
699static
700int 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 */
714static
715int 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
722static
594struct usb_device_id i2400mu_id_table[] = { 723struct 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 = {
618static 751static
619int __init i2400mu_driver_init(void) 752int __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}
623module_init(i2400mu_driver_init); 758module_init(i2400mu_driver_init);
@@ -632,7 +767,7 @@ void __exit i2400mu_driver_exit(void)
632module_exit(i2400mu_driver_exit); 767module_exit(i2400mu_driver_exit);
633 768
634MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); 769MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
635MODULE_DESCRIPTION("Intel 2400M WiMAX networking for USB"); 770MODULE_DESCRIPTION("Driver for USB based Intel Wireless WiMAX Connection 2400M "
771 "(5x50 & 6050)");
636MODULE_LICENSE("GPL"); 772MODULE_LICENSE("GPL");
637MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4); 773MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4);
638MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_3);