Loading drivers/net/wimax/i2400m/control.c +16 −8 Original line number Diff line number Diff line Loading @@ -505,9 +505,16 @@ void i2400m_report_hook(struct i2400m *i2400m, * it. */ case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { d_printf(1, dev, "ready for powersave, requesting\n"); if (i2400m_power_save_disabled) d_printf(1, dev, "ready for powersave, " "not requesting (disabled by module " "parameter)\n"); else { d_printf(1, dev, "ready for powersave, " "requesting\n"); i2400m_cmd_enter_powersave(i2400m); } } break; }; d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n", Loading Loading @@ -688,8 +695,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", i2400m, buf, buf_len); rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ if (i2400m->boot_mode) return ERR_PTR(-ENODEV); return ERR_PTR(-EL3RST); msg_l3l4_hdr = buf; /* Check msg & payload consistency */ Loading Loading @@ -1389,16 +1397,16 @@ error: * * @i2400m: device descriptor * * Gracefully stops the device, moving it to the lowest power * consumption state possible. * Release resources acquired during the running of the device; in * theory, should also tell the device to go to sleep, switch off the * radio, all that, but at this point, in most cases (driver * disconnection, reset handling) we can't even talk to the device. */ void i2400m_dev_shutdown(struct i2400m *i2400m) { int result = -ENODEV; struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(i2400m %p)\n", i2400m); result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); return; } drivers/net/wimax/i2400m/driver.c +28 −12 Original line number Diff line number Diff line Loading @@ -82,6 +82,14 @@ 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)."); /** * i2400m_queue_work - schedule work on a i2400m's queue * Loading Loading @@ -172,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m, int result; struct i2400m_work *iw; BUG_ON(i2400m->work_queue == NULL); result = -ENOMEM; iw = kzalloc(sizeof(*iw), gfp_flags); if (iw == NULL) Loading Loading @@ -377,6 +384,11 @@ error: * Uploads firmware and brings up all the resources needed to be able * to communicate with the device. * * The workqueue has to be setup early, at least before RX handling * (it's only real user for now) so it can process reports as they * arrive. We also want to destroy it if we retry, to make sure it is * flushed...easier like this. * * TX needs to be setup before the bus-specific code (otherwise on * shutdown, the bus-tx code could try to access it). */ Loading @@ -387,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) struct wimax_dev *wimax_dev = &i2400m->wimax_dev; struct net_device *net_dev = wimax_dev->net_dev; struct device *dev = i2400m_dev(i2400m); int times = 3; int times = i2400m->bus_bm_retries; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); retry: Loading @@ -402,15 +414,15 @@ retry: result = i2400m_rx_setup(i2400m); if (result < 0) goto error_rx_setup; result = i2400m->bus_dev_start(i2400m); if (result < 0) goto error_bus_dev_start; i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); if (i2400m->work_queue == NULL) { result = -ENOMEM; dev_err(dev, "cannot create workqueue\n"); goto error_create_workqueue; } result = i2400m->bus_dev_start(i2400m); if (result < 0) goto error_bus_dev_start; result = i2400m_firmware_check(i2400m); /* fw versions ok? */ if (result < 0) goto error_fw_check; Loading @@ -432,17 +444,17 @@ retry: error_dev_initialize: error_check_mac_addr: error_fw_check: destroy_workqueue(i2400m->work_queue); error_create_workqueue: i2400m->bus_dev_stop(i2400m); error_bus_dev_start: destroy_workqueue(i2400m->work_queue); error_create_workqueue: i2400m_rx_release(i2400m); error_rx_setup: i2400m_tx_release(i2400m); error_tx_setup: error_bootstrap: if (result == -ERESTARTSYS && times-- > 0) { flags = I2400M_BRI_SOFT; if (result == -EL3RST && times-- > 0) { flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; goto retry; } d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", Loading Loading @@ -471,7 +483,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) * * Returns: 0 if ok, < 0 errno code on error. * * Releases all the resources allocated to communicate with the device. * Releases all the resources allocated to communicate with the * device. Note we cannot destroy the workqueue earlier as until RX is * fully destroyed, it could still try to schedule jobs. */ static void __i2400m_dev_stop(struct i2400m *i2400m) Loading @@ -483,8 +497,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m) wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); i2400m_dev_shutdown(i2400m); i2400m->ready = 0; destroy_workqueue(i2400m->work_queue); i2400m->bus_dev_stop(i2400m); destroy_workqueue(i2400m->work_queue); i2400m_rx_release(i2400m); i2400m_tx_release(i2400m); wimax_state_change(wimax_dev, WIMAX_ST_DOWN); Loading Loading @@ -546,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) * i2400m_dev_stop() [we are shutting down anyway, so * ignore it] or we are resetting somewhere else. */ dev_err(dev, "device rebooted\n"); i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS); i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); complete(&i2400m->msg_completion); goto out; } Loading Loading @@ -596,6 +610,8 @@ out: */ int i2400m_dev_reset_handle(struct i2400m *i2400m) { 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); } Loading drivers/net/wimax/i2400m/fw.c +20 −38 Original line number Diff line number Diff line Loading @@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, unsigned int direct, unsigned int do_csum) { int ret; size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD); size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); struct device *dev = i2400m_dev(i2400m); struct { struct i2400m_bootrom_header cmd; Loading Loading @@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, cmd = (void *) bcf + offset; if (i2400m->sboot == 0) { struct i2400m_bootrom_header jump_ack; d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n", d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); cmd->data_size = 0; ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), &jump_ack, sizeof(jump_ack), 0); } else { d_printf(3, dev, "secure boot, jumping to 0x%08x\n", d_printf(1, dev, "secure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); cmd_buf = i2400m->bm_cmd_buf; memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); Loading Loading @@ -696,8 +696,7 @@ error_dev_gone: return result; error_timeout: dev_err(dev, "Timed out waiting for reboot ack, resetting\n"); i2400m->bus_reset(i2400m, I2400M_RT_BUS); dev_err(dev, "Timed out waiting for reboot ack\n"); result = -ETIMEDOUT; goto exit_timeout; } Loading Loading @@ -770,40 +769,21 @@ error_read_mac: static int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) { #define POKE(a, d) { \ .address = cpu_to_le32(a), \ .data = cpu_to_le32(d) \ } static const struct { __le32 address; __le32 data; } i2400m_pokes[] = { POKE(0x081A58, 0xA7810230), POKE(0x080040, 0x00000000), POKE(0x080048, 0x00000082), POKE(0x08004C, 0x0000081F), POKE(0x080054, 0x00000085), POKE(0x080058, 0x00000180), POKE(0x08005C, 0x00000018), POKE(0x080060, 0x00000010), POKE(0x080574, 0x00000001), POKE(0x080550, 0x00000005), POKE(0xAE0000, 0x00000000), }; #undef POKE unsigned i; int ret; unsigned i = 0; int ret = 0; struct device *dev = i2400m_dev(i2400m); dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n"); d_fnstart(5, dev, "(i2400m %p)\n", i2400m); for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) { ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data, sizeof(i2400m_pokes[i].data), i2400m_pokes[i].address, 1, 1); if (i2400m->bus_bm_pokes_table) { while (i2400m->bus_bm_pokes_table[i].address) { ret = i2400m_download_chunk( i2400m, &i2400m->bus_bm_pokes_table[i].data, sizeof(i2400m->bus_bm_pokes_table[i].data), i2400m->bus_bm_pokes_table[i].address, 1, 1); if (ret < 0) break; i++; } } d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); return ret; Loading Loading @@ -980,11 +960,12 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, { int ret = 0; struct device *dev = i2400m_dev(i2400m); int count = I2400M_BOOT_RETRIES; int count = i2400m->bus_bm_retries; d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", i2400m, bcf, bcf_size); i2400m->boot_mode = 1; wmb(); /* Make sure other readers see it */ hw_reboot: if (count-- == 0) { ret = -ERESTARTSYS; Loading Loading @@ -1033,6 +1014,7 @@ hw_reboot: d_printf(2, dev, "fw %s successfully uploaded\n", i2400m->fw_name); i2400m->boot_mode = 0; wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ error_dnload_finalize: error_dnload_bcf: error_dnload_init: Loading drivers/net/wimax/i2400m/i2400m-sdio.h +9 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,8 @@ enum { /* The number of ticks to wait for the device to signal that * it is ready */ I2400MS_INIT_SLEEP_INTERVAL = 10, /* How long to wait for the device to settle after reset */ I2400MS_SETTLE_TIME = 40, }; Loading Loading @@ -105,6 +107,10 @@ struct i2400ms { char tx_wq_name[32]; struct dentry *debugfs_dentry; wait_queue_head_t bm_wfa_wq; int bm_wait_result; size_t bm_ack_size; }; Loading @@ -129,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, struct i2400m_bootrom_header *, size_t); extern void i2400ms_bus_bm_release(struct i2400m *); extern int i2400ms_bus_bm_setup(struct i2400m *); #endif /* #ifndef __I2400M_SDIO_H__ */ drivers/net/wimax/i2400m/i2400m.h +43 −0 Original line number Diff line number Diff line Loading @@ -150,11 +150,33 @@ enum { /* Firmware uploading */ I2400M_BOOT_RETRIES = 3, I3200_BOOT_RETRIES = 3, /* Size of the Boot Mode Command buffer */ I2400M_BM_CMD_BUF_SIZE = 16 * 1024, I2400M_BM_ACK_BUF_SIZE = 256, }; /** * struct i2400m_poke_table - Hardware poke table for the Intel 2400m * * This structure will be used to create a device specific poke table * to put the device in a consistant state at boot time. * * @address: The device address to poke * * @data: The data value to poke to the device address * */ struct i2400m_poke_table{ __le32 address; __le32 data; }; #define I2400M_FW_POKE(a, d) { \ .address = cpu_to_le32(a), \ .data = cpu_to_le32(d) \ } /** * i2400m_reset_type - methods to reset a device Loading Loading @@ -224,6 +246,17 @@ struct i2400m_roq; * process, so it cannot rely on common infrastructure being laid * out. * * @bus_bm_retries: [fill] How many times shall a firmware upload / * device initialization be retried? Different models of the same * device might need different values, hence it is set by the * bus-specific driver. Note this value is used in two places, * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become * multiplicative (__i2400m_dev_start() calling N times * i2400m_fw_dnload() and this trying N times to download the * firmware), as if __i2400m_dev_start() only retries if the * firmware crashed while initializing the device (not in a * general case). * * @bus_bm_cmd_send: [fill] Function called to send a boot-mode * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This * is synchronous and has to return 0 if ok or < 0 errno code in Loading Loading @@ -252,6 +285,12 @@ struct i2400m_roq; * address provided in boot mode is kind of broken and needs to * be re-read later on. * * @bus_bm_pokes_table: [fill/optional] A table of device addresses * and values that will be poked at device init time to move the * device to the correct state for the type of boot/firmware being * used. This table MUST be terminated with (0x000000, * 0x00000000) or bad things will happen. * * * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX * stack. Due to the way a net_device is allocated, we need to Loading Loading @@ -399,6 +438,8 @@ struct i2400m { size_t bus_tx_block_size; size_t bus_pl_size_max; unsigned bus_bm_retries; int (*bus_dev_start)(struct i2400m *); void (*bus_dev_stop)(struct i2400m *); void (*bus_tx_kick)(struct i2400m *); Loading @@ -410,6 +451,7 @@ struct i2400m { struct i2400m_bootrom_header *, size_t); const char **bus_fw_names; unsigned bus_bm_mac_addr_impaired:1; const struct i2400m_poke_table *bus_bm_pokes_table; spinlock_t tx_lock; /* protect TX state */ void *tx_buf; Loading Loading @@ -709,6 +751,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = { cpu_to_le32(I2400M_SBOOT_BARKER) }; extern int i2400m_power_save_disabled; /* * Utility functions Loading Loading
drivers/net/wimax/i2400m/control.c +16 −8 Original line number Diff line number Diff line Loading @@ -505,9 +505,16 @@ void i2400m_report_hook(struct i2400m *i2400m, * it. */ case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { d_printf(1, dev, "ready for powersave, requesting\n"); if (i2400m_power_save_disabled) d_printf(1, dev, "ready for powersave, " "not requesting (disabled by module " "parameter)\n"); else { d_printf(1, dev, "ready for powersave, " "requesting\n"); i2400m_cmd_enter_powersave(i2400m); } } break; }; d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n", Loading Loading @@ -688,8 +695,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", i2400m, buf, buf_len); rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ if (i2400m->boot_mode) return ERR_PTR(-ENODEV); return ERR_PTR(-EL3RST); msg_l3l4_hdr = buf; /* Check msg & payload consistency */ Loading Loading @@ -1389,16 +1397,16 @@ error: * * @i2400m: device descriptor * * Gracefully stops the device, moving it to the lowest power * consumption state possible. * Release resources acquired during the running of the device; in * theory, should also tell the device to go to sleep, switch off the * radio, all that, but at this point, in most cases (driver * disconnection, reset handling) we can't even talk to the device. */ void i2400m_dev_shutdown(struct i2400m *i2400m) { int result = -ENODEV; struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(i2400m %p)\n", i2400m); result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); return; }
drivers/net/wimax/i2400m/driver.c +28 −12 Original line number Diff line number Diff line Loading @@ -82,6 +82,14 @@ 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)."); /** * i2400m_queue_work - schedule work on a i2400m's queue * Loading Loading @@ -172,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m, int result; struct i2400m_work *iw; BUG_ON(i2400m->work_queue == NULL); result = -ENOMEM; iw = kzalloc(sizeof(*iw), gfp_flags); if (iw == NULL) Loading Loading @@ -377,6 +384,11 @@ error: * Uploads firmware and brings up all the resources needed to be able * to communicate with the device. * * The workqueue has to be setup early, at least before RX handling * (it's only real user for now) so it can process reports as they * arrive. We also want to destroy it if we retry, to make sure it is * flushed...easier like this. * * TX needs to be setup before the bus-specific code (otherwise on * shutdown, the bus-tx code could try to access it). */ Loading @@ -387,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) struct wimax_dev *wimax_dev = &i2400m->wimax_dev; struct net_device *net_dev = wimax_dev->net_dev; struct device *dev = i2400m_dev(i2400m); int times = 3; int times = i2400m->bus_bm_retries; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); retry: Loading @@ -402,15 +414,15 @@ retry: result = i2400m_rx_setup(i2400m); if (result < 0) goto error_rx_setup; result = i2400m->bus_dev_start(i2400m); if (result < 0) goto error_bus_dev_start; i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); if (i2400m->work_queue == NULL) { result = -ENOMEM; dev_err(dev, "cannot create workqueue\n"); goto error_create_workqueue; } result = i2400m->bus_dev_start(i2400m); if (result < 0) goto error_bus_dev_start; result = i2400m_firmware_check(i2400m); /* fw versions ok? */ if (result < 0) goto error_fw_check; Loading @@ -432,17 +444,17 @@ retry: error_dev_initialize: error_check_mac_addr: error_fw_check: destroy_workqueue(i2400m->work_queue); error_create_workqueue: i2400m->bus_dev_stop(i2400m); error_bus_dev_start: destroy_workqueue(i2400m->work_queue); error_create_workqueue: i2400m_rx_release(i2400m); error_rx_setup: i2400m_tx_release(i2400m); error_tx_setup: error_bootstrap: if (result == -ERESTARTSYS && times-- > 0) { flags = I2400M_BRI_SOFT; if (result == -EL3RST && times-- > 0) { flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; goto retry; } d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", Loading Loading @@ -471,7 +483,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) * * Returns: 0 if ok, < 0 errno code on error. * * Releases all the resources allocated to communicate with the device. * Releases all the resources allocated to communicate with the * device. Note we cannot destroy the workqueue earlier as until RX is * fully destroyed, it could still try to schedule jobs. */ static void __i2400m_dev_stop(struct i2400m *i2400m) Loading @@ -483,8 +497,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m) wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); i2400m_dev_shutdown(i2400m); i2400m->ready = 0; destroy_workqueue(i2400m->work_queue); i2400m->bus_dev_stop(i2400m); destroy_workqueue(i2400m->work_queue); i2400m_rx_release(i2400m); i2400m_tx_release(i2400m); wimax_state_change(wimax_dev, WIMAX_ST_DOWN); Loading Loading @@ -546,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) * i2400m_dev_stop() [we are shutting down anyway, so * ignore it] or we are resetting somewhere else. */ dev_err(dev, "device rebooted\n"); i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS); i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); complete(&i2400m->msg_completion); goto out; } Loading Loading @@ -596,6 +610,8 @@ out: */ int i2400m_dev_reset_handle(struct i2400m *i2400m) { 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); } Loading
drivers/net/wimax/i2400m/fw.c +20 −38 Original line number Diff line number Diff line Loading @@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, unsigned int direct, unsigned int do_csum) { int ret; size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD); size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); struct device *dev = i2400m_dev(i2400m); struct { struct i2400m_bootrom_header cmd; Loading Loading @@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, cmd = (void *) bcf + offset; if (i2400m->sboot == 0) { struct i2400m_bootrom_header jump_ack; d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n", d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); cmd->data_size = 0; ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), &jump_ack, sizeof(jump_ack), 0); } else { d_printf(3, dev, "secure boot, jumping to 0x%08x\n", d_printf(1, dev, "secure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); cmd_buf = i2400m->bm_cmd_buf; memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); Loading Loading @@ -696,8 +696,7 @@ error_dev_gone: return result; error_timeout: dev_err(dev, "Timed out waiting for reboot ack, resetting\n"); i2400m->bus_reset(i2400m, I2400M_RT_BUS); dev_err(dev, "Timed out waiting for reboot ack\n"); result = -ETIMEDOUT; goto exit_timeout; } Loading Loading @@ -770,40 +769,21 @@ error_read_mac: static int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) { #define POKE(a, d) { \ .address = cpu_to_le32(a), \ .data = cpu_to_le32(d) \ } static const struct { __le32 address; __le32 data; } i2400m_pokes[] = { POKE(0x081A58, 0xA7810230), POKE(0x080040, 0x00000000), POKE(0x080048, 0x00000082), POKE(0x08004C, 0x0000081F), POKE(0x080054, 0x00000085), POKE(0x080058, 0x00000180), POKE(0x08005C, 0x00000018), POKE(0x080060, 0x00000010), POKE(0x080574, 0x00000001), POKE(0x080550, 0x00000005), POKE(0xAE0000, 0x00000000), }; #undef POKE unsigned i; int ret; unsigned i = 0; int ret = 0; struct device *dev = i2400m_dev(i2400m); dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n"); d_fnstart(5, dev, "(i2400m %p)\n", i2400m); for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) { ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data, sizeof(i2400m_pokes[i].data), i2400m_pokes[i].address, 1, 1); if (i2400m->bus_bm_pokes_table) { while (i2400m->bus_bm_pokes_table[i].address) { ret = i2400m_download_chunk( i2400m, &i2400m->bus_bm_pokes_table[i].data, sizeof(i2400m->bus_bm_pokes_table[i].data), i2400m->bus_bm_pokes_table[i].address, 1, 1); if (ret < 0) break; i++; } } d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); return ret; Loading Loading @@ -980,11 +960,12 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, { int ret = 0; struct device *dev = i2400m_dev(i2400m); int count = I2400M_BOOT_RETRIES; int count = i2400m->bus_bm_retries; d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", i2400m, bcf, bcf_size); i2400m->boot_mode = 1; wmb(); /* Make sure other readers see it */ hw_reboot: if (count-- == 0) { ret = -ERESTARTSYS; Loading Loading @@ -1033,6 +1014,7 @@ hw_reboot: d_printf(2, dev, "fw %s successfully uploaded\n", i2400m->fw_name); i2400m->boot_mode = 0; wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ error_dnload_finalize: error_dnload_bcf: error_dnload_init: Loading
drivers/net/wimax/i2400m/i2400m-sdio.h +9 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,8 @@ enum { /* The number of ticks to wait for the device to signal that * it is ready */ I2400MS_INIT_SLEEP_INTERVAL = 10, /* How long to wait for the device to settle after reset */ I2400MS_SETTLE_TIME = 40, }; Loading Loading @@ -105,6 +107,10 @@ struct i2400ms { char tx_wq_name[32]; struct dentry *debugfs_dentry; wait_queue_head_t bm_wfa_wq; int bm_wait_result; size_t bm_ack_size; }; Loading @@ -129,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, struct i2400m_bootrom_header *, size_t); extern void i2400ms_bus_bm_release(struct i2400m *); extern int i2400ms_bus_bm_setup(struct i2400m *); #endif /* #ifndef __I2400M_SDIO_H__ */
drivers/net/wimax/i2400m/i2400m.h +43 −0 Original line number Diff line number Diff line Loading @@ -150,11 +150,33 @@ enum { /* Firmware uploading */ I2400M_BOOT_RETRIES = 3, I3200_BOOT_RETRIES = 3, /* Size of the Boot Mode Command buffer */ I2400M_BM_CMD_BUF_SIZE = 16 * 1024, I2400M_BM_ACK_BUF_SIZE = 256, }; /** * struct i2400m_poke_table - Hardware poke table for the Intel 2400m * * This structure will be used to create a device specific poke table * to put the device in a consistant state at boot time. * * @address: The device address to poke * * @data: The data value to poke to the device address * */ struct i2400m_poke_table{ __le32 address; __le32 data; }; #define I2400M_FW_POKE(a, d) { \ .address = cpu_to_le32(a), \ .data = cpu_to_le32(d) \ } /** * i2400m_reset_type - methods to reset a device Loading Loading @@ -224,6 +246,17 @@ struct i2400m_roq; * process, so it cannot rely on common infrastructure being laid * out. * * @bus_bm_retries: [fill] How many times shall a firmware upload / * device initialization be retried? Different models of the same * device might need different values, hence it is set by the * bus-specific driver. Note this value is used in two places, * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become * multiplicative (__i2400m_dev_start() calling N times * i2400m_fw_dnload() and this trying N times to download the * firmware), as if __i2400m_dev_start() only retries if the * firmware crashed while initializing the device (not in a * general case). * * @bus_bm_cmd_send: [fill] Function called to send a boot-mode * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This * is synchronous and has to return 0 if ok or < 0 errno code in Loading Loading @@ -252,6 +285,12 @@ struct i2400m_roq; * address provided in boot mode is kind of broken and needs to * be re-read later on. * * @bus_bm_pokes_table: [fill/optional] A table of device addresses * and values that will be poked at device init time to move the * device to the correct state for the type of boot/firmware being * used. This table MUST be terminated with (0x000000, * 0x00000000) or bad things will happen. * * * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX * stack. Due to the way a net_device is allocated, we need to Loading Loading @@ -399,6 +438,8 @@ struct i2400m { size_t bus_tx_block_size; size_t bus_pl_size_max; unsigned bus_bm_retries; int (*bus_dev_start)(struct i2400m *); void (*bus_dev_stop)(struct i2400m *); void (*bus_tx_kick)(struct i2400m *); Loading @@ -410,6 +451,7 @@ struct i2400m { struct i2400m_bootrom_header *, size_t); const char **bus_fw_names; unsigned bus_bm_mac_addr_impaired:1; const struct i2400m_poke_table *bus_bm_pokes_table; spinlock_t tx_lock; /* protect TX state */ void *tx_buf; Loading Loading @@ -709,6 +751,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = { cpu_to_le32(I2400M_SBOOT_BARKER) }; extern int i2400m_power_save_disabled; /* * Utility functions Loading