From: Ben Hutchings Subject: ath6kl: Do not use virt_addr_valid() Date: Sun, 06 Jan 2013 05:54:24 +0000 virt_addr_valid() doesn't seem to be meant for drivers to use, and currently cannot be used from modules on MIPS: ERROR: "min_low_pfn" [drivers/net/wireless/ath/ath6kl/ath6kl_sdio.ko] undefined! Instead of trying to check the given pointer, split ath6kl_sdio_read_write_sync() into two functions: __ath6kl_sdio_read_write_sync() takes an explicit 'may_dma' parameter and ath6kl_sdio_read_write_sync() is a wrapper that passes false. Make __ath6kl_sdio_write_async() pass true since we know it always has a heap-allocated buffer and it's the one case where the performance benefit of DMA matters. --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -79,17 +79,6 @@ static inline struct ath6kl_sdio *ath6kl return ar->hif_priv; } -/* - * Macro to check if DMA buffer is WORD-aligned and DMA-able. - * Most host controllers assume the buffer is DMA'able and will - * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid - * check fails on stack memory. - */ -static inline bool buf_needs_bounce(u8 *buf) -{ - return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf); -} - static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar) { struct ath6kl_mbox_info *mbox_info = &ar->mbox_info; @@ -394,8 +383,8 @@ static int ath6kl_sdio_alloc_prep_scat_r return 0; } -static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, - u32 len, u32 request) +static int __ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, + u32 len, u32 request, bool may_dma) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); u8 *tbuf = NULL; @@ -405,7 +394,10 @@ static int ath6kl_sdio_read_write_sync(s if (request & HIF_BLOCK_BASIS) len = round_down(len, HIF_MBOX_BLOCK_SIZE); - if (buf_needs_bounce(buf)) { + /* Most host controllers assume the buffer is DMA'able. We + * must use a bounce buffer if it isn't. + */ + if ((unsigned long) buf & 0x3 || !may_dma) { if (!ar_sdio->dma_buffer) return -ENOMEM; mutex_lock(&ar_sdio->dma_buffer_mutex); @@ -428,6 +420,13 @@ static int ath6kl_sdio_read_write_sync(s return ret; } +static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, + u32 len, u32 request) +{ + return __ath6kl_sdio_read_write_sync(ar, addr, buf, len, request, + false); +} + static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio, struct bus_request *req) { @@ -437,9 +436,9 @@ static void __ath6kl_sdio_write_async(st void *context; int status; - status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address, - req->buffer, req->length, - req->request); + status = __ath6kl_sdio_read_write_sync( + ar_sdio->ar, req->address, req->buffer, req->length, + req->request, true); context = req->packet; ath6kl_sdio_free_bus_req(ar_sdio, req); ath6kl_hif_rw_comp_handler(context, status);