M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,95 @@
#------------------------------------------------------------------------------
# ISC License (ISC)
#
# <copyright file="makefile" company="Atheros">
# Copyright (c) 2005-2010 Atheros Corporation. All rights reserved.
# Copyright (c) 2012, The Linux Foundation
# All rights reserved.
# Software was previously licensed under ISC license by Qualcomm Atheros, Inc.
#
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#
#------------------------------------------------------------------------------
#==============================================================================
# Author(s): ="Atheros"
#==============================================================================
#
#SDIO HIF makefile for atheros SDIO stack
#
# Check for SDIO stack
ifdef ATH_SDIO_STACK_BASE
# Someone already set it on entry, the stack resides outside this tree, we will try to build it
_SDIO_STACK = YES
else
# Check for SDIO stack within this tree
_SDIO_STACK = $(shell if [ -f $(ATH_SRC_BASE)/sdiostack/src/Makefile ]; then echo "YES"; else echo "NO"; fi)
ifeq ($(_SDIO_STACK), YES)
# SDIO stack is part of the kit and will need to be compiled
ATH_SDIO_STACK_BASE := $(ATH_SRC_BASE)/sdiostack
endif
endif
ifeq ($(ATH_BUS_SUBTYPE),linux_sdio)
_HIF_SUB_TYPE = linux_sdio
_SDIO_STACK = NO
else
_HIF_SUB_TYPE = linux_athsdio
endif
ifeq ($(_SDIO_STACK), YES)
# Pass and translate build variables to the SDIO stack makefile
_SDIO_STACK_MAKE_PARAMS := CT_BUILD_TYPE=$(ATH_BUILD_TYPE) \
CT_OS_TYPE=linux \
CT_OS_SUB_TYPE=$(ATH_OS_SUB_TYPE) \
CT_LINUXPATH=$(ATH_LINUXPATH) \
CT_BUILD_TYPE=$(ATH_BUILD_TYPE) \
CT_CROSS_COMPILE_TYPE=$(ATH_CROSS_COMPILE_TYPE) \
CT_ARCH_CPU_TYPE=$(ATH_ARCH_CPU_TYPE) \
CT_HC_DRIVERS=$(ATH_HC_DRIVERS) \
CT_MAKE_INCLUDE_OVERRIDE=$(_LOCALMAKE_INCLUDE) \
CT_BUILD_OUTPUT_OVERRIDE=$(COMPILED_IMAGE_OBJECTS_PATH) \
BUS_BUILD=1
endif
EXTRA_CFLAGS += -I$(ATH_SRC_BASE)/hif/sdio/$(_HIF_SUB_TYPE)/include
EXTRA_CFLAGS += -DSDIO
EXTRA_CFLAGS += -I$(ATH_SDIO_STACK_BASE)/src/include
ifeq ($(ATH_OS_SUB_TYPE),linux_2_4)
obj-y += ../../hif/sdio/linux_athsdio/src/hif.o
obj-y += ../../hif/sdio/linux_athsdio/src/hif_scatter.o
endif
ifneq ($(ATH_OS_SUB_TYPE),linux_2_4)
ar6000-objs := ../../hif/sdio/$(_HIF_SUB_TYPE)/src/hif.o \
../../hif/sdio/$(_HIF_SUB_TYPE)/src/hif_scatter.o
endif
all:
ifeq ($(_SDIO_STACK),YES)
$(MAKE) $(_SDIO_STACK_MAKE_PARAMS) -C $(ATH_SDIO_STACK_BASE)/src default
-cp -f $(ATH_SDIO_STACK_BASE)/src/Module.symvers $(COMPILED_IMAGE_OBJECTS_PATH)
endif
clean:
ifeq ($(_SDIO_STACK),YES)
$(MAKE) $(_SDIO_STACK_MAKE_PARAMS) -C $(ATH_SDIO_STACK_BASE)/src clean
endif

View File

@ -0,0 +1,147 @@
//------------------------------------------------------------------------------
// ISC License (ISC)
//
// Copyright (c) 2004-2010, The Linux Foundation
// All rights reserved.
// Software was previously licensed under ISC license by Qualcomm Atheros, Inc.
//
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
//
//------------------------------------------------------------------------------
//==============================================================================
// internal header file for hif layer
//
// Author(s): ="Atheros"
//==============================================================================
#ifndef _HIF_INTERNAL_H_
#define _HIF_INTERNAL_H_
#include <linux/version.h>
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "hif.h"
#include "../../../common/hif_sdio_common.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
#include <linux/scatterlist.h>
#define HIF_LINUX_MMC_SCATTER_SUPPORT
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
#include <asm/semaphore.h>
#else
#include <linux/semaphore.h>
#endif
#define BUS_REQUEST_MAX_NUM 64
#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000
#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20
#define FLAGS_CARD_ENAB 0x02
#define FLAGS_CARD_IRQ_UNMSK 0x04
#define HIF_MBOX_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE
#define HIF_MBOX0_BLOCK_SIZE 1
#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
struct _HIF_SCATTER_REQ_PRIV;
typedef struct bus_request {
struct bus_request *next; /* link list of available requests */
struct bus_request *inusenext; /* link list of in use requests */
struct semaphore sem_req;
A_UINT32 address; /* request data */
A_UCHAR *buffer;
A_UINT32 length;
A_UINT32 request;
void *context;
A_STATUS status;
struct _HIF_SCATTER_REQ_PRIV *pScatterReq; /* this request is a scatter request */
} BUS_REQUEST;
struct hif_device {
struct sdio_func *func;
spinlock_t asynclock;
struct task_struct* async_task; /* task to handle async commands */
struct semaphore sem_async; /* wake up for async task */
int async_shutdown; /* stop the async task */
struct completion async_completion; /* thread completion */
BUS_REQUEST *asyncreq; /* request for async tasklet */
BUS_REQUEST *taskreq; /* async tasklet data */
spinlock_t lock;
BUS_REQUEST *s_busRequestFreeQueue; /* free list */
BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM]; /* available bus requests */
void *claimedContext;
HTC_CALLBACKS htcCallbacks;
A_UINT8 *dma_buffer;
DL_LIST ScatterReqHead; /* scatter request list head */
A_BOOL scatter_enabled; /* scatter enabled flag */
A_BOOL is_suspend;
A_BOOL is_disabled;
atomic_t irqHandling;
HIF_DEVICE_POWER_CHANGE_TYPE powerConfig;
const struct sdio_device_id *id;
struct mmc_host *host;
};
#define HIF_DMA_BUFFER_SIZE (32 * 1024)
#define CMD53_FIXED_ADDRESS 1
#define CMD53_INCR_ADDRESS 2
BUS_REQUEST *hifAllocateBusRequest(HIF_DEVICE *device);
void hifFreeBusRequest(HIF_DEVICE *device, BUS_REQUEST *busrequest);
void AddToAsyncList(HIF_DEVICE *device, BUS_REQUEST *busrequest);
#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
#define MAX_SCATTER_REQUESTS 4
#define MAX_SCATTER_ENTRIES_PER_REQ 16
#define MAX_SCATTER_REQ_TRANSFER_SIZE 32*1024
typedef struct _HIF_SCATTER_REQ_PRIV {
HIF_SCATTER_REQ *pHifScatterReq; /* HIF scatter request with allocated entries */
HIF_DEVICE *device; /* this device */
BUS_REQUEST *busrequest; /* request associated with request */
/* scatter list for linux */
struct scatterlist sgentries[MAX_SCATTER_ENTRIES_PER_REQ];
} HIF_SCATTER_REQ_PRIV;
#define ATH_DEBUG_SCATTER ATH_DEBUG_MAKE_MODULE_MASK(0)
A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_INFO *pInfo);
void CleanupHIFScatterResources(HIF_DEVICE *device);
A_STATUS DoHifReadWriteScatter(HIF_DEVICE *device, BUS_REQUEST *busrequest);
#else // HIF_LINUX_MMC_SCATTER_SUPPORT
static inline A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_INFO *pInfo)
{
return A_ENOTSUP;
}
static inline A_STATUS DoHifReadWriteScatter(HIF_DEVICE *device, BUS_REQUEST *busrequest)
{
return A_ENOTSUP;
}
#define CleanupHIFScatterResources(d) { }
#endif // HIF_LINUX_MMC_SCATTER_SUPPORT
#endif // _HIF_INTERNAL_H_

View File

@ -0,0 +1,35 @@
HIF support for native Linux MMC Stack.
paull@atheros.com
11/6/09
Added patches for the MMC stacks Standard Host Controller for 2.6.30 and 2.6.32
Patches enable ENE board support and speed up transfers for any Standard Host Controller
linux2.6.30_mmc_std_host.patch
linuxMMC_std_host_2.6.32-rc5sdio.patch
2/18/2009
Added patch for Freescale MX35 SD host driver. tested with SD25 AR6102 Olca 2.1.2
12/18/2008
Tested on Freescale MX27 and OMAP3530 Beageleboard Linux ver 2.6.28
adds DMA bounce buffer support
hif.c ver 5 and hif.h ver 4 are for the old HTC/HIF interface and shouold be useable with 2.1 drivers
ver 6 and 5 are for the new HTC/HIF interface
For older Linux MMC stack versions, comment out in hif.c hifDeviceInserted() the lines:
/* give us some time to enable, in ms */
func->enable_timeout = 100;
it is only required on some platforms, eg Beagleboard.
7/18/2008
a. tested on Fedora Core 9 kernel 2.6.25.6, x86 with ENE standrad host controller,using the Olca 2.1.1RC.15
b. requires applying the linux2.6.25.6mmc.patch to the kernel drivers/mmc directory
c. through put is 20-22mbs up/down link
d. new platform type is:
ATH_PLATFORM=LOCAL_i686_NATIVEMMC-SDIO
TARGET_TYPE=AR6002
e. known issues: unloading the driver on Fedora Core 9 after conecting to an AP seems to not be complete.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,412 @@
//------------------------------------------------------------------------------
// ISC License (ISC)
//
// Copyright (c) 2009-2010, The Linux Foundation
// All rights reserved.
// Software was previously licensed under ISC license by Qualcomm Atheros, Inc.
//
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
//
//------------------------------------------------------------------------------
//==============================================================================
// HIF scatter implementation
//
// Author(s): ="Atheros"
//==============================================================================
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/kthread.h>
#include "hif_internal.h"
#define ATH_MODULE_NAME hif
#include "a_debug.h"
#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
#define _CMD53_ARG_READ 0
#define _CMD53_ARG_WRITE 1
#define _CMD53_ARG_BLOCK_BASIS 1
#define _CMD53_ARG_FIXED_ADDRESS 0
#define _CMD53_ARG_INCR_ADDRESS 1
#define SDIO_SET_CMD53_ARG(arg,rw,func,mode,opcode,address,bytes_blocks) \
(arg) = (((rw) & 1) << 31) | \
(((func) & 0x7) << 28) | \
(((mode) & 1) << 27) | \
(((opcode) & 1) << 26) | \
(((address) & 0x1FFFF) << 9) | \
((bytes_blocks) & 0x1FF)
static void FreeScatterReq(HIF_DEVICE *device, HIF_SCATTER_REQ *pReq)
{
unsigned long flag;
spin_lock_irqsave(&device->lock, flag);
DL_ListInsertTail(&device->ScatterReqHead, &pReq->ListLink);
spin_unlock_irqrestore(&device->lock, flag);
}
static HIF_SCATTER_REQ *AllocScatterReq(HIF_DEVICE *device)
{
DL_LIST *pItem;
unsigned long flag;
spin_lock_irqsave(&device->lock, flag);
pItem = DL_ListRemoveItemFromHead(&device->ScatterReqHead);
spin_unlock_irqrestore(&device->lock, flag);
if (pItem != NULL) {
return A_CONTAINING_STRUCT(pItem, HIF_SCATTER_REQ, ListLink);
}
return NULL;
}
/* called by async task to perform the operation synchronously using direct MMC APIs */
A_STATUS DoHifReadWriteScatter(HIF_DEVICE *device, BUS_REQUEST *busrequest)
{
int i;
A_UINT8 rw;
A_UINT8 opcode;
struct mmc_request mmcreq;
struct mmc_command cmd;
struct mmc_data data;
HIF_SCATTER_REQ_PRIV *pReqPriv;
HIF_SCATTER_REQ *pReq;
A_STATUS status = A_OK;
struct scatterlist *pSg;
pReqPriv = busrequest->pScatterReq;
A_ASSERT(pReqPriv != NULL);
if (pReqPriv == NULL)
return A_ERROR;
pReq = pReqPriv->pHifScatterReq;
memset(&mmcreq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command));
memset(&data, 0, sizeof(struct mmc_data));
data.blksz = HIF_MBOX_BLOCK_SIZE;
data.blocks = pReq->TotalLength / HIF_MBOX_BLOCK_SIZE;
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: (%s) Address: 0x%X, (BlockLen: %d, BlockCount: %d) , (tot:%d,sg:%d)\n",
(pReq->Request & HIF_WRITE) ? "WRITE":"READ", pReq->Address, data.blksz, data.blocks,
pReq->TotalLength,pReq->ValidScatterEntries));
if (pReq->Request & HIF_WRITE) {
rw = _CMD53_ARG_WRITE;
data.flags = MMC_DATA_WRITE;
} else {
rw = _CMD53_ARG_READ;
data.flags = MMC_DATA_READ;
}
if (pReq->Request & HIF_FIXED_ADDRESS) {
opcode = _CMD53_ARG_FIXED_ADDRESS;
} else {
opcode = _CMD53_ARG_INCR_ADDRESS;
}
/* fill SG entries */
pSg = pReqPriv->sgentries;
sg_init_table(pSg, pReq->ValidScatterEntries);
/* assemble SG list */
for (i = 0 ; i < pReq->ValidScatterEntries ; i++, pSg++) {
/* setup each sg entry */
if ((unsigned long)pReq->ScatterList[i].pBuffer & 0x3) {
/* note some scatter engines can handle unaligned buffers, print this
* as informational only */
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
("HIF: (%s) Scatter Buffer is unaligned 0x%lx\n",
pReq->Request & HIF_WRITE ? "WRITE":"READ",
(unsigned long)pReq->ScatterList[i].pBuffer));
}
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, (" %d: Addr:0x%lX, Len:%d \n",
i,(unsigned long)pReq->ScatterList[i].pBuffer,pReq->ScatterList[i].Length));
sg_set_buf(pSg, pReq->ScatterList[i].pBuffer, pReq->ScatterList[i].Length);
}
/* set scatter-gather table for request */
data.sg = pReqPriv->sgentries;
data.sg_len = pReq->ValidScatterEntries;
/* set command argument */
SDIO_SET_CMD53_ARG(cmd.arg,
rw,
device->func->num,
_CMD53_ARG_BLOCK_BASIS,
opcode,
pReq->Address,
data.blocks);
cmd.opcode = SD_IO_RW_EXTENDED;
cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
mmcreq.cmd = &cmd;
mmcreq.data = &data;
mmc_set_data_timeout(&data, device->func->card);
/* synchronous call to process request */
mmc_wait_for_req(device->func->card->host, &mmcreq);
if (cmd.error) {
status = A_ERROR;
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: cmd error: %d \n",cmd.error));
}
if (data.error) {
status = A_ERROR;
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: data error: %d \n",data.error));
}
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: FAILED!!! (%s) Address: 0x%X, Block mode (BlockLen: %d, BlockCount: %d)\n",
(pReq->Request & HIF_WRITE) ? "WRITE":"READ",pReq->Address, data.blksz, data.blocks));
}
/* set completion status, fail or success */
pReq->CompletionStatus = status;
if (pReq->Request & HIF_ASYNCHRONOUS) {
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: async_task completion routine req: 0x%lX (%d)\n",(unsigned long)busrequest, status));
/* complete the request */
A_ASSERT(pReq->CompletionRoutine != NULL);
if (pReq->CompletionRoutine == NULL)
return A_ERROR;
pReq->CompletionRoutine(pReq);
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER async_task upping busrequest : 0x%lX (%d)\n", (unsigned long)busrequest,status));
/* signal wait */
up(&busrequest->sem_req);
}
return status;
}
/* callback to issue a read-write scatter request */
static A_STATUS HifReadWriteScatter(HIF_DEVICE *device, HIF_SCATTER_REQ *pReq)
{
A_STATUS status = A_EINVAL;
A_UINT32 request = pReq->Request;
HIF_SCATTER_REQ_PRIV *pReqPriv = (HIF_SCATTER_REQ_PRIV *)pReq->HIFPrivate[0];
do {
A_ASSERT(pReqPriv != NULL);
if (pReqPriv == NULL)
return A_ERROR;
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: total len: %d Scatter Entries: %d\n",
pReq->TotalLength, pReq->ValidScatterEntries));
if (!(request & HIF_EXTENDED_IO)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("HIF-SCATTER: Invalid command type: 0x%08x\n", request));
break;
}
if (!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS))) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("HIF-SCATTER: Invalid execution mode: 0x%08x\n", request));
break;
}
if (!(request & HIF_BLOCK_BASIS)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("HIF-SCATTER: Invalid data mode: 0x%08x\n", request));
break;
}
if (pReq->TotalLength > MAX_SCATTER_REQ_TRANSFER_SIZE) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("HIF-SCATTER: Invalid length: %d \n", pReq->TotalLength));
break;
}
if (pReq->TotalLength == 0) {
A_ASSERT(FALSE);
break;
}
/* add bus request to the async list for the async I/O thread to process */
AddToAsyncList(device, pReqPriv->busrequest);
if (request & HIF_SYNCHRONOUS) {
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued sync req: 0x%lX\n", (unsigned long)pReqPriv->busrequest));
/* signal thread and wait */
up(&device->sem_async);
if (down_interruptible(&pReqPriv->busrequest->sem_req) != 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,("HIF-SCATTER: interrupted! \n"));
/* interrupted, exit */
status = A_ERROR;
break;
} else {
status = pReq->CompletionStatus;
}
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued async req: 0x%lX\n", (unsigned long)pReqPriv->busrequest));
/* wake thread, it will process and then take care of the async callback */
up(&device->sem_async);
status = A_OK;
}
} while (FALSE);
if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) {
pReq->CompletionStatus = status;
pReq->CompletionRoutine(pReq);
status = A_OK;
}
return status;
}
/* setup of HIF scatter resources */
A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_INFO *pInfo)
{
A_STATUS status = A_ERROR;
int i;
HIF_SCATTER_REQ_PRIV *pReqPriv;
BUS_REQUEST *busrequest;
do {
/* check if host supports scatter requests and it meets our requirements */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
#else
if (device->func->card->host->max_hw_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
device->func->card->host->max_hw_segs, MAX_SCATTER_ENTRIES_PER_REQ));
#endif
status = A_ENOTSUP;
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("HIF-SCATTER Enabled: max scatter req : %d entries: %d \n",
MAX_SCATTER_REQUESTS, MAX_SCATTER_ENTRIES_PER_REQ));
for (i = 0; i < MAX_SCATTER_REQUESTS; i++) {
/* allocate the private request blob */
pReqPriv = (HIF_SCATTER_REQ_PRIV *)A_MALLOC(sizeof(HIF_SCATTER_REQ_PRIV));
if (NULL == pReqPriv) {
break;
}
A_MEMZERO(pReqPriv, sizeof(HIF_SCATTER_REQ_PRIV));
/* save the device instance*/
pReqPriv->device = device;
/* allocate the scatter request */
pReqPriv->pHifScatterReq = (HIF_SCATTER_REQ *)A_MALLOC(sizeof(HIF_SCATTER_REQ) +
(MAX_SCATTER_ENTRIES_PER_REQ - 1) * (sizeof(HIF_SCATTER_ITEM)));
if (NULL == pReqPriv->pHifScatterReq) {
A_FREE(pReqPriv);
break;
}
/* just zero the main part of the scatter request */
A_MEMZERO(pReqPriv->pHifScatterReq, sizeof(HIF_SCATTER_REQ));
/* back pointer to the private struct */
pReqPriv->pHifScatterReq->HIFPrivate[0] = pReqPriv;
/* allocate a bus request for this scatter request */
busrequest = hifAllocateBusRequest(device);
if (NULL == busrequest) {
A_FREE(pReqPriv->pHifScatterReq);
A_FREE(pReqPriv);
break;
}
/* assign the scatter request to this bus request */
busrequest->pScatterReq = pReqPriv;
/* point back to the request */
pReqPriv->busrequest = busrequest;
/* add it to the scatter pool */
FreeScatterReq(device,pReqPriv->pHifScatterReq);
}
if (i != MAX_SCATTER_REQUESTS) {
status = A_NO_MEMORY;
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : failed to alloc scatter resources !\n"));
break;
}
/* set scatter function pointers */
pInfo->pAllocateReqFunc = AllocScatterReq;
pInfo->pFreeReqFunc = FreeScatterReq;
pInfo->pReadWriteScatterFunc = HifReadWriteScatter;
pInfo->MaxScatterEntries = MAX_SCATTER_ENTRIES_PER_REQ;
pInfo->MaxTransferSizePerScatterReq = MAX_SCATTER_REQ_TRANSFER_SIZE;
status = A_OK;
} while (FALSE);
if (A_FAILED(status)) {
CleanupHIFScatterResources(device);
}
return status;
}
/* clean up scatter support */
void CleanupHIFScatterResources(HIF_DEVICE *device)
{
HIF_SCATTER_REQ_PRIV *pReqPriv;
HIF_SCATTER_REQ *pReq;
/* empty the free list */
while (1) {
pReq = AllocScatterReq(device);
if (NULL == pReq) {
break;
}
pReqPriv = (HIF_SCATTER_REQ_PRIV *)pReq->HIFPrivate[0];
A_ASSERT(pReqPriv != NULL);
if (pReqPriv == NULL)
return;
if (pReqPriv->busrequest != NULL) {
pReqPriv->busrequest->pScatterReq = NULL;
/* free bus request */
hifFreeBusRequest(device, pReqPriv->busrequest);
pReqPriv->busrequest = NULL;
}
if (pReqPriv->pHifScatterReq != NULL) {
A_FREE(pReqPriv->pHifScatterReq);
pReqPriv->pHifScatterReq = NULL;
}
A_FREE(pReqPriv);
}
}
#endif // HIF_LINUX_MMC_SCATTER_SUPPORT