Loading drivers/net/wimax/i2400m/control.c +15 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,21 @@ #define D_SUBMODULE control #include "debug-levels.h" static int i2400m_idle_mode_disabled;/* 0 (idle mode enabled) by default */ module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644); MODULE_PARM_DESC(idle_mode_disabled, "If true, the device will not enable idle mode negotiation " "with the base station (when connected) to save power."); /* 0 (power saving enabled) by default */ static int i2400m_power_save_disabled; module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); MODULE_PARM_DESC(power_save_disabled, "If true, the driver will not tell the device to enter " "power saving mode when it reports it is ready for it. " "False by default (so the device is told to do power " "saving)."); int i2400m_passive_mode; /* 0 (passive mode disabled) by default */ module_param_named(passive_mode, i2400m_passive_mode, int, 0644); MODULE_PARM_DESC(passive_mode, Loading drivers/net/wimax/i2400m/driver.c +128 −37 Original line number Diff line number Diff line Loading @@ -75,25 +75,6 @@ #include "debug-levels.h" int i2400m_idle_mode_disabled; /* 0 (idle mode enabled) by default */ module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644); MODULE_PARM_DESC(idle_mode_disabled, "If true, the device will not enable idle mode negotiation " "with the base station (when connected) to save power."); int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); MODULE_PARM_DESC(rx_reorder_disabled, "If true, RX reordering will be disabled."); int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */ module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); MODULE_PARM_DESC(power_save_disabled, "If true, the driver will not tell the device to enter " "power saving mode when it reports it is ready for it. " "False by default (so the device is told to do power " "saving)."); static char i2400m_debug_params[128]; module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params), 0644); Loading Loading @@ -395,6 +376,16 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) result = i2400m_dev_initialize(i2400m); if (result < 0) goto error_dev_initialize; /* We don't want any additional unwanted error recovery triggered * from any other context so if anything went wrong before we come * here, let's keep i2400m->error_recovery untouched and leave it to * dev_reset_handle(). See dev_reset_handle(). */ atomic_dec(&i2400m->error_recovery); /* Every thing works so far, ok, now we are ready to * take error recovery if it's required. */ /* At this point, reports will come for the device and set it * to the right state if it is different than UNINITIALIZED */ d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", Loading @@ -403,10 +394,10 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) error_dev_initialize: error_check_mac_addr: error_fw_check: i2400m->ready = 0; wmb(); /* see i2400m->ready's documentation */ flush_workqueue(i2400m->work_queue); error_fw_check: if (i2400m->bus_dev_stop) i2400m->bus_dev_stop(i2400m); error_bus_dev_start: Loading Loading @@ -436,7 +427,8 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) result = __i2400m_dev_start(i2400m, bm_flags); if (result >= 0) { i2400m->updown = 1; wmb(); /* see i2400m->updown's documentation */ i2400m->alive = 1; wmb();/* see i2400m->updown and i2400m->alive's doc */ } } mutex_unlock(&i2400m->init_mutex); Loading Loading @@ -497,7 +489,8 @@ void i2400m_dev_stop(struct i2400m *i2400m) if (i2400m->updown) { __i2400m_dev_stop(i2400m); i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ i2400m->alive = 0; wmb(); /* see i2400m->updown and i2400m->alive's doc */ } mutex_unlock(&i2400m->init_mutex); } Loading Loading @@ -617,12 +610,12 @@ int i2400m_post_reset(struct i2400m *i2400m) error_dev_start: if (i2400m->bus_release) i2400m->bus_release(i2400m); error_bus_setup: /* even if the device was up, it could not be recovered, so we * mark it as down. */ i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ mutex_unlock(&i2400m->init_mutex); error_bus_setup: d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); return result; } Loading Loading @@ -669,6 +662,9 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason); i2400m->boot_mode = 1; wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ result = 0; if (mutex_trylock(&i2400m->init_mutex) == 0) { /* We are still in i2400m_dev_start() [let it fail] or Loading @@ -679,32 +675,62 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) complete(&i2400m->msg_completion); goto out; } if (i2400m->updown == 0) { dev_info(dev, "%s: device is down, doing nothing\n", reason); goto out_unlock; } dev_err(dev, "%s: reinitializing driver\n", reason); rmb(); if (i2400m->updown) { __i2400m_dev_stop(i2400m); i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ } if (i2400m->alive) { result = __i2400m_dev_start(i2400m, I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); if (result < 0) { i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ dev_err(dev, "%s: cannot start the device: %d\n", reason, result); result = -EUCLEAN; if (atomic_read(&i2400m->bus_reset_retries) >= I2400M_BUS_RESET_RETRIES) { result = -ENODEV; dev_err(dev, "tried too many times to " "reset the device, giving up\n"); } out_unlock: } } if (i2400m->reset_ctx) { ctx->result = result; complete(&ctx->completion); } mutex_unlock(&i2400m->init_mutex); if (result == -EUCLEAN) { /* * We come here because the reset during operational mode * wasn't successully done and need to proceed to a bus * reset. For the dev_reset_handle() to be able to handle * the reset event later properly, we restore boot_mode back * to the state before previous reset. ie: just like we are * issuing the bus reset for the first time */ i2400m->boot_mode = 0; wmb(); atomic_inc(&i2400m->bus_reset_retries); /* ops, need to clean up [w/ init_mutex not held] */ result = i2400m_reset(i2400m, I2400M_RT_BUS); if (result >= 0) result = -ENODEV; } else { rmb(); if (i2400m->alive) { /* great, we expect the device state up and * dev_start() actually brings the device state up */ i2400m->updown = 1; wmb(); atomic_set(&i2400m->bus_reset_retries, 0); } } out: i2400m_put(i2400m); Loading @@ -728,14 +754,72 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) */ int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason) { i2400m->boot_mode = 1; wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, GFP_ATOMIC, &reason, sizeof(reason)); } EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); /* * The actual work of error recovery. * * The current implementation of error recovery is to trigger a bus reset. */ static void __i2400m_error_recovery(struct work_struct *ws) { struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); struct i2400m *i2400m = iw->i2400m; i2400m_reset(i2400m, I2400M_RT_BUS); i2400m_put(i2400m); kfree(iw); return; } /* * Schedule a work struct for error recovery. * * The intention of error recovery is to bring back the device to some * known state whenever TX sees -110 (-ETIMEOUT) on copying the data to * the device. The TX failure could mean a device bus stuck, so the current * error recovery implementation is to trigger a bus reset to the device * and hopefully it can bring back the device. * * The actual work of error recovery has to be in a thread context because * it is kicked off in the TX thread (i2400ms->tx_workqueue) which is to be * destroyed by the error recovery mechanism (currently a bus reset). * * Also, there may be already a queue of TX works that all hit * the -ETIMEOUT error condition because the device is stuck already. * Since bus reset is used as the error recovery mechanism and we don't * want consecutive bus resets simply because the multiple TX works * in the queue all hit the same device erratum, the flag "error_recovery" * is introduced for preventing unwanted consecutive bus resets. * * Error recovery shall only be invoked again if previous one was completed. * The flag error_recovery is set when error recovery mechanism is scheduled, * and is checked when we need to schedule another error recovery. If it is * in place already, then we shouldn't schedule another one. */ void i2400m_error_recovery(struct i2400m *i2400m) { struct device *dev = i2400m_dev(i2400m); if (atomic_add_return(1, &i2400m->error_recovery) == 1) { if (i2400m_schedule_work(i2400m, __i2400m_error_recovery, GFP_ATOMIC, NULL, 0) < 0) { dev_err(dev, "run out of memory for " "scheduling an error recovery ?\n"); atomic_dec(&i2400m->error_recovery); } } else atomic_dec(&i2400m->error_recovery); return; } EXPORT_SYMBOL_GPL(i2400m_error_recovery); /* * Alloc the command and ack buffers for boot mode * Loading Loading @@ -802,6 +886,13 @@ void i2400m_init(struct i2400m *i2400m) mutex_init(&i2400m->init_mutex); /* wake_tx_ws is initialized in i2400m_tx_setup() */ atomic_set(&i2400m->bus_reset_retries, 0); i2400m->alive = 0; /* initialize error_recovery to 1 for denoting we * are not yet ready to take any error recovery */ atomic_set(&i2400m->error_recovery, 1); } EXPORT_SYMBOL_GPL(i2400m_init); Loading drivers/net/wimax/i2400m/i2400m-sdio.h +4 −1 Original line number Diff line number Diff line Loading @@ -99,7 +99,10 @@ enum { * * @tx_workqueue: workqeueue used for data TX; we don't use the * system's workqueue as that might cause deadlocks with code in * the bus-generic driver. * the bus-generic driver. The read/write operation to the queue * is protected with spinlock (tx_lock in struct i2400m) to avoid * the queue being destroyed in the middle of a the queue read/write * operation. * * @debugfs_dentry: dentry for the SDIO specific debugfs files * Loading drivers/net/wimax/i2400m/i2400m.h +73 −9 Original line number Diff line number Diff line Loading @@ -160,6 +160,16 @@ #include <linux/wimax/i2400m.h> #include <asm/byteorder.h> enum { /* netdev interface */ /* * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size * * The MTU is 1400 or less */ I2400M_MAX_MTU = 1400, }; /* Misc constants */ enum { /* Size of the Boot Mode Command buffer */ Loading @@ -167,6 +177,11 @@ enum { I2400M_BM_ACK_BUF_SIZE = 256, }; enum { /* Maximum number of bus reset can be retried */ I2400M_BUS_RESET_RETRIES = 3, }; /** * struct i2400m_poke_table - Hardware poke table for the Intel 2400m * Loading Loading @@ -227,6 +242,11 @@ struct i2400m_barker_db; * so we have a tx_blk_size variable that the bus layer sets to * tell the engine how much of that we need. * * @bus_tx_room_min: [fill] Minimum room required while allocating * TX queue's buffer space for message header. SDIO requires * 224 bytes and USB 16 bytes. Refer bus specific driver code * for details. * * @bus_pl_size_max: [fill] Maximum payload size. * * @bus_setup: [optional fill] Function called by the bus-generic code Loading Loading @@ -397,7 +417,7 @@ struct i2400m_barker_db; * * @tx_size_max: biggest TX message sent. * * @rx_lock: spinlock to protect RX members * @rx_lock: spinlock to protect RX members and rx_roq_refcount. * * @rx_pl_num: total number of payloads received * Loading @@ -421,6 +441,10 @@ struct i2400m_barker_db; * delivered. Then the driver can release them to the host. See * drivers/net/i2400m/rx.c for details. * * @rx_roq_refcount: refcount rx_roq. This refcounts any access to * rx_roq thus preventing rx_roq being destroyed when rx_roq * is being accessed. rx_roq_refcount is protected by rx_lock. * * @rx_reports: reports received from the device that couldn't be * processed because the driver wasn't still ready; when ready, * they are pulled from here and chewed. Loading Loading @@ -507,6 +531,38 @@ struct i2400m_barker_db; * same. * * @pm_notifier: used to register for PM events * * @bus_reset_retries: counter for the number of bus resets attempted for * this boot. It's not for tracking the number of bus resets during * the whole driver life cycle (from insmod to rmmod) but for the * number of dev_start() executed until dev_start() returns a success * (ie: a good boot means a dev_stop() followed by a successful * dev_start()). dev_reset_handler() increments this counter whenever * it is triggering a bus reset. It checks this counter to decide if a * subsequent bus reset should be retried. dev_reset_handler() retries * the bus reset until dev_start() succeeds or the counter reaches * I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in * dev_reset_handle() when dev_start() returns a success, * ie: a successul boot is completed. * * @alive: flag to denote if the device *should* be alive. This flag is * everything like @updown (see doc for @updown) except reflecting * the device state *we expect* rather than the actual state as denoted * by @updown. It is set 1 whenever @updown is set 1 in dev_start(). * Then the device is expected to be alive all the time * (i2400m->alive remains 1) until the driver is removed. Therefore * all the device reboot events detected can be still handled properly * by either dev_reset_handle() or .pre_reset/.post_reset as long as * the driver presents. It is set 0 along with @updown in dev_stop(). * * @error_recovery: flag to denote if we are ready to take an error recovery. * 0 for ready to take an error recovery; 1 for not ready. It is * initialized to 1 while probe() since we don't tend to take any error * recovery during probe(). It is decremented by 1 whenever dev_start() * succeeds to indicate we are ready to take error recovery from now on. * It is checked every time we wanna schedule an error recovery. If an * error recovery is already in place (error_recovery was set 1), we * should not schedule another one until the last one is done. */ struct i2400m { struct wimax_dev wimax_dev; /* FIRST! See doc */ Loading @@ -522,6 +578,7 @@ struct i2400m { wait_queue_head_t state_wq; /* Woken up when on state updates */ size_t bus_tx_block_size; size_t bus_tx_room_min; size_t bus_pl_size_max; unsigned bus_bm_retries; Loading Loading @@ -550,10 +607,12 @@ struct i2400m { tx_num, tx_size_acc, tx_size_min, tx_size_max; /* RX stuff */ spinlock_t rx_lock; /* protect RX state */ /* protect RX state and rx_roq_refcount */ spinlock_t rx_lock; unsigned rx_pl_num, rx_pl_max, rx_pl_min, rx_num, rx_size_acc, rx_size_min, rx_size_max; struct i2400m_roq *rx_roq; /* not under rx_lock! */ struct i2400m_roq *rx_roq; /* access is refcounted */ struct kref rx_roq_refcount; /* refcount access to rx_roq */ u8 src_mac_addr[ETH_HLEN]; struct list_head rx_reports; /* under rx_lock! */ struct work_struct rx_report_ws; Loading Loading @@ -581,6 +640,16 @@ struct i2400m { struct i2400m_barker_db *barker; struct notifier_block pm_notifier; /* counting bus reset retries in this boot */ atomic_t bus_reset_retries; /* if the device is expected to be alive */ unsigned alive; /* 0 if we are ready for error recovery; 1 if not ready */ atomic_t error_recovery; }; Loading Loading @@ -803,6 +872,7 @@ void i2400m_put(struct i2400m *i2400m) extern int i2400m_dev_reset_handle(struct i2400m *, const char *); extern int i2400m_pre_reset(struct i2400m *); extern int i2400m_post_reset(struct i2400m *); extern void i2400m_error_recovery(struct i2400m *); /* * _setup()/_release() are called by the probe/disconnect functions of Loading @@ -815,7 +885,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *); extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *); extern void i2400m_tx_msg_sent(struct i2400m *); extern int i2400m_power_save_disabled; /* * Utility functions Loading Loading @@ -922,10 +991,5 @@ extern int i2400m_barker_db_init(const char *); extern void i2400m_barker_db_exit(void); /* Module parameters */ extern int i2400m_idle_mode_disabled; extern int i2400m_rx_reorder_disabled; #endif /* #ifndef __I2400M_H__ */ drivers/net/wimax/i2400m/netdev.c +5 −7 Original line number Diff line number Diff line Loading @@ -84,17 +84,15 @@ enum { /* netdev interface */ /* * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size * * The MTU is 1400 or less */ I2400M_MAX_MTU = 1400, /* 20 secs? yep, this is the maximum timeout that the device * might take to get out of IDLE / negotiate it with the base * station. We add 1sec for good measure. */ I2400M_TX_TIMEOUT = 21 * HZ, I2400M_TX_QLEN = 5, /* * Experimentation has determined that, 20 to be a good value * for minimizing the jitter in the throughput. */ I2400M_TX_QLEN = 20, }; Loading Loading
drivers/net/wimax/i2400m/control.c +15 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,21 @@ #define D_SUBMODULE control #include "debug-levels.h" static int i2400m_idle_mode_disabled;/* 0 (idle mode enabled) by default */ module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644); MODULE_PARM_DESC(idle_mode_disabled, "If true, the device will not enable idle mode negotiation " "with the base station (when connected) to save power."); /* 0 (power saving enabled) by default */ static int i2400m_power_save_disabled; module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); MODULE_PARM_DESC(power_save_disabled, "If true, the driver will not tell the device to enter " "power saving mode when it reports it is ready for it. " "False by default (so the device is told to do power " "saving)."); int i2400m_passive_mode; /* 0 (passive mode disabled) by default */ module_param_named(passive_mode, i2400m_passive_mode, int, 0644); MODULE_PARM_DESC(passive_mode, Loading
drivers/net/wimax/i2400m/driver.c +128 −37 Original line number Diff line number Diff line Loading @@ -75,25 +75,6 @@ #include "debug-levels.h" int i2400m_idle_mode_disabled; /* 0 (idle mode enabled) by default */ module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644); MODULE_PARM_DESC(idle_mode_disabled, "If true, the device will not enable idle mode negotiation " "with the base station (when connected) to save power."); int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); MODULE_PARM_DESC(rx_reorder_disabled, "If true, RX reordering will be disabled."); int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */ module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); MODULE_PARM_DESC(power_save_disabled, "If true, the driver will not tell the device to enter " "power saving mode when it reports it is ready for it. " "False by default (so the device is told to do power " "saving)."); static char i2400m_debug_params[128]; module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params), 0644); Loading Loading @@ -395,6 +376,16 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) result = i2400m_dev_initialize(i2400m); if (result < 0) goto error_dev_initialize; /* We don't want any additional unwanted error recovery triggered * from any other context so if anything went wrong before we come * here, let's keep i2400m->error_recovery untouched and leave it to * dev_reset_handle(). See dev_reset_handle(). */ atomic_dec(&i2400m->error_recovery); /* Every thing works so far, ok, now we are ready to * take error recovery if it's required. */ /* At this point, reports will come for the device and set it * to the right state if it is different than UNINITIALIZED */ d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", Loading @@ -403,10 +394,10 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) error_dev_initialize: error_check_mac_addr: error_fw_check: i2400m->ready = 0; wmb(); /* see i2400m->ready's documentation */ flush_workqueue(i2400m->work_queue); error_fw_check: if (i2400m->bus_dev_stop) i2400m->bus_dev_stop(i2400m); error_bus_dev_start: Loading Loading @@ -436,7 +427,8 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) result = __i2400m_dev_start(i2400m, bm_flags); if (result >= 0) { i2400m->updown = 1; wmb(); /* see i2400m->updown's documentation */ i2400m->alive = 1; wmb();/* see i2400m->updown and i2400m->alive's doc */ } } mutex_unlock(&i2400m->init_mutex); Loading Loading @@ -497,7 +489,8 @@ void i2400m_dev_stop(struct i2400m *i2400m) if (i2400m->updown) { __i2400m_dev_stop(i2400m); i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ i2400m->alive = 0; wmb(); /* see i2400m->updown and i2400m->alive's doc */ } mutex_unlock(&i2400m->init_mutex); } Loading Loading @@ -617,12 +610,12 @@ int i2400m_post_reset(struct i2400m *i2400m) error_dev_start: if (i2400m->bus_release) i2400m->bus_release(i2400m); error_bus_setup: /* even if the device was up, it could not be recovered, so we * mark it as down. */ i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ mutex_unlock(&i2400m->init_mutex); error_bus_setup: d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); return result; } Loading Loading @@ -669,6 +662,9 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason); i2400m->boot_mode = 1; wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ result = 0; if (mutex_trylock(&i2400m->init_mutex) == 0) { /* We are still in i2400m_dev_start() [let it fail] or Loading @@ -679,32 +675,62 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) complete(&i2400m->msg_completion); goto out; } if (i2400m->updown == 0) { dev_info(dev, "%s: device is down, doing nothing\n", reason); goto out_unlock; } dev_err(dev, "%s: reinitializing driver\n", reason); rmb(); if (i2400m->updown) { __i2400m_dev_stop(i2400m); i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ } if (i2400m->alive) { result = __i2400m_dev_start(i2400m, I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); if (result < 0) { i2400m->updown = 0; wmb(); /* see i2400m->updown's documentation */ dev_err(dev, "%s: cannot start the device: %d\n", reason, result); result = -EUCLEAN; if (atomic_read(&i2400m->bus_reset_retries) >= I2400M_BUS_RESET_RETRIES) { result = -ENODEV; dev_err(dev, "tried too many times to " "reset the device, giving up\n"); } out_unlock: } } if (i2400m->reset_ctx) { ctx->result = result; complete(&ctx->completion); } mutex_unlock(&i2400m->init_mutex); if (result == -EUCLEAN) { /* * We come here because the reset during operational mode * wasn't successully done and need to proceed to a bus * reset. For the dev_reset_handle() to be able to handle * the reset event later properly, we restore boot_mode back * to the state before previous reset. ie: just like we are * issuing the bus reset for the first time */ i2400m->boot_mode = 0; wmb(); atomic_inc(&i2400m->bus_reset_retries); /* ops, need to clean up [w/ init_mutex not held] */ result = i2400m_reset(i2400m, I2400M_RT_BUS); if (result >= 0) result = -ENODEV; } else { rmb(); if (i2400m->alive) { /* great, we expect the device state up and * dev_start() actually brings the device state up */ i2400m->updown = 1; wmb(); atomic_set(&i2400m->bus_reset_retries, 0); } } out: i2400m_put(i2400m); Loading @@ -728,14 +754,72 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) */ int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason) { i2400m->boot_mode = 1; wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, GFP_ATOMIC, &reason, sizeof(reason)); } EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); /* * The actual work of error recovery. * * The current implementation of error recovery is to trigger a bus reset. */ static void __i2400m_error_recovery(struct work_struct *ws) { struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); struct i2400m *i2400m = iw->i2400m; i2400m_reset(i2400m, I2400M_RT_BUS); i2400m_put(i2400m); kfree(iw); return; } /* * Schedule a work struct for error recovery. * * The intention of error recovery is to bring back the device to some * known state whenever TX sees -110 (-ETIMEOUT) on copying the data to * the device. The TX failure could mean a device bus stuck, so the current * error recovery implementation is to trigger a bus reset to the device * and hopefully it can bring back the device. * * The actual work of error recovery has to be in a thread context because * it is kicked off in the TX thread (i2400ms->tx_workqueue) which is to be * destroyed by the error recovery mechanism (currently a bus reset). * * Also, there may be already a queue of TX works that all hit * the -ETIMEOUT error condition because the device is stuck already. * Since bus reset is used as the error recovery mechanism and we don't * want consecutive bus resets simply because the multiple TX works * in the queue all hit the same device erratum, the flag "error_recovery" * is introduced for preventing unwanted consecutive bus resets. * * Error recovery shall only be invoked again if previous one was completed. * The flag error_recovery is set when error recovery mechanism is scheduled, * and is checked when we need to schedule another error recovery. If it is * in place already, then we shouldn't schedule another one. */ void i2400m_error_recovery(struct i2400m *i2400m) { struct device *dev = i2400m_dev(i2400m); if (atomic_add_return(1, &i2400m->error_recovery) == 1) { if (i2400m_schedule_work(i2400m, __i2400m_error_recovery, GFP_ATOMIC, NULL, 0) < 0) { dev_err(dev, "run out of memory for " "scheduling an error recovery ?\n"); atomic_dec(&i2400m->error_recovery); } } else atomic_dec(&i2400m->error_recovery); return; } EXPORT_SYMBOL_GPL(i2400m_error_recovery); /* * Alloc the command and ack buffers for boot mode * Loading Loading @@ -802,6 +886,13 @@ void i2400m_init(struct i2400m *i2400m) mutex_init(&i2400m->init_mutex); /* wake_tx_ws is initialized in i2400m_tx_setup() */ atomic_set(&i2400m->bus_reset_retries, 0); i2400m->alive = 0; /* initialize error_recovery to 1 for denoting we * are not yet ready to take any error recovery */ atomic_set(&i2400m->error_recovery, 1); } EXPORT_SYMBOL_GPL(i2400m_init); Loading
drivers/net/wimax/i2400m/i2400m-sdio.h +4 −1 Original line number Diff line number Diff line Loading @@ -99,7 +99,10 @@ enum { * * @tx_workqueue: workqeueue used for data TX; we don't use the * system's workqueue as that might cause deadlocks with code in * the bus-generic driver. * the bus-generic driver. The read/write operation to the queue * is protected with spinlock (tx_lock in struct i2400m) to avoid * the queue being destroyed in the middle of a the queue read/write * operation. * * @debugfs_dentry: dentry for the SDIO specific debugfs files * Loading
drivers/net/wimax/i2400m/i2400m.h +73 −9 Original line number Diff line number Diff line Loading @@ -160,6 +160,16 @@ #include <linux/wimax/i2400m.h> #include <asm/byteorder.h> enum { /* netdev interface */ /* * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size * * The MTU is 1400 or less */ I2400M_MAX_MTU = 1400, }; /* Misc constants */ enum { /* Size of the Boot Mode Command buffer */ Loading @@ -167,6 +177,11 @@ enum { I2400M_BM_ACK_BUF_SIZE = 256, }; enum { /* Maximum number of bus reset can be retried */ I2400M_BUS_RESET_RETRIES = 3, }; /** * struct i2400m_poke_table - Hardware poke table for the Intel 2400m * Loading Loading @@ -227,6 +242,11 @@ struct i2400m_barker_db; * so we have a tx_blk_size variable that the bus layer sets to * tell the engine how much of that we need. * * @bus_tx_room_min: [fill] Minimum room required while allocating * TX queue's buffer space for message header. SDIO requires * 224 bytes and USB 16 bytes. Refer bus specific driver code * for details. * * @bus_pl_size_max: [fill] Maximum payload size. * * @bus_setup: [optional fill] Function called by the bus-generic code Loading Loading @@ -397,7 +417,7 @@ struct i2400m_barker_db; * * @tx_size_max: biggest TX message sent. * * @rx_lock: spinlock to protect RX members * @rx_lock: spinlock to protect RX members and rx_roq_refcount. * * @rx_pl_num: total number of payloads received * Loading @@ -421,6 +441,10 @@ struct i2400m_barker_db; * delivered. Then the driver can release them to the host. See * drivers/net/i2400m/rx.c for details. * * @rx_roq_refcount: refcount rx_roq. This refcounts any access to * rx_roq thus preventing rx_roq being destroyed when rx_roq * is being accessed. rx_roq_refcount is protected by rx_lock. * * @rx_reports: reports received from the device that couldn't be * processed because the driver wasn't still ready; when ready, * they are pulled from here and chewed. Loading Loading @@ -507,6 +531,38 @@ struct i2400m_barker_db; * same. * * @pm_notifier: used to register for PM events * * @bus_reset_retries: counter for the number of bus resets attempted for * this boot. It's not for tracking the number of bus resets during * the whole driver life cycle (from insmod to rmmod) but for the * number of dev_start() executed until dev_start() returns a success * (ie: a good boot means a dev_stop() followed by a successful * dev_start()). dev_reset_handler() increments this counter whenever * it is triggering a bus reset. It checks this counter to decide if a * subsequent bus reset should be retried. dev_reset_handler() retries * the bus reset until dev_start() succeeds or the counter reaches * I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in * dev_reset_handle() when dev_start() returns a success, * ie: a successul boot is completed. * * @alive: flag to denote if the device *should* be alive. This flag is * everything like @updown (see doc for @updown) except reflecting * the device state *we expect* rather than the actual state as denoted * by @updown. It is set 1 whenever @updown is set 1 in dev_start(). * Then the device is expected to be alive all the time * (i2400m->alive remains 1) until the driver is removed. Therefore * all the device reboot events detected can be still handled properly * by either dev_reset_handle() or .pre_reset/.post_reset as long as * the driver presents. It is set 0 along with @updown in dev_stop(). * * @error_recovery: flag to denote if we are ready to take an error recovery. * 0 for ready to take an error recovery; 1 for not ready. It is * initialized to 1 while probe() since we don't tend to take any error * recovery during probe(). It is decremented by 1 whenever dev_start() * succeeds to indicate we are ready to take error recovery from now on. * It is checked every time we wanna schedule an error recovery. If an * error recovery is already in place (error_recovery was set 1), we * should not schedule another one until the last one is done. */ struct i2400m { struct wimax_dev wimax_dev; /* FIRST! See doc */ Loading @@ -522,6 +578,7 @@ struct i2400m { wait_queue_head_t state_wq; /* Woken up when on state updates */ size_t bus_tx_block_size; size_t bus_tx_room_min; size_t bus_pl_size_max; unsigned bus_bm_retries; Loading Loading @@ -550,10 +607,12 @@ struct i2400m { tx_num, tx_size_acc, tx_size_min, tx_size_max; /* RX stuff */ spinlock_t rx_lock; /* protect RX state */ /* protect RX state and rx_roq_refcount */ spinlock_t rx_lock; unsigned rx_pl_num, rx_pl_max, rx_pl_min, rx_num, rx_size_acc, rx_size_min, rx_size_max; struct i2400m_roq *rx_roq; /* not under rx_lock! */ struct i2400m_roq *rx_roq; /* access is refcounted */ struct kref rx_roq_refcount; /* refcount access to rx_roq */ u8 src_mac_addr[ETH_HLEN]; struct list_head rx_reports; /* under rx_lock! */ struct work_struct rx_report_ws; Loading Loading @@ -581,6 +640,16 @@ struct i2400m { struct i2400m_barker_db *barker; struct notifier_block pm_notifier; /* counting bus reset retries in this boot */ atomic_t bus_reset_retries; /* if the device is expected to be alive */ unsigned alive; /* 0 if we are ready for error recovery; 1 if not ready */ atomic_t error_recovery; }; Loading Loading @@ -803,6 +872,7 @@ void i2400m_put(struct i2400m *i2400m) extern int i2400m_dev_reset_handle(struct i2400m *, const char *); extern int i2400m_pre_reset(struct i2400m *); extern int i2400m_post_reset(struct i2400m *); extern void i2400m_error_recovery(struct i2400m *); /* * _setup()/_release() are called by the probe/disconnect functions of Loading @@ -815,7 +885,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *); extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *); extern void i2400m_tx_msg_sent(struct i2400m *); extern int i2400m_power_save_disabled; /* * Utility functions Loading Loading @@ -922,10 +991,5 @@ extern int i2400m_barker_db_init(const char *); extern void i2400m_barker_db_exit(void); /* Module parameters */ extern int i2400m_idle_mode_disabled; extern int i2400m_rx_reorder_disabled; #endif /* #ifndef __I2400M_H__ */
drivers/net/wimax/i2400m/netdev.c +5 −7 Original line number Diff line number Diff line Loading @@ -84,17 +84,15 @@ enum { /* netdev interface */ /* * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size * * The MTU is 1400 or less */ I2400M_MAX_MTU = 1400, /* 20 secs? yep, this is the maximum timeout that the device * might take to get out of IDLE / negotiate it with the base * station. We add 1sec for good measure. */ I2400M_TX_TIMEOUT = 21 * HZ, I2400M_TX_QLEN = 5, /* * Experimentation has determined that, 20 to be a good value * for minimizing the jitter in the throughput. */ I2400M_TX_QLEN = 20, }; Loading