/** * rsi_rx_done_handler() - This function is called when a packet is received * from USB stack. This is callback to receive done. * @urb: Received URB. * * Return: None. */ static void rsi_rx_done_handler(struct urb *urb) { struct rx_usb_ctrl_block *rx_cb = urb->context; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data; int status = -EINVAL; if (urb->status) goto out; if (urb->actual_length <= 0 || urb->actual_length > rx_cb->rx_skb->len) { rsi_dbg(INFO_ZONE, "%s: Invalid packet length = %d\n", __func__, urb->actual_length); goto out; } if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) { rsi_dbg(INFO_ZONE, "Max RX packets reached\n"); goto out; } skb_trim(rx_cb->rx_skb, urb->actual_length); skb_queue_tail(&dev->rx_q, rx_cb->rx_skb); rsi_set_event(&dev->rx_thread.event); status = 0; out: if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num)) rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__); if (status) dev_kfree_skb(rx_cb->rx_skb); }
/** * rsi_load_ta_instructions() - This function includes the actual funtionality * of loading the TA firmware.This function also * includes opening the TA file,reading the TA * file and writing their value in blocks of data. * @common: Pointer to the driver private structure. * * Return: status: 0 on success, -1 on failure. */ static int rsi_load_ta_instructions(struct rsi_common *common) { struct rsi_hw *adapter = common->priv; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; const struct firmware *fw_entry = NULL; u32 block_size = dev->tx_blk_size; const u8 *fw; u32 num_blocks, len; int status = 0; status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); if (status < 0) { rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", __func__, FIRMWARE_RSI9113); return status; } fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); len = fw_entry->size; if (len % 4) len += (4 - (len % 4)); num_blocks = (len / block_size); rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); status = rsi_copy_to_card(common, fw, len, num_blocks); release_firmware(fw_entry); return status; }
/** * rsi_usb_rx_thread() - This is a kernel thread to receive the packets from * the USB device. * @common: Pointer to the driver private structure. * * Return: None. */ void rsi_usb_rx_thread(struct rsi_common *common) { struct rsi_hw *adapter = common->priv; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; int status; do { rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER); if (atomic_read(&dev->rx_thread.thread_done)) goto out; mutex_lock(&common->rx_lock); status = rsi_read_pkt(common, 0); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__); mutex_unlock(&common->rx_lock); return; } mutex_unlock(&common->rx_lock); rsi_reset_event(&dev->rx_thread.event); if (adapter->rx_urb_submit(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__); return; } } while (1); out: rsi_dbg(INFO_ZONE, "%s: Terminated thread\n", __func__); complete_and_exit(&dev->rx_thread.completion, 0); }
/** * rsi_load_radio_caps() - This function is used to send radio capabilities * values to firmware. * @common: Pointer to the driver private structure. * * Return: 0 on success, corresponding negative error code on failure. */ static int rsi_load_radio_caps(struct rsi_common *common) { struct rsi_radio_caps *radio_caps; struct rsi_hw *adapter = common->priv; struct ieee80211_hw *hw = adapter->hw; u16 inx = 0; u8 ii; u8 radio_id = 0; u16 gc[20] = {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}; struct ieee80211_conf *conf = &hw->conf; struct sk_buff *skb; rsi_dbg(INFO_ZONE, "%s: Sending rate symbol req frame\n", __func__); skb = dev_alloc_skb(sizeof(struct rsi_radio_caps)); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); return -ENOMEM; } memset(skb->data, 0, sizeof(struct rsi_radio_caps)); radio_caps = (struct rsi_radio_caps *)skb->data; radio_caps->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES); radio_caps->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8); if (common->channel_width == BW_40MHZ) { radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ); radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ); if (common->channel_width) { radio_caps->desc_word[5] = cpu_to_le16(common->channel_width << 12); radio_caps->desc_word[5] |= cpu_to_le16(FULL40M_ENABLE); } if (conf_is_ht40_minus(conf)) { radio_caps->desc_word[5] = 0; radio_caps->desc_word[5] |= cpu_to_le16(LOWER_20_ENABLE); radio_caps->desc_word[5] |= cpu_to_le16(LOWER_20_ENABLE >> 12); } if (conf_is_ht40_plus(conf)) { radio_caps->desc_word[5] = 0; radio_caps->desc_word[5] |= cpu_to_le16(UPPER_20_ENABLE); radio_caps->desc_word[5] |= cpu_to_le16(UPPER_20_ENABLE >> 12); } }
/** * rsi_copy_to_card() - This function includes the actual funtionality of * copying the TA firmware to the card.Basically this * function includes opening the TA file,reading the TA * file and writing their values in blocks of data. * @common: Pointer to the driver private structure. * @fw: Pointer to the firmware value to be written. * @len: length of firmware file. * @num_blocks: Number of blocks to be written to the card. * * Return: 0 on success and -1 on failure. */ static int rsi_copy_to_card(struct rsi_common *common, const u8 *fw, u32 len, u32 num_blocks) { struct rsi_hw *adapter = common->priv; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u32 indx, ii; u32 block_size = dev->tx_blk_size; u32 lsb_address; u32 base_address; base_address = TA_LOAD_ADDRESS; for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { lsb_address = base_address; if (rsi_usb_write_register_multiple(adapter, lsb_address, (u8 *)(fw + indx), block_size)) { rsi_dbg(ERR_ZONE, "%s: Unable to load %s blk\n", __func__, FIRMWARE_RSI9113); return -EIO; } rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); base_address += block_size; } if (len % block_size) { lsb_address = base_address; if (rsi_usb_write_register_multiple(adapter, lsb_address, (u8 *)(fw + indx), len % block_size)) { rsi_dbg(ERR_ZONE, "%s: Unable to load %s blk\n", __func__, FIRMWARE_RSI9113); return -EIO; } } rsi_dbg(INIT_ZONE, "%s: Succesfully loaded %s instructions\n", __func__, FIRMWARE_RSI9113); rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); return 0; }
/* rsi_usb_reg_read() - This function reads data from given register address. * @usbdev: Pointer to the usb_device structure. * @reg: Address of the register to be read. * @value: Value to be read. * @len: length of data to be read. * * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_reg_read(struct usb_device *usbdev, u32 reg, u16 *value, u16 len) { u8 *buf; int status = -ENOMEM; buf = kmalloc(0x04, GFP_KERNEL); if (!buf) return status; status = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_READ, USB_TYPE_VENDOR, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)buf, len, HZ * 5); *value = (buf[0] | (buf[1] << 8)); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Reg read failed with error code :%d\n", __func__, status); } kfree(buf); return status; }
/** * rsi_rx_urb_submit() - This function submits the given URB to the USB stack. * @adapter: Pointer to the adapter structure. * * Return: 0 on success, a negative error code on failure. */ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1]; struct urb *urb = rx_cb->rx_urb; int status; struct sk_buff *skb; u8 dword_align_bytes = 0; #define RSI_MAX_RX_USB_PKT_SIZE 3000 skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE); if (!skb) return -ENOMEM; skb_reserve(skb, MAX_DWORD_ALIGN_BYTES); dword_align_bytes = (unsigned long)skb->data & 0x3f; if (dword_align_bytes > 0) skb_push(skb, dword_align_bytes); urb->transfer_buffer = skb->data; rx_cb->rx_skb = skb; usb_fill_bulk_urb(urb, dev->usbdev, usb_rcvbulkpipe(dev->usbdev, dev->bulkin_endpoint_addr[ep_num - 1]), urb->transfer_buffer, RSI_MAX_RX_USB_PKT_SIZE, rsi_rx_done_handler, rx_cb); status = usb_submit_urb(urb, GFP_KERNEL); if (status) rsi_dbg(ERR_ZONE, "%s: Failed in urb submission\n", __func__); return status; }
/** * rsi_debug_zone_read() - This function display the currently enabled debug zones. * @seq: Pointer to the sequence file structure. * @data: Pointer to the data. * * Return: 0 on success, -1 on failure. */ static int rsi_debug_zone_read(struct seq_file *seq, void *data) { rsi_dbg(FSM_ZONE, "%x: rsi_enabled zone", rsi_zone_enabled); seq_printf(seq, "The zones available are %#x\n", rsi_zone_enabled); return 0; }
/** * rsi_usb_card_write() - This function writes to the USB Card. * @adapter: Pointer to the adapter structure. * @buf: Pointer to the buffer from where the data has to be taken. * @len: Length to be written. * @endpoint: Type of endpoint. * * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_card_write(struct rsi_hw *adapter, u8 *buf, u16 len, u8 endpoint) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; int status; u8 *seg = dev->tx_buffer; int transfer; int ep = dev->bulkout_endpoint_addr[endpoint - 1]; memset(seg, 0, len + RSI_USB_TX_HEAD_ROOM); memcpy(seg + RSI_USB_TX_HEAD_ROOM, buf, len); len += RSI_USB_TX_HEAD_ROOM; transfer = len; status = usb_bulk_msg(dev->usbdev, usb_sndbulkpipe(dev->usbdev, ep), (void *)seg, (int)len, &transfer, HZ * 5); if (status < 0) { rsi_dbg(ERR_ZONE, "Card write failed with error code :%10d\n", status); dev->write_fail = 1; } return status; }
int rsi_coex_attach(struct rsi_common *common) { struct rsi_coex_ctrl_block *coex_cb; int cnt; coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL); if (!coex_cb) return -ENOMEM; common->coex_cb = (void *)coex_cb; coex_cb->priv = common; /* Initialize co-ex queues */ for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++) skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]); rsi_init_event(&coex_cb->coex_tx_thread.event); /* Initialize co-ex thread */ if (rsi_create_kthread(common, &coex_cb->coex_tx_thread, rsi_coex_scheduler_thread, "Coex-Tx-Thread")) { rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__); return -EINVAL; } return 0; }
/** * rsi_usb_reg_write() - This function writes the given data into the given * register address. * @usbdev: Pointer to the usb_device structure. * @reg: Address of the register. * @value: Value to write. * @len: Length of data to be written. * * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_reg_write(struct usb_device *usbdev, u32 reg, u16 value, u16 len) { u8 *usb_reg_buf; int status = -ENOMEM; usb_reg_buf = kmalloc(0x04, GFP_KERNEL); if (!usb_reg_buf) return status; usb_reg_buf[0] = (value & 0x00ff); usb_reg_buf[1] = (value & 0xff00) >> 8; usb_reg_buf[2] = 0x0; usb_reg_buf[3] = 0x0; status = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_WRITE, USB_TYPE_VENDOR, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)usb_reg_buf, len, HZ * 5); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Reg write failed with error code :%d\n", __func__, status); } kfree(usb_reg_buf); return status; }
/* rsi_usb_reg_read() - This function reads data from given register address. * @usbdev: Pointer to the usb_device structure. * @reg: Address of the register to be read. * @value: Value to be read. * @len: length of data to be read. * * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_reg_read(struct usb_device *usbdev, u32 reg, u16 *value, u16 len) { u8 *buf; int status = -ENOMEM; if (len > RSI_USB_CTRL_BUF_SIZE) return -EINVAL; buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); if (!buf) return status; status = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_READ, RSI_USB_REQ_IN, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)buf, len, USB_CTRL_GET_TIMEOUT); *value = (buf[0] | (buf[1] << 8)); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Reg read failed with error code :%d\n", __func__, status); } kfree(buf); return status; }
int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg) { u8 msg_type = msg[RSI_RX_DESC_MSG_TYPE_OFFSET]; switch (msg_type) { case COMMON_CARD_READY_IND: rsi_dbg(INFO_ZONE, "common card ready received\n"); common->hibernate_resume = false; rsi_handle_card_ready(common, msg); break; case SLEEP_NOTIFY_IND: rsi_dbg(INFO_ZONE, "sleep notify received\n"); rsi_mgmt_pkt_recv(common, msg); break; } return 0; }
static inline void rsi_modify_ps_state(struct rsi_hw *adapter, enum ps_state nstate) { rsi_dbg(INFO_ZONE, "PS state changed %s => %s\n", str_psstate(adapter->ps_state), str_psstate(nstate)); adapter->ps_state = nstate; }
void rsi_disable_ps(struct rsi_hw *adapter) { if (adapter->ps_state != PS_ENABLED) { rsi_dbg(ERR_ZONE, "%s: Cannot accept disable PS in %s state\n", __func__, str_psstate(adapter->ps_state)); return; } if (rsi_send_ps_request(adapter, false)) { rsi_dbg(ERR_ZONE, "%s: Failed to send PS request to device\n", __func__); return; } rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT); }
/** * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue * specified by the queue number. * @common: Pointer to the driver private structure. * @q_num: Queue number. * * Return: Pointer to sk_buff structure. */ static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common, u8 q_num) { if (q_num >= NUM_SOFT_QUEUES) { rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", __func__, q_num); return NULL; } return skb_dequeue(&common->tx_queue[q_num]); }
/** * rsi_core_queue_pkt() - This functions enqueues the packet to the queue * specified by the queue number. * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: None. */ static void rsi_core_queue_pkt(struct rsi_common *common, struct sk_buff *skb) { u8 q_num = skb->priority; if (q_num >= NUM_SOFT_QUEUES) { rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", __func__, q_num); dev_kfree_skb(skb); return; } skb_queue_tail(&common->tx_queue[q_num], skb); }
/** * rsi_init_dbgfs() - This function initializes the dbgfs entry. * @adapter: Pointer to the adapter structure. * * Return: 0 on success, -1 on failure. */ int rsi_init_dbgfs(struct rsi_hw *adapter) { struct rsi_common *common = adapter->priv; struct rsi_debugfs *dev_dbgfs; char devdir[6]; int ii; const struct rsi_dbg_files *files; dev_dbgfs = kzalloc(sizeof(*dev_dbgfs), GFP_KERNEL); adapter->dfsentry = dev_dbgfs; snprintf(devdir, sizeof(devdir), "%s", wiphy_name(adapter->hw->wiphy)); dev_dbgfs->subdir = debugfs_create_dir(devdir, NULL); if (IS_ERR(dev_dbgfs->subdir)) { if (dev_dbgfs->subdir == ERR_PTR(-ENODEV)) rsi_dbg(ERR_ZONE, "%s:Debugfs has not been mounted\n", __func__); else rsi_dbg(ERR_ZONE, "debugfs:%s not created\n", devdir); adapter->dfsentry = NULL; kfree(dev_dbgfs); return (int)PTR_ERR(dev_dbgfs->subdir); } else { for (ii = 0; ii < adapter->num_debugfs_entries; ii++) { files = &dev_debugfs_files[ii]; dev_dbgfs->rsi_files[ii] = debugfs_create_file(files->name, files->perms, dev_dbgfs->subdir, common, &files->fops); } } return 0; }
/** * rsi_send_internal_mgmt_frame() - This function sends management frames to * firmware.Also schedules packet to queue * for transmission. * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: 0 on success, -1 on failure. */ static int rsi_send_internal_mgmt_frame(struct rsi_common *common, struct sk_buff *skb) { struct skb_info *tx_params; if (skb == NULL) { rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__); return -ENOMEM; } tx_params = (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data; tx_params->flags |= INTERNAL_MGMT_PKT; skb_queue_tail(&common->tx_queue[MGMT_SOFT_Q], skb); rsi_set_event(&common->tx_thread.event); return 0; }
static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb) { enum rsi_coex_queues coex_q = RSI_COEX_Q_INVALID; struct sk_buff *skb; do { coex_q = rsi_coex_determine_coex_q(coex_cb); rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q); if (coex_q == RSI_COEX_Q_BT) { skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]); rsi_send_bt_pkt(coex_cb->priv, skb); } } while (coex_q != RSI_COEX_Q_INVALID); }
void rsi_conf_uapsd(struct rsi_hw *adapter) { int ret; if (adapter->ps_state != PS_ENABLED) return; ret = rsi_send_ps_request(adapter, false); if (!ret) ret = rsi_send_ps_request(adapter, true); if (ret) rsi_dbg(ERR_ZONE, "%s: Failed to send PS request to device\n", __func__); }
/** * rsi_rx_urb_submit() - This function submits the given URB to the USB stack. * @adapter: Pointer to the adapter structure. * * Return: 0 on success, a negative error code on failure. */ static int rsi_rx_urb_submit(struct rsi_hw *adapter) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; struct urb *urb = dev->rx_usb_urb[0]; int status; usb_fill_bulk_urb(urb, dev->usbdev, usb_rcvbulkpipe(dev->usbdev, dev->bulkin_endpoint_addr), urb->transfer_buffer, 3000, rsi_rx_done_handler, adapter); status = usb_submit_urb(urb, GFP_KERNEL); if (status) rsi_dbg(ERR_ZONE, "%s: Failed in urb submission\n", __func__); return status; }
/** * rsi_usb_write_register_multiple() - This function writes multiple bytes of * information to multiple registers. * @adapter: Pointer to the adapter structure. * @addr: Address of the register. * @data: Pointer to the data that has to be written. * @count: Number of multiple bytes to be written on to the registers. * * Return: status: 0 on success, a negative error code on failure. */ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, u8 *data, u32 count) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u8 *buf; u8 transfer; int status = 0; buf = kzalloc(4096, GFP_KERNEL); if (!buf) return -ENOMEM; while (count) { transfer = (u8)(min_t(u32, count, 4096)); memcpy(buf, data, transfer); status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), USB_VENDOR_REGISTER_WRITE, USB_TYPE_VENDOR, ((addr & 0xffff0000) >> 16), (addr & 0xffff), (void *)buf, transfer, HZ * 5); if (status < 0) { rsi_dbg(ERR_ZONE, "Reg write failed with error code :%d\n", status); } else { count -= transfer; data += transfer; addr += transfer; } } kfree(buf); return 0; }
/** * rsi_usb_write_register_multiple() - This function writes multiple bytes of * information to multiple registers. * @adapter: Pointer to the adapter structure. * @addr: Address of the register. * @data: Pointer to the data that has to be written. * @count: Number of multiple bytes to be written on to the registers. * * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, u8 *data, u16 count) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u8 *buf; u16 transfer; int status = 0; buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; while (count) { transfer = min_t(u16, count, RSI_USB_BUF_SIZE); memcpy(buf, data, transfer); status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), USB_VENDOR_REGISTER_WRITE, RSI_USB_REQ_OUT, ((addr & 0xffff0000) >> 16), (addr & 0xffff), (void *)buf, transfer, USB_CTRL_SET_TIMEOUT); if (status < 0) { rsi_dbg(ERR_ZONE, "Reg write failed with error code :%d\n", status); kfree(buf); return status; } count -= transfer; data += transfer; addr += transfer; } kfree(buf); return 0; }
int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg) { u16 cfm_type = get_unaligned_le16(msg + PS_CONFIRM_INDEX); switch (cfm_type) { case RSI_SLEEP_REQUEST: if (adapter->ps_state == PS_ENABLE_REQ_SENT) rsi_modify_ps_state(adapter, PS_ENABLED); break; case RSI_WAKEUP_REQUEST: if (adapter->ps_state == PS_DISABLE_REQ_SENT) rsi_modify_ps_state(adapter, PS_NONE); break; default: rsi_dbg(ERR_ZONE, "Invalid PS confirm type %x in state %s\n", cfm_type, str_psstate(adapter->ps_state)); return -1; } return 0; }
int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue) { struct rsi_common *common = (struct rsi_common *)priv; struct rsi_coex_ctrl_block *coex_cb = (struct rsi_coex_ctrl_block *)common->coex_cb; struct skb_info *tx_params = NULL; enum rsi_coex_queues coex_q; int status; coex_q = rsi_map_coex_q(hal_queue); if (coex_q == RSI_COEX_Q_INVALID) { rsi_dbg(ERR_ZONE, "Invalid coex queue\n"); return -EINVAL; } if (coex_q != RSI_COEX_Q_COMMON && coex_q != RSI_COEX_Q_WLAN) { skb_queue_tail(&coex_cb->coex_tx_qs[coex_q], skb); rsi_set_event(&coex_cb->coex_tx_thread.event); return 0; } if (common->iface_down) { tx_params = (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data; if (!(tx_params->flags & INTERNAL_MGMT_PKT)) { rsi_indicate_tx_status(common->priv, skb, -EINVAL); return 0; } } /* Send packet to hal */ if (skb->priority == MGMT_SOFT_Q) status = rsi_send_mgmt_pkt(common, skb); else status = rsi_send_data_pkt(common, skb); return status; }
/** * rsi_usb_card_write() - This function writes to the USB Card. * @adapter: Pointer to the adapter structure. * @buf: Pointer to the buffer from where the data has to be taken. * @len: Length to be written. * @endpoint: Type of endpoint. * * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_card_write(struct rsi_hw *adapter, void *buf, u16 len, u8 endpoint) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; int status; s32 transfer; status = usb_bulk_msg(dev->usbdev, usb_sndbulkpipe(dev->usbdev, dev->bulkout_endpoint_addr[endpoint - 1]), buf, len, &transfer, HZ * 5); if (status < 0) { rsi_dbg(ERR_ZONE, "Card write failed with error code :%10d\n", status); dev->write_fail = 1; } return status; }
/** * rsi_core_xmit() - This function transmits the packets received from mac80211 * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: None. */ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; struct skb_info *tx_params; struct ieee80211_hdr *tmp_hdr = NULL; u8 q_num, tid = 0; if ((!skb) || (!skb->len)) { rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", __func__); goto xmit_fail; } info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; if (common->fsm_state != FSM_MAC_INIT_DONE) { rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); goto xmit_fail; } if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) || (ieee80211_is_ctl(tmp_hdr->frame_control)) || (ieee80211_is_qos_nullfunc(tmp_hdr->frame_control))) { q_num = MGMT_SOFT_Q; skb->priority = q_num; } else { if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { tid = (skb->data[24] & IEEE80211_QOS_TID); skb->priority = TID_TO_WME_AC(tid); } else { tid = IEEE80211_NONQOS_TID; skb->priority = BE_Q; } q_num = skb->priority; tx_params->tid = tid; tx_params->sta_id = 0; } if ((q_num != MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); rsi_set_event(&common->tx_thread.event); goto xmit_fail; } rsi_core_queue_pkt(common, skb); rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__); rsi_set_event(&common->tx_thread.event); return; xmit_fail: rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); /* Dropping pkt here */ ieee80211_free_txskb(common->priv->hw, skb); }
/** * rsi_core_xmit() - This function transmits the packets received from mac80211 * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: None. */ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; struct skb_info *tx_params; struct ieee80211_hdr *wh = NULL; struct ieee80211_vif *vif; u8 q_num, tid = 0; struct rsi_sta *rsta = NULL; if ((!skb) || (!skb->len)) { rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", __func__); goto xmit_fail; } if (common->fsm_state != FSM_MAC_INIT_DONE) { rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); goto xmit_fail; } if (common->wow_flags & RSI_WOW_ENABLED) { rsi_dbg(ERR_ZONE, "%s: Blocking Tx_packets when WOWLAN is enabled\n", __func__); goto xmit_fail; } info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; wh = (struct ieee80211_hdr *)&skb->data[0]; tx_params->sta_id = 0; vif = rsi_get_vif(adapter, wh->addr2); if (!vif) goto xmit_fail; tx_params->vif = vif; tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id; if ((ieee80211_is_mgmt(wh->frame_control)) || (ieee80211_is_ctl(wh->frame_control)) || (ieee80211_is_qos_nullfunc(wh->frame_control))) { if (ieee80211_is_assoc_req(wh->frame_control) || ieee80211_is_reassoc_req(wh->frame_control)) { struct ieee80211_bss_conf *bss = &vif->bss_conf; common->eapol4_confirm = false; rsi_hal_send_sta_notify_frame(common, RSI_IFTYPE_STATION, STA_CONNECTED, bss->bssid, bss->qos, bss->aid, 0, vif); } q_num = MGMT_SOFT_Q; skb->priority = q_num; if (rsi_prepare_mgmt_desc(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare desc\n"); goto xmit_fail; } } else { if (ieee80211_is_data_qos(wh->frame_control)) { u8 *qos = ieee80211_get_qos_ctl(wh); tid = *qos & IEEE80211_QOS_CTL_TID_MASK; skb->priority = TID_TO_WME_AC(tid); } else { tid = IEEE80211_NONQOS_TID; skb->priority = BE_Q; } q_num = skb->priority; tx_params->tid = tid; if (((vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_P2P_GO)) && (!is_broadcast_ether_addr(wh->addr1)) && (!is_multicast_ether_addr(wh->addr1))) { rsta = rsi_find_sta(common, wh->addr1); if (!rsta) goto xmit_fail; tx_params->sta_id = rsta->sta_id; } else { tx_params->sta_id = 0; } if (rsta) { /* Start aggregation if not done for this tid */ if (!rsta->start_tx_aggr[tid]) { rsta->start_tx_aggr[tid] = true; ieee80211_start_tx_ba_session(rsta->sta, tid, 0); } } if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { q_num = MGMT_SOFT_Q; skb->priority = q_num; } if (rsi_prepare_data_desc(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n"); goto xmit_fail; } } if ((q_num < MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); rsi_set_event(&common->tx_thread.event); goto xmit_fail; } rsi_core_queue_pkt(common, skb); rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thread <===\n", __func__); rsi_set_event(&common->tx_thread.event); return; xmit_fail: rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); /* Dropping pkt here */ ieee80211_free_txskb(common->priv->hw, skb); }
/** * rsi_core_qos_processor() - This function is used to determine the wmm queue * based on the backoff procedure. Data packets are * dequeued from the selected hal queue and sent to * the below layers. * @common: Pointer to the driver private structure. * * Return: None. */ void rsi_core_qos_processor(struct rsi_common *common) { struct rsi_hw *adapter = common->priv; struct sk_buff *skb; unsigned long tstamp_1, tstamp_2; u8 q_num; int status; tstamp_1 = jiffies; while (1) { q_num = rsi_core_determine_hal_queue(common); rsi_dbg(DATA_TX_ZONE, "%s: Queue number = %d\n", __func__, q_num); if (q_num == INVALID_QUEUE) { rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__); break; } if (common->hibernate_resume) break; mutex_lock(&common->tx_lock); status = adapter->check_hw_queue_status(adapter, q_num); if ((status <= 0)) { mutex_unlock(&common->tx_lock); break; } if ((q_num < MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num])) <= MIN_DATA_QUEUE_WATER_MARK)) { if (ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) ieee80211_wake_queue(adapter->hw, WME_AC(q_num)); } skb = rsi_core_dequeue_pkt(common, q_num); if (skb == NULL) { rsi_dbg(ERR_ZONE, "skb null\n"); mutex_unlock(&common->tx_lock); break; } if (q_num == MGMT_BEACON_Q) { status = rsi_send_pkt_to_bus(common, skb); dev_kfree_skb(skb); } else { #ifdef CONFIG_RSI_COEX if (common->coex_mode > 1) { status = rsi_coex_send_pkt(common, skb, RSI_WLAN_Q); } else { #endif if (q_num == MGMT_SOFT_Q) status = rsi_send_mgmt_pkt(common, skb); else status = rsi_send_data_pkt(common, skb); #ifdef CONFIG_RSI_COEX } #endif } if (status) { mutex_unlock(&common->tx_lock); break; } common->tx_stats.total_tx_pkt_send[q_num]++; tstamp_2 = jiffies; mutex_unlock(&common->tx_lock); if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) schedule(); } }