Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmfmac/bcmsdh.c
178665 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2010 Broadcom Corporation3*/4/* ****************** SDIO CARD Interface Functions **************************/56#include <linux/types.h>7#include <linux/netdevice.h>8#include <linux/pci.h>9#include <linux/pci_ids.h>10#include <linux/sched.h>11#include <linux/completion.h>12#include <linux/interrupt.h>13#include <linux/scatterlist.h>14#include <linux/mmc/sdio.h>15#include <linux/mmc/core.h>16#include <linux/mmc/sdio_func.h>17#include <linux/mmc/card.h>18#include <linux/mmc/host.h>19#include <linux/pm_runtime.h>20#include <linux/suspend.h>21#include <linux/errno.h>22#include <linux/module.h>23#include <linux/acpi.h>24#include <net/cfg80211.h>2526#include <defs.h>27#include <brcm_hw_ids.h>28#include <brcmu_utils.h>29#include <brcmu_wifi.h>30#include <chipcommon.h>31#include <soc.h>32#include "chip.h"33#include "bus.h"34#include "debug.h"35#include "sdio.h"36#include "core.h"37#include "common.h"3839#define SDIOH_API_ACCESS_RETRY_LIMIT 24041#define DMA_ALIGN_MASK 0x034243#define SDIO_FUNC1_BLOCKSIZE 6444#define SDIO_FUNC2_BLOCKSIZE 51245#define SDIO_4373_FUNC2_BLOCKSIZE 25646#define SDIO_435X_FUNC2_BLOCKSIZE 25647#define SDIO_4329_FUNC2_BLOCKSIZE 12848/* Maximum milliseconds to wait for F2 to come up */49#define SDIO_WAIT_F2RDY 30005051#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */5253struct brcmf_sdiod_freezer {54atomic_t freezing;55atomic_t thread_count;56u32 frozen_count;57wait_queue_head_t thread_freeze;58struct completion resumed;59};6061static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)62{63struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);64struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;6566brcmf_dbg(INTR, "OOB intr triggered\n");6768/* out-of-band interrupt is level-triggered which won't69* be cleared until dpc70*/71if (sdiodev->irq_en) {72disable_irq_nosync(irq);73sdiodev->irq_en = false;74}7576brcmf_sdio_isr(sdiodev->bus, true);7778return IRQ_HANDLED;79}8081static void brcmf_sdiod_ib_irqhandler(struct sdio_func *func)82{83struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);84struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;8586brcmf_dbg(INTR, "IB intr triggered\n");8788brcmf_sdio_isr(sdiodev->bus, false);89}9091/* dummy handler for SDIO function 2 interrupt */92static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)93{94}9596int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)97{98struct brcmfmac_sdio_pd *pdata;99int ret = 0;100u8 data;101u32 addr, gpiocontrol;102103pdata = &sdiodev->settings->bus.sdio;104if (pdata->oob_irq_supported) {105brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",106pdata->oob_irq_nr);107spin_lock_init(&sdiodev->irq_en_lock);108sdiodev->irq_en = true;109110ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,111pdata->oob_irq_flags, "brcmf_oob_intr",112&sdiodev->func1->dev);113if (ret != 0) {114brcmf_err("request_irq failed %d\n", ret);115return ret;116}117sdiodev->oob_irq_requested = true;118119ret = enable_irq_wake(pdata->oob_irq_nr);120if (ret != 0) {121brcmf_err("enable_irq_wake failed %d\n", ret);122return ret;123}124disable_irq_wake(pdata->oob_irq_nr);125126sdio_claim_host(sdiodev->func1);127128if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) {129/* assign GPIO to SDIO core */130addr = brcmf_chip_enum_base(sdiodev->func1->device);131addr = CORE_CC_REG(addr, gpiocontrol);132gpiocontrol = brcmf_sdiod_readl(sdiodev, addr, &ret);133gpiocontrol |= 0x2;134brcmf_sdiod_writel(sdiodev, addr, gpiocontrol, &ret);135136brcmf_sdiod_writeb(sdiodev, SBSDIO_GPIO_SELECT,1370xf, &ret);138brcmf_sdiod_writeb(sdiodev, SBSDIO_GPIO_OUT, 0, &ret);139brcmf_sdiod_writeb(sdiodev, SBSDIO_GPIO_EN, 0x2, &ret);140}141142/* must configure SDIO_CCCR_IENx to enable irq */143data = brcmf_sdiod_func0_rb(sdiodev, SDIO_CCCR_IENx, &ret);144data |= SDIO_CCCR_IEN_FUNC1 | SDIO_CCCR_IEN_FUNC2 |145SDIO_CCCR_IEN_FUNC0;146brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_IENx, data, &ret);147148/* redirect, configure and enable io for interrupt signal */149data = SDIO_CCCR_BRCM_SEPINT_MASK | SDIO_CCCR_BRCM_SEPINT_OE;150if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)151data |= SDIO_CCCR_BRCM_SEPINT_ACT_HI;152brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT,153data, &ret);154sdio_release_host(sdiodev->func1);155} else {156brcmf_dbg(SDIO, "Entering\n");157sdio_claim_host(sdiodev->func1);158sdio_claim_irq(sdiodev->func1, brcmf_sdiod_ib_irqhandler);159sdio_claim_irq(sdiodev->func2, brcmf_sdiod_dummy_irqhandler);160sdio_release_host(sdiodev->func1);161sdiodev->sd_irq_requested = true;162}163164return 0;165}166167void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)168{169170brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n",171sdiodev->oob_irq_requested,172sdiodev->sd_irq_requested);173174if (sdiodev->oob_irq_requested) {175struct brcmfmac_sdio_pd *pdata;176177pdata = &sdiodev->settings->bus.sdio;178sdio_claim_host(sdiodev->func1);179brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);180brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_IENx, 0, NULL);181sdio_release_host(sdiodev->func1);182183sdiodev->oob_irq_requested = false;184free_irq(pdata->oob_irq_nr, &sdiodev->func1->dev);185sdiodev->irq_en = false;186sdiodev->oob_irq_requested = false;187}188189if (sdiodev->sd_irq_requested) {190sdio_claim_host(sdiodev->func1);191sdio_release_irq(sdiodev->func2);192sdio_release_irq(sdiodev->func1);193sdio_release_host(sdiodev->func1);194sdiodev->sd_irq_requested = false;195}196}197198void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,199enum brcmf_sdiod_state state)200{201if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM ||202state == sdiodev->state)203return;204205brcmf_dbg(TRACE, "%d -> %d\n", sdiodev->state, state);206switch (sdiodev->state) {207case BRCMF_SDIOD_DATA:208/* any other state means bus interface is down */209brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);210break;211case BRCMF_SDIOD_DOWN:212/* transition from DOWN to DATA means bus interface is up */213if (state == BRCMF_SDIOD_DATA)214brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_UP);215break;216default:217break;218}219sdiodev->state = state;220}221222static int brcmf_sdiod_set_backplane_window(struct brcmf_sdio_dev *sdiodev,223u32 addr)224{225u32 v, bar0 = addr & SBSDIO_SBWINDOW_MASK;226int err = 0, i;227228if (bar0 == sdiodev->sbwad)229return 0;230231v = bar0 >> 8;232233for (i = 0 ; i < 3 && !err ; i++, v >>= 8)234brcmf_sdiod_writeb(sdiodev, SBSDIO_FUNC1_SBADDRLOW + i,235v & 0xff, &err);236237if (!err)238sdiodev->sbwad = bar0;239240return err;241}242243u32 brcmf_sdiod_readl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)244{245u32 data = 0;246int retval;247248retval = brcmf_sdiod_set_backplane_window(sdiodev, addr);249if (retval)250goto out;251252addr &= SBSDIO_SB_OFT_ADDR_MASK;253addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;254255data = sdio_readl(sdiodev->func1, addr, &retval);256257out:258if (ret)259*ret = retval;260261return data;262}263264void brcmf_sdiod_writel(struct brcmf_sdio_dev *sdiodev, u32 addr,265u32 data, int *ret)266{267int retval;268269retval = brcmf_sdiod_set_backplane_window(sdiodev, addr);270if (retval)271goto out;272273addr &= SBSDIO_SB_OFT_ADDR_MASK;274addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;275276sdio_writel(sdiodev->func1, data, addr, &retval);277278out:279if (ret)280*ret = retval;281}282283static int brcmf_sdiod_skbuff_read(struct brcmf_sdio_dev *sdiodev,284struct sdio_func *func, u32 addr,285struct sk_buff *skb)286{287unsigned int req_sz;288int err;289290/* Single skb use the standard mmc interface */291req_sz = skb->len + 3;292req_sz &= (uint)~3;293294switch (func->num) {295case 1:296err = sdio_memcpy_fromio(func, ((u8 *)(skb->data)), addr,297req_sz);298break;299case 2:300err = sdio_readsb(func, ((u8 *)(skb->data)), addr, req_sz);301break;302default:303/* bail out as things are really fishy here */304WARN(1, "invalid sdio function number: %d\n", func->num);305err = -ENOMEDIUM;306}307308if (err == -ENOMEDIUM)309brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);310311return err;312}313314static int brcmf_sdiod_skbuff_write(struct brcmf_sdio_dev *sdiodev,315struct sdio_func *func, u32 addr,316struct sk_buff *skb)317{318unsigned int req_sz;319int err;320321/* Single skb use the standard mmc interface */322req_sz = skb->len + 3;323req_sz &= (uint)~3;324325err = sdio_memcpy_toio(func, addr, ((u8 *)(skb->data)), req_sz);326327if (err == -ENOMEDIUM)328brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);329330return err;331}332333static int mmc_submit_one(struct mmc_data *md, struct mmc_request *mr,334struct mmc_command *mc, int sg_cnt, int req_sz,335int func_blk_sz, u32 *addr,336struct brcmf_sdio_dev *sdiodev,337struct sdio_func *func, int write)338{339int ret;340341md->sg_len = sg_cnt;342md->blocks = req_sz / func_blk_sz;343mc->arg |= (*addr & 0x1FFFF) << 9; /* address */344mc->arg |= md->blocks & 0x1FF; /* block count */345/* incrementing addr for function 1 */346if (func->num == 1)347*addr += req_sz;348349mmc_set_data_timeout(md, func->card);350mmc_wait_for_req(func->card->host, mr);351352ret = mc->error ? mc->error : md->error;353if (ret == -ENOMEDIUM) {354brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);355} else if (ret != 0) {356brcmf_err("CMD53 sg block %s failed %d\n",357write ? "write" : "read", ret);358ret = -EIO;359}360361return ret;362}363364/**365* brcmf_sdiod_sglist_rw - SDIO interface function for block data access366* @sdiodev: brcmfmac sdio device367* @func: SDIO function368* @write: direction flag369* @addr: dongle memory address as source/destination370* @pktlist: skb buffer head pointer371*372* This function takes the respbonsibility as the interface function to MMC373* stack for block data access. It assumes that the skb passed down by the374* caller has already been padded and aligned.375*/376static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev,377struct sdio_func *func,378bool write, u32 addr,379struct sk_buff_head *pktlist)380{381unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;382unsigned int max_req_sz, src_offset, dst_offset;383unsigned char *pkt_data, *orig_data, *dst_data;384struct sk_buff_head local_list, *target_list;385struct sk_buff *pkt_next = NULL, *src;386unsigned short max_seg_cnt;387struct mmc_request mmc_req;388struct mmc_command mmc_cmd;389struct mmc_data mmc_dat;390struct scatterlist *sgl;391int ret = 0;392393if (!pktlist->qlen)394return -EINVAL;395396target_list = pktlist;397/* for host with broken sg support, prepare a page aligned list */398__skb_queue_head_init(&local_list);399if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {400req_sz = 0;401skb_queue_walk(pktlist, pkt_next)402req_sz += pkt_next->len;403req_sz = ALIGN(req_sz, func->cur_blksize);404while (req_sz > PAGE_SIZE) {405pkt_next = brcmu_pkt_buf_get_skb(PAGE_SIZE);406if (pkt_next == NULL) {407ret = -ENOMEM;408goto exit;409}410__skb_queue_tail(&local_list, pkt_next);411req_sz -= PAGE_SIZE;412}413pkt_next = brcmu_pkt_buf_get_skb(req_sz);414if (pkt_next == NULL) {415ret = -ENOMEM;416goto exit;417}418__skb_queue_tail(&local_list, pkt_next);419target_list = &local_list;420}421422func_blk_sz = func->cur_blksize;423max_req_sz = sdiodev->max_request_size;424max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count,425target_list->qlen);426427memset(&mmc_req, 0, sizeof(struct mmc_request));428memset(&mmc_cmd, 0, sizeof(struct mmc_command));429memset(&mmc_dat, 0, sizeof(struct mmc_data));430431mmc_dat.sg = sdiodev->sgtable.sgl;432mmc_dat.blksz = func_blk_sz;433mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;434mmc_cmd.opcode = SD_IO_RW_EXTENDED;435mmc_cmd.arg = write ? 1<<31 : 0; /* write flag */436mmc_cmd.arg |= (func->num & 0x7) << 28; /* SDIO func num */437mmc_cmd.arg |= 1 << 27; /* block mode */438/* for function 1 the addr will be incremented */439mmc_cmd.arg |= (func->num == 1) ? 1 << 26 : 0;440mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;441mmc_req.cmd = &mmc_cmd;442mmc_req.data = &mmc_dat;443444req_sz = 0;445sg_cnt = 0;446sgl = sdiodev->sgtable.sgl;447skb_queue_walk(target_list, pkt_next) {448pkt_offset = 0;449while (pkt_offset < pkt_next->len) {450pkt_data = pkt_next->data + pkt_offset;451sg_data_sz = pkt_next->len - pkt_offset;452if (sg_data_sz > sdiodev->max_segment_size)453sg_data_sz = sdiodev->max_segment_size;454if (sg_data_sz > max_req_sz - req_sz)455sg_data_sz = max_req_sz - req_sz;456457if (!sgl) {458/* out of (pre-allocated) scatterlist entries */459ret = -ENOMEM;460goto exit;461}462sg_set_buf(sgl, pkt_data, sg_data_sz);463sg_cnt++;464465sgl = sg_next(sgl);466req_sz += sg_data_sz;467pkt_offset += sg_data_sz;468if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt) {469ret = mmc_submit_one(&mmc_dat, &mmc_req, &mmc_cmd,470sg_cnt, req_sz, func_blk_sz,471&addr, sdiodev, func, write);472if (ret)473goto exit_queue_walk;474req_sz = 0;475sg_cnt = 0;476sgl = sdiodev->sgtable.sgl;477}478}479}480if (sg_cnt)481ret = mmc_submit_one(&mmc_dat, &mmc_req, &mmc_cmd,482sg_cnt, req_sz, func_blk_sz,483&addr, sdiodev, func, write);484exit_queue_walk:485if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {486src = __skb_peek(&local_list);487src_offset = 0;488skb_queue_walk(pktlist, pkt_next) {489dst_offset = 0;490491/* This is safe because we must have enough SKB data492* in the local list to cover everything in pktlist.493*/494while (1) {495req_sz = pkt_next->len - dst_offset;496if (req_sz > src->len - src_offset)497req_sz = src->len - src_offset;498499orig_data = src->data + src_offset;500dst_data = pkt_next->data + dst_offset;501memcpy(dst_data, orig_data, req_sz);502503src_offset += req_sz;504if (src_offset == src->len) {505src_offset = 0;506src = skb_peek_next(src, &local_list);507}508dst_offset += req_sz;509if (dst_offset == pkt_next->len)510break;511}512}513}514515exit:516sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);517while ((pkt_next = __skb_dequeue(&local_list)) != NULL)518brcmu_pkt_buf_free_skb(pkt_next);519520return ret;521}522523int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)524{525struct sk_buff *mypkt;526int err;527528mypkt = brcmu_pkt_buf_get_skb(nbytes);529if (!mypkt) {530brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",531nbytes);532return -EIO;533}534535err = brcmf_sdiod_recv_pkt(sdiodev, mypkt);536if (!err)537memcpy(buf, mypkt->data, nbytes);538539brcmu_pkt_buf_free_skb(mypkt);540return err;541}542543int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)544{545u32 addr = sdiodev->cc_core->base;546int err = 0;547548brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len);549550err = brcmf_sdiod_set_backplane_window(sdiodev, addr);551if (err)552goto done;553554addr &= SBSDIO_SB_OFT_ADDR_MASK;555addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;556557err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr, pkt);558559done:560return err;561}562563int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,564struct sk_buff_head *pktq, uint totlen)565{566struct sk_buff *glom_skb = NULL;567struct sk_buff *skb;568u32 addr = sdiodev->cc_core->base;569int err = 0;570571brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n",572addr, pktq->qlen);573574err = brcmf_sdiod_set_backplane_window(sdiodev, addr);575if (err)576goto done;577578addr &= SBSDIO_SB_OFT_ADDR_MASK;579addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;580581if (pktq->qlen == 1)582err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr,583__skb_peek(pktq));584else if (!sdiodev->sg_support) {585glom_skb = brcmu_pkt_buf_get_skb(totlen);586if (!glom_skb)587return -ENOMEM;588err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr,589glom_skb);590if (err)591goto done;592593skb_queue_walk(pktq, skb) {594memcpy(skb->data, glom_skb->data, skb->len);595skb_pull(glom_skb, skb->len);596}597} else598err = brcmf_sdiod_sglist_rw(sdiodev, sdiodev->func2, false,599addr, pktq);600601done:602brcmu_pkt_buf_free_skb(glom_skb);603return err;604}605606int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)607{608struct sk_buff *mypkt;609u32 addr = sdiodev->cc_core->base;610int err;611612mypkt = brcmu_pkt_buf_get_skb(nbytes);613614if (!mypkt) {615brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",616nbytes);617return -EIO;618}619620memcpy(mypkt->data, buf, nbytes);621622err = brcmf_sdiod_set_backplane_window(sdiodev, addr);623if (err)624goto out;625626addr &= SBSDIO_SB_OFT_ADDR_MASK;627addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;628629err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func2, addr, mypkt);630out:631brcmu_pkt_buf_free_skb(mypkt);632633return err;634}635636int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,637struct sk_buff_head *pktq)638{639struct sk_buff *skb;640u32 addr = sdiodev->cc_core->base;641int err;642643brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pktq->qlen);644645err = brcmf_sdiod_set_backplane_window(sdiodev, addr);646if (err)647return err;648649addr &= SBSDIO_SB_OFT_ADDR_MASK;650addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;651652if (pktq->qlen == 1 || !sdiodev->sg_support) {653skb_queue_walk(pktq, skb) {654err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func2,655addr, skb);656if (err)657break;658}659} else {660err = brcmf_sdiod_sglist_rw(sdiodev, sdiodev->func2, true,661addr, pktq);662}663664return err;665}666667int668brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,669u8 *data, uint size)670{671int err = 0;672struct sk_buff *pkt;673u32 sdaddr;674uint dsize;675676dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);677pkt = dev_alloc_skb(dsize);678if (!pkt) {679brcmf_err("dev_alloc_skb failed: len %d\n", dsize);680return -EIO;681}682pkt->priority = 0;683684/* Determine initial transfer parameters */685sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;686if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)687dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);688else689dsize = size;690691sdio_claim_host(sdiodev->func1);692693/* Do the transfer(s) */694while (size) {695/* Set the backplane window to include the start address */696err = brcmf_sdiod_set_backplane_window(sdiodev, address);697if (err)698break;699700brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",701write ? "write" : "read", dsize,702sdaddr, address & SBSDIO_SBWINDOW_MASK);703704sdaddr &= SBSDIO_SB_OFT_ADDR_MASK;705sdaddr |= SBSDIO_SB_ACCESS_2_4B_FLAG;706707skb_put(pkt, dsize);708709if (write) {710memcpy(pkt->data, data, dsize);711err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func1,712sdaddr, pkt);713} else {714err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func1,715sdaddr, pkt);716}717718if (err) {719brcmf_err("membytes transfer failed\n");720break;721}722if (!write)723memcpy(data, pkt->data, dsize);724skb_trim(pkt, 0);725726/* Adjust for next transfer (if any) */727size -= dsize;728if (size) {729data += dsize;730address += dsize;731sdaddr = 0;732dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);733}734}735736dev_kfree_skb(pkt);737738sdio_release_host(sdiodev->func1);739740return err;741}742743int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, struct sdio_func *func)744{745brcmf_dbg(SDIO, "Enter\n");746747/* Issue abort cmd52 command through F0 */748brcmf_sdiod_func0_wb(sdiodev, SDIO_CCCR_ABORT, func->num, NULL);749750brcmf_dbg(SDIO, "Exit\n");751return 0;752}753754void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)755{756struct sdio_func *func;757struct mmc_host *host;758uint max_blocks;759uint nents;760int err;761762func = sdiodev->func2;763host = func->card->host;764sdiodev->sg_support = host->max_segs > 1;765max_blocks = min_t(uint, host->max_blk_count, 511u);766sdiodev->max_request_size = min_t(uint, host->max_req_size,767max_blocks * func->cur_blksize);768sdiodev->max_segment_count = min_t(uint, host->max_segs,769SG_MAX_SINGLE_ALLOC);770sdiodev->max_segment_size = host->max_seg_size;771772if (!sdiodev->sg_support)773return;774775nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,776sdiodev->settings->bus.sdio.txglomsz);777nents *= 2;778779WARN_ON(nents > sdiodev->max_segment_count);780781brcmf_dbg(TRACE, "nents=%d\n", nents);782err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);783if (err < 0) {784brcmf_err("allocation failed: disable scatter-gather");785sdiodev->sg_support = false;786}787788sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz;789}790791static int brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev *sdiodev)792{793if (!IS_ENABLED(CONFIG_PM_SLEEP))794return 0;795796sdiodev->freezer = kzalloc(sizeof(*sdiodev->freezer), GFP_KERNEL);797if (!sdiodev->freezer)798return -ENOMEM;799atomic_set(&sdiodev->freezer->thread_count, 0);800atomic_set(&sdiodev->freezer->freezing, 0);801init_waitqueue_head(&sdiodev->freezer->thread_freeze);802init_completion(&sdiodev->freezer->resumed);803return 0;804}805806static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)807{808if (sdiodev->freezer) {809WARN_ON(atomic_read(&sdiodev->freezer->freezing));810kfree(sdiodev->freezer);811sdiodev->freezer = NULL;812}813}814815static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)816{817atomic_t *expect = &sdiodev->freezer->thread_count;818int res = 0;819820sdiodev->freezer->frozen_count = 0;821reinit_completion(&sdiodev->freezer->resumed);822atomic_set(&sdiodev->freezer->freezing, 1);823brcmf_sdio_trigger_dpc(sdiodev->bus);824wait_event(sdiodev->freezer->thread_freeze,825atomic_read(expect) == sdiodev->freezer->frozen_count);826sdio_claim_host(sdiodev->func1);827res = brcmf_sdio_sleep(sdiodev->bus, true);828sdio_release_host(sdiodev->func1);829return res;830}831832static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)833{834sdio_claim_host(sdiodev->func1);835brcmf_sdio_sleep(sdiodev->bus, false);836sdio_release_host(sdiodev->func1);837atomic_set(&sdiodev->freezer->freezing, 0);838complete_all(&sdiodev->freezer->resumed);839}840841bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev)842{843return IS_ENABLED(CONFIG_PM_SLEEP) &&844atomic_read(&sdiodev->freezer->freezing);845}846847void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)848{849if (!brcmf_sdiod_freezing(sdiodev))850return;851sdiodev->freezer->frozen_count++;852wake_up(&sdiodev->freezer->thread_freeze);853wait_for_completion(&sdiodev->freezer->resumed);854}855856void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev)857{858if (IS_ENABLED(CONFIG_PM_SLEEP))859atomic_inc(&sdiodev->freezer->thread_count);860}861862void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)863{864if (IS_ENABLED(CONFIG_PM_SLEEP))865atomic_dec(&sdiodev->freezer->thread_count);866}867868int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)869{870sdiodev->state = BRCMF_SDIOD_DOWN;871if (sdiodev->bus) {872brcmf_sdio_remove(sdiodev->bus);873sdiodev->bus = NULL;874}875876brcmf_sdiod_freezer_detach(sdiodev);877878/* Disable functions 2 then 1. */879sdio_claim_host(sdiodev->func1);880sdio_disable_func(sdiodev->func2);881sdio_disable_func(sdiodev->func1);882sdio_release_host(sdiodev->func1);883884sg_free_table(&sdiodev->sgtable);885sdiodev->sbwad = 0;886887pm_runtime_allow(sdiodev->func1->card->host->parent);888return 0;889}890891static void brcmf_sdiod_host_fixup(struct mmc_host *host)892{893/* runtime-pm powers off the device */894pm_runtime_forbid(host->parent);895/* avoid removal detection upon resume */896host->caps |= MMC_CAP_NONREMOVABLE;897}898899int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)900{901int ret = 0;902unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;903904sdio_claim_host(sdiodev->func1);905906ret = sdio_set_block_size(sdiodev->func1, SDIO_FUNC1_BLOCKSIZE);907if (ret) {908brcmf_err("Failed to set F1 blocksize\n");909sdio_release_host(sdiodev->func1);910return ret;911}912switch (sdiodev->func2->device) {913case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:914f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;915break;916case SDIO_DEVICE_ID_BROADCOM_4359:917case SDIO_DEVICE_ID_BROADCOM_4354:918case SDIO_DEVICE_ID_BROADCOM_4356:919f2_blksz = SDIO_435X_FUNC2_BLOCKSIZE;920break;921case SDIO_DEVICE_ID_BROADCOM_4329:922f2_blksz = SDIO_4329_FUNC2_BLOCKSIZE;923break;924default:925break;926}927928ret = sdio_set_block_size(sdiodev->func2, f2_blksz);929if (ret) {930brcmf_err("Failed to set F2 blocksize\n");931sdio_release_host(sdiodev->func1);932return ret;933} else {934brcmf_dbg(SDIO, "set F2 blocksize to %d\n", f2_blksz);935}936937/* increase F2 timeout */938sdiodev->func2->enable_timeout = SDIO_WAIT_F2RDY;939940/* Enable Function 1 */941ret = sdio_enable_func(sdiodev->func1);942sdio_release_host(sdiodev->func1);943if (ret) {944brcmf_err("Failed to enable F1: err=%d\n", ret);945goto out;946}947948ret = brcmf_sdiod_freezer_attach(sdiodev);949if (ret)950goto out;951952/* try to attach to the target device */953sdiodev->bus = brcmf_sdio_probe(sdiodev);954if (IS_ERR(sdiodev->bus)) {955ret = PTR_ERR(sdiodev->bus);956goto out;957}958brcmf_sdiod_host_fixup(sdiodev->func2->card->host);959out:960if (ret)961brcmf_sdiod_remove(sdiodev);962963return ret;964}965966#define BRCMF_SDIO_DEVICE(dev_id, fw_vend) \967{ \968SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id), \969.driver_data = BRCMF_FWVENDOR_ ## fw_vend \970}971972#define CYW_SDIO_DEVICE(dev_id, fw_vend) \973{ \974SDIO_DEVICE(SDIO_VENDOR_ID_CYPRESS, dev_id), \975.driver_data = BRCMF_FWVENDOR_ ## fw_vend \976}977978/* devices we support, null terminated */979static const struct sdio_device_id brcmf_sdmmc_ids[] = {980BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143, WCC),981BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241, WCC),982BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329, WCC),983BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330, WCC),984BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334, WCC),985BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340, WCC),986BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341, WCC),987BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362, WCC),988BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364, WCC),989BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339, WCC),990BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339, WCC),991BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, WCC),992BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43439, WCC),993BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, WCC),994BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, WCC),995BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC),996BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC),997BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),998BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43751, WCC),999BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43752, WCC),1000BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW),1001BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW),1002BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW),1003CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),1004{ /* end: all zeroes */ }1005};1006MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);100710081009static void brcmf_sdiod_acpi_save_power_manageable(struct brcmf_sdio_dev *sdiodev)1010{1011#if IS_ENABLED(CONFIG_ACPI)1012struct acpi_device *adev;10131014adev = ACPI_COMPANION(&sdiodev->func1->dev);1015if (adev)1016sdiodev->func1_power_manageable = adev->flags.power_manageable;10171018adev = ACPI_COMPANION(&sdiodev->func2->dev);1019if (adev)1020sdiodev->func2_power_manageable = adev->flags.power_manageable;1021#endif1022}10231024static void brcmf_sdiod_acpi_set_power_manageable(struct brcmf_sdio_dev *sdiodev,1025int enable)1026{1027#if IS_ENABLED(CONFIG_ACPI)1028struct acpi_device *adev;10291030adev = ACPI_COMPANION(&sdiodev->func1->dev);1031if (adev)1032adev->flags.power_manageable = enable ? sdiodev->func1_power_manageable : 0;10331034adev = ACPI_COMPANION(&sdiodev->func2->dev);1035if (adev)1036adev->flags.power_manageable = enable ? sdiodev->func2_power_manageable : 0;1037#endif1038}10391040static int brcmf_ops_sdio_probe(struct sdio_func *func,1041const struct sdio_device_id *id)1042{1043int err;1044struct brcmf_sdio_dev *sdiodev;1045struct brcmf_bus *bus_if;10461047if (!id) {1048dev_err(&func->dev, "Error no sdio_device_id passed for %x:%x\n", func->vendor, func->device);1049return -ENODEV;1050}10511052brcmf_dbg(SDIO, "Enter\n");1053brcmf_dbg(SDIO, "Class=%x\n", func->class);1054brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);1055brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);1056brcmf_dbg(SDIO, "Function#: %d\n", func->num);10571058/* Set MMC_QUIRK_LENIENT_FN0 for this card */1059func->card->quirks |= MMC_QUIRK_LENIENT_FN0;10601061/* Consume func num 1 but dont do anything with it. */1062if (func->num == 1)1063return 0;10641065/* Ignore anything but func 2 */1066if (func->num != 2)1067return -ENODEV;10681069bus_if = kzalloc(sizeof(*bus_if), GFP_KERNEL);1070if (!bus_if)1071return -ENOMEM;1072sdiodev = kzalloc(sizeof(*sdiodev), GFP_KERNEL);1073if (!sdiodev) {1074kfree(bus_if);1075return -ENOMEM;1076}10771078/* store refs to functions used. mmc_card does1079* not hold the F0 function pointer.1080*/1081sdiodev->func1 = func->card->sdio_func[0];1082sdiodev->func2 = func;10831084sdiodev->bus_if = bus_if;1085bus_if->bus_priv.sdio = sdiodev;1086bus_if->proto_type = BRCMF_PROTO_BCDC;1087bus_if->fwvid = id->driver_data;1088dev_set_drvdata(&func->dev, bus_if);1089dev_set_drvdata(&sdiodev->func1->dev, bus_if);1090sdiodev->dev = &sdiodev->func1->dev;10911092brcmf_sdiod_acpi_save_power_manageable(sdiodev);1093brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);10941095brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");1096err = brcmf_sdiod_probe(sdiodev);1097if (err) {1098brcmf_err("F2 error, probe failed %d...\n", err);1099goto fail;1100}11011102brcmf_dbg(SDIO, "F2 init completed...\n");1103return 0;11041105fail:1106dev_set_drvdata(&func->dev, NULL);1107dev_set_drvdata(&sdiodev->func1->dev, NULL);1108kfree(sdiodev);1109kfree(bus_if);1110return err;1111}11121113static void brcmf_ops_sdio_remove(struct sdio_func *func)1114{1115struct brcmf_bus *bus_if;1116struct brcmf_sdio_dev *sdiodev;11171118brcmf_dbg(SDIO, "Enter\n");1119brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);1120brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);1121brcmf_dbg(SDIO, "Function: %d\n", func->num);11221123bus_if = dev_get_drvdata(&func->dev);1124if (bus_if) {1125sdiodev = bus_if->bus_priv.sdio;11261127/* start by unregistering irqs */1128brcmf_sdiod_intr_unregister(sdiodev);11291130if (func->num != 1)1131return;11321133/* only proceed with rest of cleanup if func 1 */1134brcmf_sdiod_remove(sdiodev);11351136dev_set_drvdata(&sdiodev->func1->dev, NULL);1137dev_set_drvdata(&sdiodev->func2->dev, NULL);11381139kfree(bus_if);1140kfree(sdiodev);1141}11421143brcmf_dbg(SDIO, "Exit\n");1144}11451146void brcmf_sdio_wowl_config(struct device *dev, bool enabled)1147{1148struct brcmf_bus *bus_if = dev_get_drvdata(dev);1149struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;1150mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(sdiodev->func1);11511152/* Power must be preserved to be able to support WOWL. */1153if (!(pm_caps & MMC_PM_KEEP_POWER))1154goto notsup;11551156if (sdiodev->settings->bus.sdio.oob_irq_supported ||1157pm_caps & MMC_PM_WAKE_SDIO_IRQ) {1158/* Stop ACPI from turning off the device when wowl is enabled */1159brcmf_sdiod_acpi_set_power_manageable(sdiodev, !enabled);1160sdiodev->wowl_enabled = enabled;1161brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);1162return;1163}11641165notsup:1166brcmf_dbg(SDIO, "WOWL not supported\n");1167}11681169static int brcmf_ops_sdio_suspend(struct device *dev)1170{1171struct sdio_func *func;1172struct brcmf_bus *bus_if;1173struct brcmf_sdio_dev *sdiodev;1174mmc_pm_flag_t sdio_flags;1175bool cap_power_off;1176int ret = 0;11771178func = container_of(dev, struct sdio_func, dev);1179brcmf_dbg(SDIO, "Enter: F%d\n", func->num);1180if (func->num != 1)1181return 0;11821183cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);11841185bus_if = dev_get_drvdata(dev);1186sdiodev = bus_if->bus_priv.sdio;11871188if (sdiodev->wowl_enabled || !cap_power_off) {1189brcmf_sdiod_freezer_on(sdiodev);1190brcmf_sdio_wd_timer(sdiodev->bus, 0);11911192sdio_flags = MMC_PM_KEEP_POWER;11931194if (sdiodev->wowl_enabled) {1195if (sdiodev->settings->bus.sdio.oob_irq_supported)1196enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);1197else1198sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;1199}12001201if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))1202brcmf_err("Failed to set pm_flags %x\n", sdio_flags);12031204} else {1205/* power will be cut so remove device, probe again in resume */1206brcmf_sdiod_intr_unregister(sdiodev);1207ret = brcmf_sdiod_remove(sdiodev);1208if (ret)1209brcmf_err("Failed to remove device on suspend\n");1210}12111212return ret;1213}12141215static int brcmf_ops_sdio_resume(struct device *dev)1216{1217struct brcmf_bus *bus_if = dev_get_drvdata(dev);1218struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;1219struct sdio_func *func = container_of(dev, struct sdio_func, dev);1220int ret = 0;1221bool cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);12221223brcmf_dbg(SDIO, "Enter: F%d\n", func->num);1224if (func->num != 2)1225return 0;12261227if (!sdiodev->wowl_enabled && cap_power_off) {1228/* bus was powered off and device removed, probe again */1229ret = brcmf_sdiod_probe(sdiodev);1230if (ret)1231brcmf_err("Failed to probe device on resume\n");1232} else {1233if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)1234disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);12351236brcmf_sdiod_freezer_off(sdiodev);1237}12381239return ret;1240}12411242static DEFINE_SIMPLE_DEV_PM_OPS(brcmf_sdio_pm_ops,1243brcmf_ops_sdio_suspend,1244brcmf_ops_sdio_resume);12451246static struct sdio_driver brcmf_sdmmc_driver = {1247.probe = brcmf_ops_sdio_probe,1248.remove = brcmf_ops_sdio_remove,1249.name = KBUILD_MODNAME,1250.id_table = brcmf_sdmmc_ids,1251.drv = {1252.pm = pm_sleep_ptr(&brcmf_sdio_pm_ops),1253.coredump = brcmf_dev_coredump,1254},1255};12561257int brcmf_sdio_register(void)1258{1259return sdio_register_driver(&brcmf_sdmmc_driver);1260}12611262void brcmf_sdio_exit(void)1263{1264brcmf_dbg(SDIO, "Enter\n");12651266sdio_unregister_driver(&brcmf_sdmmc_driver);1267}1268126912701271