static void i2400mu_bus_dev_stop(struct i2400m *i2400m) { struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); struct device *dev = &i2400mu->usb_iface->dev; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); i2400mu_notification_release(i2400mu); i2400mu_rx_release(i2400mu); i2400mu_tx_release(i2400mu); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); }
/** * i2400m_bm_cmd - Execute a boot mode command * * @cmd: buffer containing the command data (pointing at the header). * This data can be ANYWHERE (for USB, we will copy it to an * specific buffer). Make sure everything is in proper little * endian. * * A raw buffer can be also sent, just cast it and set flags to * I2400M_BM_CMD_RAW. * * This function will generate a checksum for you if the * checksum bit in the command is set (unless I2400M_BM_CMD_RAW * is set). * * You can use the i2400m->bm_cmd_buf to stage your commands and * send them. * * If NULL, no command is sent (we just wait for an ack). * * @cmd_size: size of the command. Will be auto padded to the * bus-specific drivers padding requirements. * * @ack: buffer where to place the acknowledgement. If it is a regular * command response, all fields will be returned with the right, * native endianess. * * You *cannot* use i2400m->bm_ack_buf for this buffer. * * @ack_size: size of @ack, 16 aligned; you need to provide at least * sizeof(*ack) bytes and then enough to contain the return data * from the command * * @flags: see I2400M_BM_CMD_* above. * * @returns: bytes received by the notification; if < 0, an errno code * denoting an error or: * * -ERESTARTSYS The device has rebooted * * Executes a boot-mode command and waits for a response, doing basic * validation on it; if a zero length response is received, it retries * waiting for a response until a non-zero one is received (timing out * after %I2400M_BOOT_RETRIES retries). */ static ssize_t i2400m_bm_cmd(struct i2400m *i2400m, const struct i2400m_bootrom_header *cmd, size_t cmd_size, struct i2400m_bootrom_header *ack, size_t ack_size, int flags) { ssize_t result = -ENOMEM, rx_bytes; struct device *dev = i2400m_dev(i2400m); int opcode = cmd == NULL ? -1 : i2400m_brh_get_opcode(cmd); d_fnstart(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu)\n", i2400m, cmd, cmd_size, ack, ack_size); BUG_ON(ack_size < sizeof(*ack)); BUG_ON(i2400m->boot_mode == 0); if (cmd != NULL) { /* send the command */ result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags); if (result < 0) goto error_cmd_send; if ((flags & I2400M_BM_CMD_RAW) == 0) d_printf(5, dev, "boot-mode cmd %d csum %u rr %u da %u: " "addr 0x%04x size %u block csum 0x%04x\n", opcode, i2400m_brh_get_use_checksum(cmd), i2400m_brh_get_response_required(cmd), i2400m_brh_get_direct_access(cmd), cmd->target_addr, cmd->data_size, cmd->block_checksum); } result = i2400m->bus_bm_wait_for_ack(i2400m, ack, ack_size); if (result < 0) { dev_err(dev, "boot-mode cmd %d: error waiting for an ack: %d\n", opcode, (int) result); /* bah, %zd doesn't work */ goto error_wait_for_ack; } rx_bytes = result; /* verify the ack and read more if necessary [result is the * final amount of bytes we get in the ack] */ result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags); if (result < 0) goto error_bad_ack; /* Don't you love this stack of empty targets? Well, I don't * either, but it helps track exactly who comes in here and * why :) */ result = rx_bytes; error_bad_ack: error_wait_for_ack: error_cmd_send: d_fnend(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu) = %d\n", i2400m, cmd, cmd_size, ack, ack_size, (int) result); return result; }
/** * wimax_dev_rm - Unregister an existing WiMAX device * * @wimax_dev: WiMAX device descriptor * * Unregisters a WiMAX device previously registered for use with * wimax_add_rm(). * * IMPORTANT! Must call before calling unregister_netdev(). * * After this function returns, you will not get any more user space * control requests (via netlink or debugfs) and thus to wimax_dev->ops. * * Reentrancy control is ensured by setting the state to * %__WIMAX_ST_QUIESCING. rfkill operations coming through * wimax_*rfkill*() will be stopped by the quiescing state; ops coming * from the rfkill subsystem will be stopped by the support being * removed by wimax_rfkill_rm(). */ void wimax_dev_rm(struct wimax_dev *wimax_dev) { d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev); mutex_lock(&wimax_dev->mutex); __wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); wimax_debugfs_rm(wimax_dev); wimax_id_table_rm(wimax_dev); __wimax_state_change(wimax_dev, WIMAX_ST_DOWN); mutex_unlock(&wimax_dev->mutex); wimax_rfkill_rm(wimax_dev); d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev); }
static int i2400mu_reset_resume(struct usb_interface *iface) { int result; struct device *dev = &iface->dev; struct i2400mu *i2400mu = usb_get_intfdata(iface); struct i2400m *i2400m = &i2400mu->i2400m; d_fnstart(3, dev, "(iface %p)\n", iface); result = i2400m_dev_reset_handle(i2400m, "device reset on resume"); d_fnend(3, dev, "(iface %p) = %d\n", iface, result); return result < 0 ? result : 0; }
/* * Tear down SDIO RX * * Disables IRQs in the device and removes the IRQ handler. */ void i2400ms_rx_release(struct i2400ms *i2400ms) { int result; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); sdio_claim_host(func); sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); sdio_release_irq(func); sdio_release_host(func); d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); }
/* * Tear down of the notification mechanism * * @i2400m: device descriptor * * Kill the interrupt endpoint urb, free any allocated resources. * * We need to check if we have done it before as for example, * _suspend() call this; if after a suspend() we get a _disconnect() * (as the case is when hibernating), nothing bad happens. */ void i2400mu_notification_release(struct i2400mu *i2400mu) { struct device *dev = &i2400mu->usb_iface->dev; d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); if (i2400mu->notif_urb != NULL) { usb_kill_urb(i2400mu->notif_urb); kfree(i2400mu->notif_urb->transfer_buffer); usb_free_urb(i2400mu->notif_urb); i2400mu->notif_urb = NULL; } d_fnend(4, dev, "(i2400mu %p)\n", i2400mu); }
/* * Read data from the device (when in normal) * * Allocate an SKB of the right size, read the data in and then * deliver it to the generic layer. * * We also check for a reboot barker. That means the device died and * we have to reboot it. */ static void i2400ms_rx(struct i2400ms *i2400ms) { int ret; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; struct i2400m *i2400m = &i2400ms->i2400m; struct sk_buff *skb; ssize_t rx_size; d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms); rx_size = __i2400ms_rx_get_size(i2400ms); if (rx_size < 0) { ret = rx_size; goto error_get_size; } ret = -ENOMEM; skb = alloc_skb(rx_size, GFP_ATOMIC); if (NULL == skb) { dev_err(dev, "RX: unable to alloc skb\n"); goto error_alloc_skb; } ret = sdio_memcpy_fromio(func, skb->data, I2400MS_DATA_ADDR, rx_size); if (ret < 0) { dev_err(dev, "RX: SDIO data read failed: %d\n", ret); goto error_memcpy_fromio; } /* Check if device has reset */ if (!memcmp(skb->data, i2400m_NBOOT_BARKER, sizeof(i2400m_NBOOT_BARKER)) || !memcmp(skb->data, i2400m_SBOOT_BARKER, sizeof(i2400m_SBOOT_BARKER))) { ret = i2400m_dev_reset_handle(i2400m); kfree_skb(skb); } else { skb_put(skb, rx_size); i2400m_rx(i2400m, skb); } d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms); return; error_memcpy_fromio: kfree_skb(skb); error_alloc_skb: error_get_size: d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret); return; }
/* * Enable the SDIO function * * Tries to enable the SDIO function; might fail if it is still not * ready (in some hardware, the SDIO WiMAX function is only enabled * when we ask it to explicitly doing). Tries until a timeout is * reached. * * The @maxtries argument indicates how many times (at most) it should * be tried to enable the function. 0 means forever. This acts along * with the timeout (ie: it'll stop trying as soon as the maximum * number of tries is reached _or_ as soon as the timeout is reached). * * The reverse of this is...sdio_disable_function() * * Returns: 0 if the SDIO function was enabled, < 0 errno code on * error (-ENODEV when it was unable to enable the function). */ static int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries) { struct sdio_func *func = i2400ms->func; u64 timeout; int err; struct device *dev = &func->dev; unsigned tries = 0; d_fnstart(3, dev, "(func %p)\n", func); /* Setup timeout (FIXME: This needs to read the CIS table to * get a real timeout) and then wait for the device to signal * it is ready */ timeout = get_jiffies_64() + ioe_timeout * HZ; err = -ENODEV; while (err != 0 && time_before64(get_jiffies_64(), timeout)) { sdio_claim_host(func); /* * There is a sillicon bug on the IWMC3200, where the * IOE timeout will cause problems on Moorestown * platforms (system hang). We explicitly overwrite * func->enable_timeout here to work around the issue. */ if (i2400ms->iwmc3200) func->enable_timeout = IWMC3200_IOR_TIMEOUT; err = sdio_enable_func(func); if (0 == err) { sdio_release_host(func); d_printf(2, dev, "SDIO function enabled\n"); goto function_enabled; } d_printf(2, dev, "SDIO function failed to enable: %d\n", err); sdio_release_host(func); if (maxtries > 0 && ++tries >= maxtries) { err = -ETIME; break; } msleep(I2400MS_INIT_SLEEP_INTERVAL); } /* If timed out, device is not there yet -- get -ENODEV so * the device driver core will retry later on. */ if (err == -ETIME) { dev_err(dev, "Can't enable WiMAX function; " " has the function been enabled?\n"); err = -ENODEV; } function_enabled: d_fnend(3, dev, "(func %p) = %d\n", func, err); return err; }
/* * Do the final steps of uploading firmware * * @bcf_hdr: BCF header we are actually using * @bcf: pointer to the firmware image (which matches the first header * that is followed by the actual payloads). * @offset: [byte] offset into @bcf for the command we need to send. * * Depending on the boot mode (signed vs non-signed), different * actions need to be taken. */ static int i2400m_dnload_finalize(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf_hdr, const struct i2400m_bcf_hdr *bcf, size_t offset) { int ret = 0; struct device *dev = i2400m_dev(i2400m); struct i2400m_bootrom_header *cmd, ack; struct { struct i2400m_bootrom_header cmd; u8 cmd_pl[0]; } __packed *cmd_buf; size_t signature_block_offset, signature_block_size; d_fnstart(3, dev, "offset %zu\n", offset); cmd = (void *) bcf + offset; if (i2400m_boot_is_signed(i2400m) == 0) { struct i2400m_bootrom_header jump_ack; d_printf(1, dev, "unsecure 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)); cmd = &cmd_buf->cmd; /* now cmd points to the actual bootrom_header in cmd_buf */ 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(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)); signature_block_offset = sizeof(*bcf_hdr) + le32_to_cpu(bcf_hdr->key_size) * sizeof(u32) + le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32); signature_block_size = le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32); memcpy(cmd_buf->cmd_pl, (void *) bcf_hdr + signature_block_offset, signature_block_size); ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, sizeof(cmd_buf->cmd) + signature_block_size, &ack, sizeof(ack), I2400M_BM_CMD_RAW); } d_fnend(3, dev, "returning %d\n", ret); return ret; }
/* * Parse a 'state report' and extract carrier on/off information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for * consistent size. * @size: size of the message (header + payload). The header length * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * * Extract from the report state the system state TLV and infer from * there if we have a carrier or not. Update our local state and tell * netdev. * * When setting the carrier, it's fine to set OFF twice (for example), * as netif_carrier_off() will not generate two OFF events (just on * the transitions). */ static void i2400m_report_state_hook(struct i2400m *i2400m, const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size, const char *tag) { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; const struct i2400m_tlv_system_state *ss; const struct i2400m_tlv_rf_switches_status *rfss; const struct i2400m_tlv_media_status *ms; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", i2400m, l3l4_hdr, size, tag); tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, tlv_size, tlv))) { if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { ss = container_of(tlv, typeof(*ss), hdr); d_printf(2, dev, "%s: system state TLV " "found (0x%04x), state 0x%08x\n", tag, I2400M_TLV_SYSTEM_STATE, le32_to_cpu(ss->state)); i2400m_report_tlv_system_state(i2400m, ss); } if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { rfss = container_of(tlv, typeof(*rfss), hdr); d_printf(2, dev, "%s: RF status TLV " "found (0x%04x), sw 0x%02x hw 0x%02x\n", tag, I2400M_TLV_RF_STATUS, le32_to_cpu(rfss->sw_rf_switch), le32_to_cpu(rfss->hw_rf_switch)); i2400m_report_tlv_rf_switches_status(i2400m, rfss); } if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { ms = container_of(tlv, typeof(*ms), hdr); d_printf(2, dev, "%s: Media Status TLV: %u\n", tag, le32_to_cpu(ms->media_status)); i2400m_report_tlv_media_status(i2400m, ms); } } d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); }
/* Shutdown the wimax stack */ static int __init wimax_subsys_init(void) { int result, cnt; d_fnstart(4, NULL, "()\n"); d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params, "wimax.debug"); snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), "WiMAX"); result = genl_register_family(&wimax_gnl_family); if (unlikely(result < 0)) { printk(KERN_ERR "cannot register generic netlink family: %d\n", result); goto error_register_family; } for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) { result = genl_register_ops(&wimax_gnl_family, wimax_gnl_ops[cnt]); d_printf(4, NULL, "registering generic netlink op code " "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result); if (unlikely(result < 0)) { printk(KERN_ERR "cannot register generic netlink op " "code %u: %d\n", wimax_gnl_ops[cnt]->cmd, result); goto error_register_ops; } } result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg); if (result < 0) goto error_mc_group; d_fnend(4, NULL, "() = 0\n"); return 0; error_mc_group: error_register_ops: for (cnt--; cnt >= 0; cnt--) genl_unregister_ops(&wimax_gnl_family, wimax_gnl_ops[cnt]); genl_unregister_family(&wimax_gnl_family); error_register_family: d_fnend(4, NULL, "() = %d\n", result); return result; }
ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m, const struct i2400m_bootrom_header *_cmd, size_t cmd_size, int flags) { ssize_t result; struct device *dev = i2400m_dev(i2400m); struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd); struct i2400m_bootrom_header *cmd; size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE); d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n", i2400m, _cmd, cmd_size); result = -E2BIG; if (cmd_size > I2400M_BM_CMD_BUF_SIZE) goto error_too_big; if (_cmd != i2400m->bm_cmd_buf) memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); cmd = i2400m->bm_cmd_buf; if (cmd_size_a > cmd_size) memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); if ((flags & I2400M_BM_CMD_RAW) == 0) { if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0)) dev_warn(dev, "SW BUG: response_required == 0\n"); i2400m_bm_cmd_prepare(cmd); } d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n", opcode, cmd_size, cmd_size_a); d_dump(5, dev, cmd, cmd_size); sdio_claim_host(i2400ms->func); result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR, i2400m->bm_cmd_buf, cmd_size_a); sdio_release_host(i2400ms->func); if (result < 0) { dev_err(dev, "BM cmd %d: cannot send: %ld\n", opcode, (long) result); goto error_cmd_send; } result = cmd_size; error_cmd_send: error_too_big: d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n", i2400m, _cmd, cmd_size, (int) result); return result; }
static void i2400ms_remove(struct sdio_func *func) { struct device *dev = &func->dev; struct i2400ms *i2400ms = sdio_get_drvdata(func); struct i2400m *i2400m = &i2400ms->i2400m; struct net_device *net_dev = i2400m->wimax_dev.net_dev; d_fnstart(3, dev, "SDIO func %p\n", func); debugfs_remove_recursive(i2400ms->debugfs_dentry); i2400ms->debugfs_dentry = NULL; i2400m_release(i2400m); sdio_set_drvdata(func, NULL); free_netdev(net_dev); d_fnend(3, dev, "SDIO func %p\n", func); }
static int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) { int result = 0; struct device *dev = &iface->dev; struct i2400mu *i2400mu = usb_get_intfdata(iface); #ifdef CONFIG_PM struct usb_device *usb_dev = i2400mu->usb_dev; #endif unsigned is_autosuspend = 0; struct i2400m *i2400m = &i2400mu->i2400m; #ifdef CONFIG_PM if (usb_dev->auto_pm > 0) is_autosuspend = 1; #endif d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); if (i2400m->updown == 0) goto no_firmware; if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { result = -EBADF; d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " "not entering powersave\n"); goto error_not_now; } d_printf(1, dev, "fw up: entering powersave\n"); atomic_dec(&i2400mu->do_autopm); result = i2400m_cmd_enter_powersave(i2400m); atomic_inc(&i2400mu->do_autopm); if (result < 0 && !is_autosuspend) { dev_err(dev, "failed to suspend, will reset on resume\n"); result = 0; } if (result < 0) goto error_enter_powersave; i2400mu_notification_release(i2400mu); d_printf(1, dev, "powersave requested\n"); error_enter_powersave: error_not_now: no_firmware: d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", iface, pm_msg.event, result); return result; }
static int i2400m_open(struct net_device *net_dev) { int result; struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); if (i2400m->ready == 0) { dev_err(dev, "Device is still initializing\n"); result = -EBUSY; } else result = 0; d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", net_dev, i2400m, result); return result; }
/* * Disconect a i2400m from the system. * * i2400m_stop() has been called before, so al the rx and tx contexts * have been taken down already. Make sure the queue is stopped, * unregister netdev and i2400m, free and kill. */ static void i2400mu_disconnect(struct usb_interface *iface) { struct i2400mu *i2400mu = usb_get_intfdata(iface); struct i2400m *i2400m = &i2400mu->i2400m; struct net_device *net_dev = i2400m->wimax_dev.net_dev; struct device *dev = &iface->dev; d_fnstart(3, dev, "(iface %p i2400m %p)\n", iface, i2400m); debugfs_remove_recursive(i2400mu->debugfs_dentry); i2400m_release(i2400m); usb_set_intfdata(iface, NULL); usb_put_dev(i2400mu->usb_dev); free_netdev(net_dev); d_fnend(3, dev, "(iface %p i2400m %p) = void\n", iface, i2400m); }
/** * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data * * Called by alloc_netdev() */ void i2400m_netdev_setup(struct net_device *net_dev) { d_fnstart(3, NULL, "(net_dev %p)\n", net_dev); ether_setup(net_dev); net_dev->mtu = I2400M_MAX_MTU; net_dev->tx_queue_len = I2400M_TX_QLEN; net_dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_HIGHDMA; net_dev->flags = IFF_NOARP /* i2400m is apure IP device */ & (~IFF_BROADCAST /* i2400m is P2P */ & ~IFF_MULTICAST); net_dev->watchdog_timeo = I2400M_TX_TIMEOUT; net_dev->netdev_ops = &i2400m_netdev_ops; d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev); }
/* * Wake up the device and transmit a held SKB, then restart the net queue * * When the device goes into basestation-idle mode, we need to tell it * to exit that mode; it will negotiate with the base station, user * space may have to intervene to rehandshake crypto and then tell us * when it is ready to transmit the packet we have "queued". Still we * need to give it sometime after it reports being ok. * * On error, there is not much we can do. If the error was on TX, we * still wake the queue up to see if the next packet will be luckier. * * If _cmd_exit_idle() fails...well, it could be many things; most * commonly it is that something else took the device out of IDLE mode * (for example, the base station). In that case we get an -EILSEQ and * we are just going to ignore that one. If the device is back to * connected, then fine -- if it is someother state, the packet will * be dropped anyway. */ void i2400m_wake_tx_work(struct work_struct *ws) { int result; struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws); struct device *dev = i2400m_dev(i2400m); struct sk_buff *skb = i2400m->wake_tx_skb; unsigned long flags; spin_lock_irqsave(&i2400m->tx_lock, flags); skb = i2400m->wake_tx_skb; i2400m->wake_tx_skb = NULL; spin_unlock_irqrestore(&i2400m->tx_lock, flags); d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb); result = -EINVAL; if (skb == NULL) { dev_err(dev, "WAKE&TX: skb dissapeared!\n"); goto out_put; } result = i2400m_cmd_exit_idle(i2400m); if (result == -EILSEQ) result = 0; if (result < 0) { dev_err(dev, "WAKE&TX: device didn't get out of idle: " "%d\n", result); goto error; } result = wait_event_timeout(i2400m->state_wq, i2400m->state != I2400M_SS_IDLE, 5 * HZ); if (result == 0) result = -ETIMEDOUT; if (result < 0) { dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: " "%d\n", result); goto error; } msleep(20); /* device still needs some time or it drops it */ result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); netif_wake_queue(i2400m->wimax_dev.net_dev); error: kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */ out_put: i2400m_put(i2400m); d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n", ws, i2400m, skb, result); }
/* * Get the next TX message in the TX FIFO and send it to the device * <<<<<<< HEAD * Note we exit the loop if i2400mu_tx() fails; that function only ======= * Note we exit the loop if i2400mu_tx() fails; that funtion only >>>>>>> 296c66da8a02d52243f45b80521febece5ed498a * fails on hard error (failing to tx a buffer not being one of them, * see its doc). * * Return: 0 */ static int i2400mu_txd(void *_i2400mu) { int result = 0; struct i2400mu *i2400mu = _i2400mu; struct i2400m *i2400m = &i2400mu->i2400m; struct device *dev = &i2400mu->usb_iface->dev; struct i2400m_msg_hdr *tx_msg; size_t tx_msg_size; unsigned long flags; d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); spin_lock_irqsave(&i2400m->tx_lock, flags); BUG_ON(i2400mu->tx_kthread != NULL); i2400mu->tx_kthread = current; spin_unlock_irqrestore(&i2400m->tx_lock, flags); while (1) { d_printf(2, dev, "TX: waiting for messages\n"); tx_msg = NULL; wait_event_interruptible( i2400mu->tx_wq, (kthread_should_stop() /* check this first! */ || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) ); if (kthread_should_stop()) break; WARN_ON(tx_msg == NULL); /* should not happen...*/ d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size); d_dump(5, dev, tx_msg, tx_msg_size); /* Yeah, we ignore errors ... not much we can do */ i2400mu_tx(i2400mu, tx_msg, tx_msg_size); i2400m_tx_msg_sent(i2400m); /* ack it, advance the FIFO */ if (result < 0) break; } spin_lock_irqsave(&i2400m->tx_lock, flags); i2400mu->tx_kthread = NULL; spin_unlock_irqrestore(&i2400m->tx_lock, flags); d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result); return result; }
void i2400m_report_tlv_rf_switches_status( struct i2400m *i2400m, const struct i2400m_tlv_rf_switches_status *rfss) { struct device *dev = i2400m_dev(i2400m); enum i2400m_rf_switch_status hw, sw; enum wimax_st wimax_state; sw = le32_to_cpu(rfss->sw_rf_switch); hw = le32_to_cpu(rfss->hw_rf_switch); d_fnstart(3, dev, "(i2400m %p rfss %p [hw %u sw %u])\n", i2400m, rfss, hw, sw); wimax_state = wimax_state_get(&i2400m->wimax_dev); if (wimax_state < WIMAX_ST_RADIO_OFF) { d_printf(3, dev, "ignoring RF switches report, state %u\n", wimax_state); goto out; } switch (sw) { case I2400M_RF_SWITCH_ON: wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_ON); break; case I2400M_RF_SWITCH_OFF: wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_OFF); break; default: dev_err(dev, "HW BUG? Unknown RF SW state 0x%x\n", sw); } switch (hw) { case I2400M_RF_SWITCH_ON: wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_ON); break; case I2400M_RF_SWITCH_OFF: wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_OFF); break; default: dev_err(dev, "HW BUG? Unknown RF HW state 0x%x\n", hw); } out: d_fnend(3, dev, "(i2400m %p rfss %p [hw %u sw %u]) = void\n", i2400m, rfss, hw, sw); }
/* * Send a boot-mode command over the bulk-out pipe * * Command can be a raw command, which requires no preparation (and * which might not even be following the command format). Checks that * the right amount of data was transferred. * * To satisfy USB requirements (no onstack, vmalloc or in data segment * buffers), we copy the command to i2400m->bm_cmd_buf and send it from * there. * * @flags: pass thru from i2400m_bm_cmd() * @return: cmd_size if ok, < 0 errno code on error. */ ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m, const struct i2400m_bootrom_header *_cmd, size_t cmd_size, int flags) { ssize_t result; struct device *dev = i2400m_dev(i2400m); struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd); struct i2400m_bootrom_header *cmd; size_t cmd_size_a = ALIGN(cmd_size, 16); /* USB restriction */ d_fnstart(8, dev, "(i2400m %p cmd %p size %zu)\n", i2400m, _cmd, cmd_size); result = -E2BIG; if (cmd_size > I2400M_BM_CMD_BUF_SIZE) goto error_too_big; if (_cmd != i2400m->bm_cmd_buf) memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); cmd = i2400m->bm_cmd_buf; if (cmd_size_a > cmd_size) /* Zero pad space */ memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); if ((flags & I2400M_BM_CMD_RAW) == 0) { if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0)) dev_warn(dev, "SW BUG: response_required == 0\n"); i2400m_bm_cmd_prepare(cmd); } result = i2400mu_tx_bulk_out(i2400mu, i2400m->bm_cmd_buf, cmd_size); if (result < 0) { dev_err(dev, "boot-mode cmd %d: cannot send: %zd\n", opcode, result); goto error_cmd_send; } if (result != cmd_size) { /* all was transferred? */ dev_err(dev, "boot-mode cmd %d: incomplete transfer " "(%zu vs %zu submitted)\n", opcode, result, cmd_size); result = -EIO; goto error_cmd_size; } error_cmd_size: error_cmd_send: error_too_big: d_fnend(8, dev, "(i2400m %p cmd %p size %zu) = %zd\n", i2400m, _cmd, cmd_size, result); return result; }
/* * Tear down SDIO RX * * Disables IRQs in the device and removes the IRQ handler. */ void i2400ms_rx_release(struct i2400ms *i2400ms) { int result; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; struct i2400m *i2400m = &i2400ms->i2400m; d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); spin_lock(&i2400m->rx_lock); i2400ms->bm_ack_size = -EINTR; spin_unlock(&i2400m->rx_lock); wake_up_all(&i2400ms->bm_wfa_wq); sdio_claim_host(func); sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); sdio_release_irq(func); sdio_release_host(func); d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); }
/** * wimax_dev_add - Register a new WiMAX device * * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's * priv data). You must have called wimax_dev_init() on it before. * * @net_dev: net device the @wimax_dev is associated with. The * function expects SET_NETDEV_DEV() and register_netdev() were * already called on it. * * Registers the new WiMAX device, sets up the user-kernel control * interface (generic netlink) and common WiMAX infrastructure. * * Note that the parts that will allow interaction with user space are * setup at the very end, when the rest is in place, as once that * happens, the driver might get user space control requests via * netlink or from debugfs that might translate into calls into * wimax_dev->op_*(). */ int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev) { int result; struct device *dev = net_dev->dev.parent; char addr_str[32]; d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev); /* Do the RFKILL setup before locking, as RFKILL will call * into our functions. */ wimax_dev->net_dev = net_dev; result = wimax_rfkill_add(wimax_dev); if (result < 0) goto error_rfkill_add; /* Set up user-space interaction */ mutex_lock(&wimax_dev->mutex); wimax_id_table_add(wimax_dev); result = wimax_debugfs_add(wimax_dev); if (result < 0) { dev_err(dev, "cannot initialize debugfs: %d\n", result); goto error_debugfs_add; } __wimax_state_set(wimax_dev, WIMAX_ST_DOWN); mutex_unlock(&wimax_dev->mutex); wimax_addr_scnprint(addr_str, sizeof(addr_str), net_dev->dev_addr, net_dev->addr_len); dev_err(dev, "WiMAX interface %s (%s) ready\n", net_dev->name, addr_str); d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev); return 0; error_debugfs_add: wimax_id_table_rm(wimax_dev); mutex_unlock(&wimax_dev->mutex); wimax_rfkill_rm(wimax_dev); error_rfkill_add: d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n", wimax_dev, net_dev, result); return result; }
/** * Control the software RF Kill switch and obtain switch status * * \param wmx WiMAX device handle * * \param state State to which you want to toggle the sofware RF Kill * switch (%WIMAX_RF_ON, %WIMAX_RF_OFF or %WIMAX_RF_QUERY for just * querying the current state of the hardware and software * switches). * * \return Negative errno code on error. Otherwise, radio kill switch * status (bit 0 \e hw switch, bit 1 \e sw switch, \e 0 OFF, \e 1 * ON): * - 3 @c 0b11: Both HW and SW switches are \e on, radio is \e on * - 2 @c 0b10: HW switch is \e off, radio is \e off * - 1 @c 0b01: SW switch is \e on, radio is \e off * - 0 @c 0b00: Both HW and SW switches are \e off, radio is \e off * * Allows the caller to control the state of the software RF Kill * switch (if present) and in return, obtain the current status of * both the hardware and software RF Kill switches. * * If there is no hardware or software switch, that switch is assumed * to be always on (radio on). * * Changing the radio state might cause the device to change state, * and cause the kernel to send reports indicating so. * * \note The state of the radio (\e ON or \e OFF) is the inverse of * the state of the RF-Kill switch (\e enabled/on kills the * radio, radio \e off; \e disabled/off allows the radio to * work, radio \e on). * * \ingroup device_management * \internal * * This implementation simply marshalls the call to the kernel's * wimax_rfkill() and returns it's return code. */ int wimaxll_rfkill(struct wimaxll_handle *wmx, enum wimax_rf_state state) { ssize_t result; struct nl_msg *msg; d_fnstart(3, wmx, "(wmx %p state %u)\n", wmx, state); result = -EBADF; if (wmx->ifidx == 0) goto error_not_any; msg = nlmsg_new(); if (msg == NULL) { result = errno; wimaxll_msg(wmx, "E: RFKILL: cannot allocate generic netlink " "message: %m\n"); goto error_msg_alloc; } if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, wimaxll_family_id(wmx), 0, 0, WIMAX_GNL_OP_RFKILL, WIMAX_GNL_VERSION) == NULL) { result = -ENOMEM; wimaxll_msg(wmx, "E: RFKILL: error preparing message: " "%zd 0x%08x\n", result, (unsigned int) result); goto error_msg_prep; } nla_put_u32(msg, WIMAX_GNL_RFKILL_IFIDX, (__u32) wmx->ifidx); nla_put_u32(msg, WIMAX_GNL_RFKILL_STATE, (__u32) state); result = nl_send_auto_complete(wmx->nlh_tx, msg); if (result < 0) { wimaxll_msg(wmx, "E: RFKILL: error sending message: %zd\n", result); goto error_msg_send; } /* Read the message ACK from netlink */ result = wimaxll_wait_for_ack(wmx); if (result < 0 && result != -ENODEV) wimaxll_msg(wmx, "E: RFKILL: operation failed: %zd\n", result); error_msg_prep: error_msg_send: nlmsg_free(msg); error_msg_alloc: error_not_any: d_fnend(3, wmx, "(wmx %p state %u) = %zd\n", wmx, state, result); return result; }
/* * setup the notification endpoint * * @i2400m: device descriptor * * This procedure prepares the notification urb and handler for receiving * unsolicited barkers from the device. */ int i2400mu_notification_setup(struct i2400mu *i2400mu) { struct device *dev = &i2400mu->usb_iface->dev; int usb_pipe, ret = 0; struct usb_endpoint_descriptor *epd; char *buf; d_fnstart(4, dev, "(i2400m %p)\n", i2400mu); buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA); if (buf == NULL) { dev_err(dev, "notification: buffer allocation failed\n"); ret = -ENOMEM; goto error_buf_alloc; } i2400mu->notif_urb = usb_alloc_urb(0, GFP_KERNEL); if (!i2400mu->notif_urb) { ret = -ENOMEM; dev_err(dev, "notification: cannot allocate URB\n"); goto error_alloc_urb; } epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.notification); usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe, buf, I2400MU_MAX_NOTIFICATION_LEN, i2400mu_notification_cb, i2400mu, epd->bInterval); ret = usb_submit_urb(i2400mu->notif_urb, GFP_KERNEL); if (ret != 0) { dev_err(dev, "notification: cannot submit URB: %d\n", ret); goto error_submit; } d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret); return ret; error_submit: usb_free_urb(i2400mu->notif_urb); error_alloc_urb: kfree(buf); error_buf_alloc: d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret); return ret; }
/* * Parse a 'state report' and extract information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for * consistent size. * @size: size of the message (header + payload). The header length * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * * Walk over the TLVs in a report state and act on them. */ static void i2400m_report_state_hook(struct i2400m *i2400m, const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size, const char *tag) { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", i2400m, l3l4_hdr, size, tag); tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, tlv_size, tlv))) i2400m_report_state_parse_tlv(i2400m, tlv, tag); d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); }
static int i2400m_open(struct net_device *net_dev) { int result; struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); /* Make sure we wait until init is complete... */ mutex_lock(&i2400m->init_mutex); if (i2400m->updown) result = 0; else result = -EBUSY; mutex_unlock(&i2400m->init_mutex); d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", net_dev, i2400m, result); return result; }
/* * TX an skb to an idle device * * When the device is in basestation-idle mode, we need to wake it up * and then TX. So we queue a work_struct for doing so. * * We need to get an extra ref for the skb (so it is not dropped), as * well as be careful not to queue more than one request (won't help * at all). If more than one request comes or there are errors, we * just drop the packets (see i2400m_hard_start_xmit()). */ static int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev, struct sk_buff *skb) { int result; struct device *dev = i2400m_dev(i2400m); unsigned long flags; d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); if (net_ratelimit()) { d_printf(3, dev, "WAKE&NETTX: " "skb %p sending %d bytes to radio\n", skb, skb->len); d_dump(4, dev, skb->data, skb->len); } /* We hold a ref count for i2400m and skb, so when * stopping() the device, we need to cancel that work * and if pending, release those resources. */ result = 0; spin_lock_irqsave(&i2400m->tx_lock, flags); if (!i2400m->wake_tx_skb) { netif_stop_queue(net_dev); i2400m_get(i2400m); i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */ i2400m_tx_prep_header(skb); result = schedule_work(&i2400m->wake_tx_ws); WARN_ON(result == 0); } spin_unlock_irqrestore(&i2400m->tx_lock, flags); if (result == 0) { /* Yes, this happens even if we stopped the * queue -- blame the queue disciplines that * queue without looking -- I guess there is a reason * for that. */ if (net_ratelimit()) d_printf(1, dev, "NETTX: device exiting idle, " "dropping skb %p, queue running %d\n", skb, netif_queue_stopped(net_dev)); result = -EBUSY; } d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); return result; }
static int i2400mu_txd(void *_i2400mu) { struct i2400mu *i2400mu = _i2400mu; struct i2400m *i2400m = &i2400mu->i2400m; struct device *dev = &i2400mu->usb_iface->dev; struct i2400m_msg_hdr *tx_msg; size_t tx_msg_size; unsigned long flags; d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu); spin_lock_irqsave(&i2400m->tx_lock, flags); BUG_ON(i2400mu->tx_kthread != NULL); i2400mu->tx_kthread = current; spin_unlock_irqrestore(&i2400m->tx_lock, flags); while (1) { d_printf(2, dev, "TX: waiting for messages\n"); tx_msg = NULL; wait_event_interruptible( i2400mu->tx_wq, (kthread_should_stop() /* */ || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) ); if (kthread_should_stop()) break; WARN_ON(tx_msg == NULL); /* */ d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size); d_dump(5, dev, tx_msg, tx_msg_size); /* */ i2400mu_tx(i2400mu, tx_msg, tx_msg_size); i2400m_tx_msg_sent(i2400m); /* */ } spin_lock_irqsave(&i2400m->tx_lock, flags); i2400mu->tx_kthread = NULL; spin_unlock_irqrestore(&i2400m->tx_lock, flags); d_fnend(4, dev, "(i2400mu %p)\n", i2400mu); return 0; }
/* * Transmit a packet to the base station on behalf of the network stack. * * Returns: 0 if ok, < 0 errno code on error. * * We need to pull the ethernet header and add the hardware header, * which is currently set to all zeroes and reserved. */ static int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev, struct sk_buff *skb) { int result; struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n", i2400m, net_dev, skb); /* FIXME: check eth hdr, only IPv4 is routed by the device as of now */ net_dev->trans_start = jiffies; i2400m_tx_prep_header(skb); d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n", skb, skb->len); d_dump(4, dev, skb->data, skb->len); result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA); d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n", i2400m, net_dev, skb, result); return result; }