190aac0d8SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 290aac0d8SBjoern A. Zeeb /* Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 390aac0d8SBjoern A. Zeeb * Copyright (C) 2021 Jernej Skrabec <jernej.skrabec@gmail.com> 490aac0d8SBjoern A. Zeeb * 590aac0d8SBjoern A. Zeeb * Based on rtw88/pci.c: 690aac0d8SBjoern A. Zeeb * Copyright(c) 2018-2019 Realtek Corporation 790aac0d8SBjoern A. Zeeb */ 890aac0d8SBjoern A. Zeeb 990aac0d8SBjoern A. Zeeb #include <linux/module.h> 1090aac0d8SBjoern A. Zeeb #include <linux/mmc/host.h> 1190aac0d8SBjoern A. Zeeb #include <linux/mmc/sdio_func.h> 1290aac0d8SBjoern A. Zeeb #include "main.h" 1390aac0d8SBjoern A. Zeeb #include "debug.h" 1490aac0d8SBjoern A. Zeeb #include "fw.h" 1590aac0d8SBjoern A. Zeeb #include "ps.h" 1690aac0d8SBjoern A. Zeeb #include "reg.h" 1790aac0d8SBjoern A. Zeeb #include "rx.h" 1890aac0d8SBjoern A. Zeeb #include "sdio.h" 1990aac0d8SBjoern A. Zeeb #include "tx.h" 2090aac0d8SBjoern A. Zeeb 2190aac0d8SBjoern A. Zeeb #define RTW_SDIO_INDIRECT_RW_RETRIES 50 2290aac0d8SBjoern A. Zeeb 2390aac0d8SBjoern A. Zeeb static bool rtw_sdio_is_bus_addr(u32 addr) 2490aac0d8SBjoern A. Zeeb { 2590aac0d8SBjoern A. Zeeb return !!(addr & RTW_SDIO_BUS_MSK); 2690aac0d8SBjoern A. Zeeb } 2790aac0d8SBjoern A. Zeeb 2890aac0d8SBjoern A. Zeeb static bool rtw_sdio_bus_claim_needed(struct rtw_sdio *rtwsdio) 2990aac0d8SBjoern A. Zeeb { 3090aac0d8SBjoern A. Zeeb return !rtwsdio->irq_thread || 3190aac0d8SBjoern A. Zeeb rtwsdio->irq_thread != current; 3290aac0d8SBjoern A. Zeeb } 3390aac0d8SBjoern A. Zeeb 3490aac0d8SBjoern A. Zeeb static u32 rtw_sdio_to_bus_offset(struct rtw_dev *rtwdev, u32 addr) 3590aac0d8SBjoern A. Zeeb { 3690aac0d8SBjoern A. Zeeb switch (addr & RTW_SDIO_BUS_MSK) { 3790aac0d8SBjoern A. Zeeb case WLAN_IOREG_OFFSET: 3890aac0d8SBjoern A. Zeeb addr &= WLAN_IOREG_REG_MSK; 3990aac0d8SBjoern A. Zeeb addr |= FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 4090aac0d8SBjoern A. Zeeb REG_SDIO_CMD_ADDR_MAC_REG); 4190aac0d8SBjoern A. Zeeb break; 4290aac0d8SBjoern A. Zeeb case SDIO_LOCAL_OFFSET: 4390aac0d8SBjoern A. Zeeb addr &= SDIO_LOCAL_REG_MSK; 4490aac0d8SBjoern A. Zeeb addr |= FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 4590aac0d8SBjoern A. Zeeb REG_SDIO_CMD_ADDR_SDIO_REG); 4690aac0d8SBjoern A. Zeeb break; 4790aac0d8SBjoern A. Zeeb default: 4890aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "Cannot convert addr 0x%08x to bus offset", 4990aac0d8SBjoern A. Zeeb addr); 5090aac0d8SBjoern A. Zeeb } 5190aac0d8SBjoern A. Zeeb 5290aac0d8SBjoern A. Zeeb return addr; 5390aac0d8SBjoern A. Zeeb } 5490aac0d8SBjoern A. Zeeb 5590aac0d8SBjoern A. Zeeb static bool rtw_sdio_use_memcpy_io(struct rtw_dev *rtwdev, u32 addr, 5690aac0d8SBjoern A. Zeeb u8 alignment) 5790aac0d8SBjoern A. Zeeb { 5890aac0d8SBjoern A. Zeeb return IS_ALIGNED(addr, alignment) && 5990aac0d8SBjoern A. Zeeb test_bit(RTW_FLAG_POWERON, rtwdev->flags); 6090aac0d8SBjoern A. Zeeb } 6190aac0d8SBjoern A. Zeeb 6290aac0d8SBjoern A. Zeeb static void rtw_sdio_writel(struct rtw_dev *rtwdev, u32 val, u32 addr, 6390aac0d8SBjoern A. Zeeb int *err_ret) 6490aac0d8SBjoern A. Zeeb { 6590aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 6690aac0d8SBjoern A. Zeeb u8 buf[4]; 6790aac0d8SBjoern A. Zeeb int i; 6890aac0d8SBjoern A. Zeeb 6990aac0d8SBjoern A. Zeeb if (rtw_sdio_use_memcpy_io(rtwdev, addr, 4)) { 7090aac0d8SBjoern A. Zeeb sdio_writel(rtwsdio->sdio_func, val, addr, err_ret); 7190aac0d8SBjoern A. Zeeb return; 7290aac0d8SBjoern A. Zeeb } 7390aac0d8SBjoern A. Zeeb 7490aac0d8SBjoern A. Zeeb *(__le32 *)buf = cpu_to_le32(val); 7590aac0d8SBjoern A. Zeeb 7690aac0d8SBjoern A. Zeeb for (i = 0; i < 4; i++) { 7790aac0d8SBjoern A. Zeeb sdio_writeb(rtwsdio->sdio_func, buf[i], addr + i, err_ret); 7890aac0d8SBjoern A. Zeeb if (*err_ret) 7990aac0d8SBjoern A. Zeeb return; 8090aac0d8SBjoern A. Zeeb } 8190aac0d8SBjoern A. Zeeb } 8290aac0d8SBjoern A. Zeeb 8390aac0d8SBjoern A. Zeeb static void rtw_sdio_writew(struct rtw_dev *rtwdev, u16 val, u32 addr, 8490aac0d8SBjoern A. Zeeb int *err_ret) 8590aac0d8SBjoern A. Zeeb { 8690aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 8790aac0d8SBjoern A. Zeeb u8 buf[2]; 8890aac0d8SBjoern A. Zeeb int i; 8990aac0d8SBjoern A. Zeeb 9090aac0d8SBjoern A. Zeeb *(__le16 *)buf = cpu_to_le16(val); 9190aac0d8SBjoern A. Zeeb 9290aac0d8SBjoern A. Zeeb for (i = 0; i < 2; i++) { 9390aac0d8SBjoern A. Zeeb sdio_writeb(rtwsdio->sdio_func, buf[i], addr + i, err_ret); 9490aac0d8SBjoern A. Zeeb if (*err_ret) 9590aac0d8SBjoern A. Zeeb return; 9690aac0d8SBjoern A. Zeeb } 9790aac0d8SBjoern A. Zeeb } 9890aac0d8SBjoern A. Zeeb 9990aac0d8SBjoern A. Zeeb static u32 rtw_sdio_readl(struct rtw_dev *rtwdev, u32 addr, int *err_ret) 10090aac0d8SBjoern A. Zeeb { 10190aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 10290aac0d8SBjoern A. Zeeb u8 buf[4]; 10390aac0d8SBjoern A. Zeeb int i; 10490aac0d8SBjoern A. Zeeb 10590aac0d8SBjoern A. Zeeb if (rtw_sdio_use_memcpy_io(rtwdev, addr, 4)) 10690aac0d8SBjoern A. Zeeb return sdio_readl(rtwsdio->sdio_func, addr, err_ret); 10790aac0d8SBjoern A. Zeeb 10890aac0d8SBjoern A. Zeeb for (i = 0; i < 4; i++) { 10990aac0d8SBjoern A. Zeeb buf[i] = sdio_readb(rtwsdio->sdio_func, addr + i, err_ret); 11090aac0d8SBjoern A. Zeeb if (*err_ret) 11190aac0d8SBjoern A. Zeeb return 0; 11290aac0d8SBjoern A. Zeeb } 11390aac0d8SBjoern A. Zeeb 11490aac0d8SBjoern A. Zeeb return le32_to_cpu(*(__le32 *)buf); 11590aac0d8SBjoern A. Zeeb } 11690aac0d8SBjoern A. Zeeb 11790aac0d8SBjoern A. Zeeb static u16 rtw_sdio_readw(struct rtw_dev *rtwdev, u32 addr, int *err_ret) 11890aac0d8SBjoern A. Zeeb { 11990aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 12090aac0d8SBjoern A. Zeeb u8 buf[2]; 12190aac0d8SBjoern A. Zeeb int i; 12290aac0d8SBjoern A. Zeeb 12390aac0d8SBjoern A. Zeeb for (i = 0; i < 2; i++) { 12490aac0d8SBjoern A. Zeeb buf[i] = sdio_readb(rtwsdio->sdio_func, addr + i, err_ret); 12590aac0d8SBjoern A. Zeeb if (*err_ret) 12690aac0d8SBjoern A. Zeeb return 0; 12790aac0d8SBjoern A. Zeeb } 12890aac0d8SBjoern A. Zeeb 12990aac0d8SBjoern A. Zeeb return le16_to_cpu(*(__le16 *)buf); 13090aac0d8SBjoern A. Zeeb } 13190aac0d8SBjoern A. Zeeb 13290aac0d8SBjoern A. Zeeb static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, 13390aac0d8SBjoern A. Zeeb bool direct) 13490aac0d8SBjoern A. Zeeb { 13590aac0d8SBjoern A. Zeeb if (!direct) 13690aac0d8SBjoern A. Zeeb return addr; 13790aac0d8SBjoern A. Zeeb 13890aac0d8SBjoern A. Zeeb if (!rtw_sdio_is_bus_addr(addr)) 13990aac0d8SBjoern A. Zeeb addr |= WLAN_IOREG_OFFSET; 14090aac0d8SBjoern A. Zeeb 14190aac0d8SBjoern A. Zeeb return rtw_sdio_to_bus_offset(rtwdev, addr); 14290aac0d8SBjoern A. Zeeb } 14390aac0d8SBjoern A. Zeeb 14490aac0d8SBjoern A. Zeeb static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) 14590aac0d8SBjoern A. Zeeb { 14690aac0d8SBjoern A. Zeeb return !rtw_sdio_is_sdio30_supported(rtwdev) || 14790aac0d8SBjoern A. Zeeb rtw_sdio_is_bus_addr(addr); 14890aac0d8SBjoern A. Zeeb } 14990aac0d8SBjoern A. Zeeb 15090aac0d8SBjoern A. Zeeb static int rtw_sdio_indirect_reg_cfg(struct rtw_dev *rtwdev, u32 addr, u32 cfg) 15190aac0d8SBjoern A. Zeeb { 15290aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 15390aac0d8SBjoern A. Zeeb unsigned int retry; 15490aac0d8SBjoern A. Zeeb u32 reg_cfg; 15590aac0d8SBjoern A. Zeeb int ret; 15690aac0d8SBjoern A. Zeeb u8 tmp; 15790aac0d8SBjoern A. Zeeb 15890aac0d8SBjoern A. Zeeb reg_cfg = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_CFG); 15990aac0d8SBjoern A. Zeeb 16090aac0d8SBjoern A. Zeeb rtw_sdio_writel(rtwdev, addr | cfg | BIT_SDIO_INDIRECT_REG_CFG_UNK20, 16190aac0d8SBjoern A. Zeeb reg_cfg, &ret); 16290aac0d8SBjoern A. Zeeb if (ret) 16390aac0d8SBjoern A. Zeeb return ret; 16490aac0d8SBjoern A. Zeeb 16590aac0d8SBjoern A. Zeeb for (retry = 0; retry < RTW_SDIO_INDIRECT_RW_RETRIES; retry++) { 16690aac0d8SBjoern A. Zeeb tmp = sdio_readb(rtwsdio->sdio_func, reg_cfg + 2, &ret); 16790aac0d8SBjoern A. Zeeb if (!ret && (tmp & BIT(4))) 16890aac0d8SBjoern A. Zeeb return 0; 16990aac0d8SBjoern A. Zeeb } 17090aac0d8SBjoern A. Zeeb 17190aac0d8SBjoern A. Zeeb return -ETIMEDOUT; 17290aac0d8SBjoern A. Zeeb } 17390aac0d8SBjoern A. Zeeb 17490aac0d8SBjoern A. Zeeb static u8 rtw_sdio_indirect_read8(struct rtw_dev *rtwdev, u32 addr, 17590aac0d8SBjoern A. Zeeb int *err_ret) 17690aac0d8SBjoern A. Zeeb { 17790aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 17890aac0d8SBjoern A. Zeeb u32 reg_data; 17990aac0d8SBjoern A. Zeeb 18090aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 18190aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_READ); 18290aac0d8SBjoern A. Zeeb if (*err_ret) 18390aac0d8SBjoern A. Zeeb return 0; 18490aac0d8SBjoern A. Zeeb 18590aac0d8SBjoern A. Zeeb reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 18690aac0d8SBjoern A. Zeeb return sdio_readb(rtwsdio->sdio_func, reg_data, err_ret); 18790aac0d8SBjoern A. Zeeb } 18890aac0d8SBjoern A. Zeeb 18990aac0d8SBjoern A. Zeeb static int rtw_sdio_indirect_read_bytes(struct rtw_dev *rtwdev, u32 addr, 19090aac0d8SBjoern A. Zeeb u8 *buf, int count) 19190aac0d8SBjoern A. Zeeb { 19290aac0d8SBjoern A. Zeeb int i, ret = 0; 19390aac0d8SBjoern A. Zeeb 19490aac0d8SBjoern A. Zeeb for (i = 0; i < count; i++) { 19590aac0d8SBjoern A. Zeeb buf[i] = rtw_sdio_indirect_read8(rtwdev, addr + i, &ret); 19690aac0d8SBjoern A. Zeeb if (ret) 19790aac0d8SBjoern A. Zeeb break; 19890aac0d8SBjoern A. Zeeb } 19990aac0d8SBjoern A. Zeeb 20090aac0d8SBjoern A. Zeeb return ret; 20190aac0d8SBjoern A. Zeeb } 20290aac0d8SBjoern A. Zeeb 20390aac0d8SBjoern A. Zeeb static u16 rtw_sdio_indirect_read16(struct rtw_dev *rtwdev, u32 addr, 20490aac0d8SBjoern A. Zeeb int *err_ret) 20590aac0d8SBjoern A. Zeeb { 20690aac0d8SBjoern A. Zeeb u32 reg_data; 20790aac0d8SBjoern A. Zeeb u8 buf[2]; 20890aac0d8SBjoern A. Zeeb 20990aac0d8SBjoern A. Zeeb if (!IS_ALIGNED(addr, 2)) { 21090aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_read_bytes(rtwdev, addr, buf, 2); 21190aac0d8SBjoern A. Zeeb if (*err_ret) 21290aac0d8SBjoern A. Zeeb return 0; 21390aac0d8SBjoern A. Zeeb 21490aac0d8SBjoern A. Zeeb return le16_to_cpu(*(__le16 *)buf); 21590aac0d8SBjoern A. Zeeb } 21690aac0d8SBjoern A. Zeeb 21790aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 21890aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_READ); 21990aac0d8SBjoern A. Zeeb if (*err_ret) 22090aac0d8SBjoern A. Zeeb return 0; 22190aac0d8SBjoern A. Zeeb 22290aac0d8SBjoern A. Zeeb reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 22390aac0d8SBjoern A. Zeeb return rtw_sdio_readw(rtwdev, reg_data, err_ret); 22490aac0d8SBjoern A. Zeeb } 22590aac0d8SBjoern A. Zeeb 22690aac0d8SBjoern A. Zeeb static u32 rtw_sdio_indirect_read32(struct rtw_dev *rtwdev, u32 addr, 22790aac0d8SBjoern A. Zeeb int *err_ret) 22890aac0d8SBjoern A. Zeeb { 22990aac0d8SBjoern A. Zeeb u32 reg_data; 23090aac0d8SBjoern A. Zeeb u8 buf[4]; 23190aac0d8SBjoern A. Zeeb 23290aac0d8SBjoern A. Zeeb if (!IS_ALIGNED(addr, 4)) { 23390aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_read_bytes(rtwdev, addr, buf, 4); 23490aac0d8SBjoern A. Zeeb if (*err_ret) 23590aac0d8SBjoern A. Zeeb return 0; 23690aac0d8SBjoern A. Zeeb 23790aac0d8SBjoern A. Zeeb return le32_to_cpu(*(__le32 *)buf); 23890aac0d8SBjoern A. Zeeb } 23990aac0d8SBjoern A. Zeeb 24090aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 24190aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_READ); 24290aac0d8SBjoern A. Zeeb if (*err_ret) 24390aac0d8SBjoern A. Zeeb return 0; 24490aac0d8SBjoern A. Zeeb 24590aac0d8SBjoern A. Zeeb reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 24690aac0d8SBjoern A. Zeeb return rtw_sdio_readl(rtwdev, reg_data, err_ret); 24790aac0d8SBjoern A. Zeeb } 24890aac0d8SBjoern A. Zeeb 24990aac0d8SBjoern A. Zeeb static u8 rtw_sdio_read8(struct rtw_dev *rtwdev, u32 addr) 25090aac0d8SBjoern A. Zeeb { 25190aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 25290aac0d8SBjoern A. Zeeb bool direct, bus_claim; 25390aac0d8SBjoern A. Zeeb int ret; 25490aac0d8SBjoern A. Zeeb u8 val; 25590aac0d8SBjoern A. Zeeb 25690aac0d8SBjoern A. Zeeb direct = rtw_sdio_use_direct_io(rtwdev, addr); 25790aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 25890aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 25990aac0d8SBjoern A. Zeeb 26090aac0d8SBjoern A. Zeeb if (bus_claim) 26190aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 26290aac0d8SBjoern A. Zeeb 26390aac0d8SBjoern A. Zeeb if (direct) 26490aac0d8SBjoern A. Zeeb val = sdio_readb(rtwsdio->sdio_func, addr, &ret); 26590aac0d8SBjoern A. Zeeb else 26690aac0d8SBjoern A. Zeeb val = rtw_sdio_indirect_read8(rtwdev, addr, &ret); 26790aac0d8SBjoern A. Zeeb 26890aac0d8SBjoern A. Zeeb if (bus_claim) 26990aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 27090aac0d8SBjoern A. Zeeb 27190aac0d8SBjoern A. Zeeb if (ret) 27290aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "sdio read8 failed (0x%x): %d", addr, ret); 27390aac0d8SBjoern A. Zeeb 27490aac0d8SBjoern A. Zeeb return val; 27590aac0d8SBjoern A. Zeeb } 27690aac0d8SBjoern A. Zeeb 27790aac0d8SBjoern A. Zeeb static u16 rtw_sdio_read16(struct rtw_dev *rtwdev, u32 addr) 27890aac0d8SBjoern A. Zeeb { 27990aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 28090aac0d8SBjoern A. Zeeb bool direct, bus_claim; 28190aac0d8SBjoern A. Zeeb int ret; 28290aac0d8SBjoern A. Zeeb u16 val; 28390aac0d8SBjoern A. Zeeb 28490aac0d8SBjoern A. Zeeb direct = rtw_sdio_use_direct_io(rtwdev, addr); 28590aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 28690aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 28790aac0d8SBjoern A. Zeeb 28890aac0d8SBjoern A. Zeeb if (bus_claim) 28990aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 29090aac0d8SBjoern A. Zeeb 29190aac0d8SBjoern A. Zeeb if (direct) 29290aac0d8SBjoern A. Zeeb val = rtw_sdio_readw(rtwdev, addr, &ret); 29390aac0d8SBjoern A. Zeeb else 29490aac0d8SBjoern A. Zeeb val = rtw_sdio_indirect_read16(rtwdev, addr, &ret); 29590aac0d8SBjoern A. Zeeb 29690aac0d8SBjoern A. Zeeb if (bus_claim) 29790aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 29890aac0d8SBjoern A. Zeeb 29990aac0d8SBjoern A. Zeeb if (ret) 30090aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "sdio read16 failed (0x%x): %d", addr, ret); 30190aac0d8SBjoern A. Zeeb 30290aac0d8SBjoern A. Zeeb return val; 30390aac0d8SBjoern A. Zeeb } 30490aac0d8SBjoern A. Zeeb 30590aac0d8SBjoern A. Zeeb static u32 rtw_sdio_read32(struct rtw_dev *rtwdev, u32 addr) 30690aac0d8SBjoern A. Zeeb { 30790aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 30890aac0d8SBjoern A. Zeeb bool direct, bus_claim; 30990aac0d8SBjoern A. Zeeb u32 val; 31090aac0d8SBjoern A. Zeeb int ret; 31190aac0d8SBjoern A. Zeeb 31290aac0d8SBjoern A. Zeeb direct = rtw_sdio_use_direct_io(rtwdev, addr); 31390aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 31490aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 31590aac0d8SBjoern A. Zeeb 31690aac0d8SBjoern A. Zeeb if (bus_claim) 31790aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 31890aac0d8SBjoern A. Zeeb 31990aac0d8SBjoern A. Zeeb if (direct) 32090aac0d8SBjoern A. Zeeb val = rtw_sdio_readl(rtwdev, addr, &ret); 32190aac0d8SBjoern A. Zeeb else 32290aac0d8SBjoern A. Zeeb val = rtw_sdio_indirect_read32(rtwdev, addr, &ret); 32390aac0d8SBjoern A. Zeeb 32490aac0d8SBjoern A. Zeeb if (bus_claim) 32590aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 32690aac0d8SBjoern A. Zeeb 32790aac0d8SBjoern A. Zeeb if (ret) 32890aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "sdio read32 failed (0x%x): %d", addr, ret); 32990aac0d8SBjoern A. Zeeb 33090aac0d8SBjoern A. Zeeb return val; 33190aac0d8SBjoern A. Zeeb } 33290aac0d8SBjoern A. Zeeb 33390aac0d8SBjoern A. Zeeb static void rtw_sdio_indirect_write8(struct rtw_dev *rtwdev, u8 val, u32 addr, 33490aac0d8SBjoern A. Zeeb int *err_ret) 33590aac0d8SBjoern A. Zeeb { 33690aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 33790aac0d8SBjoern A. Zeeb u32 reg_data; 33890aac0d8SBjoern A. Zeeb 33990aac0d8SBjoern A. Zeeb reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 34090aac0d8SBjoern A. Zeeb sdio_writeb(rtwsdio->sdio_func, val, reg_data, err_ret); 34190aac0d8SBjoern A. Zeeb if (*err_ret) 34290aac0d8SBjoern A. Zeeb return; 34390aac0d8SBjoern A. Zeeb 34490aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 34590aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_WRITE); 34690aac0d8SBjoern A. Zeeb } 34790aac0d8SBjoern A. Zeeb 34890aac0d8SBjoern A. Zeeb static void rtw_sdio_indirect_write16(struct rtw_dev *rtwdev, u16 val, u32 addr, 34990aac0d8SBjoern A. Zeeb int *err_ret) 35090aac0d8SBjoern A. Zeeb { 35190aac0d8SBjoern A. Zeeb u32 reg_data; 35290aac0d8SBjoern A. Zeeb 35390aac0d8SBjoern A. Zeeb if (!IS_ALIGNED(addr, 2)) { 35490aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, true); 35590aac0d8SBjoern A. Zeeb rtw_sdio_writew(rtwdev, val, addr, err_ret); 35690aac0d8SBjoern A. Zeeb return; 35790aac0d8SBjoern A. Zeeb } 35890aac0d8SBjoern A. Zeeb 35990aac0d8SBjoern A. Zeeb reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 36090aac0d8SBjoern A. Zeeb rtw_sdio_writew(rtwdev, val, reg_data, err_ret); 36190aac0d8SBjoern A. Zeeb if (*err_ret) 36290aac0d8SBjoern A. Zeeb return; 36390aac0d8SBjoern A. Zeeb 36490aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 36590aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_WRITE | 36690aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_WORD); 36790aac0d8SBjoern A. Zeeb } 36890aac0d8SBjoern A. Zeeb 36990aac0d8SBjoern A. Zeeb static void rtw_sdio_indirect_write32(struct rtw_dev *rtwdev, u32 val, 37090aac0d8SBjoern A. Zeeb u32 addr, int *err_ret) 37190aac0d8SBjoern A. Zeeb { 37290aac0d8SBjoern A. Zeeb u32 reg_data; 37390aac0d8SBjoern A. Zeeb 37490aac0d8SBjoern A. Zeeb if (!IS_ALIGNED(addr, 4)) { 37590aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, true); 37690aac0d8SBjoern A. Zeeb rtw_sdio_writel(rtwdev, val, addr, err_ret); 37790aac0d8SBjoern A. Zeeb return; 37890aac0d8SBjoern A. Zeeb } 37990aac0d8SBjoern A. Zeeb 38090aac0d8SBjoern A. Zeeb reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 38190aac0d8SBjoern A. Zeeb rtw_sdio_writel(rtwdev, val, reg_data, err_ret); 38290aac0d8SBjoern A. Zeeb 38390aac0d8SBjoern A. Zeeb *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 38490aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_WRITE | 38590aac0d8SBjoern A. Zeeb BIT_SDIO_INDIRECT_REG_CFG_DWORD); 38690aac0d8SBjoern A. Zeeb } 38790aac0d8SBjoern A. Zeeb 38890aac0d8SBjoern A. Zeeb static void rtw_sdio_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) 38990aac0d8SBjoern A. Zeeb { 39090aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 39190aac0d8SBjoern A. Zeeb bool direct, bus_claim; 39290aac0d8SBjoern A. Zeeb int ret; 39390aac0d8SBjoern A. Zeeb 39490aac0d8SBjoern A. Zeeb direct = rtw_sdio_use_direct_io(rtwdev, addr); 39590aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 39690aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 39790aac0d8SBjoern A. Zeeb 39890aac0d8SBjoern A. Zeeb if (bus_claim) 39990aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 40090aac0d8SBjoern A. Zeeb 40190aac0d8SBjoern A. Zeeb if (direct) 40290aac0d8SBjoern A. Zeeb sdio_writeb(rtwsdio->sdio_func, val, addr, &ret); 40390aac0d8SBjoern A. Zeeb else 40490aac0d8SBjoern A. Zeeb rtw_sdio_indirect_write8(rtwdev, val, addr, &ret); 40590aac0d8SBjoern A. Zeeb 40690aac0d8SBjoern A. Zeeb if (bus_claim) 40790aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 40890aac0d8SBjoern A. Zeeb 40990aac0d8SBjoern A. Zeeb if (ret) 41090aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "sdio write8 failed (0x%x): %d", addr, ret); 41190aac0d8SBjoern A. Zeeb } 41290aac0d8SBjoern A. Zeeb 41390aac0d8SBjoern A. Zeeb static void rtw_sdio_write16(struct rtw_dev *rtwdev, u32 addr, u16 val) 41490aac0d8SBjoern A. Zeeb { 41590aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 41690aac0d8SBjoern A. Zeeb bool direct, bus_claim; 41790aac0d8SBjoern A. Zeeb int ret; 41890aac0d8SBjoern A. Zeeb 41990aac0d8SBjoern A. Zeeb direct = rtw_sdio_use_direct_io(rtwdev, addr); 42090aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 42190aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 42290aac0d8SBjoern A. Zeeb 42390aac0d8SBjoern A. Zeeb if (bus_claim) 42490aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 42590aac0d8SBjoern A. Zeeb 42690aac0d8SBjoern A. Zeeb if (direct) 42790aac0d8SBjoern A. Zeeb rtw_sdio_writew(rtwdev, val, addr, &ret); 42890aac0d8SBjoern A. Zeeb else 42990aac0d8SBjoern A. Zeeb rtw_sdio_indirect_write16(rtwdev, val, addr, &ret); 43090aac0d8SBjoern A. Zeeb 43190aac0d8SBjoern A. Zeeb if (bus_claim) 43290aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 43390aac0d8SBjoern A. Zeeb 43490aac0d8SBjoern A. Zeeb if (ret) 43590aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "sdio write16 failed (0x%x): %d", addr, ret); 43690aac0d8SBjoern A. Zeeb } 43790aac0d8SBjoern A. Zeeb 43890aac0d8SBjoern A. Zeeb static void rtw_sdio_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) 43990aac0d8SBjoern A. Zeeb { 44090aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 44190aac0d8SBjoern A. Zeeb bool direct, bus_claim; 44290aac0d8SBjoern A. Zeeb int ret; 44390aac0d8SBjoern A. Zeeb 44490aac0d8SBjoern A. Zeeb direct = rtw_sdio_use_direct_io(rtwdev, addr); 44590aac0d8SBjoern A. Zeeb addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 44690aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 44790aac0d8SBjoern A. Zeeb 44890aac0d8SBjoern A. Zeeb if (bus_claim) 44990aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 45090aac0d8SBjoern A. Zeeb 45190aac0d8SBjoern A. Zeeb if (direct) 45290aac0d8SBjoern A. Zeeb rtw_sdio_writel(rtwdev, val, addr, &ret); 45390aac0d8SBjoern A. Zeeb else 45490aac0d8SBjoern A. Zeeb rtw_sdio_indirect_write32(rtwdev, val, addr, &ret); 45590aac0d8SBjoern A. Zeeb 45690aac0d8SBjoern A. Zeeb if (bus_claim) 45790aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 45890aac0d8SBjoern A. Zeeb 45990aac0d8SBjoern A. Zeeb if (ret) 46090aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "sdio write32 failed (0x%x): %d", addr, ret); 46190aac0d8SBjoern A. Zeeb } 46290aac0d8SBjoern A. Zeeb 46390aac0d8SBjoern A. Zeeb static u32 rtw_sdio_get_tx_addr(struct rtw_dev *rtwdev, size_t size, 46490aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type queue) 46590aac0d8SBjoern A. Zeeb { 46690aac0d8SBjoern A. Zeeb u32 txaddr; 46790aac0d8SBjoern A. Zeeb 46890aac0d8SBjoern A. Zeeb switch (queue) { 46990aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BCN: 47090aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_H2C: 47190aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_HI0: 47290aac0d8SBjoern A. Zeeb txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 47390aac0d8SBjoern A. Zeeb REG_SDIO_CMD_ADDR_TXFF_HIGH); 47490aac0d8SBjoern A. Zeeb break; 47590aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_VI: 47690aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_VO: 47790aac0d8SBjoern A. Zeeb txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 47890aac0d8SBjoern A. Zeeb REG_SDIO_CMD_ADDR_TXFF_NORMAL); 47990aac0d8SBjoern A. Zeeb break; 48090aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BE: 48190aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BK: 48290aac0d8SBjoern A. Zeeb txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 48390aac0d8SBjoern A. Zeeb REG_SDIO_CMD_ADDR_TXFF_LOW); 48490aac0d8SBjoern A. Zeeb break; 48590aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_MGMT: 48690aac0d8SBjoern A. Zeeb txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 48790aac0d8SBjoern A. Zeeb REG_SDIO_CMD_ADDR_TXFF_EXTRA); 48890aac0d8SBjoern A. Zeeb break; 48990aac0d8SBjoern A. Zeeb default: 49090aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "Unsupported queue for TX addr: 0x%02x\n", 49190aac0d8SBjoern A. Zeeb queue); 49290aac0d8SBjoern A. Zeeb return 0; 49390aac0d8SBjoern A. Zeeb } 49490aac0d8SBjoern A. Zeeb 49590aac0d8SBjoern A. Zeeb txaddr += DIV_ROUND_UP(size, 4); 49690aac0d8SBjoern A. Zeeb 49790aac0d8SBjoern A. Zeeb return txaddr; 49890aac0d8SBjoern A. Zeeb }; 49990aac0d8SBjoern A. Zeeb 50090aac0d8SBjoern A. Zeeb static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) 50190aac0d8SBjoern A. Zeeb { 50290aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 503*11c53278SBjoern A. Zeeb struct mmc_host *host = rtwsdio->sdio_func->card->host; 50490aac0d8SBjoern A. Zeeb bool bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 50590aac0d8SBjoern A. Zeeb u32 rxaddr = rtwsdio->rx_addr++; 506*11c53278SBjoern A. Zeeb int ret = 0, err; 507*11c53278SBjoern A. Zeeb size_t bytes; 50890aac0d8SBjoern A. Zeeb 50990aac0d8SBjoern A. Zeeb if (bus_claim) 51090aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 51190aac0d8SBjoern A. Zeeb 512*11c53278SBjoern A. Zeeb while (count > 0) { 513*11c53278SBjoern A. Zeeb bytes = min_t(size_t, host->max_req_size, count); 514*11c53278SBjoern A. Zeeb 515*11c53278SBjoern A. Zeeb err = sdio_memcpy_fromio(rtwsdio->sdio_func, buf, 516*11c53278SBjoern A. Zeeb RTW_SDIO_ADDR_RX_RX0FF_GEN(rxaddr), 517*11c53278SBjoern A. Zeeb bytes); 518*11c53278SBjoern A. Zeeb if (err) { 51990aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, 520*11c53278SBjoern A. Zeeb "Failed to read %zu byte(s) from SDIO port 0x%08x: %d", 521*11c53278SBjoern A. Zeeb bytes, rxaddr, err); 522*11c53278SBjoern A. Zeeb 523*11c53278SBjoern A. Zeeb /* Signal to the caller that reading did not work and 524*11c53278SBjoern A. Zeeb * that the data in the buffer is short/corrupted. 525*11c53278SBjoern A. Zeeb */ 526*11c53278SBjoern A. Zeeb ret = err; 527*11c53278SBjoern A. Zeeb 528*11c53278SBjoern A. Zeeb /* Don't stop here - instead drain the remaining data 529*11c53278SBjoern A. Zeeb * from the card's buffer, else the card will return 530*11c53278SBjoern A. Zeeb * corrupt data for the next rtw_sdio_read_port() call. 531*11c53278SBjoern A. Zeeb */ 532*11c53278SBjoern A. Zeeb } 533*11c53278SBjoern A. Zeeb 534*11c53278SBjoern A. Zeeb count -= bytes; 535*11c53278SBjoern A. Zeeb buf += bytes; 536*11c53278SBjoern A. Zeeb } 53790aac0d8SBjoern A. Zeeb 53890aac0d8SBjoern A. Zeeb if (bus_claim) 53990aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 54090aac0d8SBjoern A. Zeeb 54190aac0d8SBjoern A. Zeeb return ret; 54290aac0d8SBjoern A. Zeeb } 54390aac0d8SBjoern A. Zeeb 54490aac0d8SBjoern A. Zeeb static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, 54590aac0d8SBjoern A. Zeeb size_t count) 54690aac0d8SBjoern A. Zeeb { 54790aac0d8SBjoern A. Zeeb unsigned int pages_free, pages_needed; 54890aac0d8SBjoern A. Zeeb 54990aac0d8SBjoern A. Zeeb if (rtw_chip_wcpu_11n(rtwdev)) { 55090aac0d8SBjoern A. Zeeb u32 free_txpg; 55190aac0d8SBjoern A. Zeeb 55290aac0d8SBjoern A. Zeeb free_txpg = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); 55390aac0d8SBjoern A. Zeeb 55490aac0d8SBjoern A. Zeeb switch (queue) { 55590aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BCN: 55690aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_H2C: 55790aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_HI0: 55890aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_MGMT: 55990aac0d8SBjoern A. Zeeb /* high */ 56090aac0d8SBjoern A. Zeeb pages_free = free_txpg & 0xff; 56190aac0d8SBjoern A. Zeeb break; 56290aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_VI: 56390aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_VO: 56490aac0d8SBjoern A. Zeeb /* normal */ 56590aac0d8SBjoern A. Zeeb pages_free = (free_txpg >> 8) & 0xff; 56690aac0d8SBjoern A. Zeeb break; 56790aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BE: 56890aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BK: 56990aac0d8SBjoern A. Zeeb /* low */ 57090aac0d8SBjoern A. Zeeb pages_free = (free_txpg >> 16) & 0xff; 57190aac0d8SBjoern A. Zeeb break; 57290aac0d8SBjoern A. Zeeb default: 57390aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "Unknown mapping for queue %u\n", queue); 57490aac0d8SBjoern A. Zeeb return -EINVAL; 57590aac0d8SBjoern A. Zeeb } 57690aac0d8SBjoern A. Zeeb 57790aac0d8SBjoern A. Zeeb /* add the pages from the public queue */ 57890aac0d8SBjoern A. Zeeb pages_free += (free_txpg >> 24) & 0xff; 57990aac0d8SBjoern A. Zeeb } else { 58090aac0d8SBjoern A. Zeeb u32 free_txpg[3]; 58190aac0d8SBjoern A. Zeeb 58290aac0d8SBjoern A. Zeeb free_txpg[0] = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); 58390aac0d8SBjoern A. Zeeb free_txpg[1] = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG + 4); 58490aac0d8SBjoern A. Zeeb free_txpg[2] = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG + 8); 58590aac0d8SBjoern A. Zeeb 58690aac0d8SBjoern A. Zeeb switch (queue) { 58790aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BCN: 58890aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_H2C: 58990aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_HI0: 59090aac0d8SBjoern A. Zeeb /* high */ 59190aac0d8SBjoern A. Zeeb pages_free = free_txpg[0] & 0xfff; 59290aac0d8SBjoern A. Zeeb break; 59390aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_VI: 59490aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_VO: 59590aac0d8SBjoern A. Zeeb /* normal */ 59690aac0d8SBjoern A. Zeeb pages_free = (free_txpg[0] >> 16) & 0xfff; 59790aac0d8SBjoern A. Zeeb break; 59890aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BE: 59990aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BK: 60090aac0d8SBjoern A. Zeeb /* low */ 60190aac0d8SBjoern A. Zeeb pages_free = free_txpg[1] & 0xfff; 60290aac0d8SBjoern A. Zeeb break; 60390aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_MGMT: 60490aac0d8SBjoern A. Zeeb /* extra */ 60590aac0d8SBjoern A. Zeeb pages_free = free_txpg[2] & 0xfff; 60690aac0d8SBjoern A. Zeeb break; 60790aac0d8SBjoern A. Zeeb default: 60890aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "Unknown mapping for queue %u\n", queue); 60990aac0d8SBjoern A. Zeeb return -EINVAL; 61090aac0d8SBjoern A. Zeeb } 61190aac0d8SBjoern A. Zeeb 61290aac0d8SBjoern A. Zeeb /* add the pages from the public queue */ 61390aac0d8SBjoern A. Zeeb pages_free += (free_txpg[1] >> 16) & 0xfff; 61490aac0d8SBjoern A. Zeeb } 61590aac0d8SBjoern A. Zeeb 61690aac0d8SBjoern A. Zeeb pages_needed = DIV_ROUND_UP(count, rtwdev->chip->page_size); 61790aac0d8SBjoern A. Zeeb 61890aac0d8SBjoern A. Zeeb if (pages_needed > pages_free) { 61990aac0d8SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_SDIO, 62090aac0d8SBjoern A. Zeeb "Not enough free pages (%u needed, %u free) in queue %u for %zu bytes\n", 62190aac0d8SBjoern A. Zeeb pages_needed, pages_free, queue, count); 62290aac0d8SBjoern A. Zeeb return -EBUSY; 62390aac0d8SBjoern A. Zeeb } 62490aac0d8SBjoern A. Zeeb 62590aac0d8SBjoern A. Zeeb return 0; 62690aac0d8SBjoern A. Zeeb } 62790aac0d8SBjoern A. Zeeb 62890aac0d8SBjoern A. Zeeb static int rtw_sdio_write_port(struct rtw_dev *rtwdev, struct sk_buff *skb, 62990aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type queue) 63090aac0d8SBjoern A. Zeeb { 63190aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 63290aac0d8SBjoern A. Zeeb bool bus_claim; 63390aac0d8SBjoern A. Zeeb size_t txsize; 63490aac0d8SBjoern A. Zeeb u32 txaddr; 63590aac0d8SBjoern A. Zeeb int ret; 63690aac0d8SBjoern A. Zeeb 63790aac0d8SBjoern A. Zeeb txaddr = rtw_sdio_get_tx_addr(rtwdev, skb->len, queue); 63890aac0d8SBjoern A. Zeeb if (!txaddr) 63990aac0d8SBjoern A. Zeeb return -EINVAL; 64090aac0d8SBjoern A. Zeeb 64190aac0d8SBjoern A. Zeeb txsize = sdio_align_size(rtwsdio->sdio_func, skb->len); 64290aac0d8SBjoern A. Zeeb 64390aac0d8SBjoern A. Zeeb ret = rtw_sdio_check_free_txpg(rtwdev, queue, txsize); 64490aac0d8SBjoern A. Zeeb if (ret) 64590aac0d8SBjoern A. Zeeb return ret; 64690aac0d8SBjoern A. Zeeb 64790aac0d8SBjoern A. Zeeb if (!IS_ALIGNED((unsigned long)skb->data, RTW_SDIO_DATA_PTR_ALIGN)) 64890aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "Got unaligned SKB in %s() for queue %u\n", 64990aac0d8SBjoern A. Zeeb __func__, queue); 65090aac0d8SBjoern A. Zeeb 65190aac0d8SBjoern A. Zeeb bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 65290aac0d8SBjoern A. Zeeb 65390aac0d8SBjoern A. Zeeb if (bus_claim) 65490aac0d8SBjoern A. Zeeb sdio_claim_host(rtwsdio->sdio_func); 65590aac0d8SBjoern A. Zeeb 65690aac0d8SBjoern A. Zeeb ret = sdio_memcpy_toio(rtwsdio->sdio_func, txaddr, skb->data, txsize); 65790aac0d8SBjoern A. Zeeb 65890aac0d8SBjoern A. Zeeb if (bus_claim) 65990aac0d8SBjoern A. Zeeb sdio_release_host(rtwsdio->sdio_func); 66090aac0d8SBjoern A. Zeeb 66190aac0d8SBjoern A. Zeeb if (ret) 66290aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, 66390aac0d8SBjoern A. Zeeb "Failed to write %zu byte(s) to SDIO port 0x%08x", 66490aac0d8SBjoern A. Zeeb txsize, txaddr); 66590aac0d8SBjoern A. Zeeb 66690aac0d8SBjoern A. Zeeb return ret; 66790aac0d8SBjoern A. Zeeb } 66890aac0d8SBjoern A. Zeeb 66990aac0d8SBjoern A. Zeeb static void rtw_sdio_init(struct rtw_dev *rtwdev) 67090aac0d8SBjoern A. Zeeb { 67190aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 67290aac0d8SBjoern A. Zeeb 67390aac0d8SBjoern A. Zeeb rtwsdio->irq_mask = REG_SDIO_HIMR_RX_REQUEST | REG_SDIO_HIMR_CPWM1; 67490aac0d8SBjoern A. Zeeb } 67590aac0d8SBjoern A. Zeeb 67690aac0d8SBjoern A. Zeeb static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) 67790aac0d8SBjoern A. Zeeb { 67890aac0d8SBjoern A. Zeeb u8 size, timeout; 67990aac0d8SBjoern A. Zeeb 68090aac0d8SBjoern A. Zeeb if (rtw_chip_wcpu_11n(rtwdev)) { 68190aac0d8SBjoern A. Zeeb size = 0x6; 68290aac0d8SBjoern A. Zeeb timeout = 0x6; 68390aac0d8SBjoern A. Zeeb } else { 68490aac0d8SBjoern A. Zeeb size = 0xff; 68590aac0d8SBjoern A. Zeeb timeout = 0x1; 68690aac0d8SBjoern A. Zeeb } 68790aac0d8SBjoern A. Zeeb 68890aac0d8SBjoern A. Zeeb /* Make the firmware honor the size limit configured below */ 68990aac0d8SBjoern A. Zeeb rtw_write32_set(rtwdev, REG_RXDMA_AGG_PG_TH, BIT_EN_PRE_CALC); 69090aac0d8SBjoern A. Zeeb 69190aac0d8SBjoern A. Zeeb rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_AGG_EN); 69290aac0d8SBjoern A. Zeeb 69390aac0d8SBjoern A. Zeeb rtw_write16(rtwdev, REG_RXDMA_AGG_PG_TH, 69490aac0d8SBjoern A. Zeeb FIELD_PREP(BIT_RXDMA_AGG_PG_TH, size) | 69590aac0d8SBjoern A. Zeeb FIELD_PREP(BIT_DMA_AGG_TO_V1, timeout)); 69690aac0d8SBjoern A. Zeeb 69790aac0d8SBjoern A. Zeeb rtw_write8_set(rtwdev, REG_RXDMA_MODE, BIT_DMA_MODE); 69890aac0d8SBjoern A. Zeeb } 69990aac0d8SBjoern A. Zeeb 70090aac0d8SBjoern A. Zeeb static void rtw_sdio_enable_interrupt(struct rtw_dev *rtwdev) 70190aac0d8SBjoern A. Zeeb { 70290aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 70390aac0d8SBjoern A. Zeeb 70490aac0d8SBjoern A. Zeeb rtw_write32(rtwdev, REG_SDIO_HIMR, rtwsdio->irq_mask); 70590aac0d8SBjoern A. Zeeb } 70690aac0d8SBjoern A. Zeeb 70790aac0d8SBjoern A. Zeeb static void rtw_sdio_disable_interrupt(struct rtw_dev *rtwdev) 70890aac0d8SBjoern A. Zeeb { 70990aac0d8SBjoern A. Zeeb rtw_write32(rtwdev, REG_SDIO_HIMR, 0x0); 71090aac0d8SBjoern A. Zeeb } 71190aac0d8SBjoern A. Zeeb 71290aac0d8SBjoern A. Zeeb static u8 rtw_sdio_get_tx_qsel(struct rtw_dev *rtwdev, struct sk_buff *skb, 71390aac0d8SBjoern A. Zeeb u8 queue) 71490aac0d8SBjoern A. Zeeb { 71590aac0d8SBjoern A. Zeeb switch (queue) { 71690aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_BCN: 71790aac0d8SBjoern A. Zeeb return TX_DESC_QSEL_BEACON; 71890aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_H2C: 71990aac0d8SBjoern A. Zeeb return TX_DESC_QSEL_H2C; 72090aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_MGMT: 72190aac0d8SBjoern A. Zeeb if (rtw_chip_wcpu_11n(rtwdev)) 72290aac0d8SBjoern A. Zeeb return TX_DESC_QSEL_HIGH; 72390aac0d8SBjoern A. Zeeb else 72490aac0d8SBjoern A. Zeeb return TX_DESC_QSEL_MGMT; 72590aac0d8SBjoern A. Zeeb case RTW_TX_QUEUE_HI0: 72690aac0d8SBjoern A. Zeeb return TX_DESC_QSEL_HIGH; 72790aac0d8SBjoern A. Zeeb default: 72890aac0d8SBjoern A. Zeeb return skb->priority; 72990aac0d8SBjoern A. Zeeb } 73090aac0d8SBjoern A. Zeeb } 73190aac0d8SBjoern A. Zeeb 73290aac0d8SBjoern A. Zeeb static int rtw_sdio_setup(struct rtw_dev *rtwdev) 73390aac0d8SBjoern A. Zeeb { 73490aac0d8SBjoern A. Zeeb /* nothing to do */ 73590aac0d8SBjoern A. Zeeb return 0; 73690aac0d8SBjoern A. Zeeb } 73790aac0d8SBjoern A. Zeeb 73890aac0d8SBjoern A. Zeeb static int rtw_sdio_start(struct rtw_dev *rtwdev) 73990aac0d8SBjoern A. Zeeb { 74090aac0d8SBjoern A. Zeeb rtw_sdio_enable_rx_aggregation(rtwdev); 74190aac0d8SBjoern A. Zeeb rtw_sdio_enable_interrupt(rtwdev); 74290aac0d8SBjoern A. Zeeb 74390aac0d8SBjoern A. Zeeb return 0; 74490aac0d8SBjoern A. Zeeb } 74590aac0d8SBjoern A. Zeeb 74690aac0d8SBjoern A. Zeeb static void rtw_sdio_stop(struct rtw_dev *rtwdev) 74790aac0d8SBjoern A. Zeeb { 74890aac0d8SBjoern A. Zeeb rtw_sdio_disable_interrupt(rtwdev); 74990aac0d8SBjoern A. Zeeb } 75090aac0d8SBjoern A. Zeeb 75190aac0d8SBjoern A. Zeeb static void rtw_sdio_deep_ps_enter(struct rtw_dev *rtwdev) 75290aac0d8SBjoern A. Zeeb { 75390aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 75490aac0d8SBjoern A. Zeeb bool tx_empty = true; 75590aac0d8SBjoern A. Zeeb u8 queue; 75690aac0d8SBjoern A. Zeeb 75790aac0d8SBjoern A. Zeeb if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) { 75890aac0d8SBjoern A. Zeeb /* Deep PS state is not allowed to TX-DMA */ 75990aac0d8SBjoern A. Zeeb for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) { 76090aac0d8SBjoern A. Zeeb /* BCN queue is rsvd page, does not have DMA interrupt 76190aac0d8SBjoern A. Zeeb * H2C queue is managed by firmware 76290aac0d8SBjoern A. Zeeb */ 76390aac0d8SBjoern A. Zeeb if (queue == RTW_TX_QUEUE_BCN || 76490aac0d8SBjoern A. Zeeb queue == RTW_TX_QUEUE_H2C) 76590aac0d8SBjoern A. Zeeb continue; 76690aac0d8SBjoern A. Zeeb 76790aac0d8SBjoern A. Zeeb /* check if there is any skb DMAing */ 76890aac0d8SBjoern A. Zeeb if (skb_queue_len(&rtwsdio->tx_queue[queue])) { 76990aac0d8SBjoern A. Zeeb tx_empty = false; 77090aac0d8SBjoern A. Zeeb break; 77190aac0d8SBjoern A. Zeeb } 77290aac0d8SBjoern A. Zeeb } 77390aac0d8SBjoern A. Zeeb } 77490aac0d8SBjoern A. Zeeb 77590aac0d8SBjoern A. Zeeb if (!tx_empty) { 77690aac0d8SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_PS, 77790aac0d8SBjoern A. Zeeb "TX path not empty, cannot enter deep power save state\n"); 77890aac0d8SBjoern A. Zeeb return; 77990aac0d8SBjoern A. Zeeb } 78090aac0d8SBjoern A. Zeeb 78190aac0d8SBjoern A. Zeeb set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags); 78290aac0d8SBjoern A. Zeeb rtw_power_mode_change(rtwdev, true); 78390aac0d8SBjoern A. Zeeb } 78490aac0d8SBjoern A. Zeeb 78590aac0d8SBjoern A. Zeeb static void rtw_sdio_deep_ps_leave(struct rtw_dev *rtwdev) 78690aac0d8SBjoern A. Zeeb { 78790aac0d8SBjoern A. Zeeb if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) 78890aac0d8SBjoern A. Zeeb rtw_power_mode_change(rtwdev, false); 78990aac0d8SBjoern A. Zeeb } 79090aac0d8SBjoern A. Zeeb 79190aac0d8SBjoern A. Zeeb static void rtw_sdio_deep_ps(struct rtw_dev *rtwdev, bool enter) 79290aac0d8SBjoern A. Zeeb { 79390aac0d8SBjoern A. Zeeb if (enter && !test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) 79490aac0d8SBjoern A. Zeeb rtw_sdio_deep_ps_enter(rtwdev); 79590aac0d8SBjoern A. Zeeb 79690aac0d8SBjoern A. Zeeb if (!enter && test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) 79790aac0d8SBjoern A. Zeeb rtw_sdio_deep_ps_leave(rtwdev); 79890aac0d8SBjoern A. Zeeb } 79990aac0d8SBjoern A. Zeeb 80090aac0d8SBjoern A. Zeeb static void rtw_sdio_tx_kick_off(struct rtw_dev *rtwdev) 80190aac0d8SBjoern A. Zeeb { 80290aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 80390aac0d8SBjoern A. Zeeb 80490aac0d8SBjoern A. Zeeb queue_work(rtwsdio->txwq, &rtwsdio->tx_handler_data->work); 80590aac0d8SBjoern A. Zeeb } 80690aac0d8SBjoern A. Zeeb 80790aac0d8SBjoern A. Zeeb static void rtw_sdio_link_ps(struct rtw_dev *rtwdev, bool enter) 80890aac0d8SBjoern A. Zeeb { 80990aac0d8SBjoern A. Zeeb /* nothing to do */ 81090aac0d8SBjoern A. Zeeb } 81190aac0d8SBjoern A. Zeeb 81290aac0d8SBjoern A. Zeeb static void rtw_sdio_interface_cfg(struct rtw_dev *rtwdev) 81390aac0d8SBjoern A. Zeeb { 81490aac0d8SBjoern A. Zeeb u32 val; 81590aac0d8SBjoern A. Zeeb 81690aac0d8SBjoern A. Zeeb rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); 81790aac0d8SBjoern A. Zeeb 81890aac0d8SBjoern A. Zeeb val = rtw_read32(rtwdev, REG_SDIO_TX_CTRL); 81990aac0d8SBjoern A. Zeeb val &= 0xfff8; 82090aac0d8SBjoern A. Zeeb rtw_write32(rtwdev, REG_SDIO_TX_CTRL, val); 82190aac0d8SBjoern A. Zeeb } 82290aac0d8SBjoern A. Zeeb 82390aac0d8SBjoern A. Zeeb static struct rtw_sdio_tx_data *rtw_sdio_get_tx_data(struct sk_buff *skb) 82490aac0d8SBjoern A. Zeeb { 82590aac0d8SBjoern A. Zeeb struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 82690aac0d8SBjoern A. Zeeb 82790aac0d8SBjoern A. Zeeb BUILD_BUG_ON(sizeof(struct rtw_sdio_tx_data) > 82890aac0d8SBjoern A. Zeeb sizeof(info->status.status_driver_data)); 82990aac0d8SBjoern A. Zeeb 83090aac0d8SBjoern A. Zeeb return (struct rtw_sdio_tx_data *)info->status.status_driver_data; 83190aac0d8SBjoern A. Zeeb } 83290aac0d8SBjoern A. Zeeb 83390aac0d8SBjoern A. Zeeb static void rtw_sdio_tx_skb_prepare(struct rtw_dev *rtwdev, 83490aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 83590aac0d8SBjoern A. Zeeb struct sk_buff *skb, 83690aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type queue) 83790aac0d8SBjoern A. Zeeb { 83890aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 83990aac0d8SBjoern A. Zeeb unsigned long data_addr, aligned_addr; 84090aac0d8SBjoern A. Zeeb size_t offset; 84190aac0d8SBjoern A. Zeeb u8 *pkt_desc; 84290aac0d8SBjoern A. Zeeb 84390aac0d8SBjoern A. Zeeb pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); 84490aac0d8SBjoern A. Zeeb 84590aac0d8SBjoern A. Zeeb data_addr = (unsigned long)pkt_desc; 84690aac0d8SBjoern A. Zeeb aligned_addr = ALIGN(data_addr, RTW_SDIO_DATA_PTR_ALIGN); 84790aac0d8SBjoern A. Zeeb 84890aac0d8SBjoern A. Zeeb if (data_addr != aligned_addr) { 84990aac0d8SBjoern A. Zeeb /* Ensure that the start of the pkt_desc is always aligned at 85090aac0d8SBjoern A. Zeeb * RTW_SDIO_DATA_PTR_ALIGN. 85190aac0d8SBjoern A. Zeeb */ 85290aac0d8SBjoern A. Zeeb offset = RTW_SDIO_DATA_PTR_ALIGN - (aligned_addr - data_addr); 85390aac0d8SBjoern A. Zeeb 85490aac0d8SBjoern A. Zeeb pkt_desc = skb_push(skb, offset); 85590aac0d8SBjoern A. Zeeb 85690aac0d8SBjoern A. Zeeb /* By inserting padding to align the start of the pkt_desc we 85790aac0d8SBjoern A. Zeeb * need to inform the firmware that the actual data starts at 85890aac0d8SBjoern A. Zeeb * a different offset than normal. 85990aac0d8SBjoern A. Zeeb */ 86090aac0d8SBjoern A. Zeeb pkt_info->offset += offset; 86190aac0d8SBjoern A. Zeeb } 86290aac0d8SBjoern A. Zeeb 86390aac0d8SBjoern A. Zeeb memset(pkt_desc, 0, chip->tx_pkt_desc_sz); 86490aac0d8SBjoern A. Zeeb 86590aac0d8SBjoern A. Zeeb pkt_info->qsel = rtw_sdio_get_tx_qsel(rtwdev, skb, queue); 86690aac0d8SBjoern A. Zeeb 86790aac0d8SBjoern A. Zeeb rtw_tx_fill_tx_desc(pkt_info, skb); 86890aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, pkt_desc); 86990aac0d8SBjoern A. Zeeb } 87090aac0d8SBjoern A. Zeeb 87190aac0d8SBjoern A. Zeeb static int rtw_sdio_write_data(struct rtw_dev *rtwdev, 87290aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 87390aac0d8SBjoern A. Zeeb struct sk_buff *skb, 87490aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type queue) 87590aac0d8SBjoern A. Zeeb { 87690aac0d8SBjoern A. Zeeb int ret; 87790aac0d8SBjoern A. Zeeb 87890aac0d8SBjoern A. Zeeb rtw_sdio_tx_skb_prepare(rtwdev, pkt_info, skb, queue); 87990aac0d8SBjoern A. Zeeb 88090aac0d8SBjoern A. Zeeb ret = rtw_sdio_write_port(rtwdev, skb, queue); 88190aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 88290aac0d8SBjoern A. Zeeb 88390aac0d8SBjoern A. Zeeb return ret; 88490aac0d8SBjoern A. Zeeb } 88590aac0d8SBjoern A. Zeeb 88690aac0d8SBjoern A. Zeeb static int rtw_sdio_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, 88790aac0d8SBjoern A. Zeeb u32 size) 88890aac0d8SBjoern A. Zeeb { 88990aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info = {}; 89090aac0d8SBjoern A. Zeeb struct sk_buff *skb; 89190aac0d8SBjoern A. Zeeb 89290aac0d8SBjoern A. Zeeb skb = rtw_tx_write_data_rsvd_page_get(rtwdev, &pkt_info, buf, size); 89390aac0d8SBjoern A. Zeeb if (!skb) 89490aac0d8SBjoern A. Zeeb return -ENOMEM; 89590aac0d8SBjoern A. Zeeb 89690aac0d8SBjoern A. Zeeb return rtw_sdio_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_BCN); 89790aac0d8SBjoern A. Zeeb } 89890aac0d8SBjoern A. Zeeb 89990aac0d8SBjoern A. Zeeb static int rtw_sdio_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size) 90090aac0d8SBjoern A. Zeeb { 90190aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info = {}; 90290aac0d8SBjoern A. Zeeb struct sk_buff *skb; 90390aac0d8SBjoern A. Zeeb 90490aac0d8SBjoern A. Zeeb skb = rtw_tx_write_data_h2c_get(rtwdev, &pkt_info, buf, size); 90590aac0d8SBjoern A. Zeeb if (!skb) 90690aac0d8SBjoern A. Zeeb return -ENOMEM; 90790aac0d8SBjoern A. Zeeb 90890aac0d8SBjoern A. Zeeb return rtw_sdio_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_H2C); 90990aac0d8SBjoern A. Zeeb } 91090aac0d8SBjoern A. Zeeb 91190aac0d8SBjoern A. Zeeb static int rtw_sdio_tx_write(struct rtw_dev *rtwdev, 91290aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 91390aac0d8SBjoern A. Zeeb struct sk_buff *skb) 91490aac0d8SBjoern A. Zeeb { 91590aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 91690aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type queue = rtw_tx_queue_mapping(skb); 91790aac0d8SBjoern A. Zeeb struct rtw_sdio_tx_data *tx_data; 91890aac0d8SBjoern A. Zeeb 91990aac0d8SBjoern A. Zeeb rtw_sdio_tx_skb_prepare(rtwdev, pkt_info, skb, queue); 92090aac0d8SBjoern A. Zeeb 92190aac0d8SBjoern A. Zeeb tx_data = rtw_sdio_get_tx_data(skb); 92290aac0d8SBjoern A. Zeeb tx_data->sn = pkt_info->sn; 92390aac0d8SBjoern A. Zeeb 92490aac0d8SBjoern A. Zeeb skb_queue_tail(&rtwsdio->tx_queue[queue], skb); 92590aac0d8SBjoern A. Zeeb 92690aac0d8SBjoern A. Zeeb return 0; 92790aac0d8SBjoern A. Zeeb } 92890aac0d8SBjoern A. Zeeb 92990aac0d8SBjoern A. Zeeb static void rtw_sdio_tx_err_isr(struct rtw_dev *rtwdev) 93090aac0d8SBjoern A. Zeeb { 93190aac0d8SBjoern A. Zeeb u32 val = rtw_read32(rtwdev, REG_TXDMA_STATUS); 93290aac0d8SBjoern A. Zeeb 93390aac0d8SBjoern A. Zeeb rtw_write32(rtwdev, REG_TXDMA_STATUS, val); 93490aac0d8SBjoern A. Zeeb } 93590aac0d8SBjoern A. Zeeb 93690aac0d8SBjoern A. Zeeb static void rtw_sdio_rx_skb(struct rtw_dev *rtwdev, struct sk_buff *skb, 93790aac0d8SBjoern A. Zeeb u32 pkt_offset, struct rtw_rx_pkt_stat *pkt_stat, 93890aac0d8SBjoern A. Zeeb struct ieee80211_rx_status *rx_status) 93990aac0d8SBjoern A. Zeeb { 94090aac0d8SBjoern A. Zeeb *IEEE80211_SKB_RXCB(skb) = *rx_status; 94190aac0d8SBjoern A. Zeeb 94290aac0d8SBjoern A. Zeeb if (pkt_stat->is_c2h) { 94390aac0d8SBjoern A. Zeeb skb_put(skb, pkt_stat->pkt_len + pkt_offset); 94490aac0d8SBjoern A. Zeeb rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); 94590aac0d8SBjoern A. Zeeb return; 94690aac0d8SBjoern A. Zeeb } 94790aac0d8SBjoern A. Zeeb 94890aac0d8SBjoern A. Zeeb skb_put(skb, pkt_stat->pkt_len); 94990aac0d8SBjoern A. Zeeb skb_reserve(skb, pkt_offset); 95090aac0d8SBjoern A. Zeeb 95190aac0d8SBjoern A. Zeeb rtw_rx_stats(rtwdev, pkt_stat->vif, skb); 95290aac0d8SBjoern A. Zeeb 95390aac0d8SBjoern A. Zeeb ieee80211_rx_irqsafe(rtwdev->hw, skb); 95490aac0d8SBjoern A. Zeeb } 95590aac0d8SBjoern A. Zeeb 95690aac0d8SBjoern A. Zeeb static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len) 95790aac0d8SBjoern A. Zeeb { 95890aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 95990aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 96090aac0d8SBjoern A. Zeeb u32 pkt_desc_sz = chip->rx_pkt_desc_sz; 96190aac0d8SBjoern A. Zeeb struct ieee80211_rx_status rx_status; 96290aac0d8SBjoern A. Zeeb struct rtw_rx_pkt_stat pkt_stat; 96390aac0d8SBjoern A. Zeeb struct sk_buff *skb, *split_skb; 96490aac0d8SBjoern A. Zeeb u32 pkt_offset, curr_pkt_len; 96590aac0d8SBjoern A. Zeeb size_t bufsz; 96690aac0d8SBjoern A. Zeeb u8 *rx_desc; 96790aac0d8SBjoern A. Zeeb int ret; 96890aac0d8SBjoern A. Zeeb 96990aac0d8SBjoern A. Zeeb bufsz = sdio_align_size(rtwsdio->sdio_func, rx_len); 97090aac0d8SBjoern A. Zeeb 97190aac0d8SBjoern A. Zeeb skb = dev_alloc_skb(bufsz); 97290aac0d8SBjoern A. Zeeb if (!skb) 97390aac0d8SBjoern A. Zeeb return; 97490aac0d8SBjoern A. Zeeb 97590aac0d8SBjoern A. Zeeb ret = rtw_sdio_read_port(rtwdev, skb->data, bufsz); 97690aac0d8SBjoern A. Zeeb if (ret) { 97790aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 97890aac0d8SBjoern A. Zeeb return; 97990aac0d8SBjoern A. Zeeb } 98090aac0d8SBjoern A. Zeeb 98190aac0d8SBjoern A. Zeeb while (true) { 98290aac0d8SBjoern A. Zeeb rx_desc = skb->data; 98390aac0d8SBjoern A. Zeeb chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, 98490aac0d8SBjoern A. Zeeb &rx_status); 98590aac0d8SBjoern A. Zeeb pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + 98690aac0d8SBjoern A. Zeeb pkt_stat.shift; 98790aac0d8SBjoern A. Zeeb 98890aac0d8SBjoern A. Zeeb curr_pkt_len = ALIGN(pkt_offset + pkt_stat.pkt_len, 98990aac0d8SBjoern A. Zeeb RTW_SDIO_DATA_PTR_ALIGN); 99090aac0d8SBjoern A. Zeeb 99190aac0d8SBjoern A. Zeeb if ((curr_pkt_len + pkt_desc_sz) >= rx_len) { 99290aac0d8SBjoern A. Zeeb /* Use the original skb (with it's adjusted offset) 99390aac0d8SBjoern A. Zeeb * when processing the last (or even the only) entry to 99490aac0d8SBjoern A. Zeeb * have it's memory freed automatically. 99590aac0d8SBjoern A. Zeeb */ 99690aac0d8SBjoern A. Zeeb rtw_sdio_rx_skb(rtwdev, skb, pkt_offset, &pkt_stat, 99790aac0d8SBjoern A. Zeeb &rx_status); 99890aac0d8SBjoern A. Zeeb break; 99990aac0d8SBjoern A. Zeeb } 100090aac0d8SBjoern A. Zeeb 100190aac0d8SBjoern A. Zeeb split_skb = dev_alloc_skb(curr_pkt_len); 100290aac0d8SBjoern A. Zeeb if (!split_skb) { 100390aac0d8SBjoern A. Zeeb rtw_sdio_rx_skb(rtwdev, skb, pkt_offset, &pkt_stat, 100490aac0d8SBjoern A. Zeeb &rx_status); 100590aac0d8SBjoern A. Zeeb break; 100690aac0d8SBjoern A. Zeeb } 100790aac0d8SBjoern A. Zeeb 100890aac0d8SBjoern A. Zeeb skb_copy_header(split_skb, skb); 100990aac0d8SBjoern A. Zeeb memcpy(split_skb->data, skb->data, curr_pkt_len); 101090aac0d8SBjoern A. Zeeb 101190aac0d8SBjoern A. Zeeb rtw_sdio_rx_skb(rtwdev, split_skb, pkt_offset, &pkt_stat, 101290aac0d8SBjoern A. Zeeb &rx_status); 101390aac0d8SBjoern A. Zeeb 101490aac0d8SBjoern A. Zeeb /* Move to the start of the next RX descriptor */ 101590aac0d8SBjoern A. Zeeb skb_reserve(skb, curr_pkt_len); 101690aac0d8SBjoern A. Zeeb rx_len -= curr_pkt_len; 101790aac0d8SBjoern A. Zeeb } 101890aac0d8SBjoern A. Zeeb } 101990aac0d8SBjoern A. Zeeb 102090aac0d8SBjoern A. Zeeb static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) 102190aac0d8SBjoern A. Zeeb { 102290aac0d8SBjoern A. Zeeb u32 rx_len, hisr, total_rx_bytes = 0; 102390aac0d8SBjoern A. Zeeb 102490aac0d8SBjoern A. Zeeb do { 102590aac0d8SBjoern A. Zeeb if (rtw_chip_wcpu_11n(rtwdev)) 102690aac0d8SBjoern A. Zeeb rx_len = rtw_read16(rtwdev, REG_SDIO_RX0_REQ_LEN); 102790aac0d8SBjoern A. Zeeb else 102890aac0d8SBjoern A. Zeeb rx_len = rtw_read32(rtwdev, REG_SDIO_RX0_REQ_LEN); 102990aac0d8SBjoern A. Zeeb 103090aac0d8SBjoern A. Zeeb if (!rx_len) 103190aac0d8SBjoern A. Zeeb break; 103290aac0d8SBjoern A. Zeeb 103390aac0d8SBjoern A. Zeeb rtw_sdio_rxfifo_recv(rtwdev, rx_len); 103490aac0d8SBjoern A. Zeeb 103590aac0d8SBjoern A. Zeeb total_rx_bytes += rx_len; 103690aac0d8SBjoern A. Zeeb 103790aac0d8SBjoern A. Zeeb if (rtw_chip_wcpu_11n(rtwdev)) { 103890aac0d8SBjoern A. Zeeb /* Stop if no more RX requests are pending, even if 103990aac0d8SBjoern A. Zeeb * rx_len could be greater than zero in the next 104090aac0d8SBjoern A. Zeeb * iteration. This is needed because the RX buffer may 104190aac0d8SBjoern A. Zeeb * already contain data while either HW or FW are not 104290aac0d8SBjoern A. Zeeb * done filling that buffer yet. Still reading the 104390aac0d8SBjoern A. Zeeb * buffer can result in packets where 104490aac0d8SBjoern A. Zeeb * rtw_rx_pkt_stat.pkt_len is zero or points beyond the 104590aac0d8SBjoern A. Zeeb * end of the buffer. 104690aac0d8SBjoern A. Zeeb */ 104790aac0d8SBjoern A. Zeeb hisr = rtw_read32(rtwdev, REG_SDIO_HISR); 104890aac0d8SBjoern A. Zeeb } else { 104990aac0d8SBjoern A. Zeeb /* RTW_WCPU_11AC chips have improved hardware or 105090aac0d8SBjoern A. Zeeb * firmware and can use rx_len unconditionally. 105190aac0d8SBjoern A. Zeeb */ 105290aac0d8SBjoern A. Zeeb hisr = REG_SDIO_HISR_RX_REQUEST; 105390aac0d8SBjoern A. Zeeb } 105490aac0d8SBjoern A. Zeeb } while (total_rx_bytes < SZ_64K && hisr & REG_SDIO_HISR_RX_REQUEST); 105590aac0d8SBjoern A. Zeeb } 105690aac0d8SBjoern A. Zeeb 105790aac0d8SBjoern A. Zeeb static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func) 105890aac0d8SBjoern A. Zeeb { 105990aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = sdio_get_drvdata(sdio_func); 106090aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio; 106190aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 106290aac0d8SBjoern A. Zeeb u32 hisr; 106390aac0d8SBjoern A. Zeeb 106490aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 106590aac0d8SBjoern A. Zeeb rtwsdio = (struct rtw_sdio *)rtwdev->priv; 106690aac0d8SBjoern A. Zeeb 106790aac0d8SBjoern A. Zeeb rtwsdio->irq_thread = current; 106890aac0d8SBjoern A. Zeeb 106990aac0d8SBjoern A. Zeeb hisr = rtw_read32(rtwdev, REG_SDIO_HISR); 107090aac0d8SBjoern A. Zeeb 107190aac0d8SBjoern A. Zeeb if (hisr & REG_SDIO_HISR_TXERR) 107290aac0d8SBjoern A. Zeeb rtw_sdio_tx_err_isr(rtwdev); 107390aac0d8SBjoern A. Zeeb if (hisr & REG_SDIO_HISR_RX_REQUEST) { 107490aac0d8SBjoern A. Zeeb hisr &= ~REG_SDIO_HISR_RX_REQUEST; 107590aac0d8SBjoern A. Zeeb rtw_sdio_rx_isr(rtwdev); 107690aac0d8SBjoern A. Zeeb } 107790aac0d8SBjoern A. Zeeb 107890aac0d8SBjoern A. Zeeb rtw_write32(rtwdev, REG_SDIO_HISR, hisr); 107990aac0d8SBjoern A. Zeeb 108090aac0d8SBjoern A. Zeeb rtwsdio->irq_thread = NULL; 108190aac0d8SBjoern A. Zeeb } 108290aac0d8SBjoern A. Zeeb 108390aac0d8SBjoern A. Zeeb static int __maybe_unused rtw_sdio_suspend(struct device *dev) 108490aac0d8SBjoern A. Zeeb { 108590aac0d8SBjoern A. Zeeb struct sdio_func *func = dev_to_sdio_func(dev); 108690aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = dev_get_drvdata(dev); 108790aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 108890aac0d8SBjoern A. Zeeb int ret; 108990aac0d8SBjoern A. Zeeb 109090aac0d8SBjoern A. Zeeb ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 109190aac0d8SBjoern A. Zeeb if (ret) 109290aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "Failed to host PM flag MMC_PM_KEEP_POWER"); 109390aac0d8SBjoern A. Zeeb 109490aac0d8SBjoern A. Zeeb return ret; 109590aac0d8SBjoern A. Zeeb } 109690aac0d8SBjoern A. Zeeb 109790aac0d8SBjoern A. Zeeb static int __maybe_unused rtw_sdio_resume(struct device *dev) 109890aac0d8SBjoern A. Zeeb { 109990aac0d8SBjoern A. Zeeb return 0; 110090aac0d8SBjoern A. Zeeb } 110190aac0d8SBjoern A. Zeeb 110290aac0d8SBjoern A. Zeeb SIMPLE_DEV_PM_OPS(rtw_sdio_pm_ops, rtw_sdio_suspend, rtw_sdio_resume); 110390aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_sdio_pm_ops); 110490aac0d8SBjoern A. Zeeb 110590aac0d8SBjoern A. Zeeb static int rtw_sdio_claim(struct rtw_dev *rtwdev, struct sdio_func *sdio_func) 110690aac0d8SBjoern A. Zeeb { 110790aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 110890aac0d8SBjoern A. Zeeb int ret; 110990aac0d8SBjoern A. Zeeb 111090aac0d8SBjoern A. Zeeb sdio_claim_host(sdio_func); 111190aac0d8SBjoern A. Zeeb 111290aac0d8SBjoern A. Zeeb ret = sdio_enable_func(sdio_func); 111390aac0d8SBjoern A. Zeeb if (ret) { 111490aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "Failed to enable SDIO func"); 111590aac0d8SBjoern A. Zeeb goto err_release_host; 111690aac0d8SBjoern A. Zeeb } 111790aac0d8SBjoern A. Zeeb 111890aac0d8SBjoern A. Zeeb ret = sdio_set_block_size(sdio_func, RTW_SDIO_BLOCK_SIZE); 111990aac0d8SBjoern A. Zeeb if (ret) { 112090aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "Failed to set SDIO block size to 512"); 112190aac0d8SBjoern A. Zeeb goto err_disable_func; 112290aac0d8SBjoern A. Zeeb } 112390aac0d8SBjoern A. Zeeb 112490aac0d8SBjoern A. Zeeb rtwsdio->sdio_func = sdio_func; 112590aac0d8SBjoern A. Zeeb 112690aac0d8SBjoern A. Zeeb rtwsdio->sdio3_bus_mode = mmc_card_uhs(sdio_func->card); 112790aac0d8SBjoern A. Zeeb 112890aac0d8SBjoern A. Zeeb sdio_set_drvdata(sdio_func, rtwdev->hw); 112990aac0d8SBjoern A. Zeeb SET_IEEE80211_DEV(rtwdev->hw, &sdio_func->dev); 113090aac0d8SBjoern A. Zeeb 113190aac0d8SBjoern A. Zeeb sdio_release_host(sdio_func); 113290aac0d8SBjoern A. Zeeb 113390aac0d8SBjoern A. Zeeb return 0; 113490aac0d8SBjoern A. Zeeb 113590aac0d8SBjoern A. Zeeb err_disable_func: 113690aac0d8SBjoern A. Zeeb sdio_disable_func(sdio_func); 113790aac0d8SBjoern A. Zeeb err_release_host: 113890aac0d8SBjoern A. Zeeb sdio_release_host(sdio_func); 113990aac0d8SBjoern A. Zeeb return ret; 114090aac0d8SBjoern A. Zeeb } 114190aac0d8SBjoern A. Zeeb 114290aac0d8SBjoern A. Zeeb static void rtw_sdio_declaim(struct rtw_dev *rtwdev, 114390aac0d8SBjoern A. Zeeb struct sdio_func *sdio_func) 114490aac0d8SBjoern A. Zeeb { 114590aac0d8SBjoern A. Zeeb sdio_claim_host(sdio_func); 114690aac0d8SBjoern A. Zeeb sdio_disable_func(sdio_func); 114790aac0d8SBjoern A. Zeeb sdio_release_host(sdio_func); 114890aac0d8SBjoern A. Zeeb } 114990aac0d8SBjoern A. Zeeb 115090aac0d8SBjoern A. Zeeb static struct rtw_hci_ops rtw_sdio_ops = { 115190aac0d8SBjoern A. Zeeb .tx_write = rtw_sdio_tx_write, 115290aac0d8SBjoern A. Zeeb .tx_kick_off = rtw_sdio_tx_kick_off, 115390aac0d8SBjoern A. Zeeb .setup = rtw_sdio_setup, 115490aac0d8SBjoern A. Zeeb .start = rtw_sdio_start, 115590aac0d8SBjoern A. Zeeb .stop = rtw_sdio_stop, 115690aac0d8SBjoern A. Zeeb .deep_ps = rtw_sdio_deep_ps, 115790aac0d8SBjoern A. Zeeb .link_ps = rtw_sdio_link_ps, 115890aac0d8SBjoern A. Zeeb .interface_cfg = rtw_sdio_interface_cfg, 115990aac0d8SBjoern A. Zeeb 116090aac0d8SBjoern A. Zeeb .read8 = rtw_sdio_read8, 116190aac0d8SBjoern A. Zeeb .read16 = rtw_sdio_read16, 116290aac0d8SBjoern A. Zeeb .read32 = rtw_sdio_read32, 116390aac0d8SBjoern A. Zeeb .write8 = rtw_sdio_write8, 116490aac0d8SBjoern A. Zeeb .write16 = rtw_sdio_write16, 116590aac0d8SBjoern A. Zeeb .write32 = rtw_sdio_write32, 116690aac0d8SBjoern A. Zeeb .write_data_rsvd_page = rtw_sdio_write_data_rsvd_page, 116790aac0d8SBjoern A. Zeeb .write_data_h2c = rtw_sdio_write_data_h2c, 116890aac0d8SBjoern A. Zeeb }; 116990aac0d8SBjoern A. Zeeb 117090aac0d8SBjoern A. Zeeb static int rtw_sdio_request_irq(struct rtw_dev *rtwdev, 117190aac0d8SBjoern A. Zeeb struct sdio_func *sdio_func) 117290aac0d8SBjoern A. Zeeb { 117390aac0d8SBjoern A. Zeeb int ret; 117490aac0d8SBjoern A. Zeeb 117590aac0d8SBjoern A. Zeeb sdio_claim_host(sdio_func); 117690aac0d8SBjoern A. Zeeb ret = sdio_claim_irq(sdio_func, &rtw_sdio_handle_interrupt); 117790aac0d8SBjoern A. Zeeb sdio_release_host(sdio_func); 117890aac0d8SBjoern A. Zeeb 117990aac0d8SBjoern A. Zeeb if (ret) { 118090aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to claim SDIO IRQ"); 118190aac0d8SBjoern A. Zeeb return ret; 118290aac0d8SBjoern A. Zeeb } 118390aac0d8SBjoern A. Zeeb 118490aac0d8SBjoern A. Zeeb return 0; 118590aac0d8SBjoern A. Zeeb } 118690aac0d8SBjoern A. Zeeb 118790aac0d8SBjoern A. Zeeb static void rtw_sdio_indicate_tx_status(struct rtw_dev *rtwdev, 118890aac0d8SBjoern A. Zeeb struct sk_buff *skb) 118990aac0d8SBjoern A. Zeeb { 119090aac0d8SBjoern A. Zeeb struct rtw_sdio_tx_data *tx_data = rtw_sdio_get_tx_data(skb); 119190aac0d8SBjoern A. Zeeb struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 119290aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw; 119390aac0d8SBjoern A. Zeeb 119490aac0d8SBjoern A. Zeeb /* enqueue to wait for tx report */ 119590aac0d8SBjoern A. Zeeb if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 119690aac0d8SBjoern A. Zeeb rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn); 119790aac0d8SBjoern A. Zeeb return; 119890aac0d8SBjoern A. Zeeb } 119990aac0d8SBjoern A. Zeeb 120090aac0d8SBjoern A. Zeeb /* always ACK for others, then they won't be marked as drop */ 120190aac0d8SBjoern A. Zeeb ieee80211_tx_info_clear_status(info); 120290aac0d8SBjoern A. Zeeb if (info->flags & IEEE80211_TX_CTL_NO_ACK) 120390aac0d8SBjoern A. Zeeb info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 120490aac0d8SBjoern A. Zeeb else 120590aac0d8SBjoern A. Zeeb info->flags |= IEEE80211_TX_STAT_ACK; 120690aac0d8SBjoern A. Zeeb 120790aac0d8SBjoern A. Zeeb ieee80211_tx_status_irqsafe(hw, skb); 120890aac0d8SBjoern A. Zeeb } 120990aac0d8SBjoern A. Zeeb 121090aac0d8SBjoern A. Zeeb static void rtw_sdio_process_tx_queue(struct rtw_dev *rtwdev, 121190aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type queue) 121290aac0d8SBjoern A. Zeeb { 121390aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 121490aac0d8SBjoern A. Zeeb struct sk_buff *skb; 121590aac0d8SBjoern A. Zeeb int ret; 121690aac0d8SBjoern A. Zeeb 121790aac0d8SBjoern A. Zeeb skb = skb_dequeue(&rtwsdio->tx_queue[queue]); 121890aac0d8SBjoern A. Zeeb if (!skb) 121990aac0d8SBjoern A. Zeeb return; 122090aac0d8SBjoern A. Zeeb 122190aac0d8SBjoern A. Zeeb ret = rtw_sdio_write_port(rtwdev, skb, queue); 122290aac0d8SBjoern A. Zeeb if (ret) { 122390aac0d8SBjoern A. Zeeb skb_queue_head(&rtwsdio->tx_queue[queue], skb); 122490aac0d8SBjoern A. Zeeb return; 122590aac0d8SBjoern A. Zeeb } 122690aac0d8SBjoern A. Zeeb 122790aac0d8SBjoern A. Zeeb if (queue <= RTW_TX_QUEUE_VO) 122890aac0d8SBjoern A. Zeeb rtw_sdio_indicate_tx_status(rtwdev, skb); 122990aac0d8SBjoern A. Zeeb else 123090aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 123190aac0d8SBjoern A. Zeeb } 123290aac0d8SBjoern A. Zeeb 123390aac0d8SBjoern A. Zeeb static void rtw_sdio_tx_handler(struct work_struct *work) 123490aac0d8SBjoern A. Zeeb { 123590aac0d8SBjoern A. Zeeb struct rtw_sdio_work_data *work_data = 123690aac0d8SBjoern A. Zeeb container_of(work, struct rtw_sdio_work_data, work); 123790aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio; 123890aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 123990aac0d8SBjoern A. Zeeb int limit, queue; 124090aac0d8SBjoern A. Zeeb 124190aac0d8SBjoern A. Zeeb rtwdev = work_data->rtwdev; 124290aac0d8SBjoern A. Zeeb rtwsdio = (struct rtw_sdio *)rtwdev->priv; 124390aac0d8SBjoern A. Zeeb 124490aac0d8SBjoern A. Zeeb if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) 124590aac0d8SBjoern A. Zeeb rtw_sdio_deep_ps_leave(rtwdev); 124690aac0d8SBjoern A. Zeeb 124790aac0d8SBjoern A. Zeeb for (queue = RTK_MAX_TX_QUEUE_NUM - 1; queue >= 0; queue--) { 124890aac0d8SBjoern A. Zeeb for (limit = 0; limit < 1000; limit++) { 124990aac0d8SBjoern A. Zeeb rtw_sdio_process_tx_queue(rtwdev, queue); 125090aac0d8SBjoern A. Zeeb 125190aac0d8SBjoern A. Zeeb if (skb_queue_empty(&rtwsdio->tx_queue[queue])) 125290aac0d8SBjoern A. Zeeb break; 125390aac0d8SBjoern A. Zeeb } 125490aac0d8SBjoern A. Zeeb } 125590aac0d8SBjoern A. Zeeb } 125690aac0d8SBjoern A. Zeeb 125790aac0d8SBjoern A. Zeeb static void rtw_sdio_free_irq(struct rtw_dev *rtwdev, 125890aac0d8SBjoern A. Zeeb struct sdio_func *sdio_func) 125990aac0d8SBjoern A. Zeeb { 126090aac0d8SBjoern A. Zeeb sdio_claim_host(sdio_func); 126190aac0d8SBjoern A. Zeeb sdio_release_irq(sdio_func); 126290aac0d8SBjoern A. Zeeb sdio_release_host(sdio_func); 126390aac0d8SBjoern A. Zeeb } 126490aac0d8SBjoern A. Zeeb 126590aac0d8SBjoern A. Zeeb static int rtw_sdio_init_tx(struct rtw_dev *rtwdev) 126690aac0d8SBjoern A. Zeeb { 126790aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 126890aac0d8SBjoern A. Zeeb int i; 126990aac0d8SBjoern A. Zeeb 127090aac0d8SBjoern A. Zeeb rtwsdio->txwq = create_singlethread_workqueue("rtw88_sdio: tx wq"); 127190aac0d8SBjoern A. Zeeb if (!rtwsdio->txwq) { 127290aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to create TX work queue\n"); 127390aac0d8SBjoern A. Zeeb return -ENOMEM; 127490aac0d8SBjoern A. Zeeb } 127590aac0d8SBjoern A. Zeeb 127690aac0d8SBjoern A. Zeeb for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) 127790aac0d8SBjoern A. Zeeb skb_queue_head_init(&rtwsdio->tx_queue[i]); 127890aac0d8SBjoern A. Zeeb rtwsdio->tx_handler_data = kmalloc(sizeof(*rtwsdio->tx_handler_data), 127990aac0d8SBjoern A. Zeeb GFP_KERNEL); 128090aac0d8SBjoern A. Zeeb if (!rtwsdio->tx_handler_data) 128190aac0d8SBjoern A. Zeeb goto err_destroy_wq; 128290aac0d8SBjoern A. Zeeb 128390aac0d8SBjoern A. Zeeb rtwsdio->tx_handler_data->rtwdev = rtwdev; 128490aac0d8SBjoern A. Zeeb INIT_WORK(&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler); 128590aac0d8SBjoern A. Zeeb 128690aac0d8SBjoern A. Zeeb return 0; 128790aac0d8SBjoern A. Zeeb 128890aac0d8SBjoern A. Zeeb err_destroy_wq: 128990aac0d8SBjoern A. Zeeb destroy_workqueue(rtwsdio->txwq); 129090aac0d8SBjoern A. Zeeb return -ENOMEM; 129190aac0d8SBjoern A. Zeeb } 129290aac0d8SBjoern A. Zeeb 129390aac0d8SBjoern A. Zeeb static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev) 129490aac0d8SBjoern A. Zeeb { 129590aac0d8SBjoern A. Zeeb struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 129690aac0d8SBjoern A. Zeeb int i; 129790aac0d8SBjoern A. Zeeb 129890aac0d8SBjoern A. Zeeb for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) 129990aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwsdio->tx_queue[i]); 130090aac0d8SBjoern A. Zeeb 130190aac0d8SBjoern A. Zeeb flush_workqueue(rtwsdio->txwq); 130290aac0d8SBjoern A. Zeeb destroy_workqueue(rtwsdio->txwq); 130390aac0d8SBjoern A. Zeeb kfree(rtwsdio->tx_handler_data); 130490aac0d8SBjoern A. Zeeb } 130590aac0d8SBjoern A. Zeeb 130690aac0d8SBjoern A. Zeeb int rtw_sdio_probe(struct sdio_func *sdio_func, 130790aac0d8SBjoern A. Zeeb const struct sdio_device_id *id) 130890aac0d8SBjoern A. Zeeb { 130990aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw; 131090aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 131190aac0d8SBjoern A. Zeeb int drv_data_size; 131290aac0d8SBjoern A. Zeeb int ret; 131390aac0d8SBjoern A. Zeeb 131490aac0d8SBjoern A. Zeeb drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_sdio); 131590aac0d8SBjoern A. Zeeb hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops); 131690aac0d8SBjoern A. Zeeb if (!hw) { 131790aac0d8SBjoern A. Zeeb dev_err(&sdio_func->dev, "failed to allocate hw"); 131890aac0d8SBjoern A. Zeeb return -ENOMEM; 131990aac0d8SBjoern A. Zeeb } 132090aac0d8SBjoern A. Zeeb 132190aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 132290aac0d8SBjoern A. Zeeb rtwdev->hw = hw; 132390aac0d8SBjoern A. Zeeb rtwdev->dev = &sdio_func->dev; 132490aac0d8SBjoern A. Zeeb rtwdev->chip = (struct rtw_chip_info *)id->driver_data; 132590aac0d8SBjoern A. Zeeb rtwdev->hci.ops = &rtw_sdio_ops; 132690aac0d8SBjoern A. Zeeb rtwdev->hci.type = RTW_HCI_TYPE_SDIO; 132790aac0d8SBjoern A. Zeeb 132890aac0d8SBjoern A. Zeeb ret = rtw_core_init(rtwdev); 132990aac0d8SBjoern A. Zeeb if (ret) 133090aac0d8SBjoern A. Zeeb goto err_release_hw; 133190aac0d8SBjoern A. Zeeb 133290aac0d8SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_SDIO, 133390aac0d8SBjoern A. Zeeb "rtw88 SDIO probe: vendor=0x%04x device=%04x class=%02x", 133490aac0d8SBjoern A. Zeeb id->vendor, id->device, id->class); 133590aac0d8SBjoern A. Zeeb 133690aac0d8SBjoern A. Zeeb ret = rtw_sdio_claim(rtwdev, sdio_func); 133790aac0d8SBjoern A. Zeeb if (ret) { 133890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to claim SDIO device"); 133990aac0d8SBjoern A. Zeeb goto err_deinit_core; 134090aac0d8SBjoern A. Zeeb } 134190aac0d8SBjoern A. Zeeb 134290aac0d8SBjoern A. Zeeb rtw_sdio_init(rtwdev); 134390aac0d8SBjoern A. Zeeb 134490aac0d8SBjoern A. Zeeb ret = rtw_sdio_init_tx(rtwdev); 134590aac0d8SBjoern A. Zeeb if (ret) { 134690aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init SDIO TX queue\n"); 134790aac0d8SBjoern A. Zeeb goto err_sdio_declaim; 134890aac0d8SBjoern A. Zeeb } 134990aac0d8SBjoern A. Zeeb 135090aac0d8SBjoern A. Zeeb ret = rtw_chip_info_setup(rtwdev); 135190aac0d8SBjoern A. Zeeb if (ret) { 135290aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup chip information"); 135390aac0d8SBjoern A. Zeeb goto err_destroy_txwq; 135490aac0d8SBjoern A. Zeeb } 135590aac0d8SBjoern A. Zeeb 135690aac0d8SBjoern A. Zeeb ret = rtw_sdio_request_irq(rtwdev, sdio_func); 135790aac0d8SBjoern A. Zeeb if (ret) 135890aac0d8SBjoern A. Zeeb goto err_destroy_txwq; 135990aac0d8SBjoern A. Zeeb 136090aac0d8SBjoern A. Zeeb ret = rtw_register_hw(rtwdev, hw); 136190aac0d8SBjoern A. Zeeb if (ret) { 136290aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to register hw"); 136390aac0d8SBjoern A. Zeeb goto err_free_irq; 136490aac0d8SBjoern A. Zeeb } 136590aac0d8SBjoern A. Zeeb 136690aac0d8SBjoern A. Zeeb return 0; 136790aac0d8SBjoern A. Zeeb 136890aac0d8SBjoern A. Zeeb err_free_irq: 136990aac0d8SBjoern A. Zeeb rtw_sdio_free_irq(rtwdev, sdio_func); 137090aac0d8SBjoern A. Zeeb err_destroy_txwq: 137190aac0d8SBjoern A. Zeeb rtw_sdio_deinit_tx(rtwdev); 137290aac0d8SBjoern A. Zeeb err_sdio_declaim: 137390aac0d8SBjoern A. Zeeb rtw_sdio_declaim(rtwdev, sdio_func); 137490aac0d8SBjoern A. Zeeb err_deinit_core: 137590aac0d8SBjoern A. Zeeb rtw_core_deinit(rtwdev); 137690aac0d8SBjoern A. Zeeb err_release_hw: 137790aac0d8SBjoern A. Zeeb ieee80211_free_hw(hw); 137890aac0d8SBjoern A. Zeeb 137990aac0d8SBjoern A. Zeeb return ret; 138090aac0d8SBjoern A. Zeeb } 138190aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_sdio_probe); 138290aac0d8SBjoern A. Zeeb 138390aac0d8SBjoern A. Zeeb void rtw_sdio_remove(struct sdio_func *sdio_func) 138490aac0d8SBjoern A. Zeeb { 138590aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = sdio_get_drvdata(sdio_func); 138690aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 138790aac0d8SBjoern A. Zeeb 138890aac0d8SBjoern A. Zeeb if (!hw) 138990aac0d8SBjoern A. Zeeb return; 139090aac0d8SBjoern A. Zeeb 139190aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 139290aac0d8SBjoern A. Zeeb 139390aac0d8SBjoern A. Zeeb rtw_unregister_hw(rtwdev, hw); 139490aac0d8SBjoern A. Zeeb rtw_sdio_disable_interrupt(rtwdev); 139590aac0d8SBjoern A. Zeeb rtw_sdio_free_irq(rtwdev, sdio_func); 139690aac0d8SBjoern A. Zeeb rtw_sdio_declaim(rtwdev, sdio_func); 139790aac0d8SBjoern A. Zeeb rtw_sdio_deinit_tx(rtwdev); 139890aac0d8SBjoern A. Zeeb rtw_core_deinit(rtwdev); 139990aac0d8SBjoern A. Zeeb ieee80211_free_hw(hw); 140090aac0d8SBjoern A. Zeeb } 140190aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_sdio_remove); 140290aac0d8SBjoern A. Zeeb 140390aac0d8SBjoern A. Zeeb void rtw_sdio_shutdown(struct device *dev) 140490aac0d8SBjoern A. Zeeb { 140590aac0d8SBjoern A. Zeeb struct sdio_func *sdio_func = dev_to_sdio_func(dev); 140690aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip; 140790aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw; 140890aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 140990aac0d8SBjoern A. Zeeb 141090aac0d8SBjoern A. Zeeb hw = sdio_get_drvdata(sdio_func); 141190aac0d8SBjoern A. Zeeb if (!hw) 141290aac0d8SBjoern A. Zeeb return; 141390aac0d8SBjoern A. Zeeb 141490aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 141590aac0d8SBjoern A. Zeeb chip = rtwdev->chip; 141690aac0d8SBjoern A. Zeeb 141790aac0d8SBjoern A. Zeeb if (chip->ops->shutdown) 141890aac0d8SBjoern A. Zeeb chip->ops->shutdown(rtwdev); 141990aac0d8SBjoern A. Zeeb } 142090aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_sdio_shutdown); 142190aac0d8SBjoern A. Zeeb 142290aac0d8SBjoern A. Zeeb MODULE_AUTHOR("Martin Blumenstingl"); 142390aac0d8SBjoern A. Zeeb MODULE_AUTHOR("Jernej Skrabec"); 142490aac0d8SBjoern A. Zeeb MODULE_DESCRIPTION("Realtek 802.11ac wireless SDIO driver"); 142590aac0d8SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL"); 1426