// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include "main.h"
#include "debug.h"
#include "reg.h"
#include "tx.h"
#include "rx.h"
#include "fw.h"
#include "ps.h"
#include "usb.h"
#define RTW_USB_MAX_RXQ_LEN 512
struct rtw_usb_txcb {
struct rtw_dev *rtwdev;
struct sk_buff_head tx_ack_queue;
};
static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb,
struct sk_buff *skb, int agg_num)
{
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
struct rtw_dev *rtwdev = rtwusb->rtwdev;
struct rtw_tx_pkt_info pkt_info;
le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM);
pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET);
rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data);
}
static void rtw_usb_reg_sec(struct rtw_dev *rtwdev, u32 addr, __le32 *data)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_device *udev = rtwusb->udev;
bool reg_on_section = false;
u16 t_reg = 0x4e0;
u8 t_len = 1;
int status;
/* There are three sections:
* 1. on (0x00~0xFF; 0x1000~0x10FF): this section is always powered on
* 2. off (< 0xFE00, excluding "on" section): this section could be
* powered off
* 3. local (>= 0xFE00): usb specific registers section
*/
if (addr <= 0xff || (addr >= 0x1000 && addr <= 0x10ff))
reg_on_section = true;
if (!reg_on_section)
return;
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
t_reg, 0, data, t_len, 500);
if (status != t_len && status != -ENODEV)
rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n",
__func__, t_reg, t_len, status);
}
static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_device *udev = rtwusb->udev;
__le32 *data;
unsigned long flags;
int idx, ret;
static int count;
spin_lock_irqsave(&rtwusb->usb_lock, flags);
idx = rtwusb->usb_data_index;
rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
data = &rtwusb->usb_data[idx];
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
RTW_USB_VENQT_CMD_IDX, data, len, 1000);
if (ret < 0 && ret != -ENODEV && count++ < 4)
rtw_err(rtwdev, "read register 0x%x failed with %d\n",
addr, ret);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C ||
rtwdev->chip->id == RTW_CHIP_TYPE_8822B ||
rtwdev->chip->id == RTW_CHIP_TYPE_8821C)
rtw_usb_reg_sec(rtwdev, addr, data);
return le32_to_cpu(*data);
}
static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr)
{
return (u8)rtw_usb_read(rtwdev, addr, 1);
}
static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr)
{
return (u16)rtw_usb_read(rtwdev, addr, 2);
}
static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr)
{
return (u32)rtw_usb_read(rtwdev, addr, 4);
}
static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len)
{
struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv;
struct usb_device *udev = rtwusb->udev;
unsigned long flags;
__le32 *data;
int idx, ret;
static int count;
spin_lock_irqsave(&rtwusb->usb_lock, flags);
idx = rtwusb->usb_data_index;
rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
data = &rtwusb->usb_data[idx];
*data = cpu_to_le32(val);
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
addr, 0, data, len, 30000);
if (ret < 0 && ret != -ENODEV && count++ < 4)
rtw_err(rtwdev, "write register 0x%x failed with %d\n",
addr, ret);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C ||
rtwdev->chip->id == RTW_CHIP_TYPE_8822B ||
rtwdev->chip->id == RTW_CHIP_TYPE_8821C)
rtw_usb_reg_sec(rtwdev, addr, data);
}
static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
{
rtw_usb_write(rtwdev, addr, val, 1);
}
static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
{
rtw_usb_write(rtwdev, addr, val, 2);
}
static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
{
rtw_usb_write(rtwdev, addr, val, 4);
}
static int dma_mapping_to_ep(