1*65371a3fSMartin Blumenstingl // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2*65371a3fSMartin Blumenstingl /* Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 3*65371a3fSMartin Blumenstingl * Copyright (C) 2021 Jernej Skrabec <jernej.skrabec@gmail.com> 4*65371a3fSMartin Blumenstingl * 5*65371a3fSMartin Blumenstingl * Based on rtw88/pci.c: 6*65371a3fSMartin Blumenstingl * Copyright(c) 2018-2019 Realtek Corporation 7*65371a3fSMartin Blumenstingl */ 8*65371a3fSMartin Blumenstingl 9*65371a3fSMartin Blumenstingl #include <linux/module.h> 10*65371a3fSMartin Blumenstingl #include <linux/mmc/host.h> 11*65371a3fSMartin Blumenstingl #include <linux/mmc/sdio_func.h> 12*65371a3fSMartin Blumenstingl #include "main.h" 13*65371a3fSMartin Blumenstingl #include "debug.h" 14*65371a3fSMartin Blumenstingl #include "fw.h" 15*65371a3fSMartin Blumenstingl #include "ps.h" 16*65371a3fSMartin Blumenstingl #include "reg.h" 17*65371a3fSMartin Blumenstingl #include "rx.h" 18*65371a3fSMartin Blumenstingl #include "sdio.h" 19*65371a3fSMartin Blumenstingl #include "tx.h" 20*65371a3fSMartin Blumenstingl 21*65371a3fSMartin Blumenstingl #define RTW_SDIO_INDIRECT_RW_RETRIES 50 22*65371a3fSMartin Blumenstingl 23*65371a3fSMartin Blumenstingl static bool rtw_sdio_is_bus_addr(u32 addr) 24*65371a3fSMartin Blumenstingl { 25*65371a3fSMartin Blumenstingl return !!(addr & RTW_SDIO_BUS_MSK); 26*65371a3fSMartin Blumenstingl } 27*65371a3fSMartin Blumenstingl 28*65371a3fSMartin Blumenstingl static bool rtw_sdio_bus_claim_needed(struct rtw_sdio *rtwsdio) 29*65371a3fSMartin Blumenstingl { 30*65371a3fSMartin Blumenstingl return !rtwsdio->irq_thread || 31*65371a3fSMartin Blumenstingl rtwsdio->irq_thread != current; 32*65371a3fSMartin Blumenstingl } 33*65371a3fSMartin Blumenstingl 34*65371a3fSMartin Blumenstingl static u32 rtw_sdio_to_bus_offset(struct rtw_dev *rtwdev, u32 addr) 35*65371a3fSMartin Blumenstingl { 36*65371a3fSMartin Blumenstingl switch (addr & RTW_SDIO_BUS_MSK) { 37*65371a3fSMartin Blumenstingl case WLAN_IOREG_OFFSET: 38*65371a3fSMartin Blumenstingl addr &= WLAN_IOREG_REG_MSK; 39*65371a3fSMartin Blumenstingl addr |= FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 40*65371a3fSMartin Blumenstingl REG_SDIO_CMD_ADDR_MAC_REG); 41*65371a3fSMartin Blumenstingl break; 42*65371a3fSMartin Blumenstingl case SDIO_LOCAL_OFFSET: 43*65371a3fSMartin Blumenstingl addr &= SDIO_LOCAL_REG_MSK; 44*65371a3fSMartin Blumenstingl addr |= FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 45*65371a3fSMartin Blumenstingl REG_SDIO_CMD_ADDR_SDIO_REG); 46*65371a3fSMartin Blumenstingl break; 47*65371a3fSMartin Blumenstingl default: 48*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "Cannot convert addr 0x%08x to bus offset", 49*65371a3fSMartin Blumenstingl addr); 50*65371a3fSMartin Blumenstingl } 51*65371a3fSMartin Blumenstingl 52*65371a3fSMartin Blumenstingl return addr; 53*65371a3fSMartin Blumenstingl } 54*65371a3fSMartin Blumenstingl 55*65371a3fSMartin Blumenstingl static bool rtw_sdio_use_memcpy_io(struct rtw_dev *rtwdev, u32 addr, 56*65371a3fSMartin Blumenstingl u8 alignment) 57*65371a3fSMartin Blumenstingl { 58*65371a3fSMartin Blumenstingl return IS_ALIGNED(addr, alignment) && 59*65371a3fSMartin Blumenstingl test_bit(RTW_FLAG_POWERON, rtwdev->flags); 60*65371a3fSMartin Blumenstingl } 61*65371a3fSMartin Blumenstingl 62*65371a3fSMartin Blumenstingl static void rtw_sdio_writel(struct rtw_dev *rtwdev, u32 val, u32 addr, 63*65371a3fSMartin Blumenstingl int *err_ret) 64*65371a3fSMartin Blumenstingl { 65*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 66*65371a3fSMartin Blumenstingl u8 buf[4]; 67*65371a3fSMartin Blumenstingl int i; 68*65371a3fSMartin Blumenstingl 69*65371a3fSMartin Blumenstingl if (rtw_sdio_use_memcpy_io(rtwdev, addr, 4)) { 70*65371a3fSMartin Blumenstingl sdio_writel(rtwsdio->sdio_func, val, addr, err_ret); 71*65371a3fSMartin Blumenstingl return; 72*65371a3fSMartin Blumenstingl } 73*65371a3fSMartin Blumenstingl 74*65371a3fSMartin Blumenstingl *(__le32 *)buf = cpu_to_le32(val); 75*65371a3fSMartin Blumenstingl 76*65371a3fSMartin Blumenstingl for (i = 0; i < 4; i++) { 77*65371a3fSMartin Blumenstingl sdio_writeb(rtwsdio->sdio_func, buf[i], addr + i, err_ret); 78*65371a3fSMartin Blumenstingl if (*err_ret) 79*65371a3fSMartin Blumenstingl return; 80*65371a3fSMartin Blumenstingl } 81*65371a3fSMartin Blumenstingl } 82*65371a3fSMartin Blumenstingl 83*65371a3fSMartin Blumenstingl static void rtw_sdio_writew(struct rtw_dev *rtwdev, u16 val, u32 addr, 84*65371a3fSMartin Blumenstingl int *err_ret) 85*65371a3fSMartin Blumenstingl { 86*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 87*65371a3fSMartin Blumenstingl u8 buf[2]; 88*65371a3fSMartin Blumenstingl int i; 89*65371a3fSMartin Blumenstingl 90*65371a3fSMartin Blumenstingl if (rtw_sdio_use_memcpy_io(rtwdev, addr, 2)) { 91*65371a3fSMartin Blumenstingl sdio_writew(rtwsdio->sdio_func, val, addr, err_ret); 92*65371a3fSMartin Blumenstingl return; 93*65371a3fSMartin Blumenstingl } 94*65371a3fSMartin Blumenstingl 95*65371a3fSMartin Blumenstingl *(__le16 *)buf = cpu_to_le16(val); 96*65371a3fSMartin Blumenstingl 97*65371a3fSMartin Blumenstingl for (i = 0; i < 2; i++) { 98*65371a3fSMartin Blumenstingl sdio_writeb(rtwsdio->sdio_func, buf[i], addr + i, err_ret); 99*65371a3fSMartin Blumenstingl if (*err_ret) 100*65371a3fSMartin Blumenstingl return; 101*65371a3fSMartin Blumenstingl } 102*65371a3fSMartin Blumenstingl } 103*65371a3fSMartin Blumenstingl 104*65371a3fSMartin Blumenstingl static u32 rtw_sdio_readl(struct rtw_dev *rtwdev, u32 addr, int *err_ret) 105*65371a3fSMartin Blumenstingl { 106*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 107*65371a3fSMartin Blumenstingl u8 buf[4]; 108*65371a3fSMartin Blumenstingl int i; 109*65371a3fSMartin Blumenstingl 110*65371a3fSMartin Blumenstingl if (rtw_sdio_use_memcpy_io(rtwdev, addr, 4)) 111*65371a3fSMartin Blumenstingl return sdio_readl(rtwsdio->sdio_func, addr, err_ret); 112*65371a3fSMartin Blumenstingl 113*65371a3fSMartin Blumenstingl for (i = 0; i < 4; i++) { 114*65371a3fSMartin Blumenstingl buf[i] = sdio_readb(rtwsdio->sdio_func, addr + i, err_ret); 115*65371a3fSMartin Blumenstingl if (*err_ret) 116*65371a3fSMartin Blumenstingl return 0; 117*65371a3fSMartin Blumenstingl } 118*65371a3fSMartin Blumenstingl 119*65371a3fSMartin Blumenstingl return le32_to_cpu(*(__le32 *)buf); 120*65371a3fSMartin Blumenstingl } 121*65371a3fSMartin Blumenstingl 122*65371a3fSMartin Blumenstingl static u16 rtw_sdio_readw(struct rtw_dev *rtwdev, u32 addr, int *err_ret) 123*65371a3fSMartin Blumenstingl { 124*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 125*65371a3fSMartin Blumenstingl u8 buf[2]; 126*65371a3fSMartin Blumenstingl int i; 127*65371a3fSMartin Blumenstingl 128*65371a3fSMartin Blumenstingl if (rtw_sdio_use_memcpy_io(rtwdev, addr, 2)) 129*65371a3fSMartin Blumenstingl return sdio_readw(rtwsdio->sdio_func, addr, err_ret); 130*65371a3fSMartin Blumenstingl 131*65371a3fSMartin Blumenstingl for (i = 0; i < 2; i++) { 132*65371a3fSMartin Blumenstingl buf[i] = sdio_readb(rtwsdio->sdio_func, addr + i, err_ret); 133*65371a3fSMartin Blumenstingl if (*err_ret) 134*65371a3fSMartin Blumenstingl return 0; 135*65371a3fSMartin Blumenstingl } 136*65371a3fSMartin Blumenstingl 137*65371a3fSMartin Blumenstingl return le16_to_cpu(*(__le16 *)buf); 138*65371a3fSMartin Blumenstingl } 139*65371a3fSMartin Blumenstingl 140*65371a3fSMartin Blumenstingl static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, 141*65371a3fSMartin Blumenstingl bool direct) 142*65371a3fSMartin Blumenstingl { 143*65371a3fSMartin Blumenstingl if (!direct) 144*65371a3fSMartin Blumenstingl return addr; 145*65371a3fSMartin Blumenstingl 146*65371a3fSMartin Blumenstingl if (!rtw_sdio_is_bus_addr(addr)) 147*65371a3fSMartin Blumenstingl addr |= WLAN_IOREG_OFFSET; 148*65371a3fSMartin Blumenstingl 149*65371a3fSMartin Blumenstingl return rtw_sdio_to_bus_offset(rtwdev, addr); 150*65371a3fSMartin Blumenstingl } 151*65371a3fSMartin Blumenstingl 152*65371a3fSMartin Blumenstingl static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) 153*65371a3fSMartin Blumenstingl { 154*65371a3fSMartin Blumenstingl return !rtw_sdio_is_sdio30_supported(rtwdev) || 155*65371a3fSMartin Blumenstingl rtw_sdio_is_bus_addr(addr); 156*65371a3fSMartin Blumenstingl } 157*65371a3fSMartin Blumenstingl 158*65371a3fSMartin Blumenstingl static int rtw_sdio_indirect_reg_cfg(struct rtw_dev *rtwdev, u32 addr, u32 cfg) 159*65371a3fSMartin Blumenstingl { 160*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 161*65371a3fSMartin Blumenstingl unsigned int retry; 162*65371a3fSMartin Blumenstingl u32 reg_cfg; 163*65371a3fSMartin Blumenstingl int ret; 164*65371a3fSMartin Blumenstingl u8 tmp; 165*65371a3fSMartin Blumenstingl 166*65371a3fSMartin Blumenstingl reg_cfg = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_CFG); 167*65371a3fSMartin Blumenstingl 168*65371a3fSMartin Blumenstingl rtw_sdio_writel(rtwdev, addr | cfg | BIT_SDIO_INDIRECT_REG_CFG_UNK20, 169*65371a3fSMartin Blumenstingl reg_cfg, &ret); 170*65371a3fSMartin Blumenstingl if (ret) 171*65371a3fSMartin Blumenstingl return ret; 172*65371a3fSMartin Blumenstingl 173*65371a3fSMartin Blumenstingl for (retry = 0; retry < RTW_SDIO_INDIRECT_RW_RETRIES; retry++) { 174*65371a3fSMartin Blumenstingl tmp = sdio_readb(rtwsdio->sdio_func, reg_cfg + 2, &ret); 175*65371a3fSMartin Blumenstingl if (!ret && (tmp & BIT(4))) 176*65371a3fSMartin Blumenstingl return 0; 177*65371a3fSMartin Blumenstingl } 178*65371a3fSMartin Blumenstingl 179*65371a3fSMartin Blumenstingl return -ETIMEDOUT; 180*65371a3fSMartin Blumenstingl } 181*65371a3fSMartin Blumenstingl 182*65371a3fSMartin Blumenstingl static u8 rtw_sdio_indirect_read8(struct rtw_dev *rtwdev, u32 addr, 183*65371a3fSMartin Blumenstingl int *err_ret) 184*65371a3fSMartin Blumenstingl { 185*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 186*65371a3fSMartin Blumenstingl u32 reg_data; 187*65371a3fSMartin Blumenstingl 188*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 189*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_READ); 190*65371a3fSMartin Blumenstingl if (*err_ret) 191*65371a3fSMartin Blumenstingl return 0; 192*65371a3fSMartin Blumenstingl 193*65371a3fSMartin Blumenstingl reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 194*65371a3fSMartin Blumenstingl return sdio_readb(rtwsdio->sdio_func, reg_data, err_ret); 195*65371a3fSMartin Blumenstingl } 196*65371a3fSMartin Blumenstingl 197*65371a3fSMartin Blumenstingl static int rtw_sdio_indirect_read_bytes(struct rtw_dev *rtwdev, u32 addr, 198*65371a3fSMartin Blumenstingl u8 *buf, int count) 199*65371a3fSMartin Blumenstingl { 200*65371a3fSMartin Blumenstingl int i, ret = 0; 201*65371a3fSMartin Blumenstingl 202*65371a3fSMartin Blumenstingl for (i = 0; i < count; i++) { 203*65371a3fSMartin Blumenstingl buf[i] = rtw_sdio_indirect_read8(rtwdev, addr + i, &ret); 204*65371a3fSMartin Blumenstingl if (ret) 205*65371a3fSMartin Blumenstingl break; 206*65371a3fSMartin Blumenstingl } 207*65371a3fSMartin Blumenstingl 208*65371a3fSMartin Blumenstingl return ret; 209*65371a3fSMartin Blumenstingl } 210*65371a3fSMartin Blumenstingl 211*65371a3fSMartin Blumenstingl static u16 rtw_sdio_indirect_read16(struct rtw_dev *rtwdev, u32 addr, 212*65371a3fSMartin Blumenstingl int *err_ret) 213*65371a3fSMartin Blumenstingl { 214*65371a3fSMartin Blumenstingl u32 reg_data; 215*65371a3fSMartin Blumenstingl u8 buf[2]; 216*65371a3fSMartin Blumenstingl 217*65371a3fSMartin Blumenstingl if (!IS_ALIGNED(addr, 2)) { 218*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_read_bytes(rtwdev, addr, buf, 2); 219*65371a3fSMartin Blumenstingl if (*err_ret) 220*65371a3fSMartin Blumenstingl return 0; 221*65371a3fSMartin Blumenstingl 222*65371a3fSMartin Blumenstingl return le16_to_cpu(*(__le16 *)buf); 223*65371a3fSMartin Blumenstingl } 224*65371a3fSMartin Blumenstingl 225*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 226*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_READ); 227*65371a3fSMartin Blumenstingl if (*err_ret) 228*65371a3fSMartin Blumenstingl return 0; 229*65371a3fSMartin Blumenstingl 230*65371a3fSMartin Blumenstingl reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 231*65371a3fSMartin Blumenstingl return rtw_sdio_readw(rtwdev, reg_data, err_ret); 232*65371a3fSMartin Blumenstingl } 233*65371a3fSMartin Blumenstingl 234*65371a3fSMartin Blumenstingl static u32 rtw_sdio_indirect_read32(struct rtw_dev *rtwdev, u32 addr, 235*65371a3fSMartin Blumenstingl int *err_ret) 236*65371a3fSMartin Blumenstingl { 237*65371a3fSMartin Blumenstingl u32 reg_data; 238*65371a3fSMartin Blumenstingl u8 buf[4]; 239*65371a3fSMartin Blumenstingl 240*65371a3fSMartin Blumenstingl if (!IS_ALIGNED(addr, 4)) { 241*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_read_bytes(rtwdev, addr, buf, 4); 242*65371a3fSMartin Blumenstingl if (*err_ret) 243*65371a3fSMartin Blumenstingl return 0; 244*65371a3fSMartin Blumenstingl 245*65371a3fSMartin Blumenstingl return le32_to_cpu(*(__le32 *)buf); 246*65371a3fSMartin Blumenstingl } 247*65371a3fSMartin Blumenstingl 248*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 249*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_READ); 250*65371a3fSMartin Blumenstingl if (*err_ret) 251*65371a3fSMartin Blumenstingl return 0; 252*65371a3fSMartin Blumenstingl 253*65371a3fSMartin Blumenstingl reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 254*65371a3fSMartin Blumenstingl return rtw_sdio_readl(rtwdev, reg_data, err_ret); 255*65371a3fSMartin Blumenstingl } 256*65371a3fSMartin Blumenstingl 257*65371a3fSMartin Blumenstingl static u8 rtw_sdio_read8(struct rtw_dev *rtwdev, u32 addr) 258*65371a3fSMartin Blumenstingl { 259*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 260*65371a3fSMartin Blumenstingl bool direct, bus_claim; 261*65371a3fSMartin Blumenstingl int ret; 262*65371a3fSMartin Blumenstingl u8 val; 263*65371a3fSMartin Blumenstingl 264*65371a3fSMartin Blumenstingl direct = rtw_sdio_use_direct_io(rtwdev, addr); 265*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 266*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 267*65371a3fSMartin Blumenstingl 268*65371a3fSMartin Blumenstingl if (bus_claim) 269*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 270*65371a3fSMartin Blumenstingl 271*65371a3fSMartin Blumenstingl if (direct) 272*65371a3fSMartin Blumenstingl val = sdio_readb(rtwsdio->sdio_func, addr, &ret); 273*65371a3fSMartin Blumenstingl else 274*65371a3fSMartin Blumenstingl val = rtw_sdio_indirect_read8(rtwdev, addr, &ret); 275*65371a3fSMartin Blumenstingl 276*65371a3fSMartin Blumenstingl if (bus_claim) 277*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 278*65371a3fSMartin Blumenstingl 279*65371a3fSMartin Blumenstingl if (ret) 280*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "sdio read8 failed (0x%x): %d", addr, ret); 281*65371a3fSMartin Blumenstingl 282*65371a3fSMartin Blumenstingl return val; 283*65371a3fSMartin Blumenstingl } 284*65371a3fSMartin Blumenstingl 285*65371a3fSMartin Blumenstingl static u16 rtw_sdio_read16(struct rtw_dev *rtwdev, u32 addr) 286*65371a3fSMartin Blumenstingl { 287*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 288*65371a3fSMartin Blumenstingl bool direct, bus_claim; 289*65371a3fSMartin Blumenstingl int ret; 290*65371a3fSMartin Blumenstingl u16 val; 291*65371a3fSMartin Blumenstingl 292*65371a3fSMartin Blumenstingl direct = rtw_sdio_use_direct_io(rtwdev, addr); 293*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 294*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 295*65371a3fSMartin Blumenstingl 296*65371a3fSMartin Blumenstingl if (bus_claim) 297*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 298*65371a3fSMartin Blumenstingl 299*65371a3fSMartin Blumenstingl if (direct) 300*65371a3fSMartin Blumenstingl val = rtw_sdio_readw(rtwdev, addr, &ret); 301*65371a3fSMartin Blumenstingl else 302*65371a3fSMartin Blumenstingl val = rtw_sdio_indirect_read16(rtwdev, addr, &ret); 303*65371a3fSMartin Blumenstingl 304*65371a3fSMartin Blumenstingl if (bus_claim) 305*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 306*65371a3fSMartin Blumenstingl 307*65371a3fSMartin Blumenstingl if (ret) 308*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "sdio read16 failed (0x%x): %d", addr, ret); 309*65371a3fSMartin Blumenstingl 310*65371a3fSMartin Blumenstingl return val; 311*65371a3fSMartin Blumenstingl } 312*65371a3fSMartin Blumenstingl 313*65371a3fSMartin Blumenstingl static u32 rtw_sdio_read32(struct rtw_dev *rtwdev, u32 addr) 314*65371a3fSMartin Blumenstingl { 315*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 316*65371a3fSMartin Blumenstingl bool direct, bus_claim; 317*65371a3fSMartin Blumenstingl u32 val; 318*65371a3fSMartin Blumenstingl int ret; 319*65371a3fSMartin Blumenstingl 320*65371a3fSMartin Blumenstingl direct = rtw_sdio_use_direct_io(rtwdev, addr); 321*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 322*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 323*65371a3fSMartin Blumenstingl 324*65371a3fSMartin Blumenstingl if (bus_claim) 325*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 326*65371a3fSMartin Blumenstingl 327*65371a3fSMartin Blumenstingl if (direct) 328*65371a3fSMartin Blumenstingl val = rtw_sdio_readl(rtwdev, addr, &ret); 329*65371a3fSMartin Blumenstingl else 330*65371a3fSMartin Blumenstingl val = rtw_sdio_indirect_read32(rtwdev, addr, &ret); 331*65371a3fSMartin Blumenstingl 332*65371a3fSMartin Blumenstingl if (bus_claim) 333*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 334*65371a3fSMartin Blumenstingl 335*65371a3fSMartin Blumenstingl if (ret) 336*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "sdio read32 failed (0x%x): %d", addr, ret); 337*65371a3fSMartin Blumenstingl 338*65371a3fSMartin Blumenstingl return val; 339*65371a3fSMartin Blumenstingl } 340*65371a3fSMartin Blumenstingl 341*65371a3fSMartin Blumenstingl static void rtw_sdio_indirect_write8(struct rtw_dev *rtwdev, u8 val, u32 addr, 342*65371a3fSMartin Blumenstingl int *err_ret) 343*65371a3fSMartin Blumenstingl { 344*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 345*65371a3fSMartin Blumenstingl u32 reg_data; 346*65371a3fSMartin Blumenstingl 347*65371a3fSMartin Blumenstingl reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 348*65371a3fSMartin Blumenstingl sdio_writeb(rtwsdio->sdio_func, val, reg_data, err_ret); 349*65371a3fSMartin Blumenstingl if (*err_ret) 350*65371a3fSMartin Blumenstingl return; 351*65371a3fSMartin Blumenstingl 352*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 353*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_WRITE); 354*65371a3fSMartin Blumenstingl } 355*65371a3fSMartin Blumenstingl 356*65371a3fSMartin Blumenstingl static void rtw_sdio_indirect_write16(struct rtw_dev *rtwdev, u16 val, u32 addr, 357*65371a3fSMartin Blumenstingl int *err_ret) 358*65371a3fSMartin Blumenstingl { 359*65371a3fSMartin Blumenstingl u32 reg_data; 360*65371a3fSMartin Blumenstingl 361*65371a3fSMartin Blumenstingl if (!IS_ALIGNED(addr, 2)) { 362*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, true); 363*65371a3fSMartin Blumenstingl rtw_sdio_writew(rtwdev, val, addr, err_ret); 364*65371a3fSMartin Blumenstingl return; 365*65371a3fSMartin Blumenstingl } 366*65371a3fSMartin Blumenstingl 367*65371a3fSMartin Blumenstingl reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 368*65371a3fSMartin Blumenstingl rtw_sdio_writew(rtwdev, val, reg_data, err_ret); 369*65371a3fSMartin Blumenstingl if (*err_ret) 370*65371a3fSMartin Blumenstingl return; 371*65371a3fSMartin Blumenstingl 372*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 373*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_WRITE | 374*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_WORD); 375*65371a3fSMartin Blumenstingl } 376*65371a3fSMartin Blumenstingl 377*65371a3fSMartin Blumenstingl static void rtw_sdio_indirect_write32(struct rtw_dev *rtwdev, u32 val, 378*65371a3fSMartin Blumenstingl u32 addr, int *err_ret) 379*65371a3fSMartin Blumenstingl { 380*65371a3fSMartin Blumenstingl u32 reg_data; 381*65371a3fSMartin Blumenstingl 382*65371a3fSMartin Blumenstingl if (!IS_ALIGNED(addr, 4)) { 383*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, true); 384*65371a3fSMartin Blumenstingl rtw_sdio_writel(rtwdev, val, addr, err_ret); 385*65371a3fSMartin Blumenstingl return; 386*65371a3fSMartin Blumenstingl } 387*65371a3fSMartin Blumenstingl 388*65371a3fSMartin Blumenstingl reg_data = rtw_sdio_to_bus_offset(rtwdev, REG_SDIO_INDIRECT_REG_DATA); 389*65371a3fSMartin Blumenstingl rtw_sdio_writel(rtwdev, val, reg_data, err_ret); 390*65371a3fSMartin Blumenstingl 391*65371a3fSMartin Blumenstingl *err_ret = rtw_sdio_indirect_reg_cfg(rtwdev, addr, 392*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_WRITE | 393*65371a3fSMartin Blumenstingl BIT_SDIO_INDIRECT_REG_CFG_DWORD); 394*65371a3fSMartin Blumenstingl } 395*65371a3fSMartin Blumenstingl 396*65371a3fSMartin Blumenstingl static void rtw_sdio_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) 397*65371a3fSMartin Blumenstingl { 398*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 399*65371a3fSMartin Blumenstingl bool direct, bus_claim; 400*65371a3fSMartin Blumenstingl int ret; 401*65371a3fSMartin Blumenstingl 402*65371a3fSMartin Blumenstingl direct = rtw_sdio_use_direct_io(rtwdev, addr); 403*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 404*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 405*65371a3fSMartin Blumenstingl 406*65371a3fSMartin Blumenstingl if (bus_claim) 407*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 408*65371a3fSMartin Blumenstingl 409*65371a3fSMartin Blumenstingl if (direct) 410*65371a3fSMartin Blumenstingl sdio_writeb(rtwsdio->sdio_func, val, addr, &ret); 411*65371a3fSMartin Blumenstingl else 412*65371a3fSMartin Blumenstingl rtw_sdio_indirect_write8(rtwdev, val, addr, &ret); 413*65371a3fSMartin Blumenstingl 414*65371a3fSMartin Blumenstingl if (bus_claim) 415*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 416*65371a3fSMartin Blumenstingl 417*65371a3fSMartin Blumenstingl if (ret) 418*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "sdio write8 failed (0x%x): %d", addr, ret); 419*65371a3fSMartin Blumenstingl } 420*65371a3fSMartin Blumenstingl 421*65371a3fSMartin Blumenstingl static void rtw_sdio_write16(struct rtw_dev *rtwdev, u32 addr, u16 val) 422*65371a3fSMartin Blumenstingl { 423*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 424*65371a3fSMartin Blumenstingl bool direct, bus_claim; 425*65371a3fSMartin Blumenstingl int ret; 426*65371a3fSMartin Blumenstingl 427*65371a3fSMartin Blumenstingl direct = rtw_sdio_use_direct_io(rtwdev, addr); 428*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 429*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 430*65371a3fSMartin Blumenstingl 431*65371a3fSMartin Blumenstingl if (bus_claim) 432*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 433*65371a3fSMartin Blumenstingl 434*65371a3fSMartin Blumenstingl if (direct) 435*65371a3fSMartin Blumenstingl rtw_sdio_writew(rtwdev, val, addr, &ret); 436*65371a3fSMartin Blumenstingl else 437*65371a3fSMartin Blumenstingl rtw_sdio_indirect_write16(rtwdev, val, addr, &ret); 438*65371a3fSMartin Blumenstingl 439*65371a3fSMartin Blumenstingl if (bus_claim) 440*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 441*65371a3fSMartin Blumenstingl 442*65371a3fSMartin Blumenstingl if (ret) 443*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "sdio write16 failed (0x%x): %d", addr, ret); 444*65371a3fSMartin Blumenstingl } 445*65371a3fSMartin Blumenstingl 446*65371a3fSMartin Blumenstingl static void rtw_sdio_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) 447*65371a3fSMartin Blumenstingl { 448*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 449*65371a3fSMartin Blumenstingl bool direct, bus_claim; 450*65371a3fSMartin Blumenstingl int ret; 451*65371a3fSMartin Blumenstingl 452*65371a3fSMartin Blumenstingl direct = rtw_sdio_use_direct_io(rtwdev, addr); 453*65371a3fSMartin Blumenstingl addr = rtw_sdio_to_io_address(rtwdev, addr, direct); 454*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 455*65371a3fSMartin Blumenstingl 456*65371a3fSMartin Blumenstingl if (bus_claim) 457*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 458*65371a3fSMartin Blumenstingl 459*65371a3fSMartin Blumenstingl if (direct) 460*65371a3fSMartin Blumenstingl rtw_sdio_writel(rtwdev, val, addr, &ret); 461*65371a3fSMartin Blumenstingl else 462*65371a3fSMartin Blumenstingl rtw_sdio_indirect_write32(rtwdev, val, addr, &ret); 463*65371a3fSMartin Blumenstingl 464*65371a3fSMartin Blumenstingl if (bus_claim) 465*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 466*65371a3fSMartin Blumenstingl 467*65371a3fSMartin Blumenstingl if (ret) 468*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "sdio write32 failed (0x%x): %d", addr, ret); 469*65371a3fSMartin Blumenstingl } 470*65371a3fSMartin Blumenstingl 471*65371a3fSMartin Blumenstingl static u32 rtw_sdio_get_tx_addr(struct rtw_dev *rtwdev, size_t size, 472*65371a3fSMartin Blumenstingl enum rtw_tx_queue_type queue) 473*65371a3fSMartin Blumenstingl { 474*65371a3fSMartin Blumenstingl u32 txaddr; 475*65371a3fSMartin Blumenstingl 476*65371a3fSMartin Blumenstingl switch (queue) { 477*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BCN: 478*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_H2C: 479*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_HI0: 480*65371a3fSMartin Blumenstingl txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 481*65371a3fSMartin Blumenstingl REG_SDIO_CMD_ADDR_TXFF_HIGH); 482*65371a3fSMartin Blumenstingl break; 483*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_VI: 484*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_VO: 485*65371a3fSMartin Blumenstingl txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 486*65371a3fSMartin Blumenstingl REG_SDIO_CMD_ADDR_TXFF_NORMAL); 487*65371a3fSMartin Blumenstingl break; 488*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BE: 489*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BK: 490*65371a3fSMartin Blumenstingl txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 491*65371a3fSMartin Blumenstingl REG_SDIO_CMD_ADDR_TXFF_LOW); 492*65371a3fSMartin Blumenstingl break; 493*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_MGMT: 494*65371a3fSMartin Blumenstingl txaddr = FIELD_PREP(REG_SDIO_CMD_ADDR_MSK, 495*65371a3fSMartin Blumenstingl REG_SDIO_CMD_ADDR_TXFF_EXTRA); 496*65371a3fSMartin Blumenstingl break; 497*65371a3fSMartin Blumenstingl default: 498*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "Unsupported queue for TX addr: 0x%02x\n", 499*65371a3fSMartin Blumenstingl queue); 500*65371a3fSMartin Blumenstingl return 0; 501*65371a3fSMartin Blumenstingl } 502*65371a3fSMartin Blumenstingl 503*65371a3fSMartin Blumenstingl txaddr += DIV_ROUND_UP(size, 4); 504*65371a3fSMartin Blumenstingl 505*65371a3fSMartin Blumenstingl return txaddr; 506*65371a3fSMartin Blumenstingl }; 507*65371a3fSMartin Blumenstingl 508*65371a3fSMartin Blumenstingl static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) 509*65371a3fSMartin Blumenstingl { 510*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 511*65371a3fSMartin Blumenstingl bool bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 512*65371a3fSMartin Blumenstingl u32 rxaddr = rtwsdio->rx_addr++; 513*65371a3fSMartin Blumenstingl int ret; 514*65371a3fSMartin Blumenstingl 515*65371a3fSMartin Blumenstingl if (bus_claim) 516*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 517*65371a3fSMartin Blumenstingl 518*65371a3fSMartin Blumenstingl ret = sdio_memcpy_fromio(rtwsdio->sdio_func, buf, 519*65371a3fSMartin Blumenstingl RTW_SDIO_ADDR_RX_RX0FF_GEN(rxaddr), count); 520*65371a3fSMartin Blumenstingl if (ret) 521*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, 522*65371a3fSMartin Blumenstingl "Failed to read %zu byte(s) from SDIO port 0x%08x", 523*65371a3fSMartin Blumenstingl count, rxaddr); 524*65371a3fSMartin Blumenstingl 525*65371a3fSMartin Blumenstingl if (bus_claim) 526*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 527*65371a3fSMartin Blumenstingl 528*65371a3fSMartin Blumenstingl return ret; 529*65371a3fSMartin Blumenstingl } 530*65371a3fSMartin Blumenstingl 531*65371a3fSMartin Blumenstingl static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, 532*65371a3fSMartin Blumenstingl size_t count) 533*65371a3fSMartin Blumenstingl { 534*65371a3fSMartin Blumenstingl unsigned int pages_free, pages_needed; 535*65371a3fSMartin Blumenstingl 536*65371a3fSMartin Blumenstingl if (rtw_chip_wcpu_11n(rtwdev)) { 537*65371a3fSMartin Blumenstingl u32 free_txpg; 538*65371a3fSMartin Blumenstingl 539*65371a3fSMartin Blumenstingl free_txpg = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); 540*65371a3fSMartin Blumenstingl 541*65371a3fSMartin Blumenstingl switch (queue) { 542*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BCN: 543*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_H2C: 544*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_HI0: 545*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_MGMT: 546*65371a3fSMartin Blumenstingl /* high */ 547*65371a3fSMartin Blumenstingl pages_free = free_txpg & 0xff; 548*65371a3fSMartin Blumenstingl break; 549*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_VI: 550*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_VO: 551*65371a3fSMartin Blumenstingl /* normal */ 552*65371a3fSMartin Blumenstingl pages_free = (free_txpg >> 8) & 0xff; 553*65371a3fSMartin Blumenstingl break; 554*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BE: 555*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BK: 556*65371a3fSMartin Blumenstingl /* low */ 557*65371a3fSMartin Blumenstingl pages_free = (free_txpg >> 16) & 0xff; 558*65371a3fSMartin Blumenstingl break; 559*65371a3fSMartin Blumenstingl default: 560*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "Unknown mapping for queue %u\n", queue); 561*65371a3fSMartin Blumenstingl return -EINVAL; 562*65371a3fSMartin Blumenstingl } 563*65371a3fSMartin Blumenstingl 564*65371a3fSMartin Blumenstingl /* add the pages from the public queue */ 565*65371a3fSMartin Blumenstingl pages_free += (free_txpg >> 24) & 0xff; 566*65371a3fSMartin Blumenstingl } else { 567*65371a3fSMartin Blumenstingl u32 free_txpg[3]; 568*65371a3fSMartin Blumenstingl 569*65371a3fSMartin Blumenstingl free_txpg[0] = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); 570*65371a3fSMartin Blumenstingl free_txpg[1] = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG + 4); 571*65371a3fSMartin Blumenstingl free_txpg[2] = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG + 8); 572*65371a3fSMartin Blumenstingl 573*65371a3fSMartin Blumenstingl switch (queue) { 574*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BCN: 575*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_H2C: 576*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_HI0: 577*65371a3fSMartin Blumenstingl /* high */ 578*65371a3fSMartin Blumenstingl pages_free = free_txpg[0] & 0xfff; 579*65371a3fSMartin Blumenstingl break; 580*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_VI: 581*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_VO: 582*65371a3fSMartin Blumenstingl /* normal */ 583*65371a3fSMartin Blumenstingl pages_free = (free_txpg[0] >> 16) & 0xfff; 584*65371a3fSMartin Blumenstingl break; 585*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BE: 586*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BK: 587*65371a3fSMartin Blumenstingl /* low */ 588*65371a3fSMartin Blumenstingl pages_free = free_txpg[1] & 0xfff; 589*65371a3fSMartin Blumenstingl break; 590*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_MGMT: 591*65371a3fSMartin Blumenstingl /* extra */ 592*65371a3fSMartin Blumenstingl pages_free = free_txpg[2] & 0xfff; 593*65371a3fSMartin Blumenstingl break; 594*65371a3fSMartin Blumenstingl default: 595*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "Unknown mapping for queue %u\n", queue); 596*65371a3fSMartin Blumenstingl return -EINVAL; 597*65371a3fSMartin Blumenstingl } 598*65371a3fSMartin Blumenstingl 599*65371a3fSMartin Blumenstingl /* add the pages from the public queue */ 600*65371a3fSMartin Blumenstingl pages_free += (free_txpg[1] >> 16) & 0xfff; 601*65371a3fSMartin Blumenstingl } 602*65371a3fSMartin Blumenstingl 603*65371a3fSMartin Blumenstingl pages_needed = DIV_ROUND_UP(count, rtwdev->chip->page_size); 604*65371a3fSMartin Blumenstingl 605*65371a3fSMartin Blumenstingl if (pages_needed > pages_free) { 606*65371a3fSMartin Blumenstingl rtw_dbg(rtwdev, RTW_DBG_SDIO, 607*65371a3fSMartin Blumenstingl "Not enough free pages (%u needed, %u free) in queue %u for %zu bytes\n", 608*65371a3fSMartin Blumenstingl pages_needed, pages_free, queue, count); 609*65371a3fSMartin Blumenstingl return -EBUSY; 610*65371a3fSMartin Blumenstingl } 611*65371a3fSMartin Blumenstingl 612*65371a3fSMartin Blumenstingl return 0; 613*65371a3fSMartin Blumenstingl } 614*65371a3fSMartin Blumenstingl 615*65371a3fSMartin Blumenstingl static int rtw_sdio_write_port(struct rtw_dev *rtwdev, struct sk_buff *skb, 616*65371a3fSMartin Blumenstingl enum rtw_tx_queue_type queue) 617*65371a3fSMartin Blumenstingl { 618*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 619*65371a3fSMartin Blumenstingl bool bus_claim; 620*65371a3fSMartin Blumenstingl size_t txsize; 621*65371a3fSMartin Blumenstingl u32 txaddr; 622*65371a3fSMartin Blumenstingl int ret; 623*65371a3fSMartin Blumenstingl 624*65371a3fSMartin Blumenstingl txaddr = rtw_sdio_get_tx_addr(rtwdev, skb->len, queue); 625*65371a3fSMartin Blumenstingl if (!txaddr) 626*65371a3fSMartin Blumenstingl return -EINVAL; 627*65371a3fSMartin Blumenstingl 628*65371a3fSMartin Blumenstingl txsize = sdio_align_size(rtwsdio->sdio_func, skb->len); 629*65371a3fSMartin Blumenstingl 630*65371a3fSMartin Blumenstingl ret = rtw_sdio_check_free_txpg(rtwdev, queue, txsize); 631*65371a3fSMartin Blumenstingl if (ret) 632*65371a3fSMartin Blumenstingl return ret; 633*65371a3fSMartin Blumenstingl 634*65371a3fSMartin Blumenstingl if (!IS_ALIGNED((unsigned long)skb->data, RTW_SDIO_DATA_PTR_ALIGN)) 635*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, "Got unaligned SKB in %s() for queue %u\n", 636*65371a3fSMartin Blumenstingl __func__, queue); 637*65371a3fSMartin Blumenstingl 638*65371a3fSMartin Blumenstingl bus_claim = rtw_sdio_bus_claim_needed(rtwsdio); 639*65371a3fSMartin Blumenstingl 640*65371a3fSMartin Blumenstingl if (bus_claim) 641*65371a3fSMartin Blumenstingl sdio_claim_host(rtwsdio->sdio_func); 642*65371a3fSMartin Blumenstingl 643*65371a3fSMartin Blumenstingl ret = sdio_memcpy_toio(rtwsdio->sdio_func, txaddr, skb->data, txsize); 644*65371a3fSMartin Blumenstingl 645*65371a3fSMartin Blumenstingl if (bus_claim) 646*65371a3fSMartin Blumenstingl sdio_release_host(rtwsdio->sdio_func); 647*65371a3fSMartin Blumenstingl 648*65371a3fSMartin Blumenstingl if (ret) 649*65371a3fSMartin Blumenstingl rtw_warn(rtwdev, 650*65371a3fSMartin Blumenstingl "Failed to write %zu byte(s) to SDIO port 0x%08x", 651*65371a3fSMartin Blumenstingl txsize, txaddr); 652*65371a3fSMartin Blumenstingl 653*65371a3fSMartin Blumenstingl return ret; 654*65371a3fSMartin Blumenstingl } 655*65371a3fSMartin Blumenstingl 656*65371a3fSMartin Blumenstingl static void rtw_sdio_init(struct rtw_dev *rtwdev) 657*65371a3fSMartin Blumenstingl { 658*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 659*65371a3fSMartin Blumenstingl 660*65371a3fSMartin Blumenstingl rtwsdio->irq_mask = REG_SDIO_HIMR_RX_REQUEST | REG_SDIO_HIMR_CPWM1; 661*65371a3fSMartin Blumenstingl } 662*65371a3fSMartin Blumenstingl 663*65371a3fSMartin Blumenstingl static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) 664*65371a3fSMartin Blumenstingl { 665*65371a3fSMartin Blumenstingl u8 size, timeout; 666*65371a3fSMartin Blumenstingl 667*65371a3fSMartin Blumenstingl if (rtw_chip_wcpu_11n(rtwdev)) { 668*65371a3fSMartin Blumenstingl size = 0x6; 669*65371a3fSMartin Blumenstingl timeout = 0x6; 670*65371a3fSMartin Blumenstingl } else { 671*65371a3fSMartin Blumenstingl size = 0xff; 672*65371a3fSMartin Blumenstingl timeout = 0x1; 673*65371a3fSMartin Blumenstingl } 674*65371a3fSMartin Blumenstingl 675*65371a3fSMartin Blumenstingl /* Make the firmware honor the size limit configured below */ 676*65371a3fSMartin Blumenstingl rtw_write32_set(rtwdev, REG_RXDMA_AGG_PG_TH, BIT_EN_PRE_CALC); 677*65371a3fSMartin Blumenstingl 678*65371a3fSMartin Blumenstingl rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_AGG_EN); 679*65371a3fSMartin Blumenstingl 680*65371a3fSMartin Blumenstingl rtw_write16(rtwdev, REG_RXDMA_AGG_PG_TH, 681*65371a3fSMartin Blumenstingl FIELD_PREP(BIT_RXDMA_AGG_PG_TH, size) | 682*65371a3fSMartin Blumenstingl FIELD_PREP(BIT_DMA_AGG_TO_V1, timeout)); 683*65371a3fSMartin Blumenstingl 684*65371a3fSMartin Blumenstingl rtw_write8_set(rtwdev, REG_RXDMA_MODE, BIT_DMA_MODE); 685*65371a3fSMartin Blumenstingl } 686*65371a3fSMartin Blumenstingl 687*65371a3fSMartin Blumenstingl static void rtw_sdio_enable_interrupt(struct rtw_dev *rtwdev) 688*65371a3fSMartin Blumenstingl { 689*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 690*65371a3fSMartin Blumenstingl 691*65371a3fSMartin Blumenstingl rtw_write32(rtwdev, REG_SDIO_HIMR, rtwsdio->irq_mask); 692*65371a3fSMartin Blumenstingl } 693*65371a3fSMartin Blumenstingl 694*65371a3fSMartin Blumenstingl static void rtw_sdio_disable_interrupt(struct rtw_dev *rtwdev) 695*65371a3fSMartin Blumenstingl { 696*65371a3fSMartin Blumenstingl rtw_write32(rtwdev, REG_SDIO_HIMR, 0x0); 697*65371a3fSMartin Blumenstingl } 698*65371a3fSMartin Blumenstingl 699*65371a3fSMartin Blumenstingl static u8 rtw_sdio_get_tx_qsel(struct rtw_dev *rtwdev, struct sk_buff *skb, 700*65371a3fSMartin Blumenstingl u8 queue) 701*65371a3fSMartin Blumenstingl { 702*65371a3fSMartin Blumenstingl switch (queue) { 703*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_BCN: 704*65371a3fSMartin Blumenstingl return TX_DESC_QSEL_BEACON; 705*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_H2C: 706*65371a3fSMartin Blumenstingl return TX_DESC_QSEL_H2C; 707*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_MGMT: 708*65371a3fSMartin Blumenstingl if (rtw_chip_wcpu_11n(rtwdev)) 709*65371a3fSMartin Blumenstingl return TX_DESC_QSEL_HIGH; 710*65371a3fSMartin Blumenstingl else 711*65371a3fSMartin Blumenstingl return TX_DESC_QSEL_MGMT; 712*65371a3fSMartin Blumenstingl case RTW_TX_QUEUE_HI0: 713*65371a3fSMartin Blumenstingl return TX_DESC_QSEL_HIGH; 714*65371a3fSMartin Blumenstingl default: 715*65371a3fSMartin Blumenstingl return skb->priority; 716*65371a3fSMartin Blumenstingl } 717*65371a3fSMartin Blumenstingl } 718*65371a3fSMartin Blumenstingl 719*65371a3fSMartin Blumenstingl static int rtw_sdio_setup(struct rtw_dev *rtwdev) 720*65371a3fSMartin Blumenstingl { 721*65371a3fSMartin Blumenstingl /* nothing to do */ 722*65371a3fSMartin Blumenstingl return 0; 723*65371a3fSMartin Blumenstingl } 724*65371a3fSMartin Blumenstingl 725*65371a3fSMartin Blumenstingl static int rtw_sdio_start(struct rtw_dev *rtwdev) 726*65371a3fSMartin Blumenstingl { 727*65371a3fSMartin Blumenstingl rtw_sdio_enable_rx_aggregation(rtwdev); 728*65371a3fSMartin Blumenstingl rtw_sdio_enable_interrupt(rtwdev); 729*65371a3fSMartin Blumenstingl 730*65371a3fSMartin Blumenstingl return 0; 731*65371a3fSMartin Blumenstingl } 732*65371a3fSMartin Blumenstingl 733*65371a3fSMartin Blumenstingl static void rtw_sdio_stop(struct rtw_dev *rtwdev) 734*65371a3fSMartin Blumenstingl { 735*65371a3fSMartin Blumenstingl rtw_sdio_disable_interrupt(rtwdev); 736*65371a3fSMartin Blumenstingl } 737*65371a3fSMartin Blumenstingl 738*65371a3fSMartin Blumenstingl static void rtw_sdio_deep_ps_enter(struct rtw_dev *rtwdev) 739*65371a3fSMartin Blumenstingl { 740*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 741*65371a3fSMartin Blumenstingl bool tx_empty = true; 742*65371a3fSMartin Blumenstingl u8 queue; 743*65371a3fSMartin Blumenstingl 744*65371a3fSMartin Blumenstingl if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) { 745*65371a3fSMartin Blumenstingl /* Deep PS state is not allowed to TX-DMA */ 746*65371a3fSMartin Blumenstingl for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) { 747*65371a3fSMartin Blumenstingl /* BCN queue is rsvd page, does not have DMA interrupt 748*65371a3fSMartin Blumenstingl * H2C queue is managed by firmware 749*65371a3fSMartin Blumenstingl */ 750*65371a3fSMartin Blumenstingl if (queue == RTW_TX_QUEUE_BCN || 751*65371a3fSMartin Blumenstingl queue == RTW_TX_QUEUE_H2C) 752*65371a3fSMartin Blumenstingl continue; 753*65371a3fSMartin Blumenstingl 754*65371a3fSMartin Blumenstingl /* check if there is any skb DMAing */ 755*65371a3fSMartin Blumenstingl if (skb_queue_len(&rtwsdio->tx_queue[queue])) { 756*65371a3fSMartin Blumenstingl tx_empty = false; 757*65371a3fSMartin Blumenstingl break; 758*65371a3fSMartin Blumenstingl } 759*65371a3fSMartin Blumenstingl } 760*65371a3fSMartin Blumenstingl } 761*65371a3fSMartin Blumenstingl 762*65371a3fSMartin Blumenstingl if (!tx_empty) { 763*65371a3fSMartin Blumenstingl rtw_dbg(rtwdev, RTW_DBG_PS, 764*65371a3fSMartin Blumenstingl "TX path not empty, cannot enter deep power save state\n"); 765*65371a3fSMartin Blumenstingl return; 766*65371a3fSMartin Blumenstingl } 767*65371a3fSMartin Blumenstingl 768*65371a3fSMartin Blumenstingl set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags); 769*65371a3fSMartin Blumenstingl rtw_power_mode_change(rtwdev, true); 770*65371a3fSMartin Blumenstingl } 771*65371a3fSMartin Blumenstingl 772*65371a3fSMartin Blumenstingl static void rtw_sdio_deep_ps_leave(struct rtw_dev *rtwdev) 773*65371a3fSMartin Blumenstingl { 774*65371a3fSMartin Blumenstingl if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) 775*65371a3fSMartin Blumenstingl rtw_power_mode_change(rtwdev, false); 776*65371a3fSMartin Blumenstingl } 777*65371a3fSMartin Blumenstingl 778*65371a3fSMartin Blumenstingl static void rtw_sdio_deep_ps(struct rtw_dev *rtwdev, bool enter) 779*65371a3fSMartin Blumenstingl { 780*65371a3fSMartin Blumenstingl if (enter && !test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) 781*65371a3fSMartin Blumenstingl rtw_sdio_deep_ps_enter(rtwdev); 782*65371a3fSMartin Blumenstingl 783*65371a3fSMartin Blumenstingl if (!enter && test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) 784*65371a3fSMartin Blumenstingl rtw_sdio_deep_ps_leave(rtwdev); 785*65371a3fSMartin Blumenstingl } 786*65371a3fSMartin Blumenstingl 787*65371a3fSMartin Blumenstingl static void rtw_sdio_tx_kick_off(struct rtw_dev *rtwdev) 788*65371a3fSMartin Blumenstingl { 789*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 790*65371a3fSMartin Blumenstingl 791*65371a3fSMartin Blumenstingl queue_work(rtwsdio->txwq, &rtwsdio->tx_handler_data->work); 792*65371a3fSMartin Blumenstingl } 793*65371a3fSMartin Blumenstingl 794*65371a3fSMartin Blumenstingl static void rtw_sdio_link_ps(struct rtw_dev *rtwdev, bool enter) 795*65371a3fSMartin Blumenstingl { 796*65371a3fSMartin Blumenstingl /* nothing to do */ 797*65371a3fSMartin Blumenstingl } 798*65371a3fSMartin Blumenstingl 799*65371a3fSMartin Blumenstingl static void rtw_sdio_interface_cfg(struct rtw_dev *rtwdev) 800*65371a3fSMartin Blumenstingl { 801*65371a3fSMartin Blumenstingl u32 val; 802*65371a3fSMartin Blumenstingl 803*65371a3fSMartin Blumenstingl rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); 804*65371a3fSMartin Blumenstingl 805*65371a3fSMartin Blumenstingl val = rtw_read32(rtwdev, REG_SDIO_TX_CTRL); 806*65371a3fSMartin Blumenstingl val &= 0xfff8; 807*65371a3fSMartin Blumenstingl rtw_write32(rtwdev, REG_SDIO_TX_CTRL, val); 808*65371a3fSMartin Blumenstingl } 809*65371a3fSMartin Blumenstingl 810*65371a3fSMartin Blumenstingl static struct rtw_sdio_tx_data *rtw_sdio_get_tx_data(struct sk_buff *skb) 811*65371a3fSMartin Blumenstingl { 812*65371a3fSMartin Blumenstingl struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 813*65371a3fSMartin Blumenstingl 814*65371a3fSMartin Blumenstingl BUILD_BUG_ON(sizeof(struct rtw_sdio_tx_data) > 815*65371a3fSMartin Blumenstingl sizeof(info->status.status_driver_data)); 816*65371a3fSMartin Blumenstingl 817*65371a3fSMartin Blumenstingl return (struct rtw_sdio_tx_data *)info->status.status_driver_data; 818*65371a3fSMartin Blumenstingl } 819*65371a3fSMartin Blumenstingl 820*65371a3fSMartin Blumenstingl static void rtw_sdio_tx_skb_prepare(struct rtw_dev *rtwdev, 821*65371a3fSMartin Blumenstingl struct rtw_tx_pkt_info *pkt_info, 822*65371a3fSMartin Blumenstingl struct sk_buff *skb, 823*65371a3fSMartin Blumenstingl enum rtw_tx_queue_type queue) 824*65371a3fSMartin Blumenstingl { 825*65371a3fSMartin Blumenstingl const struct rtw_chip_info *chip = rtwdev->chip; 826*65371a3fSMartin Blumenstingl unsigned long data_addr, aligned_addr; 827*65371a3fSMartin Blumenstingl size_t offset; 828*65371a3fSMartin Blumenstingl u8 *pkt_desc; 829*65371a3fSMartin Blumenstingl 830*65371a3fSMartin Blumenstingl pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); 831*65371a3fSMartin Blumenstingl 832*65371a3fSMartin Blumenstingl data_addr = (unsigned long)pkt_desc; 833*65371a3fSMartin Blumenstingl aligned_addr = ALIGN(data_addr, RTW_SDIO_DATA_PTR_ALIGN); 834*65371a3fSMartin Blumenstingl 835*65371a3fSMartin Blumenstingl if (data_addr != aligned_addr) { 836*65371a3fSMartin Blumenstingl /* Ensure that the start of the pkt_desc is always aligned at 837*65371a3fSMartin Blumenstingl * RTW_SDIO_DATA_PTR_ALIGN. 838*65371a3fSMartin Blumenstingl */ 839*65371a3fSMartin Blumenstingl offset = RTW_SDIO_DATA_PTR_ALIGN - (aligned_addr - data_addr); 840*65371a3fSMartin Blumenstingl 841*65371a3fSMartin Blumenstingl pkt_desc = skb_push(skb, offset); 842*65371a3fSMartin Blumenstingl 843*65371a3fSMartin Blumenstingl /* By inserting padding to align the start of the pkt_desc we 844*65371a3fSMartin Blumenstingl * need to inform the firmware that the actual data starts at 845*65371a3fSMartin Blumenstingl * a different offset than normal. 846*65371a3fSMartin Blumenstingl */ 847*65371a3fSMartin Blumenstingl pkt_info->offset += offset; 848*65371a3fSMartin Blumenstingl } 849*65371a3fSMartin Blumenstingl 850*65371a3fSMartin Blumenstingl memset(pkt_desc, 0, chip->tx_pkt_desc_sz); 851*65371a3fSMartin Blumenstingl 852*65371a3fSMartin Blumenstingl pkt_info->qsel = rtw_sdio_get_tx_qsel(rtwdev, skb, queue); 853*65371a3fSMartin Blumenstingl 854*65371a3fSMartin Blumenstingl rtw_tx_fill_tx_desc(pkt_info, skb); 855*65371a3fSMartin Blumenstingl rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, pkt_desc); 856*65371a3fSMartin Blumenstingl } 857*65371a3fSMartin Blumenstingl 858*65371a3fSMartin Blumenstingl static int rtw_sdio_write_data(struct rtw_dev *rtwdev, 859*65371a3fSMartin Blumenstingl struct rtw_tx_pkt_info *pkt_info, 860*65371a3fSMartin Blumenstingl struct sk_buff *skb, 861*65371a3fSMartin Blumenstingl enum rtw_tx_queue_type queue) 862*65371a3fSMartin Blumenstingl { 863*65371a3fSMartin Blumenstingl int ret; 864*65371a3fSMartin Blumenstingl 865*65371a3fSMartin Blumenstingl rtw_sdio_tx_skb_prepare(rtwdev, pkt_info, skb, queue); 866*65371a3fSMartin Blumenstingl 867*65371a3fSMartin Blumenstingl ret = rtw_sdio_write_port(rtwdev, skb, queue); 868*65371a3fSMartin Blumenstingl dev_kfree_skb_any(skb); 869*65371a3fSMartin Blumenstingl 870*65371a3fSMartin Blumenstingl return ret; 871*65371a3fSMartin Blumenstingl } 872*65371a3fSMartin Blumenstingl 873*65371a3fSMartin Blumenstingl static int rtw_sdio_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, 874*65371a3fSMartin Blumenstingl u32 size) 875*65371a3fSMartin Blumenstingl { 876*65371a3fSMartin Blumenstingl struct rtw_tx_pkt_info pkt_info = {}; 877*65371a3fSMartin Blumenstingl struct sk_buff *skb; 878*65371a3fSMartin Blumenstingl 879*65371a3fSMartin Blumenstingl skb = rtw_tx_write_data_rsvd_page_get(rtwdev, &pkt_info, buf, size); 880*65371a3fSMartin Blumenstingl if (!skb) 881*65371a3fSMartin Blumenstingl return -ENOMEM; 882*65371a3fSMartin Blumenstingl 883*65371a3fSMartin Blumenstingl return rtw_sdio_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_BCN); 884*65371a3fSMartin Blumenstingl } 885*65371a3fSMartin Blumenstingl 886*65371a3fSMartin Blumenstingl static int rtw_sdio_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size) 887*65371a3fSMartin Blumenstingl { 888*65371a3fSMartin Blumenstingl struct rtw_tx_pkt_info pkt_info = {}; 889*65371a3fSMartin Blumenstingl struct sk_buff *skb; 890*65371a3fSMartin Blumenstingl 891*65371a3fSMartin Blumenstingl skb = rtw_tx_write_data_h2c_get(rtwdev, &pkt_info, buf, size); 892*65371a3fSMartin Blumenstingl if (!skb) 893*65371a3fSMartin Blumenstingl return -ENOMEM; 894*65371a3fSMartin Blumenstingl 895*65371a3fSMartin Blumenstingl return rtw_sdio_write_data(rtwdev, &pkt_info, skb, RTW_TX_QUEUE_H2C); 896*65371a3fSMartin Blumenstingl } 897*65371a3fSMartin Blumenstingl 898*65371a3fSMartin Blumenstingl static int rtw_sdio_tx_write(struct rtw_dev *rtwdev, 899*65371a3fSMartin Blumenstingl struct rtw_tx_pkt_info *pkt_info, 900*65371a3fSMartin Blumenstingl struct sk_buff *skb) 901*65371a3fSMartin Blumenstingl { 902*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 903*65371a3fSMartin Blumenstingl enum rtw_tx_queue_type queue = rtw_tx_queue_mapping(skb); 904*65371a3fSMartin Blumenstingl struct rtw_sdio_tx_data *tx_data; 905*65371a3fSMartin Blumenstingl 906*65371a3fSMartin Blumenstingl rtw_sdio_tx_skb_prepare(rtwdev, pkt_info, skb, queue); 907*65371a3fSMartin Blumenstingl 908*65371a3fSMartin Blumenstingl tx_data = rtw_sdio_get_tx_data(skb); 909*65371a3fSMartin Blumenstingl tx_data->sn = pkt_info->sn; 910*65371a3fSMartin Blumenstingl 911*65371a3fSMartin Blumenstingl skb_queue_tail(&rtwsdio->tx_queue[queue], skb); 912*65371a3fSMartin Blumenstingl 913*65371a3fSMartin Blumenstingl return 0; 914*65371a3fSMartin Blumenstingl } 915*65371a3fSMartin Blumenstingl 916*65371a3fSMartin Blumenstingl static void rtw_sdio_tx_err_isr(struct rtw_dev *rtwdev) 917*65371a3fSMartin Blumenstingl { 918*65371a3fSMartin Blumenstingl u32 val = rtw_read32(rtwdev, REG_TXDMA_STATUS); 919*65371a3fSMartin Blumenstingl 920*65371a3fSMartin Blumenstingl rtw_write32(rtwdev, REG_TXDMA_STATUS, val); 921*65371a3fSMartin Blumenstingl } 922*65371a3fSMartin Blumenstingl 923*65371a3fSMartin Blumenstingl static void rtw_sdio_rx_skb(struct rtw_dev *rtwdev, struct sk_buff *skb, 924*65371a3fSMartin Blumenstingl u32 pkt_offset, struct rtw_rx_pkt_stat *pkt_stat, 925*65371a3fSMartin Blumenstingl struct ieee80211_rx_status *rx_status) 926*65371a3fSMartin Blumenstingl { 927*65371a3fSMartin Blumenstingl *IEEE80211_SKB_RXCB(skb) = *rx_status; 928*65371a3fSMartin Blumenstingl 929*65371a3fSMartin Blumenstingl if (pkt_stat->is_c2h) { 930*65371a3fSMartin Blumenstingl skb_put(skb, pkt_stat->pkt_len + pkt_offset); 931*65371a3fSMartin Blumenstingl rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); 932*65371a3fSMartin Blumenstingl return; 933*65371a3fSMartin Blumenstingl } 934*65371a3fSMartin Blumenstingl 935*65371a3fSMartin Blumenstingl skb_put(skb, pkt_stat->pkt_len); 936*65371a3fSMartin Blumenstingl skb_reserve(skb, pkt_offset); 937*65371a3fSMartin Blumenstingl 938*65371a3fSMartin Blumenstingl rtw_rx_stats(rtwdev, pkt_stat->vif, skb); 939*65371a3fSMartin Blumenstingl 940*65371a3fSMartin Blumenstingl ieee80211_rx_irqsafe(rtwdev->hw, skb); 941*65371a3fSMartin Blumenstingl } 942*65371a3fSMartin Blumenstingl 943*65371a3fSMartin Blumenstingl static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len) 944*65371a3fSMartin Blumenstingl { 945*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 946*65371a3fSMartin Blumenstingl const struct rtw_chip_info *chip = rtwdev->chip; 947*65371a3fSMartin Blumenstingl u32 pkt_desc_sz = chip->rx_pkt_desc_sz; 948*65371a3fSMartin Blumenstingl struct ieee80211_rx_status rx_status; 949*65371a3fSMartin Blumenstingl struct rtw_rx_pkt_stat pkt_stat; 950*65371a3fSMartin Blumenstingl struct sk_buff *skb, *split_skb; 951*65371a3fSMartin Blumenstingl u32 pkt_offset, curr_pkt_len; 952*65371a3fSMartin Blumenstingl size_t bufsz; 953*65371a3fSMartin Blumenstingl u8 *rx_desc; 954*65371a3fSMartin Blumenstingl int ret; 955*65371a3fSMartin Blumenstingl 956*65371a3fSMartin Blumenstingl bufsz = sdio_align_size(rtwsdio->sdio_func, rx_len); 957*65371a3fSMartin Blumenstingl 958*65371a3fSMartin Blumenstingl skb = dev_alloc_skb(bufsz); 959*65371a3fSMartin Blumenstingl if (!skb) 960*65371a3fSMartin Blumenstingl return; 961*65371a3fSMartin Blumenstingl 962*65371a3fSMartin Blumenstingl ret = rtw_sdio_read_port(rtwdev, skb->data, bufsz); 963*65371a3fSMartin Blumenstingl if (ret) { 964*65371a3fSMartin Blumenstingl dev_kfree_skb_any(skb); 965*65371a3fSMartin Blumenstingl return; 966*65371a3fSMartin Blumenstingl } 967*65371a3fSMartin Blumenstingl 968*65371a3fSMartin Blumenstingl while (true) { 969*65371a3fSMartin Blumenstingl rx_desc = skb->data; 970*65371a3fSMartin Blumenstingl chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, 971*65371a3fSMartin Blumenstingl &rx_status); 972*65371a3fSMartin Blumenstingl pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + 973*65371a3fSMartin Blumenstingl pkt_stat.shift; 974*65371a3fSMartin Blumenstingl 975*65371a3fSMartin Blumenstingl curr_pkt_len = ALIGN(pkt_offset + pkt_stat.pkt_len, 976*65371a3fSMartin Blumenstingl RTW_SDIO_DATA_PTR_ALIGN); 977*65371a3fSMartin Blumenstingl 978*65371a3fSMartin Blumenstingl if ((curr_pkt_len + pkt_desc_sz) >= rx_len) { 979*65371a3fSMartin Blumenstingl /* Use the original skb (with it's adjusted offset) 980*65371a3fSMartin Blumenstingl * when processing the last (or even the only) entry to 981*65371a3fSMartin Blumenstingl * have it's memory freed automatically. 982*65371a3fSMartin Blumenstingl */ 983*65371a3fSMartin Blumenstingl rtw_sdio_rx_skb(rtwdev, skb, pkt_offset, &pkt_stat, 984*65371a3fSMartin Blumenstingl &rx_status); 985*65371a3fSMartin Blumenstingl break; 986*65371a3fSMartin Blumenstingl } 987*65371a3fSMartin Blumenstingl 988*65371a3fSMartin Blumenstingl split_skb = dev_alloc_skb(curr_pkt_len); 989*65371a3fSMartin Blumenstingl if (!split_skb) { 990*65371a3fSMartin Blumenstingl rtw_sdio_rx_skb(rtwdev, skb, pkt_offset, &pkt_stat, 991*65371a3fSMartin Blumenstingl &rx_status); 992*65371a3fSMartin Blumenstingl break; 993*65371a3fSMartin Blumenstingl } 994*65371a3fSMartin Blumenstingl 995*65371a3fSMartin Blumenstingl skb_copy_header(split_skb, skb); 996*65371a3fSMartin Blumenstingl memcpy(split_skb->data, skb->data, curr_pkt_len); 997*65371a3fSMartin Blumenstingl 998*65371a3fSMartin Blumenstingl rtw_sdio_rx_skb(rtwdev, split_skb, pkt_offset, &pkt_stat, 999*65371a3fSMartin Blumenstingl &rx_status); 1000*65371a3fSMartin Blumenstingl 1001*65371a3fSMartin Blumenstingl /* Move to the start of the next RX descriptor */ 1002*65371a3fSMartin Blumenstingl skb_reserve(skb, curr_pkt_len); 1003*65371a3fSMartin Blumenstingl rx_len -= curr_pkt_len; 1004*65371a3fSMartin Blumenstingl } 1005*65371a3fSMartin Blumenstingl } 1006*65371a3fSMartin Blumenstingl 1007*65371a3fSMartin Blumenstingl static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) 1008*65371a3fSMartin Blumenstingl { 1009*65371a3fSMartin Blumenstingl u32 rx_len, total_rx_bytes = 0; 1010*65371a3fSMartin Blumenstingl 1011*65371a3fSMartin Blumenstingl while (total_rx_bytes < SZ_64K) { 1012*65371a3fSMartin Blumenstingl if (rtw_chip_wcpu_11n(rtwdev)) 1013*65371a3fSMartin Blumenstingl rx_len = rtw_read16(rtwdev, REG_SDIO_RX0_REQ_LEN); 1014*65371a3fSMartin Blumenstingl else 1015*65371a3fSMartin Blumenstingl rx_len = rtw_read32(rtwdev, REG_SDIO_RX0_REQ_LEN); 1016*65371a3fSMartin Blumenstingl 1017*65371a3fSMartin Blumenstingl if (!rx_len) 1018*65371a3fSMartin Blumenstingl break; 1019*65371a3fSMartin Blumenstingl 1020*65371a3fSMartin Blumenstingl rtw_sdio_rxfifo_recv(rtwdev, rx_len); 1021*65371a3fSMartin Blumenstingl 1022*65371a3fSMartin Blumenstingl total_rx_bytes += rx_len; 1023*65371a3fSMartin Blumenstingl } 1024*65371a3fSMartin Blumenstingl } 1025*65371a3fSMartin Blumenstingl 1026*65371a3fSMartin Blumenstingl static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func) 1027*65371a3fSMartin Blumenstingl { 1028*65371a3fSMartin Blumenstingl struct ieee80211_hw *hw = sdio_get_drvdata(sdio_func); 1029*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio; 1030*65371a3fSMartin Blumenstingl struct rtw_dev *rtwdev; 1031*65371a3fSMartin Blumenstingl u32 hisr; 1032*65371a3fSMartin Blumenstingl 1033*65371a3fSMartin Blumenstingl rtwdev = hw->priv; 1034*65371a3fSMartin Blumenstingl rtwsdio = (struct rtw_sdio *)rtwdev->priv; 1035*65371a3fSMartin Blumenstingl 1036*65371a3fSMartin Blumenstingl rtwsdio->irq_thread = current; 1037*65371a3fSMartin Blumenstingl 1038*65371a3fSMartin Blumenstingl hisr = rtw_read32(rtwdev, REG_SDIO_HISR); 1039*65371a3fSMartin Blumenstingl 1040*65371a3fSMartin Blumenstingl if (hisr & REG_SDIO_HISR_TXERR) 1041*65371a3fSMartin Blumenstingl rtw_sdio_tx_err_isr(rtwdev); 1042*65371a3fSMartin Blumenstingl if (hisr & REG_SDIO_HISR_RX_REQUEST) { 1043*65371a3fSMartin Blumenstingl hisr &= ~REG_SDIO_HISR_RX_REQUEST; 1044*65371a3fSMartin Blumenstingl rtw_sdio_rx_isr(rtwdev); 1045*65371a3fSMartin Blumenstingl } 1046*65371a3fSMartin Blumenstingl 1047*65371a3fSMartin Blumenstingl rtw_write32(rtwdev, REG_SDIO_HISR, hisr); 1048*65371a3fSMartin Blumenstingl 1049*65371a3fSMartin Blumenstingl rtwsdio->irq_thread = NULL; 1050*65371a3fSMartin Blumenstingl } 1051*65371a3fSMartin Blumenstingl 1052*65371a3fSMartin Blumenstingl static int __maybe_unused rtw_sdio_suspend(struct device *dev) 1053*65371a3fSMartin Blumenstingl { 1054*65371a3fSMartin Blumenstingl struct sdio_func *func = dev_to_sdio_func(dev); 1055*65371a3fSMartin Blumenstingl struct ieee80211_hw *hw = dev_get_drvdata(dev); 1056*65371a3fSMartin Blumenstingl struct rtw_dev *rtwdev = hw->priv; 1057*65371a3fSMartin Blumenstingl int ret; 1058*65371a3fSMartin Blumenstingl 1059*65371a3fSMartin Blumenstingl ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 1060*65371a3fSMartin Blumenstingl if (ret) 1061*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "Failed to host PM flag MMC_PM_KEEP_POWER"); 1062*65371a3fSMartin Blumenstingl 1063*65371a3fSMartin Blumenstingl return ret; 1064*65371a3fSMartin Blumenstingl } 1065*65371a3fSMartin Blumenstingl 1066*65371a3fSMartin Blumenstingl static int __maybe_unused rtw_sdio_resume(struct device *dev) 1067*65371a3fSMartin Blumenstingl { 1068*65371a3fSMartin Blumenstingl return 0; 1069*65371a3fSMartin Blumenstingl } 1070*65371a3fSMartin Blumenstingl 1071*65371a3fSMartin Blumenstingl SIMPLE_DEV_PM_OPS(rtw_sdio_pm_ops, rtw_sdio_suspend, rtw_sdio_resume); 1072*65371a3fSMartin Blumenstingl EXPORT_SYMBOL(rtw_sdio_pm_ops); 1073*65371a3fSMartin Blumenstingl 1074*65371a3fSMartin Blumenstingl static int rtw_sdio_claim(struct rtw_dev *rtwdev, struct sdio_func *sdio_func) 1075*65371a3fSMartin Blumenstingl { 1076*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 1077*65371a3fSMartin Blumenstingl int ret; 1078*65371a3fSMartin Blumenstingl 1079*65371a3fSMartin Blumenstingl sdio_claim_host(sdio_func); 1080*65371a3fSMartin Blumenstingl 1081*65371a3fSMartin Blumenstingl ret = sdio_enable_func(sdio_func); 1082*65371a3fSMartin Blumenstingl if (ret) { 1083*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "Failed to enable SDIO func"); 1084*65371a3fSMartin Blumenstingl goto err_release_host; 1085*65371a3fSMartin Blumenstingl } 1086*65371a3fSMartin Blumenstingl 1087*65371a3fSMartin Blumenstingl ret = sdio_set_block_size(sdio_func, RTW_SDIO_BLOCK_SIZE); 1088*65371a3fSMartin Blumenstingl if (ret) { 1089*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "Failed to set SDIO block size to 512"); 1090*65371a3fSMartin Blumenstingl goto err_disable_func; 1091*65371a3fSMartin Blumenstingl } 1092*65371a3fSMartin Blumenstingl 1093*65371a3fSMartin Blumenstingl rtwsdio->sdio_func = sdio_func; 1094*65371a3fSMartin Blumenstingl 1095*65371a3fSMartin Blumenstingl rtwsdio->sdio3_bus_mode = mmc_card_uhs(sdio_func->card); 1096*65371a3fSMartin Blumenstingl 1097*65371a3fSMartin Blumenstingl sdio_set_drvdata(sdio_func, rtwdev->hw); 1098*65371a3fSMartin Blumenstingl SET_IEEE80211_DEV(rtwdev->hw, &sdio_func->dev); 1099*65371a3fSMartin Blumenstingl 1100*65371a3fSMartin Blumenstingl sdio_release_host(sdio_func); 1101*65371a3fSMartin Blumenstingl 1102*65371a3fSMartin Blumenstingl return 0; 1103*65371a3fSMartin Blumenstingl 1104*65371a3fSMartin Blumenstingl err_disable_func: 1105*65371a3fSMartin Blumenstingl sdio_disable_func(sdio_func); 1106*65371a3fSMartin Blumenstingl err_release_host: 1107*65371a3fSMartin Blumenstingl sdio_release_host(sdio_func); 1108*65371a3fSMartin Blumenstingl return ret; 1109*65371a3fSMartin Blumenstingl } 1110*65371a3fSMartin Blumenstingl 1111*65371a3fSMartin Blumenstingl static void rtw_sdio_declaim(struct rtw_dev *rtwdev, 1112*65371a3fSMartin Blumenstingl struct sdio_func *sdio_func) 1113*65371a3fSMartin Blumenstingl { 1114*65371a3fSMartin Blumenstingl sdio_claim_host(sdio_func); 1115*65371a3fSMartin Blumenstingl sdio_disable_func(sdio_func); 1116*65371a3fSMartin Blumenstingl sdio_release_host(sdio_func); 1117*65371a3fSMartin Blumenstingl } 1118*65371a3fSMartin Blumenstingl 1119*65371a3fSMartin Blumenstingl static struct rtw_hci_ops rtw_sdio_ops = { 1120*65371a3fSMartin Blumenstingl .tx_write = rtw_sdio_tx_write, 1121*65371a3fSMartin Blumenstingl .tx_kick_off = rtw_sdio_tx_kick_off, 1122*65371a3fSMartin Blumenstingl .setup = rtw_sdio_setup, 1123*65371a3fSMartin Blumenstingl .start = rtw_sdio_start, 1124*65371a3fSMartin Blumenstingl .stop = rtw_sdio_stop, 1125*65371a3fSMartin Blumenstingl .deep_ps = rtw_sdio_deep_ps, 1126*65371a3fSMartin Blumenstingl .link_ps = rtw_sdio_link_ps, 1127*65371a3fSMartin Blumenstingl .interface_cfg = rtw_sdio_interface_cfg, 1128*65371a3fSMartin Blumenstingl 1129*65371a3fSMartin Blumenstingl .read8 = rtw_sdio_read8, 1130*65371a3fSMartin Blumenstingl .read16 = rtw_sdio_read16, 1131*65371a3fSMartin Blumenstingl .read32 = rtw_sdio_read32, 1132*65371a3fSMartin Blumenstingl .write8 = rtw_sdio_write8, 1133*65371a3fSMartin Blumenstingl .write16 = rtw_sdio_write16, 1134*65371a3fSMartin Blumenstingl .write32 = rtw_sdio_write32, 1135*65371a3fSMartin Blumenstingl .write_data_rsvd_page = rtw_sdio_write_data_rsvd_page, 1136*65371a3fSMartin Blumenstingl .write_data_h2c = rtw_sdio_write_data_h2c, 1137*65371a3fSMartin Blumenstingl }; 1138*65371a3fSMartin Blumenstingl 1139*65371a3fSMartin Blumenstingl static int rtw_sdio_request_irq(struct rtw_dev *rtwdev, 1140*65371a3fSMartin Blumenstingl struct sdio_func *sdio_func) 1141*65371a3fSMartin Blumenstingl { 1142*65371a3fSMartin Blumenstingl int ret; 1143*65371a3fSMartin Blumenstingl 1144*65371a3fSMartin Blumenstingl sdio_claim_host(sdio_func); 1145*65371a3fSMartin Blumenstingl ret = sdio_claim_irq(sdio_func, &rtw_sdio_handle_interrupt); 1146*65371a3fSMartin Blumenstingl sdio_release_host(sdio_func); 1147*65371a3fSMartin Blumenstingl 1148*65371a3fSMartin Blumenstingl if (ret) { 1149*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "failed to claim SDIO IRQ"); 1150*65371a3fSMartin Blumenstingl return ret; 1151*65371a3fSMartin Blumenstingl } 1152*65371a3fSMartin Blumenstingl 1153*65371a3fSMartin Blumenstingl return 0; 1154*65371a3fSMartin Blumenstingl } 1155*65371a3fSMartin Blumenstingl 1156*65371a3fSMartin Blumenstingl static void rtw_sdio_indicate_tx_status(struct rtw_dev *rtwdev, 1157*65371a3fSMartin Blumenstingl struct sk_buff *skb) 1158*65371a3fSMartin Blumenstingl { 1159*65371a3fSMartin Blumenstingl struct rtw_sdio_tx_data *tx_data = rtw_sdio_get_tx_data(skb); 1160*65371a3fSMartin Blumenstingl struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1161*65371a3fSMartin Blumenstingl struct ieee80211_hw *hw = rtwdev->hw; 1162*65371a3fSMartin Blumenstingl 1163*65371a3fSMartin Blumenstingl /* enqueue to wait for tx report */ 1164*65371a3fSMartin Blumenstingl if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 1165*65371a3fSMartin Blumenstingl rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn); 1166*65371a3fSMartin Blumenstingl return; 1167*65371a3fSMartin Blumenstingl } 1168*65371a3fSMartin Blumenstingl 1169*65371a3fSMartin Blumenstingl /* always ACK for others, then they won't be marked as drop */ 1170*65371a3fSMartin Blumenstingl ieee80211_tx_info_clear_status(info); 1171*65371a3fSMartin Blumenstingl if (info->flags & IEEE80211_TX_CTL_NO_ACK) 1172*65371a3fSMartin Blumenstingl info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 1173*65371a3fSMartin Blumenstingl else 1174*65371a3fSMartin Blumenstingl info->flags |= IEEE80211_TX_STAT_ACK; 1175*65371a3fSMartin Blumenstingl 1176*65371a3fSMartin Blumenstingl ieee80211_tx_status_irqsafe(hw, skb); 1177*65371a3fSMartin Blumenstingl } 1178*65371a3fSMartin Blumenstingl 1179*65371a3fSMartin Blumenstingl static void rtw_sdio_process_tx_queue(struct rtw_dev *rtwdev, 1180*65371a3fSMartin Blumenstingl enum rtw_tx_queue_type queue) 1181*65371a3fSMartin Blumenstingl { 1182*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 1183*65371a3fSMartin Blumenstingl struct sk_buff *skb; 1184*65371a3fSMartin Blumenstingl int ret; 1185*65371a3fSMartin Blumenstingl 1186*65371a3fSMartin Blumenstingl skb = skb_dequeue(&rtwsdio->tx_queue[queue]); 1187*65371a3fSMartin Blumenstingl if (!skb) 1188*65371a3fSMartin Blumenstingl return; 1189*65371a3fSMartin Blumenstingl 1190*65371a3fSMartin Blumenstingl ret = rtw_sdio_write_port(rtwdev, skb, queue); 1191*65371a3fSMartin Blumenstingl if (ret) { 1192*65371a3fSMartin Blumenstingl skb_queue_head(&rtwsdio->tx_queue[queue], skb); 1193*65371a3fSMartin Blumenstingl return; 1194*65371a3fSMartin Blumenstingl } 1195*65371a3fSMartin Blumenstingl 1196*65371a3fSMartin Blumenstingl if (queue <= RTW_TX_QUEUE_VO) 1197*65371a3fSMartin Blumenstingl rtw_sdio_indicate_tx_status(rtwdev, skb); 1198*65371a3fSMartin Blumenstingl else 1199*65371a3fSMartin Blumenstingl dev_kfree_skb_any(skb); 1200*65371a3fSMartin Blumenstingl } 1201*65371a3fSMartin Blumenstingl 1202*65371a3fSMartin Blumenstingl static void rtw_sdio_tx_handler(struct work_struct *work) 1203*65371a3fSMartin Blumenstingl { 1204*65371a3fSMartin Blumenstingl struct rtw_sdio_work_data *work_data = 1205*65371a3fSMartin Blumenstingl container_of(work, struct rtw_sdio_work_data, work); 1206*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio; 1207*65371a3fSMartin Blumenstingl struct rtw_dev *rtwdev; 1208*65371a3fSMartin Blumenstingl int limit, queue; 1209*65371a3fSMartin Blumenstingl 1210*65371a3fSMartin Blumenstingl rtwdev = work_data->rtwdev; 1211*65371a3fSMartin Blumenstingl rtwsdio = (struct rtw_sdio *)rtwdev->priv; 1212*65371a3fSMartin Blumenstingl 1213*65371a3fSMartin Blumenstingl if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) 1214*65371a3fSMartin Blumenstingl rtw_sdio_deep_ps_leave(rtwdev); 1215*65371a3fSMartin Blumenstingl 1216*65371a3fSMartin Blumenstingl for (queue = RTK_MAX_TX_QUEUE_NUM - 1; queue >= 0; queue--) { 1217*65371a3fSMartin Blumenstingl for (limit = 0; limit < 1000; limit++) { 1218*65371a3fSMartin Blumenstingl rtw_sdio_process_tx_queue(rtwdev, queue); 1219*65371a3fSMartin Blumenstingl 1220*65371a3fSMartin Blumenstingl if (skb_queue_empty(&rtwsdio->tx_queue[queue])) 1221*65371a3fSMartin Blumenstingl break; 1222*65371a3fSMartin Blumenstingl } 1223*65371a3fSMartin Blumenstingl } 1224*65371a3fSMartin Blumenstingl } 1225*65371a3fSMartin Blumenstingl 1226*65371a3fSMartin Blumenstingl static void rtw_sdio_free_irq(struct rtw_dev *rtwdev, 1227*65371a3fSMartin Blumenstingl struct sdio_func *sdio_func) 1228*65371a3fSMartin Blumenstingl { 1229*65371a3fSMartin Blumenstingl sdio_claim_host(sdio_func); 1230*65371a3fSMartin Blumenstingl sdio_release_irq(sdio_func); 1231*65371a3fSMartin Blumenstingl sdio_release_host(sdio_func); 1232*65371a3fSMartin Blumenstingl } 1233*65371a3fSMartin Blumenstingl 1234*65371a3fSMartin Blumenstingl static int rtw_sdio_init_tx(struct rtw_dev *rtwdev) 1235*65371a3fSMartin Blumenstingl { 1236*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 1237*65371a3fSMartin Blumenstingl int i; 1238*65371a3fSMartin Blumenstingl 1239*65371a3fSMartin Blumenstingl rtwsdio->txwq = create_singlethread_workqueue("rtw88_sdio: tx wq"); 1240*65371a3fSMartin Blumenstingl if (!rtwsdio->txwq) { 1241*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "failed to create TX work queue\n"); 1242*65371a3fSMartin Blumenstingl return -ENOMEM; 1243*65371a3fSMartin Blumenstingl } 1244*65371a3fSMartin Blumenstingl 1245*65371a3fSMartin Blumenstingl for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) 1246*65371a3fSMartin Blumenstingl skb_queue_head_init(&rtwsdio->tx_queue[i]); 1247*65371a3fSMartin Blumenstingl rtwsdio->tx_handler_data = kmalloc(sizeof(*rtwsdio->tx_handler_data), 1248*65371a3fSMartin Blumenstingl GFP_KERNEL); 1249*65371a3fSMartin Blumenstingl if (!rtwsdio->tx_handler_data) 1250*65371a3fSMartin Blumenstingl goto err_destroy_wq; 1251*65371a3fSMartin Blumenstingl 1252*65371a3fSMartin Blumenstingl rtwsdio->tx_handler_data->rtwdev = rtwdev; 1253*65371a3fSMartin Blumenstingl INIT_WORK(&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler); 1254*65371a3fSMartin Blumenstingl 1255*65371a3fSMartin Blumenstingl return 0; 1256*65371a3fSMartin Blumenstingl 1257*65371a3fSMartin Blumenstingl err_destroy_wq: 1258*65371a3fSMartin Blumenstingl destroy_workqueue(rtwsdio->txwq); 1259*65371a3fSMartin Blumenstingl return -ENOMEM; 1260*65371a3fSMartin Blumenstingl } 1261*65371a3fSMartin Blumenstingl 1262*65371a3fSMartin Blumenstingl static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev) 1263*65371a3fSMartin Blumenstingl { 1264*65371a3fSMartin Blumenstingl struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; 1265*65371a3fSMartin Blumenstingl int i; 1266*65371a3fSMartin Blumenstingl 1267*65371a3fSMartin Blumenstingl for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) 1268*65371a3fSMartin Blumenstingl skb_queue_purge(&rtwsdio->tx_queue[i]); 1269*65371a3fSMartin Blumenstingl 1270*65371a3fSMartin Blumenstingl flush_workqueue(rtwsdio->txwq); 1271*65371a3fSMartin Blumenstingl destroy_workqueue(rtwsdio->txwq); 1272*65371a3fSMartin Blumenstingl kfree(rtwsdio->tx_handler_data); 1273*65371a3fSMartin Blumenstingl } 1274*65371a3fSMartin Blumenstingl 1275*65371a3fSMartin Blumenstingl int rtw_sdio_probe(struct sdio_func *sdio_func, 1276*65371a3fSMartin Blumenstingl const struct sdio_device_id *id) 1277*65371a3fSMartin Blumenstingl { 1278*65371a3fSMartin Blumenstingl struct ieee80211_hw *hw; 1279*65371a3fSMartin Blumenstingl struct rtw_dev *rtwdev; 1280*65371a3fSMartin Blumenstingl int drv_data_size; 1281*65371a3fSMartin Blumenstingl int ret; 1282*65371a3fSMartin Blumenstingl 1283*65371a3fSMartin Blumenstingl drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_sdio); 1284*65371a3fSMartin Blumenstingl hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops); 1285*65371a3fSMartin Blumenstingl if (!hw) { 1286*65371a3fSMartin Blumenstingl dev_err(&sdio_func->dev, "failed to allocate hw"); 1287*65371a3fSMartin Blumenstingl return -ENOMEM; 1288*65371a3fSMartin Blumenstingl } 1289*65371a3fSMartin Blumenstingl 1290*65371a3fSMartin Blumenstingl rtwdev = hw->priv; 1291*65371a3fSMartin Blumenstingl rtwdev->hw = hw; 1292*65371a3fSMartin Blumenstingl rtwdev->dev = &sdio_func->dev; 1293*65371a3fSMartin Blumenstingl rtwdev->chip = (struct rtw_chip_info *)id->driver_data; 1294*65371a3fSMartin Blumenstingl rtwdev->hci.ops = &rtw_sdio_ops; 1295*65371a3fSMartin Blumenstingl rtwdev->hci.type = RTW_HCI_TYPE_SDIO; 1296*65371a3fSMartin Blumenstingl 1297*65371a3fSMartin Blumenstingl ret = rtw_core_init(rtwdev); 1298*65371a3fSMartin Blumenstingl if (ret) 1299*65371a3fSMartin Blumenstingl goto err_release_hw; 1300*65371a3fSMartin Blumenstingl 1301*65371a3fSMartin Blumenstingl rtw_dbg(rtwdev, RTW_DBG_SDIO, 1302*65371a3fSMartin Blumenstingl "rtw88 SDIO probe: vendor=0x%04x device=%04x class=%02x", 1303*65371a3fSMartin Blumenstingl id->vendor, id->device, id->class); 1304*65371a3fSMartin Blumenstingl 1305*65371a3fSMartin Blumenstingl ret = rtw_sdio_claim(rtwdev, sdio_func); 1306*65371a3fSMartin Blumenstingl if (ret) { 1307*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "failed to claim SDIO device"); 1308*65371a3fSMartin Blumenstingl goto err_deinit_core; 1309*65371a3fSMartin Blumenstingl } 1310*65371a3fSMartin Blumenstingl 1311*65371a3fSMartin Blumenstingl rtw_sdio_init(rtwdev); 1312*65371a3fSMartin Blumenstingl 1313*65371a3fSMartin Blumenstingl ret = rtw_sdio_init_tx(rtwdev); 1314*65371a3fSMartin Blumenstingl if (ret) { 1315*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "failed to init SDIO TX queue\n"); 1316*65371a3fSMartin Blumenstingl goto err_sdio_declaim; 1317*65371a3fSMartin Blumenstingl } 1318*65371a3fSMartin Blumenstingl 1319*65371a3fSMartin Blumenstingl ret = rtw_chip_info_setup(rtwdev); 1320*65371a3fSMartin Blumenstingl if (ret) { 1321*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "failed to setup chip information"); 1322*65371a3fSMartin Blumenstingl goto err_destroy_txwq; 1323*65371a3fSMartin Blumenstingl } 1324*65371a3fSMartin Blumenstingl 1325*65371a3fSMartin Blumenstingl ret = rtw_sdio_request_irq(rtwdev, sdio_func); 1326*65371a3fSMartin Blumenstingl if (ret) 1327*65371a3fSMartin Blumenstingl goto err_destroy_txwq; 1328*65371a3fSMartin Blumenstingl 1329*65371a3fSMartin Blumenstingl ret = rtw_register_hw(rtwdev, hw); 1330*65371a3fSMartin Blumenstingl if (ret) { 1331*65371a3fSMartin Blumenstingl rtw_err(rtwdev, "failed to register hw"); 1332*65371a3fSMartin Blumenstingl goto err_free_irq; 1333*65371a3fSMartin Blumenstingl } 1334*65371a3fSMartin Blumenstingl 1335*65371a3fSMartin Blumenstingl return 0; 1336*65371a3fSMartin Blumenstingl 1337*65371a3fSMartin Blumenstingl err_free_irq: 1338*65371a3fSMartin Blumenstingl rtw_sdio_free_irq(rtwdev, sdio_func); 1339*65371a3fSMartin Blumenstingl err_destroy_txwq: 1340*65371a3fSMartin Blumenstingl rtw_sdio_deinit_tx(rtwdev); 1341*65371a3fSMartin Blumenstingl err_sdio_declaim: 1342*65371a3fSMartin Blumenstingl rtw_sdio_declaim(rtwdev, sdio_func); 1343*65371a3fSMartin Blumenstingl err_deinit_core: 1344*65371a3fSMartin Blumenstingl rtw_core_deinit(rtwdev); 1345*65371a3fSMartin Blumenstingl err_release_hw: 1346*65371a3fSMartin Blumenstingl ieee80211_free_hw(hw); 1347*65371a3fSMartin Blumenstingl 1348*65371a3fSMartin Blumenstingl return ret; 1349*65371a3fSMartin Blumenstingl } 1350*65371a3fSMartin Blumenstingl EXPORT_SYMBOL(rtw_sdio_probe); 1351*65371a3fSMartin Blumenstingl 1352*65371a3fSMartin Blumenstingl void rtw_sdio_remove(struct sdio_func *sdio_func) 1353*65371a3fSMartin Blumenstingl { 1354*65371a3fSMartin Blumenstingl struct ieee80211_hw *hw = sdio_get_drvdata(sdio_func); 1355*65371a3fSMartin Blumenstingl struct rtw_dev *rtwdev; 1356*65371a3fSMartin Blumenstingl 1357*65371a3fSMartin Blumenstingl if (!hw) 1358*65371a3fSMartin Blumenstingl return; 1359*65371a3fSMartin Blumenstingl 1360*65371a3fSMartin Blumenstingl rtwdev = hw->priv; 1361*65371a3fSMartin Blumenstingl 1362*65371a3fSMartin Blumenstingl rtw_unregister_hw(rtwdev, hw); 1363*65371a3fSMartin Blumenstingl rtw_sdio_disable_interrupt(rtwdev); 1364*65371a3fSMartin Blumenstingl rtw_sdio_free_irq(rtwdev, sdio_func); 1365*65371a3fSMartin Blumenstingl rtw_sdio_declaim(rtwdev, sdio_func); 1366*65371a3fSMartin Blumenstingl rtw_sdio_deinit_tx(rtwdev); 1367*65371a3fSMartin Blumenstingl rtw_core_deinit(rtwdev); 1368*65371a3fSMartin Blumenstingl ieee80211_free_hw(hw); 1369*65371a3fSMartin Blumenstingl } 1370*65371a3fSMartin Blumenstingl EXPORT_SYMBOL(rtw_sdio_remove); 1371*65371a3fSMartin Blumenstingl 1372*65371a3fSMartin Blumenstingl void rtw_sdio_shutdown(struct device *dev) 1373*65371a3fSMartin Blumenstingl { 1374*65371a3fSMartin Blumenstingl struct sdio_func *sdio_func = dev_to_sdio_func(dev); 1375*65371a3fSMartin Blumenstingl const struct rtw_chip_info *chip; 1376*65371a3fSMartin Blumenstingl struct ieee80211_hw *hw; 1377*65371a3fSMartin Blumenstingl struct rtw_dev *rtwdev; 1378*65371a3fSMartin Blumenstingl 1379*65371a3fSMartin Blumenstingl hw = sdio_get_drvdata(sdio_func); 1380*65371a3fSMartin Blumenstingl if (!hw) 1381*65371a3fSMartin Blumenstingl return; 1382*65371a3fSMartin Blumenstingl 1383*65371a3fSMartin Blumenstingl rtwdev = hw->priv; 1384*65371a3fSMartin Blumenstingl chip = rtwdev->chip; 1385*65371a3fSMartin Blumenstingl 1386*65371a3fSMartin Blumenstingl if (chip->ops->shutdown) 1387*65371a3fSMartin Blumenstingl chip->ops->shutdown(rtwdev); 1388*65371a3fSMartin Blumenstingl } 1389*65371a3fSMartin Blumenstingl EXPORT_SYMBOL(rtw_sdio_shutdown); 1390*65371a3fSMartin Blumenstingl 1391*65371a3fSMartin Blumenstingl MODULE_AUTHOR("Martin Blumenstingl"); 1392*65371a3fSMartin Blumenstingl MODULE_AUTHOR("Jernej Skrabec"); 1393*65371a3fSMartin Blumenstingl MODULE_DESCRIPTION("Realtek 802.11ac wireless SDIO driver"); 1394*65371a3fSMartin Blumenstingl MODULE_LICENSE("Dual BSD/GPL"); 1395