static A_STATUS AllocateDMABounceBuffer(HIF_DEVICE *device, HIF_SCATTER_DMA_BOUNCE_INFO *pBounceInfo) { A_STATUS status = A_OK; A_UINT32 temp; SDDMA_DESCRIPTION *pDescription; pDescription = SDGET_DMA_DESCRIPTION(device->handle); do { pBounceInfo->BufferSize = MAX_SCATTER_REQ_TRANSFER_SIZE + 2*(A_GET_CACHE_LINE_BYTES()); /* allocate the bounce buffer */ pBounceInfo->pBounceBuffer = (A_UINT8 *)kmalloc(pBounceInfo->BufferSize, GFP_KERNEL | GFP_DMA | GFP_ATOMIC); if (NULL == pBounceInfo->pBounceBuffer) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,("HIF : *** unable to allocate bounce buffer \n")); status = A_NO_MEMORY; break; } temp = (A_UINT32)A_ALIGN_TO_CACHE_LINE(pBounceInfo->pBounceBuffer); /* check bounce buffer address alignment */ if ((temp & pDescription->AddressAlignment) == 0) { /* no illegal address bits */ break; } /* free the buffer we just allocated, we need to allocate a larger buffer */ FreeBounceBuffer(device, pBounceInfo); /* increase buffer size by padding it by the required alignment */ pBounceInfo->BufferSize = MAX_SCATTER_REQ_TRANSFER_SIZE + 2*(A_GET_CACHE_LINE_BYTES()) + (pDescription->AddressAlignment + 1); pBounceInfo->pBounceBuffer = (A_UINT8 *)kmalloc(pBounceInfo->BufferSize, GFP_KERNEL | GFP_DMA | GFP_ATOMIC); if (NULL == pBounceInfo->pBounceBuffer) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,("HIF : *** unable to allocate bounce buffer \n")); status = A_NO_MEMORY; break; } /* figure out required alignment */ temp = (A_UINT32)A_ALIGN_TO_CACHE_LINE(pBounceInfo->pBounceBuffer); temp += (pDescription->AddressAlignment + 1); temp &= ~pDescription->AddressAlignment; pBounceInfo->AlignmentOffset = temp - (A_UINT32)pBounceInfo->pBounceBuffer; AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("HIF : Bounce Buffer (0x%X) will apply alignment: %d \n", (A_UINT32)pBounceInfo->pBounceBuffer, pBounceInfo->AlignmentOffset)); } while (FALSE); return status; }
/* function to set up virtual scatter support if HIF layer has not implemented the interface */ static A_STATUS DevSetupVirtualScatterSupport(AR6K_DEVICE *pDev) { A_STATUS status = A_OK; int bufferSize, sgreqSize; int i; DEV_SCATTER_DMA_VIRTUAL_INFO *pVirtualInfo; HIF_SCATTER_REQ *pReq; bufferSize = sizeof(DEV_SCATTER_DMA_VIRTUAL_INFO) + 2 * (A_GET_CACHE_LINE_BYTES()) + AR6K_MAX_TRANSFER_SIZE_PER_SCATTER; sgreqSize = sizeof(HIF_SCATTER_REQ) + (AR6K_SCATTER_ENTRIES_PER_REQ - 1) * (sizeof(HIF_SCATTER_ITEM)); for (i = 0; i < AR6K_SCATTER_REQS; i++) { /* allocate the scatter request, buffer info and the actual virtual buffer itself */ pReq = (HIF_SCATTER_REQ *)A_MALLOC(sgreqSize + bufferSize); if (NULL == pReq) { status = A_NO_MEMORY; break; } A_MEMZERO(pReq, sgreqSize); /* the virtual DMA starts after the scatter request struct */ pVirtualInfo = (DEV_SCATTER_DMA_VIRTUAL_INFO *)((A_UINT8 *)pReq + sgreqSize); A_MEMZERO(pVirtualInfo, sizeof(DEV_SCATTER_DMA_VIRTUAL_INFO)); pVirtualInfo->pVirtDmaBuffer = &pVirtualInfo->DataArea[0]; /* align buffer to cache line in case host controller can actually DMA this */ pVirtualInfo->pVirtDmaBuffer = A_ALIGN_TO_CACHE_LINE(pVirtualInfo->pVirtDmaBuffer); /* store the structure in the private area */ pReq->HIFPrivate[0] = pVirtualInfo; /* we emulate a DMA bounce interface */ pReq->ScatterMethod = HIF_SCATTER_DMA_BOUNCE; pReq->pScatterBounceBuffer = pVirtualInfo->pVirtDmaBuffer; /* free request to the list */ DevFreeScatterReq((HIF_DEVICE *)pDev,pReq); } if (A_FAILED(status)) { DevCleanupVirtualScatterSupport(pDev); } else { pDev->HifScatterInfo.pAllocateReqFunc = DevAllocScatterReq; pDev->HifScatterInfo.pFreeReqFunc = DevFreeScatterReq; pDev->HifScatterInfo.pReadWriteScatterFunc = DevReadWriteScatter; if (pDev->MailBoxInfo.MboxBusIFType == MBOX_BUS_IF_SPI) { AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6K: SPI bus requires RX scatter limits\n")); pDev->HifScatterInfo.MaxScatterEntries = AR6K_MIN_SCATTER_ENTRIES_PER_REQ; pDev->HifScatterInfo.MaxTransferSizePerScatterReq = AR6K_MIN_TRANSFER_SIZE_PER_SCATTER; } else { pDev->HifScatterInfo.MaxScatterEntries = AR6K_SCATTER_ENTRIES_PER_REQ; pDev->HifScatterInfo.MaxTransferSizePerScatterReq = AR6K_MAX_TRANSFER_SIZE_PER_SCATTER; } pDev->ScatterIsVirtual = TRUE; } return status; }