162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2018-2019 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/usb.h> 762306a36Sopenharmony_ci#include <linux/mutex.h> 862306a36Sopenharmony_ci#include "main.h" 962306a36Sopenharmony_ci#include "debug.h" 1062306a36Sopenharmony_ci#include "reg.h" 1162306a36Sopenharmony_ci#include "tx.h" 1262306a36Sopenharmony_ci#include "rx.h" 1362306a36Sopenharmony_ci#include "fw.h" 1462306a36Sopenharmony_ci#include "ps.h" 1562306a36Sopenharmony_ci#include "usb.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define RTW_USB_MAX_RXQ_LEN 512 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct rtw_usb_txcb { 2062306a36Sopenharmony_ci struct rtw_dev *rtwdev; 2162306a36Sopenharmony_ci struct sk_buff_head tx_ack_queue; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, 2562306a36Sopenharmony_ci struct sk_buff *skb, int agg_num) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; 2862306a36Sopenharmony_ci struct rtw_dev *rtwdev = rtwusb->rtwdev; 2962306a36Sopenharmony_ci struct rtw_tx_pkt_info pkt_info; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM); 3262306a36Sopenharmony_ci pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET); 3362306a36Sopenharmony_ci rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void rtw_usb_reg_sec(struct rtw_dev *rtwdev, u32 addr, __le32 *data) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 3962306a36Sopenharmony_ci struct usb_device *udev = rtwusb->udev; 4062306a36Sopenharmony_ci bool reg_on_section = false; 4162306a36Sopenharmony_ci u16 t_reg = 0x4e0; 4262306a36Sopenharmony_ci u8 t_len = 1; 4362306a36Sopenharmony_ci int status; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* There are three sections: 4662306a36Sopenharmony_ci * 1. on (0x00~0xFF; 0x1000~0x10FF): this section is always powered on 4762306a36Sopenharmony_ci * 2. off (< 0xFE00, excluding "on" section): this section could be 4862306a36Sopenharmony_ci * powered off 4962306a36Sopenharmony_ci * 3. local (>= 0xFE00): usb specific registers section 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci if (addr <= 0xff || (addr >= 0x1000 && addr <= 0x10ff)) 5262306a36Sopenharmony_ci reg_on_section = true; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (!reg_on_section) 5562306a36Sopenharmony_ci return; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 5862306a36Sopenharmony_ci RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, 5962306a36Sopenharmony_ci t_reg, 0, data, t_len, 500); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (status != t_len && status != -ENODEV) 6262306a36Sopenharmony_ci rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n", 6362306a36Sopenharmony_ci __func__, t_reg, t_len, status); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 6962306a36Sopenharmony_ci struct usb_device *udev = rtwusb->udev; 7062306a36Sopenharmony_ci __le32 *data; 7162306a36Sopenharmony_ci unsigned long flags; 7262306a36Sopenharmony_ci int idx, ret; 7362306a36Sopenharmony_ci static int count; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci spin_lock_irqsave(&rtwusb->usb_lock, flags); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci idx = rtwusb->usb_data_index; 7862306a36Sopenharmony_ci rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwusb->usb_lock, flags); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci data = &rtwusb->usb_data[idx]; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 8562306a36Sopenharmony_ci RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr, 8662306a36Sopenharmony_ci RTW_USB_VENQT_CMD_IDX, data, len, 1000); 8762306a36Sopenharmony_ci if (ret < 0 && ret != -ENODEV && count++ < 4) 8862306a36Sopenharmony_ci rtw_err(rtwdev, "read register 0x%x failed with %d\n", 8962306a36Sopenharmony_ci addr, ret); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || 9262306a36Sopenharmony_ci rtwdev->chip->id == RTW_CHIP_TYPE_8822B || 9362306a36Sopenharmony_ci rtwdev->chip->id == RTW_CHIP_TYPE_8821C) 9462306a36Sopenharmony_ci rtw_usb_reg_sec(rtwdev, addr, data); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return le32_to_cpu(*data); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return (u8)rtw_usb_read(rtwdev, addr, 1); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return (u16)rtw_usb_read(rtwdev, addr, 2); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return (u32)rtw_usb_read(rtwdev, addr, 4); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv; 11762306a36Sopenharmony_ci struct usb_device *udev = rtwusb->udev; 11862306a36Sopenharmony_ci unsigned long flags; 11962306a36Sopenharmony_ci __le32 *data; 12062306a36Sopenharmony_ci int idx, ret; 12162306a36Sopenharmony_ci static int count; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci spin_lock_irqsave(&rtwusb->usb_lock, flags); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci idx = rtwusb->usb_data_index; 12662306a36Sopenharmony_ci rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwusb->usb_lock, flags); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci data = &rtwusb->usb_data[idx]; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci *data = cpu_to_le32(val); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 13562306a36Sopenharmony_ci RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, 13662306a36Sopenharmony_ci addr, 0, data, len, 30000); 13762306a36Sopenharmony_ci if (ret < 0 && ret != -ENODEV && count++ < 4) 13862306a36Sopenharmony_ci rtw_err(rtwdev, "write register 0x%x failed with %d\n", 13962306a36Sopenharmony_ci addr, ret); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || 14262306a36Sopenharmony_ci rtwdev->chip->id == RTW_CHIP_TYPE_8822B || 14362306a36Sopenharmony_ci rtwdev->chip->id == RTW_CHIP_TYPE_8821C) 14462306a36Sopenharmony_ci rtw_usb_reg_sec(rtwdev, addr, data); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci rtw_usb_write(rtwdev, addr, val, 1); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci rtw_usb_write(rtwdev, addr, val, 2); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci rtw_usb_write(rtwdev, addr, val, 4); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci switch (dma_mapping) { 16562306a36Sopenharmony_ci case RTW_DMA_MAPPING_HIGH: 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci case RTW_DMA_MAPPING_NORMAL: 16862306a36Sopenharmony_ci return 1; 16962306a36Sopenharmony_ci case RTW_DMA_MAPPING_LOW: 17062306a36Sopenharmony_ci return 2; 17162306a36Sopenharmony_ci case RTW_DMA_MAPPING_EXTRA: 17262306a36Sopenharmony_ci return 3; 17362306a36Sopenharmony_ci default: 17462306a36Sopenharmony_ci return -EINVAL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic int rtw_usb_parse(struct rtw_dev *rtwdev, 17962306a36Sopenharmony_ci struct usb_interface *interface) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 18262306a36Sopenharmony_ci struct usb_host_interface *host_interface = &interface->altsetting[0]; 18362306a36Sopenharmony_ci struct usb_interface_descriptor *interface_desc = &host_interface->desc; 18462306a36Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 18562306a36Sopenharmony_ci int num_out_pipes = 0; 18662306a36Sopenharmony_ci int i; 18762306a36Sopenharmony_ci u8 num; 18862306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 18962306a36Sopenharmony_ci const struct rtw_rqpn *rqpn; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for (i = 0; i < interface_desc->bNumEndpoints; i++) { 19262306a36Sopenharmony_ci endpoint = &host_interface->endpoint[i].desc; 19362306a36Sopenharmony_ci num = usb_endpoint_num(endpoint); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (usb_endpoint_dir_in(endpoint) && 19662306a36Sopenharmony_ci usb_endpoint_xfer_bulk(endpoint)) { 19762306a36Sopenharmony_ci if (rtwusb->pipe_in) { 19862306a36Sopenharmony_ci rtw_err(rtwdev, "IN pipes overflow\n"); 19962306a36Sopenharmony_ci return -EINVAL; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci rtwusb->pipe_in = num; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (usb_endpoint_dir_in(endpoint) && 20662306a36Sopenharmony_ci usb_endpoint_xfer_int(endpoint)) { 20762306a36Sopenharmony_ci if (rtwusb->pipe_interrupt) { 20862306a36Sopenharmony_ci rtw_err(rtwdev, "INT pipes overflow\n"); 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci rtwusb->pipe_interrupt = num; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (usb_endpoint_dir_out(endpoint) && 21662306a36Sopenharmony_ci usb_endpoint_xfer_bulk(endpoint)) { 21762306a36Sopenharmony_ci if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) { 21862306a36Sopenharmony_ci rtw_err(rtwdev, "OUT pipes overflow\n"); 21962306a36Sopenharmony_ci return -EINVAL; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci rtwusb->out_ep[num_out_pipes++] = num; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci rtwdev->hci.bulkout_num = num_out_pipes; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (num_out_pipes < 1 || num_out_pipes > 4) { 22962306a36Sopenharmony_ci rtw_err(rtwdev, "invalid number of endpoints %d\n", num_out_pipes); 23062306a36Sopenharmony_ci return -EINVAL; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci rqpn = &chip->rqpn_table[num_out_pipes]; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = dma_mapping_to_ep(rqpn->dma_map_be); 23662306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = dma_mapping_to_ep(rqpn->dma_map_bk); 23762306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = dma_mapping_to_ep(rqpn->dma_map_bk); 23862306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = dma_mapping_to_ep(rqpn->dma_map_be); 23962306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = dma_mapping_to_ep(rqpn->dma_map_vi); 24062306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = dma_mapping_to_ep(rqpn->dma_map_vi); 24162306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = dma_mapping_to_ep(rqpn->dma_map_vo); 24262306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = dma_mapping_to_ep(rqpn->dma_map_vo); 24362306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID8] = -EINVAL; 24462306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID9] = -EINVAL; 24562306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID10] = -EINVAL; 24662306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID11] = -EINVAL; 24762306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID12] = -EINVAL; 24862306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID13] = -EINVAL; 24962306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID14] = -EINVAL; 25062306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_TID15] = -EINVAL; 25162306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_BEACON] = dma_mapping_to_ep(rqpn->dma_map_hi); 25262306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_HIGH] = dma_mapping_to_ep(rqpn->dma_map_hi); 25362306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_MGMT] = dma_mapping_to_ep(rqpn->dma_map_mg); 25462306a36Sopenharmony_ci rtwusb->qsel_to_ep[TX_DESC_QSEL_H2C] = dma_mapping_to_ep(rqpn->dma_map_hi); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void rtw_usb_write_port_tx_complete(struct urb *urb) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct rtw_usb_txcb *txcb = urb->context; 26262306a36Sopenharmony_ci struct rtw_dev *rtwdev = txcb->rtwdev; 26362306a36Sopenharmony_ci struct ieee80211_hw *hw = rtwdev->hw; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci while (true) { 26662306a36Sopenharmony_ci struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue); 26762306a36Sopenharmony_ci struct ieee80211_tx_info *info; 26862306a36Sopenharmony_ci struct rtw_usb_tx_data *tx_data; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!skb) 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 27462306a36Sopenharmony_ci tx_data = rtw_usb_get_tx_data(skb); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* enqueue to wait for tx report */ 27762306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 27862306a36Sopenharmony_ci rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn); 27962306a36Sopenharmony_ci continue; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* always ACK for others, then they won't be marked as drop */ 28362306a36Sopenharmony_ci ieee80211_tx_info_clear_status(info); 28462306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 28562306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 28662306a36Sopenharmony_ci else 28762306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ieee80211_tx_status_irqsafe(hw, skb); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci kfree(txcb); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep)) 29862306a36Sopenharmony_ci return -EINVAL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return rtwusb->qsel_to_ep[qsel]; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb, 30462306a36Sopenharmony_ci usb_complete_t cb, void *context) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 30762306a36Sopenharmony_ci struct usb_device *usbd = rtwusb->udev; 30862306a36Sopenharmony_ci struct urb *urb; 30962306a36Sopenharmony_ci unsigned int pipe; 31062306a36Sopenharmony_ci int ret; 31162306a36Sopenharmony_ci int ep = qsel_to_ep(rtwusb, qsel); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (ep < 0) 31462306a36Sopenharmony_ci return ep; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]); 31762306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 31862306a36Sopenharmony_ci if (!urb) 31962306a36Sopenharmony_ci return -ENOMEM; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context); 32262306a36Sopenharmony_ci urb->transfer_flags |= URB_ZERO_PACKET; 32362306a36Sopenharmony_ci ret = usb_submit_urb(urb, GFP_ATOMIC); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci usb_free_urb(urb); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return ret; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct rtw_dev *rtwdev = rtwusb->rtwdev; 33362306a36Sopenharmony_ci struct rtw_tx_desc *tx_desc; 33462306a36Sopenharmony_ci struct rtw_usb_txcb *txcb; 33562306a36Sopenharmony_ci struct sk_buff *skb_head; 33662306a36Sopenharmony_ci struct sk_buff *skb_iter; 33762306a36Sopenharmony_ci int agg_num = 0; 33862306a36Sopenharmony_ci unsigned int align_next = 0; 33962306a36Sopenharmony_ci u8 qsel; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (skb_queue_empty(list)) 34262306a36Sopenharmony_ci return false; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); 34562306a36Sopenharmony_ci if (!txcb) 34662306a36Sopenharmony_ci return false; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci txcb->rtwdev = rtwdev; 34962306a36Sopenharmony_ci skb_queue_head_init(&txcb->tx_ack_queue); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci skb_iter = skb_dequeue(list); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (skb_queue_empty(list)) { 35462306a36Sopenharmony_ci skb_head = skb_iter; 35562306a36Sopenharmony_ci goto queue; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ); 35962306a36Sopenharmony_ci if (!skb_head) { 36062306a36Sopenharmony_ci skb_head = skb_iter; 36162306a36Sopenharmony_ci goto queue; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci while (skb_iter) { 36562306a36Sopenharmony_ci unsigned long flags; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci skb_put(skb_head, align_next); 36862306a36Sopenharmony_ci skb_put_data(skb_head, skb_iter->data, skb_iter->len); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci align_next = ALIGN(skb_iter->len, 8) - skb_iter->len; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci agg_num++; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci skb_queue_tail(&txcb->tx_ack_queue, skb_iter); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci spin_lock_irqsave(&list->lock, flags); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci skb_iter = skb_peek(list); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ) 38162306a36Sopenharmony_ci __skb_unlink(skb_iter, list); 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci skb_iter = NULL; 38462306a36Sopenharmony_ci spin_unlock_irqrestore(&list->lock, flags); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (agg_num > 1) 38862306a36Sopenharmony_ci rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ciqueue: 39162306a36Sopenharmony_ci skb_queue_tail(&txcb->tx_ack_queue, skb_head); 39262306a36Sopenharmony_ci tx_desc = (struct rtw_tx_desc *)skb_head->data; 39362306a36Sopenharmony_ci qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return true; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void rtw_usb_tx_handler(struct work_struct *work) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work); 40362306a36Sopenharmony_ci int i, limit; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) { 40662306a36Sopenharmony_ci for (limit = 0; limit < 200; limit++) { 40762306a36Sopenharmony_ci struct sk_buff_head *list = &rtwusb->tx_queue[i]; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (!rtw_usb_tx_agg_skb(rtwusb, list)) 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci int i; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) 42062306a36Sopenharmony_ci skb_queue_purge(&rtwusb->tx_queue[i]); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void rtw_usb_write_port_complete(struct urb *urb) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct sk_buff *skb = urb->context; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int rtw_usb_write_data(struct rtw_dev *rtwdev, 43162306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 43262306a36Sopenharmony_ci u8 *buf) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 43562306a36Sopenharmony_ci struct sk_buff *skb; 43662306a36Sopenharmony_ci unsigned int desclen, headsize, size; 43762306a36Sopenharmony_ci u8 qsel; 43862306a36Sopenharmony_ci int ret = 0; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci size = pkt_info->tx_pkt_size; 44162306a36Sopenharmony_ci qsel = pkt_info->qsel; 44262306a36Sopenharmony_ci desclen = chip->tx_pkt_desc_sz; 44362306a36Sopenharmony_ci headsize = pkt_info->offset ? pkt_info->offset : desclen; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci skb = dev_alloc_skb(headsize + size); 44662306a36Sopenharmony_ci if (unlikely(!skb)) 44762306a36Sopenharmony_ci return -ENOMEM; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci skb_reserve(skb, headsize); 45062306a36Sopenharmony_ci skb_put_data(skb, buf, size); 45162306a36Sopenharmony_ci skb_push(skb, headsize); 45262306a36Sopenharmony_ci memset(skb->data, 0, headsize); 45362306a36Sopenharmony_ci rtw_tx_fill_tx_desc(pkt_info, skb); 45462306a36Sopenharmony_ci rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ret = rtw_usb_write_port(rtwdev, qsel, skb, 45762306a36Sopenharmony_ci rtw_usb_write_port_complete, skb); 45862306a36Sopenharmony_ci if (unlikely(ret)) 45962306a36Sopenharmony_ci rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, 46562306a36Sopenharmony_ci u32 size) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 46862306a36Sopenharmony_ci struct rtw_tx_pkt_info pkt_info = {0}; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci pkt_info.tx_pkt_size = size; 47162306a36Sopenharmony_ci pkt_info.qsel = TX_DESC_QSEL_BEACON; 47262306a36Sopenharmony_ci pkt_info.offset = chip->tx_pkt_desc_sz; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return rtw_usb_write_data(rtwdev, &pkt_info, buf); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct rtw_tx_pkt_info pkt_info = {0}; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci pkt_info.tx_pkt_size = size; 48262306a36Sopenharmony_ci pkt_info.qsel = TX_DESC_QSEL_H2C; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return rtw_usb_write_data(rtwdev, &pkt_info, buf); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 49062306a36Sopenharmony_ci __le16 fc = hdr->frame_control; 49162306a36Sopenharmony_ci u8 qsel; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) 49462306a36Sopenharmony_ci qsel = TX_DESC_QSEL_MGMT; 49562306a36Sopenharmony_ci else if (is_broadcast_ether_addr(hdr->addr1) || 49662306a36Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) 49762306a36Sopenharmony_ci qsel = TX_DESC_QSEL_HIGH; 49862306a36Sopenharmony_ci else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK) 49962306a36Sopenharmony_ci qsel = skb->priority; 50062306a36Sopenharmony_ci else 50162306a36Sopenharmony_ci qsel = TX_DESC_QSEL_BEACON; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return qsel; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic int rtw_usb_tx_write(struct rtw_dev *rtwdev, 50762306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 50862306a36Sopenharmony_ci struct sk_buff *skb) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 51162306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 51262306a36Sopenharmony_ci struct rtw_usb_tx_data *tx_data; 51362306a36Sopenharmony_ci u8 *pkt_desc; 51462306a36Sopenharmony_ci int ep; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb); 51762306a36Sopenharmony_ci pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); 51862306a36Sopenharmony_ci memset(pkt_desc, 0, chip->tx_pkt_desc_sz); 51962306a36Sopenharmony_ci ep = qsel_to_ep(rtwusb, pkt_info->qsel); 52062306a36Sopenharmony_ci rtw_tx_fill_tx_desc(pkt_info, skb); 52162306a36Sopenharmony_ci rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); 52262306a36Sopenharmony_ci tx_data = rtw_usb_get_tx_data(skb); 52362306a36Sopenharmony_ci tx_data->sn = pkt_info->sn; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci skb_queue_tail(&rtwusb->tx_queue[ep], skb); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci queue_work(rtwusb->txwq, &rtwusb->tx_work); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void rtw_usb_rx_handler(struct work_struct *work) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work); 54062306a36Sopenharmony_ci struct rtw_dev *rtwdev = rtwusb->rtwdev; 54162306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 54262306a36Sopenharmony_ci struct rtw_rx_pkt_stat pkt_stat; 54362306a36Sopenharmony_ci struct ieee80211_rx_status rx_status; 54462306a36Sopenharmony_ci struct sk_buff *skb; 54562306a36Sopenharmony_ci u32 pkt_desc_sz = chip->rx_pkt_desc_sz; 54662306a36Sopenharmony_ci u32 pkt_offset; 54762306a36Sopenharmony_ci u8 *rx_desc; 54862306a36Sopenharmony_ci int limit; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci for (limit = 0; limit < 200; limit++) { 55162306a36Sopenharmony_ci skb = skb_dequeue(&rtwusb->rx_queue); 55262306a36Sopenharmony_ci if (!skb) 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci rx_desc = skb->data; 55662306a36Sopenharmony_ci chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, 55762306a36Sopenharmony_ci &rx_status); 55862306a36Sopenharmony_ci pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + 55962306a36Sopenharmony_ci pkt_stat.shift; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (pkt_stat.is_c2h) { 56262306a36Sopenharmony_ci skb_put(skb, pkt_stat.pkt_len + pkt_offset); 56362306a36Sopenharmony_ci rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); 56462306a36Sopenharmony_ci continue; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) { 56862306a36Sopenharmony_ci dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n"); 56962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 57062306a36Sopenharmony_ci continue; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci skb_put(skb, pkt_stat.pkt_len); 57462306a36Sopenharmony_ci skb_reserve(skb, pkt_offset); 57562306a36Sopenharmony_ci memcpy(skb->cb, &rx_status, sizeof(rx_status)); 57662306a36Sopenharmony_ci ieee80211_rx_irqsafe(rtwdev->hw, skb); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void rtw_usb_read_port_complete(struct urb *urb); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci struct rtw_dev *rtwdev = rtwusb->rtwdev; 58562306a36Sopenharmony_ci int error; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC); 58862306a36Sopenharmony_ci if (!rxcb->rx_skb) 58962306a36Sopenharmony_ci return; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, 59262306a36Sopenharmony_ci usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in), 59362306a36Sopenharmony_ci rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ, 59462306a36Sopenharmony_ci rtw_usb_read_port_complete, rxcb); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC); 59762306a36Sopenharmony_ci if (error) { 59862306a36Sopenharmony_ci kfree_skb(rxcb->rx_skb); 59962306a36Sopenharmony_ci if (error != -ENODEV) 60062306a36Sopenharmony_ci rtw_err(rtwdev, "Err sending rx data urb %d\n", 60162306a36Sopenharmony_ci error); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void rtw_usb_read_port_complete(struct urb *urb) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct rx_usb_ctrl_block *rxcb = urb->context; 60862306a36Sopenharmony_ci struct rtw_dev *rtwdev = rxcb->rtwdev; 60962306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 61062306a36Sopenharmony_ci struct sk_buff *skb = rxcb->rx_skb; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (urb->status == 0) { 61362306a36Sopenharmony_ci if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ || 61462306a36Sopenharmony_ci urb->actual_length < 24) { 61562306a36Sopenharmony_ci rtw_err(rtwdev, "failed to get urb length:%d\n", 61662306a36Sopenharmony_ci urb->actual_length); 61762306a36Sopenharmony_ci if (skb) 61862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 61962306a36Sopenharmony_ci } else { 62062306a36Sopenharmony_ci skb_queue_tail(&rtwusb->rx_queue, skb); 62162306a36Sopenharmony_ci queue_work(rtwusb->rxwq, &rtwusb->rx_work); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci rtw_usb_rx_resubmit(rtwusb, rxcb); 62462306a36Sopenharmony_ci } else { 62562306a36Sopenharmony_ci switch (urb->status) { 62662306a36Sopenharmony_ci case -EINVAL: 62762306a36Sopenharmony_ci case -EPIPE: 62862306a36Sopenharmony_ci case -ENODEV: 62962306a36Sopenharmony_ci case -ESHUTDOWN: 63062306a36Sopenharmony_ci case -ENOENT: 63162306a36Sopenharmony_ci case -EPROTO: 63262306a36Sopenharmony_ci case -EILSEQ: 63362306a36Sopenharmony_ci case -ETIME: 63462306a36Sopenharmony_ci case -ECOMM: 63562306a36Sopenharmony_ci case -EOVERFLOW: 63662306a36Sopenharmony_ci case -EINPROGRESS: 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci default: 63962306a36Sopenharmony_ci rtw_err(rtwdev, "status %d\n", urb->status); 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci if (skb) 64362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct rx_usb_ctrl_block *rxcb; 65062306a36Sopenharmony_ci int i; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 65362306a36Sopenharmony_ci rxcb = &rtwusb->rx_cb[i]; 65462306a36Sopenharmony_ci usb_kill_urb(rxcb->rx_urb); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct rx_usb_ctrl_block *rxcb; 66162306a36Sopenharmony_ci int i; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 66462306a36Sopenharmony_ci rxcb = &rtwusb->rx_cb[i]; 66562306a36Sopenharmony_ci usb_kill_urb(rxcb->rx_urb); 66662306a36Sopenharmony_ci usb_free_urb(rxcb->rx_urb); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci int i; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 67562306a36Sopenharmony_ci struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci rxcb->rtwdev = rtwusb->rtwdev; 67862306a36Sopenharmony_ci rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 67962306a36Sopenharmony_ci if (!rxcb->rx_urb) 68062306a36Sopenharmony_ci goto err; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_cierr: 68562306a36Sopenharmony_ci rtw_usb_free_rx_bufs(rtwusb); 68662306a36Sopenharmony_ci return -ENOMEM; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic int rtw_usb_setup(struct rtw_dev *rtwdev) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci /* empty function for rtw_hci_ops */ 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic int rtw_usb_start(struct rtw_dev *rtwdev) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic void rtw_usb_stop(struct rtw_dev *rtwdev) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci /* empty function for rtw_hci_ops */ 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci /* empty function for rtw_hci_ops */ 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic void rtw_usb_interface_cfg(struct rtw_dev *rtwdev) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci /* empty function for rtw_hci_ops */ 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic struct rtw_hci_ops rtw_usb_ops = { 72062306a36Sopenharmony_ci .tx_write = rtw_usb_tx_write, 72162306a36Sopenharmony_ci .tx_kick_off = rtw_usb_tx_kick_off, 72262306a36Sopenharmony_ci .setup = rtw_usb_setup, 72362306a36Sopenharmony_ci .start = rtw_usb_start, 72462306a36Sopenharmony_ci .stop = rtw_usb_stop, 72562306a36Sopenharmony_ci .deep_ps = rtw_usb_deep_ps, 72662306a36Sopenharmony_ci .link_ps = rtw_usb_link_ps, 72762306a36Sopenharmony_ci .interface_cfg = rtw_usb_interface_cfg, 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci .write8 = rtw_usb_write8, 73062306a36Sopenharmony_ci .write16 = rtw_usb_write16, 73162306a36Sopenharmony_ci .write32 = rtw_usb_write32, 73262306a36Sopenharmony_ci .read8 = rtw_usb_read8, 73362306a36Sopenharmony_ci .read16 = rtw_usb_read16, 73462306a36Sopenharmony_ci .read32 = rtw_usb_read32, 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci .write_data_rsvd_page = rtw_usb_write_data_rsvd_page, 73762306a36Sopenharmony_ci .write_data_h2c = rtw_usb_write_data_h2c, 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int rtw_usb_init_rx(struct rtw_dev *rtwdev) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 74362306a36Sopenharmony_ci int i; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); 74662306a36Sopenharmony_ci if (!rtwusb->rxwq) { 74762306a36Sopenharmony_ci rtw_err(rtwdev, "failed to create RX work queue\n"); 74862306a36Sopenharmony_ci return -ENOMEM; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci skb_queue_head_init(&rtwusb->rx_queue); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 75662306a36Sopenharmony_ci struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci rtw_usb_rx_resubmit(rtwusb, rxcb); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic void rtw_usb_deinit_rx(struct rtw_dev *rtwdev) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci skb_queue_purge(&rtwusb->rx_queue); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci flush_workqueue(rtwusb->rxwq); 77162306a36Sopenharmony_ci destroy_workqueue(rtwusb->rxwq); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int rtw_usb_init_tx(struct rtw_dev *rtwdev) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 77762306a36Sopenharmony_ci int i; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq"); 78062306a36Sopenharmony_ci if (!rtwusb->txwq) { 78162306a36Sopenharmony_ci rtw_err(rtwdev, "failed to create TX work queue\n"); 78262306a36Sopenharmony_ci return -ENOMEM; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) 78662306a36Sopenharmony_ci skb_queue_head_init(&rtwusb->tx_queue[i]); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci return 0; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void rtw_usb_deinit_tx(struct rtw_dev *rtwdev) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci rtw_usb_tx_queue_purge(rtwusb); 79862306a36Sopenharmony_ci flush_workqueue(rtwusb->txwq); 79962306a36Sopenharmony_ci destroy_workqueue(rtwusb->txwq); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic int rtw_usb_intf_init(struct rtw_dev *rtwdev, 80362306a36Sopenharmony_ci struct usb_interface *intf) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 80662306a36Sopenharmony_ci struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf)); 80762306a36Sopenharmony_ci int ret; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci rtwusb->udev = udev; 81062306a36Sopenharmony_ci ret = rtw_usb_parse(rtwdev, intf); 81162306a36Sopenharmony_ci if (ret) 81262306a36Sopenharmony_ci return ret; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci rtwusb->usb_data = kcalloc(RTW_USB_MAX_RXTX_COUNT, sizeof(u32), 81562306a36Sopenharmony_ci GFP_KERNEL); 81662306a36Sopenharmony_ci if (!rtwusb->usb_data) 81762306a36Sopenharmony_ci return -ENOMEM; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci usb_set_intfdata(intf, rtwdev->hw); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); 82262306a36Sopenharmony_ci spin_lock_init(&rtwusb->usb_lock); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return 0; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic void rtw_usb_intf_deinit(struct rtw_dev *rtwdev, 82862306a36Sopenharmony_ci struct usb_interface *intf) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci usb_put_dev(rtwusb->udev); 83362306a36Sopenharmony_ci kfree(rtwusb->usb_data); 83462306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ciint rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct rtw_dev *rtwdev; 84062306a36Sopenharmony_ci struct ieee80211_hw *hw; 84162306a36Sopenharmony_ci struct rtw_usb *rtwusb; 84262306a36Sopenharmony_ci int drv_data_size; 84362306a36Sopenharmony_ci int ret; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb); 84662306a36Sopenharmony_ci hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops); 84762306a36Sopenharmony_ci if (!hw) 84862306a36Sopenharmony_ci return -ENOMEM; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci rtwdev = hw->priv; 85162306a36Sopenharmony_ci rtwdev->hw = hw; 85262306a36Sopenharmony_ci rtwdev->dev = &intf->dev; 85362306a36Sopenharmony_ci rtwdev->chip = (struct rtw_chip_info *)id->driver_info; 85462306a36Sopenharmony_ci rtwdev->hci.ops = &rtw_usb_ops; 85562306a36Sopenharmony_ci rtwdev->hci.type = RTW_HCI_TYPE_USB; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci rtwusb = rtw_get_usb_priv(rtwdev); 85862306a36Sopenharmony_ci rtwusb->rtwdev = rtwdev; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci ret = rtw_usb_alloc_rx_bufs(rtwusb); 86162306a36Sopenharmony_ci if (ret) 86262306a36Sopenharmony_ci goto err_release_hw; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ret = rtw_core_init(rtwdev); 86562306a36Sopenharmony_ci if (ret) 86662306a36Sopenharmony_ci goto err_free_rx_bufs; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci ret = rtw_usb_intf_init(rtwdev, intf); 86962306a36Sopenharmony_ci if (ret) { 87062306a36Sopenharmony_ci rtw_err(rtwdev, "failed to init USB interface\n"); 87162306a36Sopenharmony_ci goto err_deinit_core; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ret = rtw_usb_init_tx(rtwdev); 87562306a36Sopenharmony_ci if (ret) { 87662306a36Sopenharmony_ci rtw_err(rtwdev, "failed to init USB TX\n"); 87762306a36Sopenharmony_ci goto err_destroy_usb; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci ret = rtw_usb_init_rx(rtwdev); 88162306a36Sopenharmony_ci if (ret) { 88262306a36Sopenharmony_ci rtw_err(rtwdev, "failed to init USB RX\n"); 88362306a36Sopenharmony_ci goto err_destroy_txwq; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci ret = rtw_chip_info_setup(rtwdev); 88762306a36Sopenharmony_ci if (ret) { 88862306a36Sopenharmony_ci rtw_err(rtwdev, "failed to setup chip information\n"); 88962306a36Sopenharmony_ci goto err_destroy_rxwq; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci ret = rtw_register_hw(rtwdev, rtwdev->hw); 89362306a36Sopenharmony_ci if (ret) { 89462306a36Sopenharmony_ci rtw_err(rtwdev, "failed to register hw\n"); 89562306a36Sopenharmony_ci goto err_destroy_rxwq; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cierr_destroy_rxwq: 90162306a36Sopenharmony_ci rtw_usb_deinit_rx(rtwdev); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cierr_destroy_txwq: 90462306a36Sopenharmony_ci rtw_usb_deinit_tx(rtwdev); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cierr_destroy_usb: 90762306a36Sopenharmony_ci rtw_usb_intf_deinit(rtwdev, intf); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cierr_deinit_core: 91062306a36Sopenharmony_ci rtw_core_deinit(rtwdev); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cierr_free_rx_bufs: 91362306a36Sopenharmony_ci rtw_usb_free_rx_bufs(rtwusb); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cierr_release_hw: 91662306a36Sopenharmony_ci ieee80211_free_hw(hw); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci return ret; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_usb_probe); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_civoid rtw_usb_disconnect(struct usb_interface *intf) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(intf); 92562306a36Sopenharmony_ci struct rtw_dev *rtwdev; 92662306a36Sopenharmony_ci struct rtw_usb *rtwusb; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (!hw) 92962306a36Sopenharmony_ci return; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci rtwdev = hw->priv; 93262306a36Sopenharmony_ci rtwusb = rtw_get_usb_priv(rtwdev); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci rtw_usb_cancel_rx_bufs(rtwusb); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci rtw_unregister_hw(rtwdev, hw); 93762306a36Sopenharmony_ci rtw_usb_deinit_tx(rtwdev); 93862306a36Sopenharmony_ci rtw_usb_deinit_rx(rtwdev); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (rtwusb->udev->state != USB_STATE_NOTATTACHED) 94162306a36Sopenharmony_ci usb_reset_device(rtwusb->udev); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci rtw_usb_free_rx_bufs(rtwusb); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci rtw_usb_intf_deinit(rtwdev, intf); 94662306a36Sopenharmony_ci rtw_core_deinit(rtwdev); 94762306a36Sopenharmony_ci ieee80211_free_hw(hw); 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_usb_disconnect); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ciMODULE_AUTHOR("Realtek Corporation"); 95262306a36Sopenharmony_ciMODULE_DESCRIPTION("Realtek USB 802.11ac wireless driver"); 95362306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 954