1bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo/* 2bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * Copyright (c) 2004-2011 Atheros Communications Inc. 31b2df4073447234034e2329f0df584c6346a8ec3Vasanthakumar Thiagarajan * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. 4bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * 5bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * Permission to use, copy, modify, and/or distribute this software for any 6bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * purpose with or without fee is hereby granted, provided that the above 7bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * copyright notice and this permission notice appear in all copies. 8bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * 9bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo */ 17bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 189d9779e723a5d23b94abbe5bb7d1197921f6f3ddPaul Gortmaker#include <linux/module.h> 19bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/card.h> 20bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/mmc.h> 21bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/host.h> 22bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/sdio_func.h> 23bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/sdio_ids.h> 24bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/sdio.h> 25bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include <linux/mmc/sd.h> 262e1cb23c5e3c38b25a678a8a14d7464341e8207fKalle Valo#include "hif.h" 27bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include "hif-ops.h" 28bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include "target.h" 29bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#include "debug.h" 309df337a104ab99c595cc4ede2c917ba1c2b66374Vivek Natarajan#include "cfg80211.h" 31e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo#include "trace.h" 32bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 33bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostruct ath6kl_sdio { 34bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct sdio_func *func; 35bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 3612eb9444a8df7ab4aa5f4c91f8e3049af5d9819bKalle Valo /* protects access to bus_req_freeq */ 37bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo spinlock_t lock; 38bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 39bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* free list */ 40bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct list_head bus_req_freeq; 41bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 42bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* available bus requests */ 43bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request bus_req[BUS_REQUEST_MAX_NUM]; 44bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 45bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl *ar; 46fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani 47bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u8 *dma_buffer; 48bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 49fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani /* protects access to dma_buffer */ 50fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani struct mutex dma_buffer_mutex; 51fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani 52bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* scatter request list head */ 53bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct list_head scat_req; 54bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 55d1f4159723450252b643bcddff064153f32918bcRaja Mani atomic_t irq_handling; 56d1f4159723450252b643bcddff064153f32918bcRaja Mani wait_queue_head_t irq_wq; 579d82682d45ef7407474e0ae043a587cb33a7fa26Vasanthakumar Thiagarajan 5812eb9444a8df7ab4aa5f4c91f8e3049af5d9819bKalle Valo /* protects access to scat_req */ 59bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo spinlock_t scat_lock; 6012eb9444a8df7ab4aa5f4c91f8e3049af5d9819bKalle Valo 6132a07e4448f78158a75f7c1f0056289647d83946Kalle Valo bool scatter_enabled; 6232a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 63bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bool is_disabled; 64bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo const struct sdio_device_id *id; 65bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct work_struct wr_async_work; 66bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct list_head wr_asyncq; 6712eb9444a8df7ab4aa5f4c91f8e3049af5d9819bKalle Valo 6812eb9444a8df7ab4aa5f4c91f8e3049af5d9819bKalle Valo /* protects access to wr_asyncq */ 69bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo spinlock_t wr_async_lock; 70bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo}; 71bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 72bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#define CMD53_ARG_READ 0 73bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#define CMD53_ARG_WRITE 1 74bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#define CMD53_ARG_BLOCK_BASIS 1 75bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#define CMD53_ARG_FIXED_ADDRESS 0 76bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo#define CMD53_ARG_INCR_ADDRESS 1 77bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 78bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar) 79bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 80bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ar->hif_priv; 81bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 82bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 83bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo/* 84bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * Macro to check if DMA buffer is WORD-aligned and DMA-able. 85bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * Most host controllers assume the buffer is DMA'able and will 86bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid 87bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * check fails on stack memory. 88bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo */ 89bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic inline bool buf_needs_bounce(u8 *buf) 90bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 91bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf); 92bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 93bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 94bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_set_mbox_info(struct ath6kl *ar) 95bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 96bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_mbox_info *mbox_info = &ar->mbox_info; 97bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 98bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* EP1 has an extended range */ 99bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mbox_info->htc_addr = HIF_MBOX_BASE_ADDR; 100bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR; 101bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH; 102bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mbox_info->block_size = HIF_MBOX_BLOCK_SIZE; 103bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR; 104bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mbox_info->gmbox_sz = HIF_GMBOX_WIDTH; 105bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 106bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 107bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func, 108bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u8 mode, u8 opcode, u32 addr, 109bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u16 blksz) 110bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 111bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo *arg = (((rw & 1) << 31) | 112bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((func & 0x7) << 28) | 113bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((mode & 1) << 27) | 114bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((opcode & 1) << 26) | 115bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((addr & 0x1FFFF) << 9) | 116bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo (blksz & 0x1FF)); 117bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 118bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 119bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw, 120bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo unsigned int address, 121bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo unsigned char val) 122bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 123bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo const u8 func = 0; 124bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 125bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo *arg = ((write & 1) << 31) | 126bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((func & 0x7) << 28) | 127bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((raw & 1) << 27) | 128bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo (1 << 26) | 129bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ((address & 0x1FFFF) << 9) | 130bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo (1 << 8) | 131bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo (val & 0xFF); 132bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 133bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 134bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card, 135bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo unsigned int address, 136bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo unsigned char byte) 137bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 138bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct mmc_command io_cmd; 139bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 140bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo memset(&io_cmd, 0, sizeof(io_cmd)); 141bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte); 142bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo io_cmd.opcode = SD_IO_RW_DIRECT; 143bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; 144bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 145bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return mmc_wait_for_cmd(card->host, &io_cmd, 0); 146bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 147bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 148da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajanstatic int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr, 149da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan u8 *buf, u32 len) 150da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan{ 151da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan int ret = 0; 152da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan 153861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan sdio_claim_host(func); 154861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan 155da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan if (request & HIF_WRITE) { 156f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo /* FIXME: looks like ugly workaround for something */ 157da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan if (addr >= HIF_MBOX_BASE_ADDR && 158da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan addr <= HIF_MBOX_END_ADDR) 159da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan addr += (HIF_MBOX_WIDTH - len); 160da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan 161f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo /* FIXME: this also looks like ugly workaround */ 162da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan if (addr == HIF_MBOX0_EXT_BASE_ADDR) 163da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan addr += HIF_MBOX0_EXT_WIDTH - len; 164da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan 165da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan if (request & HIF_FIXED_ADDRESS) 166da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan ret = sdio_writesb(func, addr, buf, len); 167da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan else 168da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan ret = sdio_memcpy_toio(func, addr, buf, len); 169da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan } else { 170da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan if (request & HIF_FIXED_ADDRESS) 171da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan ret = sdio_readsb(func, buf, addr, len); 172da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan else 173da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan ret = sdio_memcpy_fromio(func, buf, addr, len); 174da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan } 175da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan 176861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan sdio_release_host(func); 177861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan 178f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo ath6kl_dbg(ATH6KL_DBG_SDIO, "%s addr 0x%x%s buf 0x%p len %d\n", 179f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo request & HIF_WRITE ? "wr" : "rd", addr, 180f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len); 181f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo ath6kl_dbg_dump(ATH6KL_DBG_SDIO_DUMP, NULL, "sdio ", buf, len); 182f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo 183e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo trace_ath6kl_sdio(addr, request, buf, len); 184e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo 185da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan return ret; 186da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan} 187da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan 188bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio) 189bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 190bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request *bus_req; 191bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 192151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->lock); 193bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 194bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (list_empty(&ar_sdio->bus_req_freeq)) { 195151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->lock); 196bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return NULL; 197bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 198bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 199bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req = list_first_entry(&ar_sdio->bus_req_freeq, 200bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request, list); 201bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_del(&bus_req->list); 202bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 203151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->lock); 204f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n", 205f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo __func__, bus_req); 206bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 207bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return bus_req; 208bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 209bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 210bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio, 211bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request *bus_req) 212bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 213f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n", 214f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo __func__, bus_req); 215bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 216151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->lock); 217bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); 218151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->lock); 219bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 220bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 221bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req, 222bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct mmc_data *data) 223bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 224bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct scatterlist *sg; 225bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int i; 226bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 227bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo data->blksz = HIF_MBOX_BLOCK_SIZE; 228bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE; 229bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 230bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_dbg(ATH6KL_DBG_SCATTER, 231bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo "hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n", 232bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo (scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr, 233bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo data->blksz, data->blocks, scat_req->len, 234bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->scat_entries); 235bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 236bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE : 237bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo MMC_DATA_READ; 238bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 239bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* fill SG entries */ 240d4df78904d12850c1c57bfffde8eff5195f3cd4dVasanthakumar Thiagarajan sg = scat_req->sgentries; 241bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sg_init_table(sg, scat_req->scat_entries); 242bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 243bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* assemble SG list */ 244bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo for (i = 0; i < scat_req->scat_entries; i++, sg++) { 245bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n", 246bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo i, scat_req->scat_list[i].buf, 247bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->scat_list[i].len); 248bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 249bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sg_set_buf(sg, scat_req->scat_list[i].buf, 250bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->scat_list[i].len); 251bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 252bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 253bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* set scatter-gather table for request */ 254d4df78904d12850c1c57bfffde8eff5195f3cd4dVasanthakumar Thiagarajan data->sg = scat_req->sgentries; 255bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo data->sg_len = scat_req->scat_entries; 256bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 257bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 258bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio, 259bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request *req) 260bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 261bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct mmc_request mmc_req; 262bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct mmc_command cmd; 263bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct mmc_data data; 264bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct hif_scatter_req *scat_req; 265bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u8 opcode, rw; 266348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan int status, len; 267bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 268bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req = req->scat_req; 269bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 270348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan if (scat_req->virt_scat) { 271348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan len = scat_req->len; 272348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan if (scat_req->req & HIF_BLOCK_BASIS) 273348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan len = round_down(len, HIF_MBOX_BLOCK_SIZE); 274348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan 275348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan status = ath6kl_sdio_io(ar_sdio->func, scat_req->req, 276348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan scat_req->addr, scat_req->virt_dma_buf, 277348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan len); 278348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan goto scat_complete; 279348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan } 280348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan 281bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo memset(&mmc_req, 0, sizeof(struct mmc_request)); 282bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo memset(&cmd, 0, sizeof(struct mmc_command)); 283bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo memset(&data, 0, sizeof(struct mmc_data)); 284bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 285d4df78904d12850c1c57bfffde8eff5195f3cd4dVasanthakumar Thiagarajan ath6kl_sdio_setup_scat_data(scat_req, &data); 286bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 287bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo opcode = (scat_req->req & HIF_FIXED_ADDRESS) ? 288bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS; 289bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 290bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ; 291bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 292bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* Fixup the address so that the last byte will fall on MBOX EOM */ 293bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (scat_req->req & HIF_WRITE) { 294bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (scat_req->addr == HIF_MBOX_BASE_ADDR) 295bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->addr += HIF_MBOX_WIDTH - scat_req->len; 296bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo else 297bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* Uses extended address range */ 298bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len; 299bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 300bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 301bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* set command argument */ 302bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num, 303bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr, 304bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo data.blocks); 305bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 306bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo cmd.opcode = SD_IO_RW_EXTENDED; 307bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; 308bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 309bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mmc_req.cmd = &cmd; 310bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mmc_req.data = &data; 311bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 312861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan sdio_claim_host(ar_sdio->func); 313861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan 314bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mmc_set_data_timeout(&data, ar_sdio->func->card); 315e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo 316e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo trace_ath6kl_sdio_scat(scat_req->addr, 317e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo scat_req->req, 318e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo scat_req->len, 319e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo scat_req->scat_entries, 320e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo scat_req->scat_list); 321e60c81543fd4edabe5b6fd2ea68d2db6f6204177Kalle Valo 322bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* synchronous call to process request */ 323bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req); 324bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 325861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan sdio_release_host(ar_sdio->func); 326861dd058f495973c7ad2a44b8f68f3cc05733eabVasanthakumar Thiagarajan 327bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo status = cmd.error ? cmd.error : data.error; 328348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajan 329348a8fbce79e15b1918390120c0d63baa85343a0Vasanthakumar Thiagarajanscat_complete: 330bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->status = status; 331bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 332bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (scat_req->status) 333bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("Scatter write request failed:%d\n", 334bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo scat_req->status); 335bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 336bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (scat_req->req & HIF_ASYNCHRONOUS) 337e041c7f9af5a3583ee2bd20af1b03ec56b6adccaVasanthakumar Thiagarajan scat_req->complete(ar_sdio->ar->htc_target, scat_req); 338bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 339bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return status; 340bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 341bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 3423df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajanstatic int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio, 3433df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan int n_scat_entry, int n_scat_req, 3443df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan bool virt_scat) 3453df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan{ 3463df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan struct hif_scatter_req *s_req; 3473df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan struct bus_request *bus_req; 34837291fc61253cd34db40b7a60be4497db776db41Geert Uytterhoeven int i, scat_req_sz, scat_list_sz, size; 349cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan u8 *virt_buf; 3503df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 35131b9cc9a873dcab161999622314f98a75d838975Kalle Valo scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item); 3523df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan scat_req_sz = sizeof(*s_req) + scat_list_sz; 3533df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 3543df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan if (!virt_scat) 35537291fc61253cd34db40b7a60be4497db776db41Geert Uytterhoeven size = sizeof(struct scatterlist) * n_scat_entry; 356cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan else 35737291fc61253cd34db40b7a60be4497db776db41Geert Uytterhoeven size = 2 * L1_CACHE_BYTES + 35837291fc61253cd34db40b7a60be4497db776db41Geert Uytterhoeven ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER; 3593df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 3603df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan for (i = 0; i < n_scat_req; i++) { 3613df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan /* allocate the scatter request */ 3623df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan s_req = kzalloc(scat_req_sz, GFP_KERNEL); 3633df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan if (!s_req) 3643df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan return -ENOMEM; 3653df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 366cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan if (virt_scat) { 36737291fc61253cd34db40b7a60be4497db776db41Geert Uytterhoeven virt_buf = kzalloc(size, GFP_KERNEL); 368cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan if (!virt_buf) { 369cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan kfree(s_req); 370cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan return -ENOMEM; 371cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan } 372cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan 373cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan s_req->virt_dma_buf = 374cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan (u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf); 375cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan } else { 3763df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan /* allocate sglist */ 37737291fc61253cd34db40b7a60be4497db776db41Geert Uytterhoeven s_req->sgentries = kzalloc(size, GFP_KERNEL); 3783df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 3793df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan if (!s_req->sgentries) { 3803df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan kfree(s_req); 3813df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan return -ENOMEM; 3823df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan } 3833df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan } 3843df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 3853df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan /* allocate a bus request for this scatter request */ 3863df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); 3873df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan if (!bus_req) { 3883df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan kfree(s_req->sgentries); 389cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan kfree(s_req->virt_dma_buf); 3903df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan kfree(s_req); 3913df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan return -ENOMEM; 3923df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan } 3933df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 3943df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan /* assign the scatter request to this bus request */ 3953df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan bus_req->scat_req = s_req; 3963df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan s_req->busrequest = bus_req; 3973df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 3984a005c3ed0e6424e991daeea385bd08a9b97b67aVasanthakumar Thiagarajan s_req->virt_scat = virt_scat; 3994a005c3ed0e6424e991daeea385bd08a9b97b67aVasanthakumar Thiagarajan 4003df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan /* add it to the scatter pool */ 4013df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan hif_scatter_req_add(ar_sdio->ar, s_req); 4023df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan } 4033df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 4043df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan return 0; 4053df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan} 4063df505add2e5a370fb04dac1135e751bdd18e08fVasanthakumar Thiagarajan 407bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, 408bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u32 len, u32 request) 409bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 410bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 411bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u8 *tbuf = NULL; 412bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret; 413bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bool bounced = false; 414bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 415bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (request & HIF_BLOCK_BASIS) 416bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo len = round_down(len, HIF_MBOX_BLOCK_SIZE); 417bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 418bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (buf_needs_bounce(buf)) { 419bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (!ar_sdio->dma_buffer) 420bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return -ENOMEM; 421fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani mutex_lock(&ar_sdio->dma_buffer_mutex); 422bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo tbuf = ar_sdio->dma_buffer; 423daa16bc52ad8e9513506fca29a038a1460e63638Raja Mani 424daa16bc52ad8e9513506fca29a038a1460e63638Raja Mani if (request & HIF_WRITE) 425daa16bc52ad8e9513506fca29a038a1460e63638Raja Mani memcpy(tbuf, buf, len); 426daa16bc52ad8e9513506fca29a038a1460e63638Raja Mani 427bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bounced = true; 428a5d8f9dfcf5ead45a2f164f15ca4839325c08815Kalle Valo } else { 429bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo tbuf = buf; 430a5d8f9dfcf5ead45a2f164f15ca4839325c08815Kalle Valo } 431bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 432da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len); 433da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan if ((request & HIF_READ) && bounced) 434da220695f03a81fc8f6fcf1921e2b6f1c2be6db6Vasanthakumar Thiagarajan memcpy(buf, tbuf, len); 435bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 436fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani if (bounced) 437fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani mutex_unlock(&ar_sdio->dma_buffer_mutex); 438fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani 439bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 440bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 441bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 442bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio, 443bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request *req) 444bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 445a5d8f9dfcf5ead45a2f164f15ca4839325c08815Kalle Valo if (req->scat_req) { 446bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_sdio_scat_rw(ar_sdio, req); 447a5d8f9dfcf5ead45a2f164f15ca4839325c08815Kalle Valo } else { 448bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo void *context; 449bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int status; 450bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 451bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address, 452bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo req->buffer, req->length, 453bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo req->request); 454bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo context = req->packet; 455bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_sdio_free_bus_req(ar_sdio, req); 4568e8ddb2b8d19a952e1dff7a2a8a9d606e52fc3e3Kalle Valo ath6kl_hif_rw_comp_handler(context, status); 457bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 458bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 459bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 460bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_write_async_work(struct work_struct *work) 461bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 462bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio; 463bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request *req, *tmp_req; 464bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 465bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work); 466bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 467151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->wr_async_lock); 468bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { 469bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_del(&req->list); 470151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->wr_async_lock); 471bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo __ath6kl_sdio_write_async(ar_sdio, req); 472151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->wr_async_lock); 473bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 474151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->wr_async_lock); 475bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 476bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 477bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_irq_handler(struct sdio_func *func) 478bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 479bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int status; 480bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio; 481bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 482f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); 483f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo 484bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio = sdio_get_drvdata(func); 485d1f4159723450252b643bcddff064153f32918bcRaja Mani atomic_set(&ar_sdio->irq_handling, 1); 486bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* 487bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * Release the host during interrups so we can pick it back up when 488bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * we process commands. 489bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo */ 490bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_release_host(ar_sdio->func); 491bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 4928e8ddb2b8d19a952e1dff7a2a8a9d606e52fc3e3Kalle Valo status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); 493bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_claim_host(ar_sdio->func); 494d1f4159723450252b643bcddff064153f32918bcRaja Mani 495d1f4159723450252b643bcddff064153f32918bcRaja Mani atomic_set(&ar_sdio->irq_handling, 0); 496d1f4159723450252b643bcddff064153f32918bcRaja Mani wake_up(&ar_sdio->irq_wq); 497d1f4159723450252b643bcddff064153f32918bcRaja Mani 498bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo WARN_ON(status && status != -ECANCELED); 499bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 500bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 501b2e756989e9744d94f7cbae47586858c3efc8430Kalle Valostatic int ath6kl_sdio_power_on(struct ath6kl *ar) 502bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 503b2e756989e9744d94f7cbae47586858c3efc8430Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 504bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct sdio_func *func = ar_sdio->func; 505bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret = 0; 506bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 507bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (!ar_sdio->is_disabled) 508bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return 0; 509bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 5103ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, "sdio power on\n"); 5113ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo 512bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_claim_host(func); 513bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 514bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = sdio_enable_func(func); 515bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) { 516bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("Unable to enable sdio func: %d)\n", ret); 517bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_release_host(func); 518bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 519bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 520bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 521bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_release_host(func); 522bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 523bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* 524bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * Wait for hardware to initialise. It should take a lot less than 525bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo * 10 ms but let's be conservative here. 526bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo */ 527bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo msleep(10); 528bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 529bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->is_disabled = false; 530bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 531bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 532bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 533bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 534b2e756989e9744d94f7cbae47586858c3efc8430Kalle Valostatic int ath6kl_sdio_power_off(struct ath6kl *ar) 535bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 536b2e756989e9744d94f7cbae47586858c3efc8430Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 537bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret; 538bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 539bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ar_sdio->is_disabled) 540bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return 0; 541bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 5423ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, "sdio power off\n"); 5433ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo 544bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* Disable the card */ 545bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_claim_host(ar_sdio->func); 546bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = sdio_disable_func(ar_sdio->func); 547bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_release_host(ar_sdio->func); 548bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 549bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) 550bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 551bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 552bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->is_disabled = true; 553bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 554bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 555bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 556bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 557bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer, 558bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo u32 length, u32 request, 559bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct htc_packet *packet) 560bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 561bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 562bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct bus_request *bus_req; 563bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 564bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); 565bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 56693b42cae16d7af185ebdee0f4e85feccfd40d986Vasanthakumar Thiagarajan if (WARN_ON_ONCE(!bus_req)) 567bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return -ENOMEM; 568bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 569bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req->address = address; 570bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req->buffer = buffer; 571bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req->length = length; 572bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req->request = request; 573bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo bus_req->packet = packet; 574bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 575151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->wr_async_lock); 576bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq); 577151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->wr_async_lock); 578bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work); 579bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 580bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return 0; 581bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 582bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 583bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_irq_enable(struct ath6kl *ar) 584bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 585bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 586bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret; 587bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 588bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_claim_host(ar_sdio->func); 589bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 590bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo /* Register the isr */ 591bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler); 592bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) 593bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("Failed to claim sdio irq: %d\n", ret); 594bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 595bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_release_host(ar_sdio->func); 596bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 597bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 598d1f4159723450252b643bcddff064153f32918bcRaja Manistatic bool ath6kl_sdio_is_on_irq(struct ath6kl *ar) 599d1f4159723450252b643bcddff064153f32918bcRaja Mani{ 600d1f4159723450252b643bcddff064153f32918bcRaja Mani struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 601d1f4159723450252b643bcddff064153f32918bcRaja Mani 602d1f4159723450252b643bcddff064153f32918bcRaja Mani return !atomic_read(&ar_sdio->irq_handling); 603d1f4159723450252b643bcddff064153f32918bcRaja Mani} 604d1f4159723450252b643bcddff064153f32918bcRaja Mani 605bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_irq_disable(struct ath6kl *ar) 606bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 607bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 608bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret; 609bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 610bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_claim_host(ar_sdio->func); 611bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 612d1f4159723450252b643bcddff064153f32918bcRaja Mani if (atomic_read(&ar_sdio->irq_handling)) { 613d1f4159723450252b643bcddff064153f32918bcRaja Mani sdio_release_host(ar_sdio->func); 614d1f4159723450252b643bcddff064153f32918bcRaja Mani 615d1f4159723450252b643bcddff064153f32918bcRaja Mani ret = wait_event_interruptible(ar_sdio->irq_wq, 616d1f4159723450252b643bcddff064153f32918bcRaja Mani ath6kl_sdio_is_on_irq(ar)); 617d1f4159723450252b643bcddff064153f32918bcRaja Mani if (ret) 618d1f4159723450252b643bcddff064153f32918bcRaja Mani return; 619d1f4159723450252b643bcddff064153f32918bcRaja Mani 620d1f4159723450252b643bcddff064153f32918bcRaja Mani sdio_claim_host(ar_sdio->func); 621d1f4159723450252b643bcddff064153f32918bcRaja Mani } 622bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 623bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = sdio_release_irq(ar_sdio->func); 624bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) 625bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("Failed to release sdio irq: %d\n", ret); 626bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 627bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_release_host(ar_sdio->func); 628bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 629bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 630bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) 631bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 632bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 633bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct hif_scatter_req *node = NULL; 634bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 635151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->scat_lock); 636bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 637bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (!list_empty(&ar_sdio->scat_req)) { 638bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo node = list_first_entry(&ar_sdio->scat_req, 639bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct hif_scatter_req, list); 640bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_del(&node->list); 641b29072cc7b0e08ace48ab709c40cf6246fb2e8b0Chilam Ng 642b29072cc7b0e08ace48ab709c40cf6246fb2e8b0Chilam Ng node->scat_q_depth = get_queue_depth(&ar_sdio->scat_req); 643bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 644bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 645151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->scat_lock); 646bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 647bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return node; 648bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 649bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 650bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_scatter_req_add(struct ath6kl *ar, 651bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct hif_scatter_req *s_req) 652bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 653bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 654bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 655151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->scat_lock); 656bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 657bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo list_add_tail(&s_req->list, &ar_sdio->scat_req); 658bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 659151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->scat_lock); 660bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 661bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 662c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan/* scatter gather read write request */ 663c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajanstatic int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, 664c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan struct hif_scatter_req *scat_req) 665c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan{ 666c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 667c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan u32 request = scat_req->req; 668c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan int status = 0; 669c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan 670c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan if (!scat_req->len) 671c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan return -EINVAL; 672c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan 673c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan ath6kl_dbg(ATH6KL_DBG_SCATTER, 67496f1fadc94bc8dcde814109439e416143eed50faKalle Valo "hif-scatter: total len: %d scatter entries: %d\n", 67596f1fadc94bc8dcde814109439e416143eed50faKalle Valo scat_req->len, scat_req->scat_entries); 676c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan 677a5d8f9dfcf5ead45a2f164f15ca4839325c08815Kalle Valo if (request & HIF_SYNCHRONOUS) { 678d4df78904d12850c1c57bfffde8eff5195f3cd4dVasanthakumar Thiagarajan status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); 679a5d8f9dfcf5ead45a2f164f15ca4839325c08815Kalle Valo } else { 680151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->wr_async_lock); 681d4df78904d12850c1c57bfffde8eff5195f3cd4dVasanthakumar Thiagarajan list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq); 682151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->wr_async_lock); 683c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work); 684c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan } 685c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan 686c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan return status; 687c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan} 688c630d18a5ea0213f6ad8e34b62f9c78038f371d8Vasanthakumar Thiagarajan 68918a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan/* clean up scatter support */ 69018a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajanstatic void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar) 69118a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan{ 69218a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 69318a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan struct hif_scatter_req *s_req, *tmp_req; 69418a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 69518a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan /* empty the free list */ 696151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->scat_lock); 69718a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) { 69818a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan list_del(&s_req->list); 699151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->scat_lock); 70018a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 70132a07e4448f78158a75f7c1f0056289647d83946Kalle Valo /* 70232a07e4448f78158a75f7c1f0056289647d83946Kalle Valo * FIXME: should we also call completion handler with 70332a07e4448f78158a75f7c1f0056289647d83946Kalle Valo * ath6kl_hif_rw_comp_handler() with status -ECANCELED so 70432a07e4448f78158a75f7c1f0056289647d83946Kalle Valo * that the packet is properly freed? 70532a07e4448f78158a75f7c1f0056289647d83946Kalle Valo */ 70618a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan if (s_req->busrequest) 70718a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest); 70818a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan kfree(s_req->virt_dma_buf); 70918a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan kfree(s_req->sgentries); 71018a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan kfree(s_req); 71118a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 712151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_lock_bh(&ar_sdio->scat_lock); 71318a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan } 714151bd30bdf88551d68a743b7f7504ca0f3ff2796Vasanthakumar Thiagarajan spin_unlock_bh(&ar_sdio->scat_lock); 71518a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan} 71618a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 71718a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan/* setup of HIF scatter resources */ 71850745af7ebb38d3f8f2487f92db6c59c13dc0b89Vasanthakumar Thiagarajanstatic int ath6kl_sdio_enable_scatter(struct ath6kl *ar) 71918a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan{ 72018a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 72150745af7ebb38d3f8f2487f92db6c59c13dc0b89Vasanthakumar Thiagarajan struct htc_target *target = ar->htc_target; 722527f6570300980251e818e80865b437eefb4e5d3Andi Kleen int ret = 0; 723cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan bool virt_scat = false; 72418a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 72532a07e4448f78158a75f7c1f0056289647d83946Kalle Valo if (ar_sdio->scatter_enabled) 72632a07e4448f78158a75f7c1f0056289647d83946Kalle Valo return 0; 72732a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 72832a07e4448f78158a75f7c1f0056289647d83946Kalle Valo ar_sdio->scatter_enabled = true; 72932a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 73018a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan /* check if host supports scatter and it meets our requirements */ 73118a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) { 732cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ath6kl_err("host only supports scatter of :%d entries, need: %d\n", 73318a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan ar_sdio->func->card->host->max_segs, 73418a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan MAX_SCATTER_ENTRIES_PER_REQ); 735cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan virt_scat = true; 73618a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan } 73718a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 738cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan if (!virt_scat) { 739cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio, 740cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan MAX_SCATTER_ENTRIES_PER_REQ, 741cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan MAX_SCATTER_REQUESTS, virt_scat); 742cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan 743cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan if (!ret) { 7443ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, 7453ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo "hif-scatter enabled requests %d entries %d\n", 746cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan MAX_SCATTER_REQUESTS, 747cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan MAX_SCATTER_ENTRIES_PER_REQ); 748cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan 74950745af7ebb38d3f8f2487f92db6c59c13dc0b89Vasanthakumar Thiagarajan target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ; 75050745af7ebb38d3f8f2487f92db6c59c13dc0b89Vasanthakumar Thiagarajan target->max_xfer_szper_scatreq = 751cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan MAX_SCATTER_REQ_TRANSFER_SIZE; 752cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan } else { 753cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ath6kl_sdio_cleanup_scatter(ar); 754cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n"); 755cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan } 756cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan } 75718a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 758cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan if (virt_scat || ret) { 759cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio, 760cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ATH6KL_SCATTER_ENTRIES_PER_REQ, 761cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ATH6KL_SCATTER_REQS, virt_scat); 762cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan 763cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan if (ret) { 764cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ath6kl_err("failed to alloc virtual scatter resources !\n"); 765cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ath6kl_sdio_cleanup_scatter(ar); 766cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan return ret; 767cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan } 768cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan 7693ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, 7703ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo "virtual scatter enabled requests %d entries %d\n", 771cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ); 772cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan 77350745af7ebb38d3f8f2487f92db6c59c13dc0b89Vasanthakumar Thiagarajan target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ; 77450745af7ebb38d3f8f2487f92db6c59c13dc0b89Vasanthakumar Thiagarajan target->max_xfer_szper_scatreq = 775cfeab10b117cee7c2b3a8aaf1dc49d28482aeca0Vasanthakumar Thiagarajan ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER; 77618a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan } 77718a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 77818a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan return 0; 77918a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan} 78018a0f93e539cd9269d604ad9de59bca49c488808Vasanthakumar Thiagarajan 781e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valostatic int ath6kl_sdio_config(struct ath6kl *ar) 782e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo{ 783e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 784e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo struct sdio_func *func = ar_sdio->func; 785e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo int ret; 786e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 787e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo sdio_claim_host(func); 788e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 789e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >= 790e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo MANUFACTURER_ID_AR6003_BASE) { 791e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo /* enable 4-bit ASYNC interrupt on AR6003 or later */ 792e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card, 793e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo CCCR_SDIO_IRQ_MODE_REG, 794e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo SDIO_IRQ_MODE_ASYNC_4BIT_IRQ); 795e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo if (ret) { 796e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ath6kl_err("Failed to enable 4-bit async irq mode %d\n", 797e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ret); 798e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo goto out; 799e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo } 800e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 801e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, "4-bit async irq mode enabled\n"); 802e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo } 803e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 804e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo /* give us some time to enable, in ms */ 805e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo func->enable_timeout = 100; 806e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 807e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); 808e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo if (ret) { 809e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ath6kl_err("Set sdio block size %d failed: %d)\n", 810e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo HIF_MBOX_BLOCK_SIZE, ret); 811e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo goto out; 812e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo } 813e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 814e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valoout: 815e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo sdio_release_host(func); 816e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 817e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo return ret; 818e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo} 819e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo 820e390af779dc671551800514d391928f5a798089aRaja Manistatic int ath6kl_set_sdio_pm_caps(struct ath6kl *ar) 821abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo{ 822abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 823abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo struct sdio_func *func = ar_sdio->func; 824abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo mmc_pm_flag_t flags; 825abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo int ret; 826abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo 827abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo flags = sdio_get_host_pm_caps(func); 828abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo 829b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags); 830b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 831e390af779dc671551800514d391928f5a798089aRaja Mani if (!(flags & MMC_PM_WAKE_SDIO_IRQ) || 832e390af779dc671551800514d391928f5a798089aRaja Mani !(flags & MMC_PM_KEEP_POWER)) 833e390af779dc671551800514d391928f5a798089aRaja Mani return -EINVAL; 834abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo 835abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 836abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo if (ret) { 837e390af779dc671551800514d391928f5a798089aRaja Mani ath6kl_err("set sdio keep pwr flag failed: %d\n", ret); 838abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo return ret; 839abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo } 840abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo 84110509f903ebb7d2a02571f30cb937dd923b023cfKalle Valo /* sdio irq wakes up host */ 842e390af779dc671551800514d391928f5a798089aRaja Mani ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); 843e390af779dc671551800514d391928f5a798089aRaja Mani if (ret) 844e390af779dc671551800514d391928f5a798089aRaja Mani ath6kl_err("set sdio wake irq flag failed: %d\n", ret); 845e390af779dc671551800514d391928f5a798089aRaja Mani 846e390af779dc671551800514d391928f5a798089aRaja Mani return ret; 847e390af779dc671551800514d391928f5a798089aRaja Mani} 848e390af779dc671551800514d391928f5a798089aRaja Mani 849e390af779dc671551800514d391928f5a798089aRaja Manistatic int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) 850e390af779dc671551800514d391928f5a798089aRaja Mani{ 851e390af779dc671551800514d391928f5a798089aRaja Mani struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 852e390af779dc671551800514d391928f5a798089aRaja Mani struct sdio_func *func = ar_sdio->func; 853e390af779dc671551800514d391928f5a798089aRaja Mani mmc_pm_flag_t flags; 8541e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani bool try_deepsleep = false; 855e390af779dc671551800514d391928f5a798089aRaja Mani int ret; 85610509f903ebb7d2a02571f30cb937dd923b023cfKalle Valo 857e390af779dc671551800514d391928f5a798089aRaja Mani if (ar->suspend_mode == WLAN_POWER_STATE_WOW || 858e390af779dc671551800514d391928f5a798089aRaja Mani (!ar->suspend_mode && wow)) { 859e390af779dc671551800514d391928f5a798089aRaja Mani ret = ath6kl_set_sdio_pm_caps(ar); 860e390af779dc671551800514d391928f5a798089aRaja Mani if (ret) 861e390af779dc671551800514d391928f5a798089aRaja Mani goto cut_pwr; 862e390af779dc671551800514d391928f5a798089aRaja Mani 863d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); 8641e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani if (ret && ret != -ENOTCONN) 8651e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani ath6kl_err("wow suspend failed: %d\n", ret); 8661e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani 8677433a49010fbb637de6ce14080fd89067156ccb7Kalle Valo if (ret && 8687433a49010fbb637de6ce14080fd89067156ccb7Kalle Valo (!ar->wow_suspend_mode || 8697433a49010fbb637de6ce14080fd89067156ccb7Kalle Valo ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP)) 8707433a49010fbb637de6ce14080fd89067156ccb7Kalle Valo try_deepsleep = true; 8711e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani else if (ret && 8721e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani ar->wow_suspend_mode == WLAN_POWER_STATE_CUT_PWR) 8737433a49010fbb637de6ce14080fd89067156ccb7Kalle Valo goto cut_pwr; 8741e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani if (!ret) 8751e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani return 0; 876e390af779dc671551800514d391928f5a798089aRaja Mani } 877e390af779dc671551800514d391928f5a798089aRaja Mani 878e390af779dc671551800514d391928f5a798089aRaja Mani if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || 8791e9a905d9afd289bf19f02092a56660c2bcc50dbRaja Mani !ar->suspend_mode || try_deepsleep) { 880e390af779dc671551800514d391928f5a798089aRaja Mani flags = sdio_get_host_pm_caps(func); 881e390af779dc671551800514d391928f5a798089aRaja Mani if (!(flags & MMC_PM_KEEP_POWER)) 882e390af779dc671551800514d391928f5a798089aRaja Mani goto cut_pwr; 883e390af779dc671551800514d391928f5a798089aRaja Mani 884e390af779dc671551800514d391928f5a798089aRaja Mani ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 885d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani if (ret) 886e390af779dc671551800514d391928f5a798089aRaja Mani goto cut_pwr; 887d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani 888cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan /* 889cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan * Workaround to support Deep Sleep with MSM, set the host pm 890cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan * flag as MMC_PM_WAKE_SDIO_IRQ to allow SDCC deiver to disable 891cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan * the sdc2_clock and internally allows MSM to enter 892cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan * TCXO shutdown properly. 893cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan */ 894cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan if ((flags & MMC_PM_WAKE_SDIO_IRQ)) { 895cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan ret = sdio_set_host_pm_flags(func, 896cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan MMC_PM_WAKE_SDIO_IRQ); 897cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan if (ret) 898cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan goto cut_pwr; 899cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan } 900cca4d5adcff515b4bf5402dc23792f5123872906Santosh Sajjan 901e390af779dc671551800514d391928f5a798089aRaja Mani ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, 902e390af779dc671551800514d391928f5a798089aRaja Mani NULL); 903e390af779dc671551800514d391928f5a798089aRaja Mani if (ret) 904e390af779dc671551800514d391928f5a798089aRaja Mani goto cut_pwr; 905e390af779dc671551800514d391928f5a798089aRaja Mani 906e390af779dc671551800514d391928f5a798089aRaja Mani return 0; 907d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani } 908d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani 909e390af779dc671551800514d391928f5a798089aRaja Manicut_pwr: 9105699257f69f9584d10b53bb595ed58a434d64321Ming Jiang if (func->card && func->card->host) 9115699257f69f9584d10b53bb595ed58a434d64321Ming Jiang func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER; 9125699257f69f9584d10b53bb595ed58a434d64321Ming Jiang 913e390af779dc671551800514d391928f5a798089aRaja Mani return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL); 914abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo} 915abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo 916aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ngstatic int ath6kl_sdio_resume(struct ath6kl *ar) 917aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ng{ 918b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo switch (ar->state) { 919b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo case ATH6KL_STATE_OFF: 920b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo case ATH6KL_STATE_CUTPOWER: 921b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo ath6kl_dbg(ATH6KL_DBG_SUSPEND, 922b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo "sdio resume configuring sdio\n"); 923b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 924b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo /* need to set sdio settings after power is cut from sdio */ 925b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo ath6kl_sdio_config(ar); 926b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo break; 927b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 928b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo case ATH6KL_STATE_ON: 929b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo break; 930b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 931b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo case ATH6KL_STATE_DEEPSLEEP: 932b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo break; 933d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani 934d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani case ATH6KL_STATE_WOW: 935d7c44e0ba5003c22a9ff3545fc2f51eaca8a95b1Raja Mani break; 936390a8c8fae2e7072579198414e631984a61c485eRaja Mani 937390a8c8fae2e7072579198414e631984a61c485eRaja Mani case ATH6KL_STATE_SUSPENDING: 938390a8c8fae2e7072579198414e631984a61c485eRaja Mani break; 939390a8c8fae2e7072579198414e631984a61c485eRaja Mani 940390a8c8fae2e7072579198414e631984a61c485eRaja Mani case ATH6KL_STATE_RESUMING: 941390a8c8fae2e7072579198414e631984a61c485eRaja Mani break; 94284caf8005b09e0a4a57fce44119489d1b0bbbe94Vasanthakumar Thiagarajan 94384caf8005b09e0a4a57fce44119489d1b0bbbe94Vasanthakumar Thiagarajan case ATH6KL_STATE_RECOVERY: 94484caf8005b09e0a4a57fce44119489d1b0bbbe94Vasanthakumar Thiagarajan break; 945b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo } 946b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 94752d81a6883fb36c4304fb5619bfa5f61eb7986efKalle Valo ath6kl_cfg80211_resume(ar); 948aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ng 949aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ng return 0; 950aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ng} 951aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ng 952c71114959dc952a509822f22251d01004b3b94ccKalle Valo/* set the window address register (using 4-byte register access ). */ 953c71114959dc952a509822f22251d01004b3b94ccKalle Valostatic int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) 954c71114959dc952a509822f22251d01004b3b94ccKalle Valo{ 955c71114959dc952a509822f22251d01004b3b94ccKalle Valo int status; 956c71114959dc952a509822f22251d01004b3b94ccKalle Valo u8 addr_val[4]; 957c71114959dc952a509822f22251d01004b3b94ccKalle Valo s32 i; 958c71114959dc952a509822f22251d01004b3b94ccKalle Valo 959c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* 960c71114959dc952a509822f22251d01004b3b94ccKalle Valo * Write bytes 1,2,3 of the register to set the upper address bytes, 961c71114959dc952a509822f22251d01004b3b94ccKalle Valo * the LSB is written last to initiate the access cycle 962c71114959dc952a509822f22251d01004b3b94ccKalle Valo */ 963c71114959dc952a509822f22251d01004b3b94ccKalle Valo 964c71114959dc952a509822f22251d01004b3b94ccKalle Valo for (i = 1; i <= 3; i++) { 965c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* 966c71114959dc952a509822f22251d01004b3b94ccKalle Valo * Fill the buffer with the address byte value we want to 967c71114959dc952a509822f22251d01004b3b94ccKalle Valo * hit 4 times. 968c71114959dc952a509822f22251d01004b3b94ccKalle Valo */ 969c71114959dc952a509822f22251d01004b3b94ccKalle Valo memset(addr_val, ((u8 *)&addr)[i], 4); 970c71114959dc952a509822f22251d01004b3b94ccKalle Valo 971c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* 972c71114959dc952a509822f22251d01004b3b94ccKalle Valo * Hit each byte of the register address with a 4-byte 973c71114959dc952a509822f22251d01004b3b94ccKalle Valo * write operation to the same address, this is a harmless 974c71114959dc952a509822f22251d01004b3b94ccKalle Valo * operation. 975c71114959dc952a509822f22251d01004b3b94ccKalle Valo */ 976c71114959dc952a509822f22251d01004b3b94ccKalle Valo status = ath6kl_sdio_read_write_sync(ar, reg_addr + i, addr_val, 977c71114959dc952a509822f22251d01004b3b94ccKalle Valo 4, HIF_WR_SYNC_BYTE_FIX); 978c71114959dc952a509822f22251d01004b3b94ccKalle Valo if (status) 979c71114959dc952a509822f22251d01004b3b94ccKalle Valo break; 980c71114959dc952a509822f22251d01004b3b94ccKalle Valo } 981c71114959dc952a509822f22251d01004b3b94ccKalle Valo 982c71114959dc952a509822f22251d01004b3b94ccKalle Valo if (status) { 983cdeb860252e66bdaf1ab70420274df879f243d3dKalle Valo ath6kl_err("%s: failed to write initial bytes of 0x%x to window reg: 0x%X\n", 984cdeb860252e66bdaf1ab70420274df879f243d3dKalle Valo __func__, addr, reg_addr); 985c71114959dc952a509822f22251d01004b3b94ccKalle Valo return status; 986c71114959dc952a509822f22251d01004b3b94ccKalle Valo } 987c71114959dc952a509822f22251d01004b3b94ccKalle Valo 988c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* 989c71114959dc952a509822f22251d01004b3b94ccKalle Valo * Write the address register again, this time write the whole 990c71114959dc952a509822f22251d01004b3b94ccKalle Valo * 4-byte value. The effect here is that the LSB write causes the 991c71114959dc952a509822f22251d01004b3b94ccKalle Valo * cycle to start, the extra 3 byte write to bytes 1,2,3 has no 992c71114959dc952a509822f22251d01004b3b94ccKalle Valo * effect since we are writing the same values again 993c71114959dc952a509822f22251d01004b3b94ccKalle Valo */ 994c71114959dc952a509822f22251d01004b3b94ccKalle Valo status = ath6kl_sdio_read_write_sync(ar, reg_addr, (u8 *)(&addr), 995c71114959dc952a509822f22251d01004b3b94ccKalle Valo 4, HIF_WR_SYNC_BYTE_INC); 996c71114959dc952a509822f22251d01004b3b94ccKalle Valo 997c71114959dc952a509822f22251d01004b3b94ccKalle Valo if (status) { 998c71114959dc952a509822f22251d01004b3b94ccKalle Valo ath6kl_err("%s: failed to write 0x%x to window reg: 0x%X\n", 999c71114959dc952a509822f22251d01004b3b94ccKalle Valo __func__, addr, reg_addr); 1000c71114959dc952a509822f22251d01004b3b94ccKalle Valo return status; 1001c71114959dc952a509822f22251d01004b3b94ccKalle Valo } 1002c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1003c71114959dc952a509822f22251d01004b3b94ccKalle Valo return 0; 1004c71114959dc952a509822f22251d01004b3b94ccKalle Valo} 1005c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1006c71114959dc952a509822f22251d01004b3b94ccKalle Valostatic int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data) 1007c71114959dc952a509822f22251d01004b3b94ccKalle Valo{ 1008c71114959dc952a509822f22251d01004b3b94ccKalle Valo int status; 1009c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1010c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* set window register to start read cycle */ 1011c71114959dc952a509822f22251d01004b3b94ccKalle Valo status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, 1012c71114959dc952a509822f22251d01004b3b94ccKalle Valo address); 1013c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1014c71114959dc952a509822f22251d01004b3b94ccKalle Valo if (status) 1015c71114959dc952a509822f22251d01004b3b94ccKalle Valo return status; 1016c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1017c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* read the data */ 1018c71114959dc952a509822f22251d01004b3b94ccKalle Valo status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS, 1019c71114959dc952a509822f22251d01004b3b94ccKalle Valo (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC); 1020c71114959dc952a509822f22251d01004b3b94ccKalle Valo if (status) { 1021c71114959dc952a509822f22251d01004b3b94ccKalle Valo ath6kl_err("%s: failed to read from window data addr\n", 102296f1fadc94bc8dcde814109439e416143eed50faKalle Valo __func__); 1023c71114959dc952a509822f22251d01004b3b94ccKalle Valo return status; 1024c71114959dc952a509822f22251d01004b3b94ccKalle Valo } 1025c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1026c71114959dc952a509822f22251d01004b3b94ccKalle Valo return status; 1027c71114959dc952a509822f22251d01004b3b94ccKalle Valo} 1028c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1029c71114959dc952a509822f22251d01004b3b94ccKalle Valostatic int ath6kl_sdio_diag_write32(struct ath6kl *ar, u32 address, 1030c71114959dc952a509822f22251d01004b3b94ccKalle Valo __le32 data) 1031c71114959dc952a509822f22251d01004b3b94ccKalle Valo{ 1032c71114959dc952a509822f22251d01004b3b94ccKalle Valo int status; 1033c71114959dc952a509822f22251d01004b3b94ccKalle Valo u32 val = (__force u32) data; 1034c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1035c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* set write data */ 1036c71114959dc952a509822f22251d01004b3b94ccKalle Valo status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS, 1037c71114959dc952a509822f22251d01004b3b94ccKalle Valo (u8 *) &val, sizeof(u32), HIF_WR_SYNC_BYTE_INC); 1038c71114959dc952a509822f22251d01004b3b94ccKalle Valo if (status) { 1039c71114959dc952a509822f22251d01004b3b94ccKalle Valo ath6kl_err("%s: failed to write 0x%x to window data addr\n", 1040c71114959dc952a509822f22251d01004b3b94ccKalle Valo __func__, data); 1041c71114959dc952a509822f22251d01004b3b94ccKalle Valo return status; 1042c71114959dc952a509822f22251d01004b3b94ccKalle Valo } 1043c71114959dc952a509822f22251d01004b3b94ccKalle Valo 1044c71114959dc952a509822f22251d01004b3b94ccKalle Valo /* set window register, which starts the write cycle */ 1045c71114959dc952a509822f22251d01004b3b94ccKalle Valo return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS, 1046c71114959dc952a509822f22251d01004b3b94ccKalle Valo address); 1047c71114959dc952a509822f22251d01004b3b94ccKalle Valo} 1048c71114959dc952a509822f22251d01004b3b94ccKalle Valo 104966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valostatic int ath6kl_sdio_bmi_credits(struct ath6kl *ar) 105066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo{ 105166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo u32 addr; 105266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo unsigned long timeout; 105366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo int ret; 105466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 105566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ar->bmi.cmd_credits = 0; 105666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 105766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo /* Read the counter register to get the command credits */ 105866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; 105966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 106066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); 106166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) { 106266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo /* 106366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Hit the credit counter with a 4-byte access, the first byte 106466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * read will hit the counter and cause a decrement, while the 106566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * remaining 3 bytes has no effect. The rationale behind this 106666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * is to make all HIF accesses 4-byte aligned. 106766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo */ 106866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret = ath6kl_sdio_read_write_sync(ar, addr, 106966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo (u8 *)&ar->bmi.cmd_credits, 4, 107066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo HIF_RD_SYNC_BYTE_INC); 107166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (ret) { 1072cdeb860252e66bdaf1ab70420274df879f243d3dKalle Valo ath6kl_err("Unable to decrement the command credit count register: %d\n", 1073cdeb860252e66bdaf1ab70420274df879f243d3dKalle Valo ret); 107466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return ret; 107566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 107666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 107766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo /* The counter is only 8 bits. 107866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Ignore anything in the upper 3 bytes 107966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo */ 108066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ar->bmi.cmd_credits &= 0xFF; 108166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 108266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 108366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (!ar->bmi.cmd_credits) { 108466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ath6kl_err("bmi communication timeout\n"); 108566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return -ETIMEDOUT; 108666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 108766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 108866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return 0; 108966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo} 109066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 109166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valostatic int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar) 109266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo{ 109366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo unsigned long timeout; 109466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo u32 rx_word = 0; 109566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo int ret = 0; 109666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 109766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); 109866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo while ((time_before(jiffies, timeout)) && !rx_word) { 109966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret = ath6kl_sdio_read_write_sync(ar, 110066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo RX_LOOKAHEAD_VALID_ADDRESS, 110166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo (u8 *)&rx_word, sizeof(rx_word), 110266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo HIF_RD_SYNC_BYTE_INC); 110366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (ret) { 110466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n"); 110566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return ret; 110666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 110766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 110866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo /* all we really want is one bit */ 110966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo rx_word &= (1 << ENDPOINT1); 111066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 111166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 111266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (!rx_word) { 111366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ath6kl_err("bmi_recv_buf FIFO empty\n"); 111466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return -EINVAL; 111566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 111666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 111766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return ret; 111866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo} 111966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 112066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valostatic int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) 112166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo{ 112266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo int ret; 112366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo u32 addr; 112466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 112566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret = ath6kl_sdio_bmi_credits(ar); 112666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (ret) 112766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return ret; 112866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 112966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo addr = ar->mbox_info.htc_addr; 113066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 113166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len, 113266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo HIF_WR_SYNC_BYTE_INC); 1133bf9781454731c17085bc4708c09ada50f1b63120Mohammed Shafi Shajakhan if (ret) { 113466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ath6kl_err("unable to send the bmi data to the device\n"); 1135bf9781454731c17085bc4708c09ada50f1b63120Mohammed Shafi Shajakhan return ret; 1136bf9781454731c17085bc4708c09ada50f1b63120Mohammed Shafi Shajakhan } 113766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 1138bf9781454731c17085bc4708c09ada50f1b63120Mohammed Shafi Shajakhan return 0; 113966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo} 114066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 114166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valostatic int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len) 114266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo{ 114366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo int ret; 114466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo u32 addr; 114566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 114666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo /* 114766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * During normal bootup, small reads may be required. 114866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Rather than issue an HIF Read and then wait as the Target 114966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * adds successive bytes to the FIFO, we wait here until 115066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * we know that response data is available. 115166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 115266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * This allows us to cleanly timeout on an unexpected 115366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Target failure rather than risk problems at the HIF level. 115466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * In particular, this avoids SDIO timeouts and possibly garbage 115566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * data on some host controllers. And on an interconnect 115666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * such as Compact Flash (as well as some SDIO masters) which 115766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * does not provide any indication on data timeout, it avoids 115866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * a potential hang or garbage response. 115966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 116066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Synchronization is more difficult for reads larger than the 116166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * size of the MBOX FIFO (128B), because the Target is unable 116266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * to push the 129th byte of data until AFTER the Host posts an 116366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * HIF Read and removes some FIFO data. So for large reads the 116466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Host proceeds to post an HIF Read BEFORE all the data is 116566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * actually available to read. Fortunately, large BMI reads do 116666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * not occur in practice -- they're supported for debug/development. 116766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 116866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * So Host/Target BMI synchronization is divided into these cases: 116966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * CASE 1: length < 4 117066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Should not happen 117166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 117266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * CASE 2: 4 <= length <= 128 117366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Wait for first 4 bytes to be in FIFO 117466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * If CONSERVATIVE_BMI_READ is enabled, also wait for 117566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * a BMI command credit, which indicates that the ENTIRE 117666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * response is available in the the FIFO 117766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 117866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * CASE 3: length > 128 117966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * Wait for the first 4 bytes to be in FIFO 118066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 118166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * For most uses, a small timeout should be sufficient and we will 118266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * usually see a response quickly; but there may be some unusual 118366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * (debug) cases of BMI_EXECUTE where we want an larger timeout. 118466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * For now, we use an unbounded busy loop while waiting for 118566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * BMI_EXECUTE. 118666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * 118766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * If BMI_EXECUTE ever needs to support longer-latency execution, 118866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * especially in production, this code needs to be enhanced to sleep 118966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently 119066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo * a function of Host processor speed. 119166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo */ 119266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (len >= 4) { /* NB: Currently, always true */ 119366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret = ath6kl_bmi_get_rx_lkahd(ar); 119466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (ret) 119566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return ret; 119666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 119766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 119866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo addr = ar->mbox_info.htc_addr; 119966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len, 120066b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo HIF_RD_SYNC_BYTE_INC); 120166b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo if (ret) { 120266b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ath6kl_err("Unable to read the bmi data from the device: %d\n", 120366b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo ret); 120466b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return ret; 120566b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo } 120666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 120766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo return 0; 120866b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo} 120966b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo 121032a07e4448f78158a75f7c1f0056289647d83946Kalle Valostatic void ath6kl_sdio_stop(struct ath6kl *ar) 121132a07e4448f78158a75f7c1f0056289647d83946Kalle Valo{ 121232a07e4448f78158a75f7c1f0056289647d83946Kalle Valo struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); 121332a07e4448f78158a75f7c1f0056289647d83946Kalle Valo struct bus_request *req, *tmp_req; 121432a07e4448f78158a75f7c1f0056289647d83946Kalle Valo void *context; 121532a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 121632a07e4448f78158a75f7c1f0056289647d83946Kalle Valo /* FIXME: make sure that wq is not queued again */ 121732a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 121832a07e4448f78158a75f7c1f0056289647d83946Kalle Valo cancel_work_sync(&ar_sdio->wr_async_work); 121932a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 122032a07e4448f78158a75f7c1f0056289647d83946Kalle Valo spin_lock_bh(&ar_sdio->wr_async_lock); 122132a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 122232a07e4448f78158a75f7c1f0056289647d83946Kalle Valo list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { 122332a07e4448f78158a75f7c1f0056289647d83946Kalle Valo list_del(&req->list); 122432a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 122532a07e4448f78158a75f7c1f0056289647d83946Kalle Valo if (req->scat_req) { 122632a07e4448f78158a75f7c1f0056289647d83946Kalle Valo /* this is a scatter gather request */ 122732a07e4448f78158a75f7c1f0056289647d83946Kalle Valo req->scat_req->status = -ECANCELED; 122832a07e4448f78158a75f7c1f0056289647d83946Kalle Valo req->scat_req->complete(ar_sdio->ar->htc_target, 122932a07e4448f78158a75f7c1f0056289647d83946Kalle Valo req->scat_req); 123032a07e4448f78158a75f7c1f0056289647d83946Kalle Valo } else { 123132a07e4448f78158a75f7c1f0056289647d83946Kalle Valo context = req->packet; 123232a07e4448f78158a75f7c1f0056289647d83946Kalle Valo ath6kl_sdio_free_bus_req(ar_sdio, req); 123332a07e4448f78158a75f7c1f0056289647d83946Kalle Valo ath6kl_hif_rw_comp_handler(context, -ECANCELED); 123432a07e4448f78158a75f7c1f0056289647d83946Kalle Valo } 123532a07e4448f78158a75f7c1f0056289647d83946Kalle Valo } 123632a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 123732a07e4448f78158a75f7c1f0056289647d83946Kalle Valo spin_unlock_bh(&ar_sdio->wr_async_lock); 123832a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 123932a07e4448f78158a75f7c1f0056289647d83946Kalle Valo WARN_ON(get_queue_depth(&ar_sdio->scat_req) != 4); 124032a07e4448f78158a75f7c1f0056289647d83946Kalle Valo} 124132a07e4448f78158a75f7c1f0056289647d83946Kalle Valo 1242bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic const struct ath6kl_hif_ops ath6kl_sdio_ops = { 1243bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .read_write_sync = ath6kl_sdio_read_write_sync, 1244bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .write_async = ath6kl_sdio_write_async, 1245bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .irq_enable = ath6kl_sdio_irq_enable, 1246bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .irq_disable = ath6kl_sdio_irq_disable, 1247bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .scatter_req_get = ath6kl_sdio_scatter_req_get, 1248bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .scatter_req_add = ath6kl_sdio_scatter_req_add, 1249bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .enable_scatter = ath6kl_sdio_enable_scatter, 1250f74a7361b8affcd76ffe1e2baa5748af4d63bceaVasanthakumar Thiagarajan .scat_req_rw = ath6kl_sdio_async_rw_scatter, 1251bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .cleanup_scatter = ath6kl_sdio_cleanup_scatter, 1252abcb344b3b823c8c9eac6e13e45a53eaf1d5d00bKalle Valo .suspend = ath6kl_sdio_suspend, 1253aa6cffc1a275a9369ca83e13cebc4b09e4f23954Chilam Ng .resume = ath6kl_sdio_resume, 1254c71114959dc952a509822f22251d01004b3b94ccKalle Valo .diag_read32 = ath6kl_sdio_diag_read32, 1255c71114959dc952a509822f22251d01004b3b94ccKalle Valo .diag_write32 = ath6kl_sdio_diag_write32, 125666b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo .bmi_read = ath6kl_sdio_bmi_read, 125766b693c3b84876d33afd35b9d717d8b9d07384c8Kalle Valo .bmi_write = ath6kl_sdio_bmi_write, 1258b2e756989e9744d94f7cbae47586858c3efc8430Kalle Valo .power_on = ath6kl_sdio_power_on, 1259b2e756989e9744d94f7cbae47586858c3efc8430Kalle Valo .power_off = ath6kl_sdio_power_off, 126032a07e4448f78158a75f7c1f0056289647d83946Kalle Valo .stop = ath6kl_sdio_stop, 1261bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo}; 1262bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1263b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo#ifdef CONFIG_PM_SLEEP 1264b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1265b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo/* 1266b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo * Empty handlers so that mmc subsystem doesn't remove us entirely during 1267b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo * suspend. We instead follow cfg80211 suspend/resume handlers. 1268b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo */ 1269b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valostatic int ath6kl_sdio_pm_suspend(struct device *device) 1270b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo{ 1271b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio pm suspend\n"); 1272b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1273b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo return 0; 1274b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo} 1275b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1276b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valostatic int ath6kl_sdio_pm_resume(struct device *device) 1277b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo{ 1278b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio pm resume\n"); 1279b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1280b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo return 0; 1281b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo} 1282b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1283b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valostatic SIMPLE_DEV_PM_OPS(ath6kl_sdio_pm_ops, ath6kl_sdio_pm_suspend, 1284b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo ath6kl_sdio_pm_resume); 1285b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1286b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo#define ATH6KL_SDIO_PM_OPS (&ath6kl_sdio_pm_ops) 1287b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1288b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo#else 1289b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1290b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo#define ATH6KL_SDIO_PM_OPS NULL 1291b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1292b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo#endif /* CONFIG_PM_SLEEP */ 1293b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo 1294bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic int ath6kl_sdio_probe(struct sdio_func *func, 1295bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo const struct sdio_device_id *id) 1296bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 1297bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret; 1298bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio; 1299bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl *ar; 1300bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int count; 1301bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 13023ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, 13033ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", 1304f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo func->num, func->vendor, func->device, 1305f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo func->max_blksize, func->cur_blksize); 1306bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1307bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL); 1308bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (!ar_sdio) 1309bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return -ENOMEM; 1310bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1311bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL); 1312bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (!ar_sdio->dma_buffer) { 1313bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = -ENOMEM; 1314bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo goto err_hif; 1315bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 1316bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1317bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->func = func; 1318bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_set_drvdata(func, ar_sdio); 1319bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1320bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->id = id; 1321bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->is_disabled = true; 1322bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1323bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo spin_lock_init(&ar_sdio->lock); 1324bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo spin_lock_init(&ar_sdio->scat_lock); 1325bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo spin_lock_init(&ar_sdio->wr_async_lock); 1326fdb28589b10f1bd4c407ea304399c2ff1cae1504Raja Mani mutex_init(&ar_sdio->dma_buffer_mutex); 1327bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1328bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo INIT_LIST_HEAD(&ar_sdio->scat_req); 1329bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); 1330bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo INIT_LIST_HEAD(&ar_sdio->wr_asyncq); 1331bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1332bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); 1333bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1334d1f4159723450252b643bcddff064153f32918bcRaja Mani init_waitqueue_head(&ar_sdio->irq_wq); 1335d1f4159723450252b643bcddff064153f32918bcRaja Mani 1336bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) 1337bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); 1338bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 133945eaa78f757b3b3992ca02c753764665e9fba0a4Kalle Valo ar = ath6kl_core_create(&ar_sdio->func->dev); 1340bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (!ar) { 1341bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("Failed to alloc ath6kl core\n"); 1342bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = -ENOMEM; 1343bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo goto err_dma; 1344bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 1345bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1346bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio->ar = ar; 134777eab1e929c371f98c6a17a8c5f566529d3b0be2Kalle Valo ar->hif_type = ATH6KL_HIF_TYPE_SDIO; 1348bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar->hif_priv = ar_sdio; 1349bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar->hif_ops = &ath6kl_sdio_ops; 13501f4c894d3a35e88331c01e681d033a2000c3667bKalle Valo ar->bmi.max_data_size = 256; 1351bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1352bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_sdio_set_mbox_info(ar); 1353bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1354e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ret = ath6kl_sdio_config(ar); 1355bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) { 1356e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo ath6kl_err("Failed to config sdio: %d\n", ret); 1357e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo goto err_core_alloc; 1358bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 1359bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1360e76ac2bf637defbe3b7fc644813be584b941ff0aKalle Valo ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_MBOX); 1361bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) { 1362bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("Failed to init ath6kl core\n"); 1363e28e810486a6826417e77e634666f0dfc2bfe548Kalle Valo goto err_core_alloc; 1364bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo } 1365bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1366bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 1367bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 13688dafb70edc7151bdb319b6d22895d9886c7172ebVasanthakumar Thiagarajanerr_core_alloc: 136945eaa78f757b3b3992ca02c753764665e9fba0a4Kalle Valo ath6kl_core_destroy(ar_sdio->ar); 1370bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valoerr_dma: 1371bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo kfree(ar_sdio->dma_buffer); 1372bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valoerr_hif: 1373bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo kfree(ar_sdio); 1374bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1375bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 1376bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 1377bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1378bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void ath6kl_sdio_remove(struct sdio_func *func) 1379bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 1380bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo struct ath6kl_sdio *ar_sdio; 1381bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 13823ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo ath6kl_dbg(ATH6KL_DBG_BOOT, 13833ef987bee7d56604bcbdbaebf85c51ca2ad87503Kalle Valo "sdio removed func %d vendor 0x%x device 0x%x\n", 1384f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo func->num, func->vendor, func->device); 1385f7325b85efe1395b52ef1006dafe3c0d4ff79f15Kalle Valo 1386bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ar_sdio = sdio_get_drvdata(func); 1387bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1388bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_stop_txrx(ar_sdio->ar); 1389bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo cancel_work_sync(&ar_sdio->wr_async_work); 1390bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 13916db8fa53ad4fa6d4b390e9bdd68f1238a01070eeVasanthakumar Thiagarajan ath6kl_core_cleanup(ar_sdio->ar); 13920e7de662bcf33567cc957995c38dc10959cc22bfVasanthakumar Thiagarajan ath6kl_core_destroy(ar_sdio->ar); 1393bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1394bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo kfree(ar_sdio->dma_buffer); 1395bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo kfree(ar_sdio); 1396bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 1397bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1398bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic const struct sdio_device_id ath6kl_sdio_devices[] = { 1399bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))}, 1400bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))}, 1401d93e2c2f2109a3b804fa799079a6dd4d315af857Naveen Gangadharan {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))}, 1402d93e2c2f2109a3b804fa799079a6dd4d315af857Naveen Gangadharan {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))}, 1403beb4be849a92172b4b95185a19db1691e6223f22Srinivas Kandagatla {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))}, 1404bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo {}, 1405bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo}; 1406bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1407bdcd81707973cf8aa9305337166f8ee842a050d4Kalle ValoMODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); 1408bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1409bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic struct sdio_driver ath6kl_sdio_driver = { 1410241b128b6b69ad41fc6f12cba45a3c3e64bce673Kalle Valo .name = "ath6kl_sdio", 1411bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .id_table = ath6kl_sdio_devices, 1412bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .probe = ath6kl_sdio_probe, 1413bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo .remove = ath6kl_sdio_remove, 1414b4b2a0b116d79510640622a5f28f219065e61b03Kalle Valo .drv.pm = ATH6KL_SDIO_PM_OPS, 1415bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo}; 1416bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1417bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic int __init ath6kl_sdio_init(void) 1418bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 1419bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo int ret; 1420bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1421bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ret = sdio_register_driver(&ath6kl_sdio_driver); 1422bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo if (ret) 1423bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo ath6kl_err("sdio driver registration failed: %d\n", ret); 1424bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1425bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo return ret; 1426bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 1427bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1428bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valostatic void __exit ath6kl_sdio_exit(void) 1429bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo{ 1430bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo sdio_unregister_driver(&ath6kl_sdio_driver); 1431bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo} 1432bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1433bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valomodule_init(ath6kl_sdio_init); 1434bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valomodule_exit(ath6kl_sdio_exit); 1435bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1436bdcd81707973cf8aa9305337166f8ee842a050d4Kalle ValoMODULE_AUTHOR("Atheros Communications, Inc."); 1437bdcd81707973cf8aa9305337166f8ee842a050d4Kalle ValoMODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); 1438bdcd81707973cf8aa9305337166f8ee842a050d4Kalle ValoMODULE_LICENSE("Dual BSD/GPL"); 1439bdcd81707973cf8aa9305337166f8ee842a050d4Kalle Valo 1440c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_OTP_FILE); 1441c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_FIRMWARE_FILE); 1442c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_PATCH_FILE); 14430d0192babc2f5ff9a5c047e61567d414806c1137Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE); 14440d0192babc2f5ff9a5c047e61567d414806c1137Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE); 1445c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_OTP_FILE); 1446c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_FIRMWARE_FILE); 1447c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_PATCH_FILE); 14480d0192babc2f5ff9a5c047e61567d414806c1137Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE); 14490d0192babc2f5ff9a5c047e61567d414806c1137Kalle ValoMODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE); 1450c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE); 1451f0ea5d588a50f080dd0738bab651f967c4d0020eKalle ValoMODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); 1452f0ea5d588a50f080dd0738bab651f967c4d0020eKalle ValoMODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); 1453c0038972b1253ad7f3ab7cc35ed57a830f5c8568Kalle ValoMODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE); 1454f0ea5d588a50f080dd0738bab651f967c4d0020eKalle ValoMODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); 1455f0ea5d588a50f080dd0738bab651f967c4d0020eKalle ValoMODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); 14566146ca69031e3ad697d801e7e242b554d7969de1Ray ChenMODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); 14576146ca69031e3ad697d801e7e242b554d7969de1Ray ChenMODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); 14586146ca69031e3ad697d801e7e242b554d7969de1Ray ChenMODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); 1459bf744f11788280bcbd9bb8ec62974274b72a75bfBala ShanmugamMODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); 1460bf744f11788280bcbd9bb8ec62974274b72a75bfBala ShanmugamMODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); 1461bf744f11788280bcbd9bb8ec62974274b72a75bfBala ShanmugamMODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); 1462