Initial host-common file folder cleanup and moves

Initial host-common file folder cleanup and moves
on top of baseline reference of MCL WLAN driver
SU#5.0.0.160.

Move dp, ht comm, hif, wmi and qdf folders one level up

Change-Id: I2120898024b1eafd5d651c48768dbf48bf05995d
Dieser Commit ist enthalten in:
Prakash Dhavali
2016-03-02 00:54:45 -08:00
Ursprung abcec8c47e
Commit 142cee4bf2
549 geänderte Dateien mit 0 neuen und 467753 gelöschten Zeilen

208
htc/dl_list.h Normale Datei
Datei anzeigen

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/* ============================================================================== */
/* Double-link list definitions (adapted from Atheros SDIO stack) */
/* */
/* Author(s): ="Atheros" */
/* ============================================================================== */
#ifndef __DL_LIST_H___
#define __DL_LIST_H___
#define A_CONTAINING_STRUCT(address, struct_type, field_name) \
((struct_type *)((char *)(address) - (char *)(&((struct_type *)0)->field_name)))
/* list functions */
/* pointers for the list */
typedef struct _DL_LIST {
struct _DL_LIST *pPrev;
struct _DL_LIST *pNext;
} DL_LIST, *PDL_LIST;
/*
* DL_LIST_INIT , initialize doubly linked list
*/
#define DL_LIST_INIT(pList) \
{(pList)->pPrev = pList; (pList)->pNext = pList; }
/* faster macro to init list and add a single item */
#define DL_LIST_INIT_AND_ADD(pList,pItem) \
{ (pList)->pPrev = (pItem); \
(pList)->pNext = (pItem); \
(pItem)->pNext = (pList); \
(pItem)->pPrev = (pList); \
}
#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList)))
#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext
#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev
/*
* ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member
* NOT: do not use this function if the items in the list are deleted inside the
* iteration loop
*/
#define ITERATE_OVER_LIST(pStart, pTemp) \
for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext)
static __inline bool dl_list_is_entry_in_list(const DL_LIST *pList,
const DL_LIST *pEntry)
{
const DL_LIST *pTmp;
if (pList == pEntry)
return true;
ITERATE_OVER_LIST(pList, pTmp) {
if (pTmp == pEntry) {
return true;
}
}
return false;
}
/* safe iterate macro that allows the item to be removed from the list
* the iteration continues to the next item in the list
*/
#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \
{ \
PDL_LIST pTemp; \
pTemp = (pStart)->pNext; \
while (pTemp != (pStart)) { \
(pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \
pTemp = pTemp->pNext; \
#define ITERATE_IS_VALID(pStart) dl_list_is_entry_in_list(pStart, pTemp)
#define ITERATE_RESET(pStart) pTemp=(pStart)->pNext
#define ITERATE_END }}
/*
* dl_list_insert_tail - insert pAdd to the end of the list
*/
static __inline PDL_LIST dl_list_insert_tail(PDL_LIST pList, PDL_LIST pAdd)
{
/* insert at tail */
pAdd->pPrev = pList->pPrev;
pAdd->pNext = pList;
if (pList->pPrev) {
pList->pPrev->pNext = pAdd;
}
pList->pPrev = pAdd;
return pAdd;
}
/*
* dl_list_insert_head - insert pAdd into the head of the list
*/
static __inline PDL_LIST dl_list_insert_head(PDL_LIST pList, PDL_LIST pAdd)
{
/* insert at head */
pAdd->pPrev = pList;
pAdd->pNext = pList->pNext;
pList->pNext->pPrev = pAdd;
pList->pNext = pAdd;
return pAdd;
}
#define DL_ListAdd(pList,pItem) dl_list_insert_head((pList),(pItem))
/*
* dl_list_remove - remove pDel from list
*/
static __inline PDL_LIST dl_list_remove(PDL_LIST pDel)
{
if (pDel->pNext != NULL) {
pDel->pNext->pPrev = pDel->pPrev;
}
if (pDel->pPrev != NULL) {
pDel->pPrev->pNext = pDel->pNext;
}
/* point back to itself just to be safe, incase remove is called again */
pDel->pNext = pDel;
pDel->pPrev = pDel;
return pDel;
}
/*
* dl_list_remove_item_from_head - get a list item from the head
*/
static __inline PDL_LIST dl_list_remove_item_from_head(PDL_LIST pList)
{
PDL_LIST pItem = NULL;
if (pList->pNext != pList) {
pItem = pList->pNext;
/* remove the first item from head */
dl_list_remove(pItem);
}
return pItem;
}
static __inline PDL_LIST dl_list_remove_item_from_tail(PDL_LIST pList)
{
PDL_LIST pItem = NULL;
if (pList->pPrev != pList) {
pItem = pList->pPrev;
/* remove the item from tail */
dl_list_remove(pItem);
}
return pItem;
}
/* transfer src list items to the tail of the destination list */
static __inline void dl_list_transfer_items_to_tail(PDL_LIST pDest, PDL_LIST pSrc)
{
/* only concatenate if src is not empty */
if (!DL_LIST_IS_EMPTY(pSrc)) {
/* cut out circular list in src and re-attach to end of dest */
pSrc->pPrev->pNext = pDest;
pSrc->pNext->pPrev = pDest->pPrev;
pDest->pPrev->pNext = pSrc->pNext;
pDest->pPrev = pSrc->pPrev;
/* terminate src list, it is now empty */
pSrc->pPrev = pSrc;
pSrc->pNext = pSrc;
}
}
/* transfer src list items to the head of the destination list */
static __inline void dl_list_transfer_items_to_head(PDL_LIST pDest, PDL_LIST pSrc)
{
/* only concatenate if src is not empty */
if (!DL_LIST_IS_EMPTY(pSrc)) {
/* cut out circular list in src and re-attach to start of dest */
pSrc->pNext->pPrev = pDest;
pDest->pNext->pPrev = pSrc->pPrev;
pSrc->pPrev->pNext = pDest->pNext;
pDest->pNext = pSrc->pNext;
/* terminate src list, it is now empty */
pSrc->pPrev = pSrc;
pSrc->pNext = pSrc;
}
}
#endif /* __DL_LIST_H___ */

881
htc/htc.c Normale Datei
Datei anzeigen

@@ -0,0 +1,881 @@
/*
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include "ol_if_athvar.h"
#include "htc_debug.h"
#include "htc_internal.h"
#include <cdf_nbuf.h> /* cdf_nbuf_t */
#include <cdf_types.h> /* cdf_print */
#include <hif.h>
#include "epping_main.h"
#include "hif_io32.h"
#include "cds_concurrency.h"
#include <cds_api.h>
#ifdef DEBUG
static ATH_DEBUG_MASK_DESCRIPTION g_htc_debug_description[] = {
{ATH_DEBUG_SEND, "Send"},
{ATH_DEBUG_RECV, "Recv"},
{ATH_DEBUG_SYNC, "Sync"},
{ATH_DEBUG_DUMP, "Dump Data (RX or TX)"},
{ATH_DEBUG_SETUP, "Setup"},
};
ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc,
"htc",
"Host Target Communications",
ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO |
ATH_DEBUG_SETUP,
ATH_DEBUG_DESCRIPTION_COUNT
(g_htc_debug_description),
g_htc_debug_description);
#endif
extern unsigned int htc_credit_flow;
static void reset_endpoint_states(HTC_TARGET *target);
static void destroy_htc_tx_ctrl_packet(HTC_PACKET *pPacket)
{
cdf_nbuf_t netbuf;
netbuf = (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("free ctrl netbuf :0x%p \n", netbuf));
if (netbuf != NULL) {
cdf_nbuf_free(netbuf);
}
cdf_mem_free(pPacket);
}
static HTC_PACKET *build_htc_tx_ctrl_packet(cdf_device_t osdev)
{
HTC_PACKET *pPacket = NULL;
cdf_nbuf_t netbuf;
do {
pPacket = (HTC_PACKET *) cdf_mem_malloc(sizeof(HTC_PACKET));
if (NULL == pPacket) {
break;
}
A_MEMZERO(pPacket, sizeof(HTC_PACKET));
netbuf =
cdf_nbuf_alloc(osdev, HTC_CONTROL_BUFFER_SIZE, 20, 4, true);
if (NULL == netbuf) {
cdf_mem_free(pPacket);
pPacket = NULL;
cdf_print("%s: nbuf alloc failed\n", __func__);
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("alloc ctrl netbuf :0x%p \n", netbuf));
SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf);
} while (false);
return pPacket;
}
void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
{
#ifdef TODO_FIXME
LOCK_HTC(target);
HTC_PACKET_ENQUEUE(&target->ControlBufferTXFreeList, pPacket);
UNLOCK_HTC(target);
/* TODO_FIXME netbufs cannot be RESET! */
#else
destroy_htc_tx_ctrl_packet(pPacket);
#endif
}
HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target)
{
#ifdef TODO_FIXME
HTC_PACKET *pPacket;
LOCK_HTC(target);
pPacket = htc_packet_dequeue(&target->ControlBufferTXFreeList);
UNLOCK_HTC(target);
return pPacket;
#else
return build_htc_tx_ctrl_packet(target->osdev);
#endif
}
/* Set the target failure handling callback */
void htc_set_target_failure_callback(HTC_HANDLE HTCHandle,
HTC_TARGET_FAILURE Callback)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
target->HTCInitInfo.TargetFailure = Callback;
}
void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
hif_dump(target->hif_dev, CmdId, start);
}
/* cleanup the HTC instance */
static void htc_cleanup(HTC_TARGET *target)
{
HTC_PACKET *pPacket;
/* cdf_nbuf_t netbuf; */
if (target->hif_dev != NULL) {
hif_detach_htc(target->hif_dev);
target->hif_dev = NULL;
}
while (true) {
pPacket = allocate_htc_packet_container(target);
if (NULL == pPacket) {
break;
}
cdf_mem_free(pPacket);
}
pPacket = target->pBundleFreeList;
while (pPacket) {
HTC_PACKET *pPacketTmp = (HTC_PACKET *) pPacket->ListLink.pNext;
cdf_mem_free(pPacket);
pPacket = pPacketTmp;
}
#ifdef TODO_FIXME
while (true) {
pPacket = htc_alloc_control_tx_packet(target);
if (NULL == pPacket) {
break;
}
netbuf = (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
if (netbuf != NULL) {
cdf_nbuf_free(netbuf);
}
cdf_mem_free(pPacket);
}
#endif
cdf_spinlock_destroy(&target->HTCLock);
cdf_spinlock_destroy(&target->HTCRxLock);
cdf_spinlock_destroy(&target->HTCTxLock);
cdf_spinlock_destroy(&target->HTCCreditLock);
/* free our instance */
cdf_mem_free(target);
}
/* registered target arrival callback from the HIF layer */
HTC_HANDLE htc_create(void *ol_sc, HTC_INIT_INFO *pInfo, cdf_device_t osdev)
{
struct hif_msg_callbacks htcCallbacks;
HTC_ENDPOINT *pEndpoint = NULL;
HTC_TARGET *target = NULL;
int i;
if (ol_sc == NULL) {
HTC_ERROR("%s: ol_sc = NULL", __func__);
return NULL;
}
HTC_TRACE("+htc_create .. HIF :%p", ol_sc);
A_REGISTER_MODULE_DEBUG_INFO(htc);
target = (HTC_TARGET *) cdf_mem_malloc(sizeof(HTC_TARGET));
if (target == NULL) {
HTC_ERROR("%s: Unable to allocate memory", __func__);
return NULL;
}
A_MEMZERO(target, sizeof(HTC_TARGET));
htc_runtime_pm_init(target);
cdf_spinlock_init(&target->HTCLock);
cdf_spinlock_init(&target->HTCRxLock);
cdf_spinlock_init(&target->HTCTxLock);
cdf_spinlock_init(&target->HTCCreditLock);
do {
A_MEMCPY(&target->HTCInitInfo, pInfo, sizeof(HTC_INIT_INFO));
target->host_handle = pInfo->pContext;
target->osdev = osdev;
reset_endpoint_states(target);
INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) {
HTC_PACKET *pPacket =
(HTC_PACKET *) cdf_mem_malloc(sizeof(HTC_PACKET));
if (pPacket != NULL) {
A_MEMZERO(pPacket, sizeof(HTC_PACKET));
free_htc_packet_container(target, pPacket);
}
}
#ifdef TODO_FIXME
for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) {
pPacket = build_htc_tx_ctrl_packet();
if (NULL == pPacket) {
break;
}
htc_free_control_tx_packet(target, pPacket);
}
#endif
/* setup HIF layer callbacks */
cdf_mem_zero(&htcCallbacks, sizeof(struct hif_msg_callbacks));
htcCallbacks.Context = target;
htcCallbacks.rxCompletionHandler = htc_rx_completion_handler;
htcCallbacks.txCompletionHandler = htc_tx_completion_handler;
htcCallbacks.txResourceAvailHandler = htc_tx_resource_avail_handler;
htcCallbacks.fwEventHandler = htc_fw_event_handler;
target->hif_dev = ol_sc;
/* Get HIF default pipe for HTC message exchange */
pEndpoint = &target->endpoint[ENDPOINT_0];
hif_post_init(target->hif_dev, target, &htcCallbacks);
hif_get_default_pipe(target->hif_dev, &pEndpoint->UL_PipeID,
&pEndpoint->DL_PipeID);
} while (false);
htc_recv_init(target);
HTC_TRACE("-htc_create: (0x%p)", target);
return (HTC_HANDLE) target;
}
void htc_destroy(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("+htc_destroy .. Destroying :0x%p\n", target));
hif_stop(htc_get_hif_device(HTCHandle));
if (target)
htc_cleanup(target);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_destroy\n"));
}
/* get the low level HIF device for the caller , the caller may wish to do low level
* HIF requests */
void *htc_get_hif_device(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
return target->hif_dev;
}
void htc_control_tx_complete(void *Context, HTC_PACKET *pPacket)
{
HTC_TARGET *target = (HTC_TARGET *) Context;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("+-htc_control_tx_complete 0x%p (l:%d) \n", pPacket,
pPacket->ActualLength));
htc_free_control_tx_packet(target, pPacket);
}
/* TODO, this is just a temporary max packet size */
#define MAX_MESSAGE_SIZE 1536
/**
* htc_setup_target_buffer_assignments() - setup target buffer assignments
* @target: HTC Target Pointer
*
* Return: A_STATUS
*/
A_STATUS htc_setup_target_buffer_assignments(HTC_TARGET *target)
{
HTC_SERVICE_TX_CREDIT_ALLOCATION *pEntry;
A_STATUS status;
int credits;
int creditsPerMaxMsg;
creditsPerMaxMsg = MAX_MESSAGE_SIZE / target->TargetCreditSize;
if (MAX_MESSAGE_SIZE % target->TargetCreditSize) {
creditsPerMaxMsg++;
}
/* TODO, this should be configured by the caller! */
credits = target->TotalTransmitCredits;
pEntry = &target->ServiceTxAllocTable[0];
/*
* Allocate all credists/HTC buffers to WMI.
* no buffers are used/required for data. data always
* remains on host.
*/
status = A_OK;
pEntry++;
pEntry->service_id = WMI_CONTROL_SVC;
pEntry->CreditAllocation = credits;
if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
/* endpoint ping is a testing tool directly on top of HTC in
* both target and host sides.
* In target side, the endppint ping fw has no wlan stack and the
* FW mboxping app directly sits on HTC and it simply drops
* or loops back TX packets. For rx perf, FW mboxping app
* generates packets and passes packets to HTC to send to host.
* There is no WMI mesage exchanges between host and target
* in endpoint ping case.
* In host side, the endpoint ping driver is a Ethernet driver
* and it directly sits on HTC. Only HIF, HTC, CDF, ADF are
* used by the endpoint ping driver. There is no wifi stack
* at all in host side also. For tx perf use case,
* the user space mboxping app sends the raw packets to endpoint
* ping driver and it directly forwards to HTC for transmission
* to stress the bus. For the rx perf, HTC passes the received
* packets to endpoint ping driver and it is passed to the user
* space through the Ethernet interface.
* For credit allocation, in SDIO bus case, only BE service is
* used for tx/rx perf testing so that all credits are given
* to BE service. In PCIe and USB bus case, endpoint ping uses both
* BE and BK services to stress the bus so that the total credits
* are equally distributed to BE and BK services.
*/
pEntry->service_id = WMI_DATA_BE_SVC;
pEntry->CreditAllocation = (credits >> 1);
pEntry++;
pEntry->service_id = WMI_DATA_BK_SVC;
pEntry->CreditAllocation = (credits >> 1);
}
if (A_SUCCESS(status)) {
int i;
for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
if (target->ServiceTxAllocTable[i].service_id != 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("HTC Service Index : %d TX : 0x%2.2X : alloc:%d\n",
i,
target->ServiceTxAllocTable[i].
service_id,
target->ServiceTxAllocTable[i].
CreditAllocation));
}
}
}
return status;
}
A_UINT8 htc_get_credit_allocation(HTC_TARGET *target, A_UINT16 service_id)
{
A_UINT8 allocation = 0;
int i;
for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
if (target->ServiceTxAllocTable[i].service_id == service_id) {
allocation =
target->ServiceTxAllocTable[i].CreditAllocation;
}
}
if (0 == allocation) {
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("HTC Service TX : 0x%2.2X : allocation is zero!\n",
service_id));
}
return allocation;
}
A_STATUS htc_wait_target(HTC_HANDLE HTCHandle)
{
A_STATUS status = A_OK;
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_READY_EX_MSG *pReadyMsg;
HTC_SERVICE_CONNECT_REQ connect;
HTC_SERVICE_CONNECT_RESP resp;
HTC_READY_MSG *rdy_msg;
A_UINT16 htc_rdy_msg_id;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("htc_wait_target - Enter (target:0x%p) \n", HTCHandle));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("+HWT\n"));
do {
status = hif_start(target->hif_dev);
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("hif_start failed\n"));
break;
}
status = htc_wait_recv_ctrl_message(target);
if (A_FAILED(status)) {
break;
}
if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Invalid HTC Ready Msg Len:%d! \n",
target->CtrlResponseLength));
status = A_ECOMM;
break;
}
pReadyMsg = (HTC_READY_EX_MSG *) target->CtrlResponseBuffer;
rdy_msg = &pReadyMsg->Version2_0_Info;
htc_rdy_msg_id =
HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID);
if (htc_rdy_msg_id != HTC_MSG_READY_ID) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Invalid HTC Ready Msg : 0x%X ! \n",
htc_rdy_msg_id));
status = A_ECOMM;
break;
}
target->TotalTransmitCredits =
HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITCOUNT);
target->TargetCreditSize =
(int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE);
target->MaxMsgsPerHTCBundle =
(A_UINT8) pReadyMsg->MaxMsgsPerHTCBundle;
/* for old fw this value is set to 0. But the minimum value should be 1,
* i.e., no bundling */
if (target->MaxMsgsPerHTCBundle < 1)
target->MaxMsgsPerHTCBundle = 1;
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("Target Ready! : transmit resources : %d size:%d, MaxMsgsPerHTCBundle = %d\n",
target->TotalTransmitCredits,
target->TargetCreditSize,
target->MaxMsgsPerHTCBundle));
if ((0 == target->TotalTransmitCredits)
|| (0 == target->TargetCreditSize)) {
status = A_ECOMM;
break;
}
/* done processing */
target->CtrlResponseProcessing = false;
htc_setup_target_buffer_assignments(target);
/* setup our pseudo HTC control endpoint connection */
A_MEMZERO(&connect, sizeof(connect));
A_MEMZERO(&resp, sizeof(resp));
connect.EpCallbacks.pContext = target;
connect.EpCallbacks.EpTxComplete = htc_control_tx_complete;
connect.EpCallbacks.EpRecv = htc_control_rx_complete;
connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS;
connect.service_id = HTC_CTRL_RSVD_SVC;
/* connect fake service */
status = htc_connect_service((HTC_HANDLE) target,
&connect, &resp);
} while (false);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Exit (%d)\n", status));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("-HWT\n"));
return status;
}
/* start HTC, this is called after all services are connected */
static A_STATUS htc_config_target_hif_pipe(HTC_TARGET *target)
{
return A_OK;
}
static void reset_endpoint_states(HTC_TARGET *target)
{
HTC_ENDPOINT *pEndpoint;
int i;
for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
pEndpoint = &target->endpoint[i];
pEndpoint->service_id = 0;
pEndpoint->MaxMsgLength = 0;
pEndpoint->MaxTxQueueDepth = 0;
pEndpoint->Id = i;
INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
INIT_HTC_PACKET_QUEUE(&pEndpoint->TxLookupQueue);
INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBufferHoldQueue);
pEndpoint->target = target;
/* pEndpoint->TxCreditFlowEnabled = (A_BOOL)htc_credit_flow; */
pEndpoint->TxCreditFlowEnabled = (A_BOOL) 1;
cdf_atomic_init(&pEndpoint->TxProcessCount);
}
}
A_STATUS htc_start(HTC_HANDLE HTCHandle)
{
cdf_nbuf_t netbuf;
A_STATUS status = A_OK;
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_SETUP_COMPLETE_EX_MSG *pSetupComp;
HTC_PACKET *pSendPacket;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Enter\n"));
do {
htc_config_target_hif_pipe(target);
/* allocate a buffer to send */
pSendPacket = htc_alloc_control_tx_packet(target);
if (NULL == pSendPacket) {
AR_DEBUG_ASSERT(false);
cdf_print("%s: allocControlTxPacket failed\n",
__func__);
status = A_NO_MEMORY;
break;
}
netbuf =
(cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
/* assemble setup complete message */
cdf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_EX_MSG));
pSetupComp =
(HTC_SETUP_COMPLETE_EX_MSG *) cdf_nbuf_data(netbuf);
A_MEMZERO(pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG));
HTC_SET_FIELD(pSetupComp, HTC_SETUP_COMPLETE_EX_MSG,
MESSAGEID, HTC_MSG_SETUP_COMPLETE_EX_ID);
if (!htc_credit_flow) {
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("HTC will not use TX credit flow control\n"));
pSetupComp->SetupFlags |=
HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW;
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("HTC using TX credit flow control\n"));
}
#ifdef HIF_SDIO
#if ENABLE_BUNDLE_RX
if (HTC_ENABLE_BUNDLE(target))
pSetupComp->SetupFlags |=
HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV;
#endif /* ENABLE_BUNDLE_RX */
#endif /* HIF_SDIO */
SET_HTC_PACKET_INFO_TX(pSendPacket,
NULL,
(A_UINT8 *) pSetupComp,
sizeof(HTC_SETUP_COMPLETE_EX_MSG),
ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
if (A_FAILED(status)) {
break;
}
} while (false);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Exit\n"));
return status;
}
/*flush all queued buffers for surpriseremove case*/
void htc_flush_surprise_remove(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
int i;
HTC_ENDPOINT *pEndpoint;
#ifdef RX_SG_SUPPORT
cdf_nbuf_t netbuf;
cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_flush_surprise_remove \n"));
/* cleanup endpoints */
for (i = 0; i < ENDPOINT_MAX; i++) {
pEndpoint = &target->endpoint[i];
htc_flush_rx_hold_queue(target, pEndpoint);
htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL);
}
hif_flush_surprise_remove(target->hif_dev);
#ifdef RX_SG_SUPPORT
LOCK_HTC_RX(target);
while ((netbuf = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) {
cdf_nbuf_free(netbuf);
}
RESET_RX_SG_CONFIG(target);
UNLOCK_HTC_RX(target);
#endif
reset_endpoint_states(target);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_flush_surprise_remove \n"));
}
/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
void htc_stop(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
int i;
HTC_ENDPOINT *pEndpoint;
#ifdef RX_SG_SUPPORT
cdf_nbuf_t netbuf;
cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_stop \n"));
/* cleanup endpoints */
for (i = 0; i < ENDPOINT_MAX; i++) {
pEndpoint = &target->endpoint[i];
htc_flush_rx_hold_queue(target, pEndpoint);
htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL);
if (pEndpoint->ul_is_polled) {
cdf_softirq_timer_cancel(&pEndpoint->ul_poll_timer);
cdf_softirq_timer_free(&pEndpoint->ul_poll_timer);
}
}
/* Note: htc_flush_endpoint_tx for all endpoints should be called before
* hif_stop - otherwise htc_tx_completion_handler called from
* hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer,
* might queue the packet again to HIF Layer - which could cause tx
* buffer leak
*/
hif_stop(target->hif_dev);
#ifdef RX_SG_SUPPORT
LOCK_HTC_RX(target);
while ((netbuf = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) {
cdf_nbuf_free(netbuf);
}
RESET_RX_SG_CONFIG(target);
UNLOCK_HTC_RX(target);
#endif
reset_endpoint_states(target);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop\n"));
}
/**
* htc_runtime_pm_init(): runtime pm related intialization
*
* need to initialize a work item.
*/
void htc_runtime_pm_init(HTC_TARGET *target)
{
cdf_create_work(&target->queue_kicker, htc_kick_queues, target);
}
/**
* htc_runtime_suspend(): ensure htc is ready to suspend
*
* htc is ready to suspend if there are no pending pactets
* in the txrx queues.
*
* Return: 0 on success or -EBUSY if there are queued packets.
*/
int htc_runtime_suspend(void)
{
ol_txrx_pdev_handle txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX);
if (txrx_pdev == NULL) {
HTC_ERROR("%s: txrx context null", __func__);
return CDF_STATUS_E_FAULT;
}
if (ol_txrx_get_tx_pending(txrx_pdev))
return -EBUSY;
else
return 0;
}
/**
* htc_runtime_resume(): resume htc
*
* The htc message queue needs to be kicked off after
* a runtime resume. Otherwise messages would get stuck.
*
* Return: 0 for success;
*/
int htc_runtime_resume(void)
{
HTC_HANDLE htc_ctx = cds_get_context(CDF_MODULE_ID_HTC);
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_ctx);
if (target == NULL)
return 0;
cdf_schedule_work(&target->queue_kicker);
return 0;
}
void htc_dump_credit_states(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint;
int i;
for (i = 0; i < ENDPOINT_MAX; i++) {
pEndpoint = &target->endpoint[i];
if (0 == pEndpoint->service_id)
continue;
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
("--- EP : %d service_id: 0x%X --------------\n",
pEndpoint->Id, pEndpoint->service_id));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
(" TxCredits : %d\n",
pEndpoint->TxCredits));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
(" TxCreditSize : %d\n",
pEndpoint->TxCreditSize));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
(" TxCreditsPerMaxMsg : %d\n",
pEndpoint->TxCreditsPerMaxMsg));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
(" TxQueueDepth : %d\n",
HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
("----------------------------------------------------\n"));
}
}
A_BOOL htc_get_endpoint_statistics(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint,
HTC_ENDPOINT_STAT_ACTION Action,
HTC_ENDPOINT_STATS *pStats)
{
#ifdef HTC_EP_STAT_PROFILING
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
A_BOOL clearStats = false;
A_BOOL sample = false;
switch (Action) {
case HTC_EP_STAT_SAMPLE:
sample = true;
break;
case HTC_EP_STAT_SAMPLE_AND_CLEAR:
sample = true;
clearStats = true;
break;
case HTC_EP_STAT_CLEAR:
clearStats = true;
break;
default:
break;
}
A_ASSERT(Endpoint < ENDPOINT_MAX);
/* lock out TX and RX while we sample and/or clear */
LOCK_HTC_TX(target);
LOCK_HTC_RX(target);
if (sample) {
A_ASSERT(pStats != NULL);
/* return the stats to the caller */
A_MEMCPY(pStats, &target->endpoint[Endpoint].endpoint_stats,
sizeof(HTC_ENDPOINT_STATS));
}
if (clearStats) {
/* reset stats */
A_MEMZERO(&target->endpoint[Endpoint].endpoint_stats,
sizeof(HTC_ENDPOINT_STATS));
}
UNLOCK_HTC_RX(target);
UNLOCK_HTC_TX(target);
return true;
#else
return false;
#endif
}
void *htc_get_targetdef(HTC_HANDLE htc_handle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
return hif_get_targetdef(target->hif_dev);
}
/**
* htc_set_target_to_sleep() - set target to sleep
* @context: ol_softc context
*
* Return: none
*/
void htc_set_target_to_sleep(void *context)
{
struct ol_softc *scn = (struct ol_softc *)context;
hif_set_target_sleep(scn, true, false);
}
/**
* htc_cancel_deferred_target_sleep() - cancel deferred target sleep
* @context: ol_softc context
*
* Return: none
*/
void htc_cancel_deferred_target_sleep(void *context)
{
struct ol_softc *scn = (struct ol_softc *)context;
hif_cancel_deferred_target_sleep(scn);
}
#ifdef IPA_OFFLOAD
/**
* htc_ipa_get_ce_resource() - get uc resource on lower layer
* @htc_handle: htc context
* @ce_sr_base_paddr: copyengine source ring base physical address
* @ce_sr_ring_size: copyengine source ring size
* @ce_reg_paddr: copyengine register physical address
*
* Return: None
*/
void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle,
cdf_dma_addr_t *ce_sr_base_paddr,
uint32_t *ce_sr_ring_size,
cdf_dma_addr_t *ce_reg_paddr)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
if (target->hif_dev != NULL) {
hif_ipa_get_ce_resource(target->hif_dev,
ce_sr_base_paddr,
ce_sr_ring_size, ce_reg_paddr);
}
}
#endif /* IPA_OFFLOAD */

718
htc/htc_api.h Normale Datei
Datei anzeigen

@@ -0,0 +1,718 @@
/*
* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef _HTC_API_H_
#define _HTC_API_H_
#include <athdefs.h>
#include "osapi_linux.h"
#include "htc_packet.h"
#include <htc.h>
#include <htc_services.h>
#include <cdf_types.h> /* cdf_device_t */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* TODO.. for BMI */
#define ENDPOINT1 0
/* TODO -remove me, but we have to fix BMI first */
#define HTC_MAILBOX_NUM_MAX 4
/* this is the amount of header room required by users of HTC */
#define HTC_HEADER_LEN HTC_HDR_LENGTH
typedef void *HTC_HANDLE;
typedef A_UINT16 HTC_SERVICE_ID;
typedef void (*HTC_TARGET_FAILURE)(void *Instance, CDF_STATUS Status);
typedef struct _HTC_INIT_INFO {
void *pContext; /* context for target notifications */
void (*TargetFailure)(void *Instance, CDF_STATUS Status);
void (*TargetSendSuspendComplete)(void *ctx);
} HTC_INIT_INFO;
/* Struct for HTC layer packet stats*/
struct ol_ath_htc_stats {
int htc_get_pkt_q_fail_count;
int htc_pkt_q_empty_count;
int htc_send_q_empty_count;
};
/* To resume HTT Tx queue during runtime resume */
typedef void (*HTC_EP_RESUME_TX_QUEUE)(void *);
/* per service connection send completion */
typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *, HTC_PACKET *);
/* per service connection callback when a plurality of packets have been sent
* The HTC_PACKET_QUEUE is a temporary queue object (e.g. freed on return from the callback)
* to hold a list of completed send packets.
* If the handler cannot fully traverse the packet queue before returning, it should
* transfer the items of the queue into the caller's private queue using:
* HTC_PACKET_ENQUEUE() */
typedef void (*HTC_EP_SEND_PKT_COMP_MULTIPLE)(void *,
HTC_PACKET_QUEUE *);
/* per service connection pkt received */
typedef void (*HTC_EP_RECV_PKT)(void *, HTC_PACKET *);
/* per service connection callback when a plurality of packets are received
* The HTC_PACKET_QUEUE is a temporary queue object (e.g. freed on return from the callback)
* to hold a list of recv packets.
* If the handler cannot fully traverse the packet queue before returning, it should
* transfer the items of the queue into the caller's private queue using:
* HTC_PACKET_ENQUEUE() */
typedef void (*HTC_EP_RECV_PKT_MULTIPLE)(void *, HTC_PACKET_QUEUE *);
/* Optional per service connection receive buffer re-fill callback,
* On some OSes (like Linux) packets are allocated from a global pool and indicated up
* to the network stack. The driver never gets the packets back from the OS. For these OSes
* a refill callback can be used to allocate and re-queue buffers into HTC.
*
* On other OSes, the network stack can call into the driver's OS-specifc "return_packet" handler and
* the driver can re-queue these buffers into HTC. In this regard a refill callback is
* unnecessary */
typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint);
/* Optional per service connection receive buffer allocation callback.
* On some systems packet buffers are an extremely limited resource. Rather than
* queue largest-possible-sized buffers to HTC, some systems would rather
* allocate a specific size as the packet is received. The trade off is
* slightly more processing (callback invoked for each RX packet)
* for the benefit of committing fewer buffer resources into HTC.
*
* The callback is provided the length of the pending packet to fetch. This includes the
* HTC header length plus the length of payload. The callback can return a pointer to
* the allocated HTC packet for immediate use.
*
* Alternatively a variant of this handler can be used to allocate large receive packets as needed.
* For example an application can use the refill mechanism for normal packets and the recv-alloc mechanism to
* handle the case where a large packet buffer is required. This can significantly reduce the
* amount of "committed" memory used to receive packets.
*
* */
typedef HTC_PACKET *(*HTC_EP_RECV_ALLOC)(void *,
HTC_ENDPOINT_ID Endpoint,
int Length);
typedef enum _HTC_SEND_FULL_ACTION {
HTC_SEND_FULL_KEEP = 0, /* packet that overflowed should be kept in the queue */
HTC_SEND_FULL_DROP = 1, /* packet that overflowed should be dropped */
} HTC_SEND_FULL_ACTION;
/* Optional per service connection callback when a send queue is full. This can occur if the
* host continues queueing up TX packets faster than credits can arrive
* To prevent the host (on some Oses like Linux) from continuously queueing packets
* and consuming resources, this callback is provided so that that the host
* can disable TX in the subsystem (i.e. network stack).
* This callback is invoked for each packet that "overflows" the HTC queue. The callback can
* determine whether the new packet that overflowed the queue can be kept (HTC_SEND_FULL_KEEP) or
* dropped (HTC_SEND_FULL_DROP). If a packet is dropped, the EpTxComplete handler will be called
* and the packet's status field will be set to A_NO_RESOURCE.
* Other OSes require a "per-packet" indication for each completed TX packet, this
* closed loop mechanism will prevent the network stack from overunning the NIC
* The packet to keep or drop is passed for inspection to the registered handler the handler
* must ONLY inspect the packet, it may not free or reclaim the packet. */
typedef HTC_SEND_FULL_ACTION (*HTC_EP_SEND_QUEUE_FULL)(void *,
HTC_PACKET *
pPacket);
typedef struct _HTC_EP_CALLBACKS {
void *pContext; /* context for each callback */
HTC_EP_SEND_PKT_COMPLETE EpTxComplete; /* tx completion callback for connected endpoint */
HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */
HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */
HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */
HTC_EP_RECV_ALLOC EpRecvAlloc; /* OPTIONAL recv allocation callback */
HTC_EP_RECV_ALLOC EpRecvAllocThresh; /* OPTIONAL recv allocation callback based on a threshold */
HTC_EP_SEND_PKT_COMP_MULTIPLE EpTxCompleteMultiple; /* OPTIONAL completion handler for multiple complete
indications (EpTxComplete must be NULL) */
HTC_EP_RECV_PKT_MULTIPLE EpRecvPktMultiple; /* OPTIONAL completion handler for multiple
recv packet indications (EpRecv must be NULL) */
HTC_EP_RESUME_TX_QUEUE ep_resume_tx_queue;
int RecvAllocThreshold; /* if EpRecvAllocThresh is non-NULL, HTC will compare the
threshold value to the current recv packet length and invoke
the EpRecvAllocThresh callback to acquire a packet buffer */
int RecvRefillWaterMark; /* if a EpRecvRefill handler is provided, this value
can be used to set a trigger refill callback
when the recv queue drops below this value
if set to 0, the refill is only called when packets
are empty */
} HTC_EP_CALLBACKS;
/* service connection information */
typedef struct _HTC_SERVICE_CONNECT_REQ {
HTC_SERVICE_ID service_id; /* service ID to connect to */
A_UINT16 ConnectionFlags; /* connection flags, see htc protocol definition */
A_UINT8 *pMetaData; /* ptr to optional service-specific meta-data */
A_UINT8 MetaDataLength; /* optional meta data length */
HTC_EP_CALLBACKS EpCallbacks; /* endpoint callbacks */
int MaxSendQueueDepth; /* maximum depth of any send queue */
A_UINT32 LocalConnectionFlags; /* HTC flags for the host-side (local) connection */
unsigned int MaxSendMsgSize; /* override max message size in send direction */
} HTC_SERVICE_CONNECT_REQ;
#define HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING (1 << 0) /* enable send bundle padding for this endpoint */
/* service connection response information */
typedef struct _HTC_SERVICE_CONNECT_RESP {
A_UINT8 *pMetaData; /* caller supplied buffer to optional meta-data */
A_UINT8 BufferLength; /* length of caller supplied buffer */
A_UINT8 ActualLength; /* actual length of meta data */
HTC_ENDPOINT_ID Endpoint; /* endpoint to communicate over */
unsigned int MaxMsgLength; /* max length of all messages over this endpoint */
A_UINT8 ConnectRespCode; /* connect response code from target */
} HTC_SERVICE_CONNECT_RESP;
/* endpoint distribution structure */
typedef struct _HTC_ENDPOINT_CREDIT_DIST {
struct _HTC_ENDPOINT_CREDIT_DIST *pNext;
struct _HTC_ENDPOINT_CREDIT_DIST *pPrev;
HTC_SERVICE_ID service_id; /* Service ID (set by HTC) */
HTC_ENDPOINT_ID Endpoint; /* endpoint for this distribution struct (set by HTC) */
A_UINT32 DistFlags; /* distribution flags, distribution function can
set default activity using SET_EP_ACTIVE() macro */
int TxCreditsNorm; /* credits for normal operation, anything above this
indicates the endpoint is over-subscribed, this field
is only relevant to the credit distribution function */
int TxCreditsMin; /* floor for credit distribution, this field is
only relevant to the credit distribution function */
int TxCreditsAssigned; /* number of credits assigned to this EP, this field
is only relevant to the credit dist function */
int TxCredits; /* current credits available, this field is used by
HTC to determine whether a message can be sent or
must be queued */
int TxCreditsToDist; /* pending credits to distribute on this endpoint, this
is set by HTC when credit reports arrive.
The credit distribution functions sets this to zero
when it distributes the credits */
int TxCreditsSeek; /* this is the number of credits that the current pending TX
packet needs to transmit. This is set by HTC when
and endpoint needs credits in order to transmit */
int TxCreditSize; /* size in bytes of each credit (set by HTC) */
int TxCreditsPerMaxMsg; /* credits required for a maximum sized messages (set by HTC) */
void *pHTCReserved; /* reserved for HTC use */
int TxQueueDepth; /* current depth of TX queue , i.e. messages waiting for credits
This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE
or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint
that has non-zero credits to recover
*/
} HTC_ENDPOINT_CREDIT_DIST;
#define HTC_EP_ACTIVE ((A_UINT32) (1u << 31))
/* macro to check if an endpoint has gone active, useful for credit
* distributions */
#define IS_EP_ACTIVE(epDist) ((epDist)->DistFlags & HTC_EP_ACTIVE)
#define SET_EP_ACTIVE(epDist) (epDist)->DistFlags |= HTC_EP_ACTIVE
/* credit distibution code that is passed into the distrbution function,
* there are mandatory and optional codes that must be handled */
typedef enum _HTC_CREDIT_DIST_REASON {
HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed
send operations (MANDATORY) resulting in credit reports */
HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occured (OPTIONAL) */
HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */
HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by
the distribution function */
} HTC_CREDIT_DIST_REASON;
typedef void (*HTC_CREDIT_DIST_CALLBACK)(void *Context,
HTC_ENDPOINT_CREDIT_DIST *
pEPList,
HTC_CREDIT_DIST_REASON
Reason);
typedef void (*HTC_CREDIT_INIT_CALLBACK)(void *Context,
HTC_ENDPOINT_CREDIT_DIST *
pEPList, int TotalCredits);
/* endpoint statistics action */
typedef enum _HTC_ENDPOINT_STAT_ACTION {
HTC_EP_STAT_SAMPLE = 0, /* only read statistics */
HTC_EP_STAT_SAMPLE_AND_CLEAR = 1, /* sample and immediately clear statistics */
HTC_EP_STAT_CLEAR /* clear only */
} HTC_ENDPOINT_STAT_ACTION;
/* endpoint statistics */
typedef struct _HTC_ENDPOINT_STATS {
A_UINT32 TxPosted; /* number of TX packets posted to the endpoint */
A_UINT32 TxCreditLowIndications; /* number of times the host set the credit-low flag in a send message on
this endpoint */
A_UINT32 TxIssued; /* running count of total TX packets issued */
A_UINT32 TxPacketsBundled; /* running count of TX packets that were issued in bundles */
A_UINT32 TxBundles; /* running count of TX bundles that were issued */
A_UINT32 TxDropped; /* tx packets that were dropped */
A_UINT32 TxCreditRpts; /* running count of total credit reports received for this endpoint */
A_UINT32 TxCreditRptsFromRx; /* credit reports received from this endpoint's RX packets */
A_UINT32 TxCreditRptsFromOther; /* credit reports received from RX packets of other endpoints */
A_UINT32 TxCreditRptsFromEp0; /* credit reports received from endpoint 0 RX packets */
A_UINT32 TxCreditsFromRx; /* count of credits received via Rx packets on this endpoint */
A_UINT32 TxCreditsFromOther; /* count of credits received via another endpoint */
A_UINT32 TxCreditsFromEp0; /* count of credits received via another endpoint */
A_UINT32 TxCreditsConsummed; /* count of consummed credits */
A_UINT32 TxCreditsReturned; /* count of credits returned */
A_UINT32 RxReceived; /* count of RX packets received */
A_UINT32 RxLookAheads; /* count of lookahead records
found in messages received on this endpoint */
A_UINT32 RxPacketsBundled; /* count of recv packets received in a bundle */
A_UINT32 RxBundleLookAheads; /* count of number of bundled lookaheads */
A_UINT32 RxBundleIndFromHdr; /* count of the number of bundle indications from the HTC header */
A_UINT32 RxAllocThreshHit; /* count of the number of times the recv allocation threshhold was hit */
A_UINT32 RxAllocThreshBytes; /* total number of bytes */
} HTC_ENDPOINT_STATS;
/* ------ Function Prototypes ------ */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Create an instance of HTC over the underlying HIF device
@function name: htc_create
@input: HifDevice - hif device handle,
pInfo - initialization information
@output:
@return: HTC_HANDLE on success, NULL on failure
@notes:
@example:
@see also: htc_destroy
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
HTC_HANDLE htc_create(void *HifDevice,
HTC_INIT_INFO *pInfo, cdf_device_t osdev);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Get the underlying HIF device handle
@function name: htc_get_hif_device
@input: HTCHandle - handle passed into the AddInstance callback
@output:
@return: opaque HIF device handle usable in HIF API calls.
@notes:
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void *htc_get_hif_device(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Set credit distribution parameters
@function name: htc_set_credit_distribution
@input: HTCHandle - HTC handle
pCreditDistCont - caller supplied context to pass into distribution functions
CreditDistFunc - Distribution function callback
CreditDistInit - Credit Distribution initialization callback
ServicePriorityOrder - Array containing list of service IDs, lowest index is highest
priority
ListLength - number of elements in ServicePriorityOrder
@output:
@return:
@notes: The user can set a custom credit distribution function to handle special requirements
for each endpoint. A default credit distribution routine can be used by setting
CreditInitFunc to NULL. The default credit distribution is only provided for simple
"fair" credit distribution without regard to any prioritization.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
void *pCreditDistContext,
HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
HTC_SERVICE_ID ServicePriorityOrder[],
int ListLength);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Wait for the target to indicate the HTC layer is ready
@function name: htc_wait_target
@input: HTCHandle - HTC handle
@output:
@return:
@notes: This API blocks until the target responds with an HTC ready message.
The caller should not connect services until the target has indicated it is
ready.
@example:
@see also: htc_connect_service
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_wait_target(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Start target service communications
@function name: htc_start
@input: HTCHandle - HTC handle
@output:
@return:
@notes: This API indicates to the target that the service connection phase is complete
and the target can freely start all connected services. This API should only be
called AFTER all service connections have been made. TCStart will issue a
SETUP_COMPLETE message to the target to indicate that all service connections
have been made and the target can start communicating over the endpoints.
@example:
@see also: htc_connect_service
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_start(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Add receive packet to HTC
@function name: htc_add_receive_pkt
@input: HTCHandle - HTC handle
pPacket - HTC receive packet to add
@output:
@return: A_OK on success
@notes: user must supply HTC packets for capturing incomming HTC frames. The caller
must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
macro.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Connect to an HTC service
@function name: htc_connect_service
@input: HTCHandle - HTC handle
pReq - connection details
@output: pResp - connection response
@return:
@notes: Service connections must be performed before htc_start. User provides callback handlers
for various endpoint events.
@example:
@see also: htc_start
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
HTC_SERVICE_CONNECT_REQ *pReq,
HTC_SERVICE_CONNECT_RESP *pResp);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: HTC register log dump
@function name: htc_dump
@input: HTCHandle - HTC handle
CmdId - Log command
start - start/print logs
@output:
@return:
@notes: Register logs will be started/printed.
be flushed.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Send an HTC packet
@function name: htc_send_pkt
@input: HTCHandle - HTC handle
pPacket - packet to send
@output:
@return: A_OK
@notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro.
This interface is fully asynchronous. On error, HTC SendPkt will
call the registered Endpoint callback to cleanup the packet.
@example:
@see also: htc_flush_endpoint
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_send_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Send an HTC packet containing a tx descriptor and data
@function name: htc_send_data_pkt
@input: HTCHandle - HTC handle
pPacket - packet to send
@output:
@return: A_OK
@notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro.
Caller must provide headroom in an initial fragment added to the
network buffer to store a HTC_FRAME_HDR.
This interface is fully asynchronous. On error, htc_send_data_pkt will
call the registered Endpoint EpDataTxComplete callback to cleanup
the packet.
@example:
@see also: htc_send_pkt
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifdef ATH_11AC_TXCOMPACT
A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, cdf_nbuf_t netbuf,
int Epid, int ActualLength);
#else /*ATH_11AC_TXCOMPACT */
A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
A_UINT8 more_data);
#endif /*ATH_11AC_TXCOMPACT */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Flush HTC when target is removed surprisely service communications
@function name: htc_flush_surprise_remove
@input: HTCHandle - HTC handle
@output:
@return:
@notes: All receive and pending TX packets will
be flushed.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_flush_surprise_remove(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Stop HTC service communications
@function name: htc_stop
@input: HTCHandle - HTC handle
@output:
@return:
@notes: HTC communications is halted. All receive and pending TX packets will
be flushed.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_stop(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Destory HTC service
@function name: htc_destroy
@input: HTCHandle
@output:
@return:
@notes: This cleans up all resources allocated by htc_create().
@example:
@see also: htc_create
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_destroy(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Flush pending TX packets
@function name: htc_flush_endpoint
@input: HTCHandle - HTC handle
Endpoint - Endpoint to flush
Tag - flush tag
@output:
@return:
@notes: The Tag parameter is used to selectively flush packets with matching tags.
The value of 0 forces all packets to be flush regardless of tag.
@example:
@see also: htc_send_pkt
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint,
HTC_TX_TAG Tag);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Dump credit distribution state
@function name: htc_dump_credit_states
@input: HTCHandle - HTC handle
@output:
@return:
@notes: This dumps all credit distribution information to the debugger
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_dump_credit_states(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Indicate a traffic activity change on an endpoint
@function name: htc_indicate_activity_change
@input: HTCHandle - HTC handle
Endpoint - endpoint in which activity has changed
Active - true if active, false if it has become inactive
@output:
@return:
@notes: This triggers the registered credit distribution function to
re-adjust credits for active/inactive endpoints.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_indicate_activity_change(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint, A_BOOL Active);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Get endpoint statistics
@function name: htc_get_endpoint_statistics
@input: HTCHandle - HTC handle
Endpoint - Endpoint identifier
Action - action to take with statistics
@output:
pStats - statistics that were sampled (can be NULL if Action is HTC_EP_STAT_CLEAR)
@return: true if statistics profiling is enabled, otherwise false.
@notes: Statistics is a compile-time option and this function may return false
if HTC is not compiled with profiling.
The caller can specify the statistic "action" to take when sampling
the statistics. This includes:
HTC_EP_STAT_SAMPLE: The pStats structure is filled with the current values.
HTC_EP_STAT_SAMPLE_AND_CLEAR: The structure is filled and the current statistics
are cleared.
HTC_EP_STAT_CLEA : the statistics are cleared, the called can pass a NULL value for
pStats
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_BOOL htc_get_endpoint_statistics(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint,
HTC_ENDPOINT_STAT_ACTION Action,
HTC_ENDPOINT_STATS *pStats);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Unblock HTC message reception
@function name: htc_unblock_recv
@input: HTCHandle - HTC handle
@output:
@return:
@notes:
HTC will block the receiver if the EpRecvAlloc callback fails to provide a packet.
The caller can use this API to indicate to HTC when resources (buffers) are available
such that the receiver can be unblocked and HTC may re-attempt fetching the pending message.
This API is not required if the user uses the EpRecvRefill callback or uses the HTCAddReceivePacket()
API to recycle or provide receive packets to HTC.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_unblock_recv(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: send a series of HTC packets
@function name: htc_send_pkts_multiple
@input: HTCHandle - HTC handle
pPktQueue - local queue holding packets to send
@output:
@return: A_OK
@notes: Caller must initialize each packet using SET_HTC_PACKET_INFO_TX() macro.
The queue must only contain packets directed at the same endpoint.
Caller supplies a pointer to an HTC_PACKET_QUEUE structure holding the TX packets in FIFO order.
This API will remove the packets from the pkt queue and place them into the HTC Tx Queue
and bundle messages where possible.
The caller may allocate the pkt queue on the stack to hold the packets.
This interface is fully asynchronous. On error, htc_send_pkts will
call the registered Endpoint callback to cleanup the packet.
@example:
@see also: htc_flush_endpoint
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_send_pkts_multiple(HTC_HANDLE HTCHandle,
HTC_PACKET_QUEUE *pPktQueue);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Add multiple receive packets to HTC
@function name: htc_add_receive_pkt_multiple
@input: HTCHandle - HTC handle
pPktQueue - HTC receive packet queue holding packets to add
@output:
@return: A_OK on success
@notes: user must supply HTC packets for capturing incomming HTC frames. The caller
must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
macro. The queue must only contain recv packets for the same endpoint.
Caller supplies a pointer to an HTC_PACKET_QUEUE structure holding the recv packet.
This API will remove the packets from the pkt queue and place them into internal
recv packet list.
The caller may allocate the pkt queue on the stack to hold the packets.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle,
HTC_PACKET_QUEUE *pPktQueue);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Check if an endpoint is marked active
@function name: htc_is_endpoint_active
@input: HTCHandle - HTC handle
Endpoint - endpoint to check for active state
@output:
@return: returns true if Endpoint is Active
@notes:
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_BOOL htc_is_endpoint_active(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Get the number of recv buffers currently queued into an HTC endpoint
@function name: htc_get_num_recv_buffers
@input: HTCHandle - HTC handle
Endpoint - endpoint to check
@output:
@return: returns number of buffers in queue
@notes:
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Set the target failure handling callback in HTC layer
@function name: htc_set_target_failure_callback
@input: HTCHandle - HTC handle
Callback - target failure handling callback
@output:
@return:
@notes:
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void htc_set_target_failure_callback(HTC_HANDLE HTCHandle,
HTC_TARGET_FAILURE Callback);
/* internally used functions for testing... */
void htc_enable_recv(HTC_HANDLE HTCHandle);
void htc_disable_recv(HTC_HANDLE HTCHandle);
A_STATUS HTCWaitForPendingRecv(HTC_HANDLE HTCHandle,
A_UINT32 TimeoutInMs,
A_BOOL *pbIsRecvPending);
/* function to fetch stats from htc layer*/
struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE
HTCHandle);
#ifdef HIF_USB
#define HTCReturnReceivePkt(target,p,osbuf) \
A_NETBUF_FREE(osbuf); \
if(p->Status == A_CLONE) { \
cdf_mem_free(p); \
}
#else
#define HTCReturnReceivePkt(target,p,osbuf) htc_add_receive_pkt(target,p)
#endif
#ifdef WLAN_FEATURE_FASTPATH
#define HTC_TX_DESC_FILL(_htc_tx_desc, _download_len, _ep_id, _seq_no) \
do { \
HTC_WRITE32((_htc_tx_desc), \
SM((_download_len), HTC_FRAME_HDR_PAYLOADLEN) | \
SM((_ep_id), HTC_FRAME_HDR_ENDPOINTID)); \
\
HTC_WRITE32((A_UINT32 *)(_htc_tx_desc) + 1, \
SM((_seq_no), HTC_FRAME_HDR_CONTROLBYTES1));\
} while (0)
#endif /* WLAN_FEATURE_FASTPATH */
#ifdef __cplusplus
}
#endif
void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, int *credit);
void htc_dump_counter_info(HTC_HANDLE HTCHandle);
void *htc_get_targetdef(HTC_HANDLE htc_handle);
void htc_set_target_to_sleep(void *context);
void htc_cancel_deferred_target_sleep(void *context);
int htc_runtime_suspend(void);
int htc_runtime_resume(void);
/* Disable ASPM : Disable PCIe low power */
void htc_disable_aspm(void);
#ifdef IPA_OFFLOAD
void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle,
cdf_dma_addr_t *ce_sr_base_paddr,
uint32_t *ce_sr_ring_size,
cdf_dma_addr_t *ce_reg_paddr);
#else
#define htc_ipa_get_ce_resource(htc_handle, \
ce_sr_base_paddr, \
ce_sr_ring_size, \
ce_reg_paddr) /* NO-OP */
#endif /* IPA_OFFLOAD */
#endif /* _HTC_API_H_ */

50
htc/htc_debug.h Normale Datei
Datei anzeigen

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef HTC_DEBUG_H_
#define HTC_DEBUG_H_
#define ATH_MODULE_NAME htc
#include "a_debug.h"
#include "cdf_trace.h"
/* ------- Debug related stuff ------- */
#define ATH_DEBUG_SEND ATH_DEBUG_MAKE_MODULE_MASK(0)
#define ATH_DEBUG_RECV ATH_DEBUG_MAKE_MODULE_MASK(1)
#define ATH_DEBUG_SYNC ATH_DEBUG_MAKE_MODULE_MASK(2)
#define ATH_DEBUG_DUMP ATH_DEBUG_MAKE_MODULE_MASK(3)
#define ATH_DEBUG_SETUP ATH_DEBUG_MAKE_MODULE_MASK(4)
#define HTC_ERROR(args ...) \
CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_ERROR, ## args)
#define HTC_WARN(args ...) \
CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_WARN, ## args)
#define HTC_INFO(args ...) \
CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_INFO, ## args)
#define HTC_TRACE(args ...) \
CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_DEBUG, ## args)
#endif /*HTC_DEBUG_H_ */

317
htc/htc_internal.h Normale Datei
Datei anzeigen

@@ -0,0 +1,317 @@
/*
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef _HTC_INTERNAL_H_
#define _HTC_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <athdefs.h>
#include "a_types.h"
#include "osapi_linux.h"
#include <cdf_nbuf.h>
#include <cdf_types.h>
#include <cdf_lock.h>
#include <cdf_softirq_timer.h>
#include <cdf_atomic.h>
#include "hif.h"
#include <htc.h>
#include "htc_api.h"
#include "htc_packet.h"
/* HTC operational parameters */
#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
#define HTC_TARGET_DEBUG_INTR_MASK 0x01
#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
#define HTC_MIN_MSG_PER_BUNDLE 2
#if defined(HIF_USB)
#define HTC_MAX_MSG_PER_BUNDLE 9
#else
#define HTC_MAX_MSG_PER_BUNDLE 16
#endif
/*
* HTC_MAX_TX_BUNDLE_SEND_LIMIT -
* This value is in units of tx frame fragments.
* It needs to be at least as large as the maximum number of tx frames in a
* HTC download bundle times the average number of fragments in each such frame
* (In certain operating systems, such as Linux, we expect to only have
* a single fragment per frame anyway.)
*/
#define HTC_MAX_TX_BUNDLE_SEND_LIMIT 255
#define HTC_PACKET_CONTAINER_ALLOCATION 32
#define NUM_CONTROL_TX_BUFFERS 2
#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH)
#define HTC_CONTROL_BUFFER_ALIGN 32
#define HTC_TARGET_RESPONSE_POLL_MS 10
#if !defined(A_SIMOS_DEVHOST)
#define HTC_TARGET_MAX_RESPONSE_POLL 200 /* actual HW */
#else
#define HTC_TARGET_MAX_RESPONSE_POLL 600 /* host + target simulation */
#endif
#define HTC_SERVICE_TX_PACKET_TAG HTC_TX_PACKET_TAG_INTERNAL
#define HTC_CREDIT_HISTORY_MAX 1024
typedef enum {
HTC_REQUEST_CREDIT,
HTC_PROCESS_CREDIT_REPORT,
HTC_SUSPEND_ACK,
HTC_SUSPEND_NACK,
} htc_credit_exchange_type;
typedef struct {
htc_credit_exchange_type type;
uint64_t time;
uint32_t tx_credit;
uint32_t htc_tx_queue_depth;
} HTC_CREDIT_HISTORY;
typedef struct _HTC_ENDPOINT {
HTC_ENDPOINT_ID Id;
/* service ID this endpoint is bound to
* non-zero value means this endpoint is in use
*/
HTC_SERVICE_ID service_id;
HTC_EP_CALLBACKS EpCallBacks; /* callbacks associated with this endpoint */
HTC_PACKET_QUEUE TxQueue; /* HTC frame buffer TX queue */
int MaxTxQueueDepth; /* max depth of the TX queue before we need to
call driver's full handler */
int MaxMsgLength; /* max length of endpoint message */
uint8_t UL_PipeID;
uint8_t DL_PipeID;
int ul_is_polled; /* Need to call HIF to get tx completion callbacks? */
cdf_softirq_timer_t ul_poll_timer;
int ul_poll_timer_active;
int ul_outstanding_cnt;
int dl_is_polled; /* Need to call HIF to fetch rx? (Not currently supported.) */
#if 0 /* not currently supported */
cdf_softirq_timer_t dl_poll_timer;
#endif
HTC_PACKET_QUEUE TxLookupQueue; /* lookup queue to match netbufs to htc packets */
HTC_PACKET_QUEUE RxBufferHoldQueue; /* temporary hold queue for back compatibility */
A_UINT8 SeqNo; /* TX seq no (helpful) for debugging */
cdf_atomic_t TxProcessCount; /* serialization */
struct _HTC_TARGET *target;
int TxCredits; /* TX credits available on this endpoint */
int TxCreditSize; /* size in bytes of each credit (set by HTC) */
int TxCreditsPerMaxMsg; /* credits required per max message (precalculated) */
#ifdef HTC_EP_STAT_PROFILING
HTC_ENDPOINT_STATS endpoint_stats; /* endpoint statistics */
#endif
A_BOOL TxCreditFlowEnabled;
} HTC_ENDPOINT;
#ifdef HTC_EP_STAT_PROFILING
#define INC_HTC_EP_STAT(p, stat, count) ((p)->endpoint_stats.stat += (count))
#else
#define INC_HTC_EP_STAT(p, stat, count)
#endif
typedef struct {
A_UINT16 service_id;
A_UINT8 CreditAllocation;
} HTC_SERVICE_TX_CREDIT_ALLOCATION;
#define HTC_MAX_SERVICE_ALLOC_ENTRIES 8
/* Error codes for HTC layer packet stats*/
enum ol_ath_htc_pkt_ecodes {
GET_HTC_PKT_Q_FAIL = 0, /* error- get packet at head of HTC_PACKET_Q */
HTC_PKT_Q_EMPTY,
HTC_SEND_Q_EMPTY
};
/* our HTC target state */
typedef struct _HTC_TARGET {
struct ol_softc *hif_dev;
HTC_ENDPOINT endpoint[ENDPOINT_MAX];
cdf_spinlock_t HTCLock;
cdf_spinlock_t HTCRxLock;
cdf_spinlock_t HTCTxLock;
cdf_spinlock_t HTCCreditLock;
A_UINT32 HTCStateFlags;
void *host_handle;
HTC_INIT_INFO HTCInitInfo;
HTC_PACKET *pHTCPacketStructPool; /* pool of HTC packets */
HTC_PACKET_QUEUE ControlBufferTXFreeList;
A_UINT8 CtrlResponseBuffer[HTC_MAX_CONTROL_MESSAGE_LENGTH];
int CtrlResponseLength;
cdf_event_t ctrl_response_valid;
A_BOOL CtrlResponseProcessing;
int TotalTransmitCredits;
HTC_SERVICE_TX_CREDIT_ALLOCATION
ServiceTxAllocTable[HTC_MAX_SERVICE_ALLOC_ENTRIES];
int TargetCreditSize;
#ifdef RX_SG_SUPPORT
cdf_nbuf_queue_t RxSgQueue;
A_BOOL IsRxSgInprogress;
A_UINT32 CurRxSgTotalLen; /* current total length */
A_UINT32 ExpRxSgTotalLen; /* expected total length */
#endif
cdf_device_t osdev;
struct ol_ath_htc_stats htc_pkt_stats;
HTC_PACKET *pBundleFreeList;
A_UINT32 ce_send_cnt;
A_UINT32 TX_comp_cnt;
A_UINT8 MaxMsgsPerHTCBundle;
cdf_work_t queue_kicker;
} HTC_TARGET;
#define HTC_ENABLE_BUNDLE(target) (target->MaxMsgsPerHTCBundle > 1)
#ifdef RX_SG_SUPPORT
#define RESET_RX_SG_CONFIG(_target) \
_target->ExpRxSgTotalLen = 0; \
_target->CurRxSgTotalLen = 0; \
_target->IsRxSgInprogress = false;
#endif
#define HTC_STATE_STOPPING (1 << 0)
#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING)
#define LOCK_HTC(t) cdf_spin_lock_bh(&(t)->HTCLock);
#define UNLOCK_HTC(t) cdf_spin_unlock_bh(&(t)->HTCLock);
#define LOCK_HTC_RX(t) cdf_spin_lock_bh(&(t)->HTCRxLock);
#define UNLOCK_HTC_RX(t) cdf_spin_unlock_bh(&(t)->HTCRxLock);
#define LOCK_HTC_TX(t) cdf_spin_lock_bh(&(t)->HTCTxLock);
#define UNLOCK_HTC_TX(t) cdf_spin_unlock_bh(&(t)->HTCTxLock);
#define LOCK_HTC_CREDIT(t) cdf_spin_lock_bh(&(t)->HTCCreditLock);
#define UNLOCK_HTC_CREDIT(t) cdf_spin_unlock_bh(&(t)->HTCCreditLock);
#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd))
#define IS_TX_CREDIT_FLOW_ENABLED(ep) ((ep)->TxCreditFlowEnabled)
#define HTC_POLL_CLEANUP_PERIOD_MS 10 /* milliseconds */
/* Macro to Increment the HTC_PACKET_ERRORS for Tx.*/
#define OL_ATH_HTC_PKT_ERROR_COUNT_INCR(_target,_ecode) \
do { \
if(_ecode==GET_HTC_PKT_Q_FAIL) (_target->htc_pkt_stats.htc_get_pkt_q_fail_count)+=1; \
if(_ecode==HTC_PKT_Q_EMPTY) (_target->htc_pkt_stats.htc_pkt_q_empty_count)+=1; \
if(_ecode==HTC_SEND_Q_EMPTY) (_target->htc_pkt_stats.htc_send_q_empty_count)+=1; \
} while(0);
/* internal HTC functions */
CDF_STATUS htc_rx_completion_handler(void *Context, cdf_nbuf_t netbuf,
uint8_t pipeID);
CDF_STATUS htc_tx_completion_handler(void *Context, cdf_nbuf_t netbuf,
unsigned int transferID, uint32_t toeplitz_hash_result);
HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target);
void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket);
HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target);
void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket);
void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint);
void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
HTC_TX_TAG Tag);
void htc_recv_init(HTC_TARGET *target);
A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target);
void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket);
HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target);
A_UINT8 htc_get_credit_allocation(HTC_TARGET *target, A_UINT16 service_id);
void htc_tx_resource_avail_handler(void *context, A_UINT8 pipeID);
void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket);
void htc_process_credit_rpt(HTC_TARGET *target,
HTC_CREDIT_REPORT *pRpt,
int NumEntries, HTC_ENDPOINT_ID FromEndpoint);
void htc_fw_event_handler(void *context, CDF_STATUS status);
void htc_send_complete_check_cleanup(void *context);
void htc_runtime_pm_init(HTC_TARGET *target);
void htc_kick_queues(void *context);
void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit,
uint32_t htc_tx_queue_depth);
static inline void htc_send_complete_poll_timer_stop(HTC_ENDPOINT *
pEndpoint) {
LOCK_HTC_TX(pEndpoint->target);
if (pEndpoint->ul_poll_timer_active) {
/* cdf_softirq_timer_cancel(&pEndpoint->ul_poll_timer); */
pEndpoint->ul_poll_timer_active = 0;
}
UNLOCK_HTC_TX(pEndpoint->target);
}
static inline void htc_send_complete_poll_timer_start(HTC_ENDPOINT *
pEndpoint) {
LOCK_HTC_TX(pEndpoint->target);
if (pEndpoint->ul_outstanding_cnt
&& !pEndpoint->ul_poll_timer_active) {
/*
cdf_softirq_timer_start(
&pEndpoint->ul_poll_timer, HTC_POLL_CLEANUP_PERIOD_MS);
*/
pEndpoint->ul_poll_timer_active = 1;
}
UNLOCK_HTC_TX(pEndpoint->target);
}
static inline void
htc_send_complete_check(HTC_ENDPOINT *pEndpoint, int force) {
/*
* Stop the polling-cleanup timer that will result in a later call to
* this function. It may get started again below, if there are still
* outsending sends.
*/
htc_send_complete_poll_timer_stop(pEndpoint);
/*
* Check whether HIF has any prior sends that have finished,
* have not had the post-processing done.
*/
hif_send_complete_check(pEndpoint->target->hif_dev,
pEndpoint->UL_PipeID, force);
/*
* If there are still outstanding sends after polling, start a timer
* to check again a little later.
*/
htc_send_complete_poll_timer_start(pEndpoint);
}
#ifdef __cplusplus
}
#endif
#ifndef DEBUG_BUNDLE
#define DEBUG_BUNDLE 0
#endif
#ifdef HIF_SDIO
#ifndef ENABLE_BUNDLE_TX
#define ENABLE_BUNDLE_TX 1
#endif
#ifndef ENABLE_BUNDLE_RX
#define ENABLE_BUNDLE_RX 1
#endif
#endif /* HIF_SDIO */
#endif /* !_HTC_HOST_INTERNAL_H_ */

280
htc/htc_packet.h Normale Datei
Datei anzeigen

@@ -0,0 +1,280 @@
/*
* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef HTC_PACKET_H_
#define HTC_PACKET_H_
#include <osdep.h>
#include <a_types.h> /* A_UINT16, etc. */
#include "dl_list.h"
/* ------ Endpoint IDS ------ */
typedef enum {
ENDPOINT_UNUSED = -1,
ENDPOINT_0 = 0,
ENDPOINT_1 = 1,
ENDPOINT_2 = 2,
ENDPOINT_3,
ENDPOINT_4,
ENDPOINT_5,
ENDPOINT_6,
ENDPOINT_7,
ENDPOINT_8,
ENDPOINT_MAX,
} HTC_ENDPOINT_ID;
struct _HTC_PACKET;
typedef void (*HTC_PACKET_COMPLETION)(void *, struct _HTC_PACKET *);
typedef A_UINT16 HTC_TX_TAG;
typedef struct _HTC_TX_PACKET_INFO {
HTC_TX_TAG Tag; /* tag used to selective flush packets */
int CreditsUsed; /* number of credits used for this TX packet (HTC internal) */
A_UINT8 SendFlags; /* send flags (HTC internal) */
int SeqNo; /* internal seq no for debugging (HTC internal) */
A_UINT32 Flags; /* internal use */
} HTC_TX_PACKET_INFO;
/**
* HTC_TX_PACKET_TAG_XXX - #defines for tagging packets for special handling
* HTC_TX_PACKET_TAG_ALL: zero is reserved and used to flush ALL packets
* HTC_TX_PACKET_TAG_INTERNAL: internal tags start here
* HTC_TX_PACKET_TAG_USER_DEFINED: user-defined tags start here
* HTC_TX_PACKET_TAG_BUNDLED: indicate this is a bundled tx packet
* HTC_TX_PACKET_TAG_AUTO_PM: indicate a power management wmi command
*/
#define HTC_TX_PACKET_TAG_ALL 0
#define HTC_TX_PACKET_TAG_INTERNAL 1
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9)
#define HTC_TX_PACKET_TAG_BUNDLED (HTC_TX_PACKET_TAG_USER_DEFINED + 1)
#define HTC_TX_PACKET_TAG_AUTO_PM (HTC_TX_PACKET_TAG_USER_DEFINED + 2)
/* Tag packet for runtime put after sending */
#define HTC_TX_PACKET_TAG_RUNTIME_PUT (HTC_TX_PACKET_TAG_USER_DEFINED + 3)
#define HTC_TX_PACKET_FLAG_FIXUP_NETBUF (1 << 0)
typedef struct _HTC_RX_PACKET_INFO {
A_UINT32 ExpectedHdr; /* HTC internal use */
A_UINT32 HTCRxFlags; /* HTC internal use */
A_UINT32 IndicationFlags; /* indication flags set on each RX packet indication */
} HTC_RX_PACKET_INFO;
#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0) /* more packets on this endpoint are being fetched */
/* wrapper around endpoint-specific packets */
typedef struct _HTC_PACKET {
DL_LIST ListLink; /* double link */
void *pPktContext; /* caller's per packet specific context */
A_UINT8 *pBufferStart; /* the true buffer start , the caller can
store the real buffer start here. In
receive callbacks, the HTC layer sets pBuffer
to the start of the payload past the header. This
field allows the caller to reset pBuffer when it
recycles receive packets back to HTC */
/*
* Pointer to the start of the buffer. In the transmit
* direction this points to the start of the payload. In the
* receive direction, however, the buffer when queued up
* points to the start of the HTC header but when returned
* to the caller points to the start of the payload
*/
A_UINT8 *pBuffer; /* payload start (RX/TX) */
A_UINT32 BufferLength; /* length of buffer */
A_UINT32 ActualLength; /* actual length of payload */
HTC_ENDPOINT_ID Endpoint; /* endpoint that this packet was sent/recv'd from */
A_STATUS Status; /* completion status */
union {
HTC_TX_PACKET_INFO AsTx; /* Tx Packet specific info */
HTC_RX_PACKET_INFO AsRx; /* Rx Packet specific info */
} PktInfo;
/* the following fields are for internal HTC use */
A_UINT32 netbufOrigHeadRoom;
HTC_PACKET_COMPLETION Completion; /* completion */
void *pContext; /* HTC private completion context */
void *pNetBufContext; /* optimization for network-oriented data, the HTC packet
can pass the network buffer corresponding to the HTC packet
lower layers may optimized the transfer knowing this is
a network buffer */
} HTC_PACKET;
#define COMPLETE_HTC_PACKET(p,status) \
{ \
(p)->Status = (status); \
(p)->Completion((p)->pContext,(p)); \
}
#define INIT_HTC_PACKET_INFO(p,b,len) \
{ \
(p)->pBufferStart = (b); \
(p)->BufferLength = (len); \
}
/* macro to set an initial RX packet for refilling HTC */
#define SET_HTC_PACKET_INFO_RX_REFILL(p,c,b,len,ep) \
{ \
(p)->pPktContext = (c); \
(p)->pBuffer = (b); \
(p)->pBufferStart = (b); \
(p)->BufferLength = (len); \
(p)->Endpoint = (ep); \
}
/* fast macro to recycle an RX packet that will be re-queued to HTC */
#define HTC_PACKET_RESET_RX(p) \
{ (p)->pBuffer = (p)->pBufferStart; (p)->ActualLength = 0; }
/* macro to set packet parameters for TX */
#define SET_HTC_PACKET_INFO_TX(p,c,b,len,ep,tag) \
{ \
(p)->pPktContext = (c); \
(p)->pBuffer = (b); \
(p)->ActualLength = (len); \
(p)->Endpoint = (ep); \
(p)->PktInfo.AsTx.Tag = (tag); \
(p)->PktInfo.AsTx.Flags = 0; \
(p)->PktInfo.AsTx.SendFlags = 0; \
}
#define SET_HTC_PACKET_NET_BUF_CONTEXT(p,nb) \
(p)->pNetBufContext = (nb)
#define GET_HTC_PACKET_NET_BUF_CONTEXT(p) (p)->pNetBufContext
/* HTC Packet Queueing Macros */
typedef struct _HTC_PACKET_QUEUE {
DL_LIST QueueHead;
int Depth;
} HTC_PACKET_QUEUE;
/* initialize queue */
#define INIT_HTC_PACKET_QUEUE(pQ) \
{ \
DL_LIST_INIT(& (pQ)->QueueHead); \
(pQ)->Depth = 0; \
}
/* enqueue HTC packet to the tail of the queue */
#define HTC_PACKET_ENQUEUE(pQ,p) \
{ dl_list_insert_tail(& (pQ)->QueueHead,& (p)->ListLink); \
(pQ)->Depth ++; \
}
/* enqueue HTC packet to the tail of the queue */
#define HTC_PACKET_ENQUEUE_TO_HEAD(pQ,p) \
{ dl_list_insert_head(& (pQ)->QueueHead,& (p)->ListLink); \
(pQ)->Depth ++; \
}
/* test if a queue is empty */
#define HTC_QUEUE_EMPTY(pQ) ((pQ)->Depth == 0)
/* get packet at head without removing it */
static INLINE HTC_PACKET *htc_get_pkt_at_head(HTC_PACKET_QUEUE *queue)
{
if (queue->Depth == 0) {
return NULL;
}
return
A_CONTAINING_STRUCT((DL_LIST_GET_ITEM_AT_HEAD(&queue->QueueHead)),
HTC_PACKET, ListLink);
}
/* remove a packet from a queue, where-ever it is in the queue */
#define HTC_PACKET_REMOVE(pQ,p) \
{ \
dl_list_remove(& (p)->ListLink); \
(pQ)->Depth --; \
}
/* dequeue an HTC packet from the head of the queue */
static INLINE HTC_PACKET *htc_packet_dequeue(HTC_PACKET_QUEUE *queue)
{
DL_LIST *pItem = dl_list_remove_item_from_head(&queue->QueueHead);
if (pItem != NULL) {
queue->Depth--;
return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink);
}
return NULL;
}
/* dequeue an HTC packet from the tail of the queue */
static INLINE HTC_PACKET *htc_packet_dequeue_tail(HTC_PACKET_QUEUE *queue)
{
DL_LIST *pItem = dl_list_remove_item_from_tail(&queue->QueueHead);
if (pItem != NULL) {
queue->Depth--;
return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink);
}
return NULL;
}
#define HTC_PACKET_QUEUE_DEPTH(pQ) (pQ)->Depth
#define HTC_GET_ENDPOINT_FROM_PKT(p) (p)->Endpoint
#define HTC_GET_TAG_FROM_PKT(p) (p)->PktInfo.AsTx.Tag
/* transfer the packets from one queue to the tail of another queue */
#define HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(pQDest,pQSrc) \
{ \
dl_list_transfer_items_to_tail(&(pQDest)->QueueHead,&(pQSrc)->QueueHead); \
(pQDest)->Depth += (pQSrc)->Depth; \
(pQSrc)->Depth = 0; \
}
/*
* Transfer the packets from one queue to the head of another queue.
* This xfer_to_head(q1,q2) is basically equivalent to xfer_to_tail(q2,q1),
* but it updates the queue descriptor object for the initial queue to refer
* to the concatenated queue.
*/
#define HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(pQDest, pQSrc) \
{ \
dl_list_transfer_items_to_head(&(pQDest)->QueueHead,&(pQSrc)->QueueHead); \
(pQDest)->Depth += (pQSrc)->Depth; \
(pQSrc)->Depth = 0; \
}
/* fast version to init and add a single packet to a queue */
#define INIT_HTC_PACKET_QUEUE_AND_ADD(pQ,pP) \
{ \
DL_LIST_INIT_AND_ADD(&(pQ)->QueueHead,&(pP)->ListLink) \
(pQ)->Depth = 1; \
}
#define HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQ, pPTemp) \
ITERATE_OVER_LIST_ALLOW_REMOVE(&(pQ)->QueueHead,(pPTemp), HTC_PACKET, ListLink)
#define HTC_PACKET_QUEUE_ITERATE_IS_VALID(pQ) ITERATE_IS_VALID(&(pQ)->QueueHead)
#define HTC_PACKET_QUEUE_ITERATE_RESET(pQ) ITERATE_RESET(&(pQ)->QueueHead)
#define HTC_PACKET_QUEUE_ITERATE_END ITERATE_END
#endif /*HTC_PACKET_H_ */

749
htc/htc_recv.c Normale Datei
Datei anzeigen

@@ -0,0 +1,749 @@
/*
* Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include "htc_debug.h"
#include "htc_internal.h"
#include "cds_api.h"
#include <cdf_nbuf.h> /* cdf_nbuf_t */
#include "epping_main.h"
/* HTC Control message receive timeout msec */
#define HTC_CONTROL_RX_TIMEOUT 3000
#ifdef DEBUG
void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
{
A_CHAR stream[60];
A_CHAR byteOffsetStr[10];
A_UINT32 i;
A_UINT16 offset, count, byteOffset;
A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length,
pDescription);
count = 0;
offset = 0;
byteOffset = 0;
for (i = 0; i < length; i++) {
A_SNPRINTF(stream + offset, (sizeof(stream) - offset),
"%02X ", buffer[i]);
count++;
offset += 3;
if (count == 16) {
count = 0;
offset = 0;
A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X",
byteOffset);
A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
A_MEMZERO(stream, 60);
byteOffset += 16;
}
}
if (offset != 0) {
A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X",
byteOffset);
A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
}
A_PRINTF("<------------------------------------------------->\n");
}
#else
void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
{
}
#endif
static A_STATUS htc_process_trailer(HTC_TARGET *target,
A_UINT8 *pBuffer,
int Length, HTC_ENDPOINT_ID FromEndpoint);
static void do_recv_completion(HTC_ENDPOINT *pEndpoint,
HTC_PACKET_QUEUE *pQueueToIndicate)
{
do {
if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
/* nothing to indicate */
break;
}
if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
(" HTC calling ep %d, recv multiple callback (%d pkts) \n",
pEndpoint->Id,
HTC_PACKET_QUEUE_DEPTH
(pQueueToIndicate)));
/* a recv multiple handler is being used, pass the queue to the handler */
pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint->
EpCallBacks.
pContext,
pQueueToIndicate);
INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
} else {
HTC_PACKET *pPacket;
/* using legacy EpRecv */
while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) {
pPacket = htc_packet_dequeue(pQueueToIndicate);
if (pEndpoint->EpCallBacks.EpRecv == NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTC ep %d has NULL recv callback on packet %p\n",
pEndpoint->Id,
pPacket));
continue;
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("HTC calling ep %d recv callback on packet %p\n",
pEndpoint->Id, pPacket));
pEndpoint->EpCallBacks.EpRecv(pEndpoint->
EpCallBacks.
pContext,
pPacket);
}
}
} while (false);
}
static void recv_packet_completion(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
HTC_PACKET *pPacket)
{
HTC_PACKET_QUEUE container;
INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket);
/* do completion */
do_recv_completion(pEndpoint, &container);
}
void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket)
{
/* TODO, can't really receive HTC control messages yet.... */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Invalid call to htc_control_rx_complete\n"));
}
void htc_unblock_recv(HTC_HANDLE HTCHandle)
{
/* TODO find the Need in new model */
}
void htc_enable_recv(HTC_HANDLE HTCHandle)
{
/* TODO find the Need in new model */
}
void htc_disable_recv(HTC_HANDLE HTCHandle)
{
/* TODO find the Need in new model */
}
int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue);
}
HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target)
{
HTC_PACKET *pPacket;
LOCK_HTC_RX(target);
if (NULL == target->pHTCPacketStructPool) {
UNLOCK_HTC_RX(target);
return NULL;
}
pPacket = target->pHTCPacketStructPool;
target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext;
UNLOCK_HTC_RX(target);
pPacket->ListLink.pNext = NULL;
return pPacket;
}
void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket)
{
LOCK_HTC_RX(target);
if (NULL == target->pHTCPacketStructPool) {
target->pHTCPacketStructPool = pPacket;
pPacket->ListLink.pNext = NULL;
} else {
pPacket->ListLink.pNext =
(DL_LIST *) target->pHTCPacketStructPool;
target->pHTCPacketStructPool = pPacket;
}
UNLOCK_HTC_RX(target);
}
#ifdef RX_SG_SUPPORT
cdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target)
{
cdf_nbuf_t skb;
uint8_t *anbdata;
uint8_t *anbdata_new;
uint32_t anblen;
cdf_nbuf_t new_skb = NULL;
uint32_t sg_queue_len;
cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
sg_queue_len = cdf_nbuf_queue_len(rx_sg_queue);
if (sg_queue_len <= 1) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("rx_sg_to_single_netbuf: invalid sg queue len %u\n"));
goto _failed;
}
new_skb = cdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false);
if (new_skb == NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n",
target->ExpRxSgTotalLen));
goto _failed;
}
cdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen);
skb = cdf_nbuf_queue_remove(rx_sg_queue);
do {
cdf_nbuf_peek_header(skb, &anbdata, &anblen);
cdf_mem_copy(anbdata_new, anbdata, cdf_nbuf_len(skb));
cdf_nbuf_put_tail(new_skb, cdf_nbuf_len(skb));
anbdata_new += cdf_nbuf_len(skb);
cdf_nbuf_free(skb);
skb = cdf_nbuf_queue_remove(rx_sg_queue);
} while (skb != NULL);
RESET_RX_SG_CONFIG(target);
return new_skb;
_failed:
while ((skb = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) {
cdf_nbuf_free(skb);
}
RESET_RX_SG_CONFIG(target);
return NULL;
}
#endif
CDF_STATUS htc_rx_completion_handler(void *Context, cdf_nbuf_t netbuf,
uint8_t pipeID)
{
CDF_STATUS status = CDF_STATUS_SUCCESS;
HTC_FRAME_HDR *HtcHdr;
HTC_TARGET *target = (HTC_TARGET *) Context;
uint8_t *netdata;
uint32_t netlen;
HTC_ENDPOINT *pEndpoint;
HTC_PACKET *pPacket;
A_UINT16 payloadLen;
uint32_t trailerlen = 0;
A_UINT8 htc_ep_id;
#ifdef RX_SG_SUPPORT
LOCK_HTC_RX(target);
if (target->IsRxSgInprogress) {
target->CurRxSgTotalLen += cdf_nbuf_len(netbuf);
cdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) {
netbuf = rx_sg_to_single_netbuf(target);
if (netbuf == NULL) {
UNLOCK_HTC_RX(target);
goto _out;
}
} else {
netbuf = NULL;
UNLOCK_HTC_RX(target);
goto _out;
}
}
UNLOCK_HTC_RX(target);
#endif
netdata = cdf_nbuf_data(netbuf);
netlen = cdf_nbuf_len(netbuf);
HtcHdr = (HTC_FRAME_HDR *) netdata;
do {
htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID);
if (htc_ep_id >= ENDPOINT_MAX) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTC Rx: invalid EndpointID=%d\n",
htc_ep_id));
debug_dump_bytes((A_UINT8 *) HtcHdr,
sizeof(HTC_FRAME_HDR), "BAD HTC Header");
status = CDF_STATUS_E_FAILURE;
CDF_BUG(0);
break;
}
pEndpoint = &target->endpoint[htc_ep_id];
/*
* If this endpoint that received a message from the target has
* a to-target HIF pipe whose send completions are polled rather
* than interrupt-driven, this is a good point to ask HIF to check
* whether it has any completed sends to handle.
*/
if (pEndpoint->ul_is_polled) {
htc_send_complete_check(pEndpoint, 1);
}
payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN);
if (netlen < (payloadLen + HTC_HDR_LENGTH)) {
#ifdef RX_SG_SUPPORT
LOCK_HTC_RX(target);
target->IsRxSgInprogress = true;
cdf_nbuf_queue_init(&target->RxSgQueue);
cdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH);
target->CurRxSgTotalLen += netlen;
UNLOCK_HTC_RX(target);
netbuf = NULL;
break;
#else
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTC Rx: insufficient length, got:%d expected =%zu\n",
netlen, payloadLen + HTC_HDR_LENGTH));
debug_dump_bytes((A_UINT8 *) HtcHdr,
sizeof(HTC_FRAME_HDR),
"BAD RX packet length");
status = CDF_STATUS_E_FAILURE;
CDF_BUG(0);
break;
#endif
}
#ifdef HTC_EP_STAT_PROFILING
LOCK_HTC_RX(target);
INC_HTC_EP_STAT(pEndpoint, RxReceived, 1);
UNLOCK_HTC_RX(target);
#endif
/* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */
{
A_UINT8 temp;
A_STATUS temp_status;
/* get flags to check for trailer */
temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS);
if (temp & HTC_FLAGS_RECV_TRAILER) {
/* extract the trailer length */
temp =
HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR,
CONTROLBYTES0);
if ((temp < sizeof(HTC_RECORD_HDR))
|| (temp > payloadLen)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n",
payloadLen, temp));
status = CDF_STATUS_E_INVAL;
break;
}
trailerlen = temp;
/* process trailer data that follows HDR + application payload */
temp_status = htc_process_trailer(target,
((A_UINT8 *) HtcHdr +
HTC_HDR_LENGTH +
payloadLen - temp),
temp, htc_ep_id);
if (A_FAILED(temp_status)) {
status = CDF_STATUS_E_FAILURE;
break;
}
}
}
if (((int)payloadLen - (int)trailerlen) <= 0) {
/* zero length packet with trailer data, just drop these */
break;
}
if (htc_ep_id == ENDPOINT_0) {
A_UINT16 message_id;
HTC_UNKNOWN_MSG *htc_msg;
int wow_nack = 0;
/* remove HTC header */
cdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH);
netdata = cdf_nbuf_data(netbuf);
netlen = cdf_nbuf_len(netbuf);
htc_msg = (HTC_UNKNOWN_MSG *) netdata;
message_id =
HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID);
switch (message_id) {
default:
/* handle HTC control message */
if (target->CtrlResponseProcessing) {
/* this is a fatal error, target should not be sending unsolicited messages
* on the endpoint 0 */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTC Rx Ctrl still processing\n"));
status = CDF_STATUS_E_FAILURE;
CDF_BUG(false);
break;
}
LOCK_HTC_RX(target);
target->CtrlResponseLength =
min((int)netlen,
HTC_MAX_CONTROL_MESSAGE_LENGTH);
A_MEMCPY(target->CtrlResponseBuffer, netdata,
target->CtrlResponseLength);
/* Requester will clear this flag */
target->CtrlResponseProcessing = true;
UNLOCK_HTC_RX(target);
cdf_event_set(&target->ctrl_response_valid);
break;
case HTC_MSG_SEND_SUSPEND_COMPLETE:
wow_nack = 0;
LOCK_HTC_CREDIT(target);
htc_credit_record(HTC_SUSPEND_ACK,
pEndpoint->TxCredits,
HTC_PACKET_QUEUE_DEPTH(
&pEndpoint->TxQueue));
UNLOCK_HTC_CREDIT(target);
target->HTCInitInfo.
TargetSendSuspendComplete((void *)
&wow_nack);
break;
case HTC_MSG_NACK_SUSPEND:
wow_nack = 1;
LOCK_HTC_CREDIT(target);
htc_credit_record(HTC_SUSPEND_ACK,
pEndpoint->TxCredits,
HTC_PACKET_QUEUE_DEPTH(
&pEndpoint->TxQueue));
UNLOCK_HTC_CREDIT(target);
target->HTCInitInfo.
TargetSendSuspendComplete((void *)
&wow_nack);
break;
}
cdf_nbuf_free(netbuf);
netbuf = NULL;
break;
}
/* the current message based HIF architecture allocates net bufs for recv packets
* since this layer bridges that HIF to upper layers , which expects HTC packets,
* we form the packets here
* TODO_FIXME */
pPacket = allocate_htc_packet_container(target);
if (NULL == pPacket) {
status = CDF_STATUS_E_RESOURCES;
break;
}
pPacket->Status = CDF_STATUS_SUCCESS;
pPacket->Endpoint = htc_ep_id;
pPacket->pPktContext = netbuf;
pPacket->pBuffer = cdf_nbuf_data(netbuf) + HTC_HDR_LENGTH;
pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen;
cdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN);
cdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength);
recv_packet_completion(target, pEndpoint, pPacket);
/* recover the packet container */
free_htc_packet_container(target, pPacket);
netbuf = NULL;
} while (false);
#ifdef RX_SG_SUPPORT
_out:
#endif
if (netbuf != NULL) {
cdf_nbuf_free(netbuf);
}
return status;
}
A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle,
HTC_PACKET_QUEUE *pPktQueue)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint;
HTC_PACKET *pFirstPacket;
A_STATUS status = A_OK;
HTC_PACKET *pPacket;
pFirstPacket = htc_get_pkt_at_head(pPktQueue);
if (NULL == pFirstPacket) {
A_ASSERT(false);
return A_EINVAL;
}
AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n",
pFirstPacket->Endpoint,
HTC_PACKET_QUEUE_DEPTH(pPktQueue),
pFirstPacket->BufferLength));
pEndpoint = &target->endpoint[pFirstPacket->Endpoint];
LOCK_HTC_RX(target);
do {
if (HTC_STOPPING(target)) {
status = A_ERROR;
break;
}
/* store receive packets */
HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,
pPktQueue);
} while (false);
UNLOCK_HTC_RX(target);
if (A_FAILED(status)) {
/* walk through queue and mark each one canceled */
HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
pPacket->Status = A_ECANCELED;
}
HTC_PACKET_QUEUE_ITERATE_END;
do_recv_completion(pEndpoint, pPktQueue);
}
return status;
}
A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
{
HTC_PACKET_QUEUE queue;
INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket);
return htc_add_receive_pkt_multiple(HTCHandle, &queue);
}
void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
{
HTC_PACKET *pPacket;
HTC_PACKET_QUEUE container;
LOCK_HTC_RX(target);
while (1) {
pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue);
if (NULL == pPacket) {
break;
}
UNLOCK_HTC_RX(target);
pPacket->Status = A_ECANCELED;
pPacket->ActualLength = 0;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
(" Flushing RX packet:%p, length:%d, ep:%d \n",
pPacket, pPacket->BufferLength,
pPacket->Endpoint));
INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket);
/* give the packet back */
do_recv_completion(pEndpoint, &container);
LOCK_HTC_RX(target);
}
UNLOCK_HTC_RX(target);
}
void htc_recv_init(HTC_TARGET *target)
{
/* Initialize ctrl_response_valid to block */
cdf_event_init(&target->ctrl_response_valid);
}
/* polling routine to wait for a control packet to be received */
A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target)
{
/* int count = HTC_TARGET_MAX_RESPONSE_POLL; */
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n"));
/* Wait for BMI request/response transaction to complete */
if (cdf_wait_single_event(&target->ctrl_response_valid,
cdf_system_msecs_to_ticks(HTC_CONTROL_RX_TIMEOUT))) {
CDF_BUG(0);
return A_ERROR;
}
LOCK_HTC_RX(target);
/* caller will clear this flag */
target->CtrlResponseProcessing = true;
UNLOCK_HTC_RX(target);
#if 0
while (count > 0) {
LOCK_HTC_RX(target);
if (target->CtrlResponseValid) {
target->CtrlResponseValid = false;
/* caller will clear this flag */
target->CtrlResponseProcessing = true;
UNLOCK_HTC_RX(target);
break;
}
UNLOCK_HTC_RX(target);
count--;
A_MSLEEP(HTC_TARGET_RESPONSE_POLL_MS);
}
if (count <= 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("-HTCWaitCtrlMessageRecv: Timeout!\n"));
return A_ECOMM;
}
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n"));
return A_OK;
}
static A_STATUS htc_process_trailer(HTC_TARGET *target,
A_UINT8 *pBuffer,
int Length, HTC_ENDPOINT_ID FromEndpoint)
{
HTC_RECORD_HDR *pRecord;
A_UINT8 htc_rec_id;
A_UINT8 htc_rec_len;
A_UINT8 *pRecordBuf;
A_UINT8 *pOrigBuffer;
int origLength;
A_STATUS status;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("+htc_process_trailer (length:%d) \n", Length));
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer");
}
pOrigBuffer = pBuffer;
origLength = Length;
status = A_OK;
while (Length > 0) {
if (Length < sizeof(HTC_RECORD_HDR)) {
status = A_EPROTO;
break;
}
/* these are byte aligned structs */
pRecord = (HTC_RECORD_HDR *) pBuffer;
Length -= sizeof(HTC_RECORD_HDR);
pBuffer += sizeof(HTC_RECORD_HDR);
htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH);
htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID);
if (htc_rec_len > Length) {
/* no room left in buffer for record */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
htc_rec_len, htc_rec_id, Length));
status = A_EPROTO;
break;
}
/* start of record follows the header */
pRecordBuf = pBuffer;
switch (htc_rec_id) {
case HTC_RECORD_CREDITS:
AR_DEBUG_ASSERT(htc_rec_len >=
sizeof(HTC_CREDIT_REPORT));
htc_process_credit_rpt(target,
(HTC_CREDIT_REPORT *) pRecordBuf,
htc_rec_len /
(sizeof(HTC_CREDIT_REPORT)),
FromEndpoint);
break;
#ifdef HIF_SDIO
case HTC_RECORD_LOOKAHEAD:
/* Process in HIF layer */
break;
case HTC_RECORD_LOOKAHEAD_BUNDLE:
/* Process in HIF layer */
break;
#endif /* HIF_SDIO */
default:
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" HTC unhandled record: id:%d length:%d \n",
htc_rec_id, htc_rec_len));
break;
}
if (A_FAILED(status)) {
break;
}
/* advance buffer past this record for next time around */
pBuffer += htc_rec_len;
Length -= htc_rec_len;
}
if (A_FAILED(status)) {
debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer");
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer \n"));
return status;
}

2002
htc/htc_send.c Normale Datei

Datei-Diff unterdrückt, da er zu groß ist Diff laden

369
htc/htc_services.c Normale Datei
Datei anzeigen

@@ -0,0 +1,369 @@
/*
* Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include "htc_debug.h"
#include "htc_internal.h"
#include <cdf_nbuf.h> /* cdf_nbuf_t */
#include "hif.h"
/* use credit flow control over HTC */
unsigned int htc_credit_flow = 1;
#ifndef DEBUG_CREDIT
#define DEBUG_CREDIT 0
#endif
A_STATUS htc_connect_service(HTC_HANDLE HTCHandle,
HTC_SERVICE_CONNECT_REQ *pConnectReq,
HTC_SERVICE_CONNECT_RESP *pConnectResp)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
A_STATUS status = A_OK;
HTC_PACKET *pSendPacket = NULL;
HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
HTC_CONNECT_SERVICE_MSG *pConnectMsg;
HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
HTC_ENDPOINT *pEndpoint;
unsigned int maxMsgSize = 0;
cdf_nbuf_t netbuf;
A_UINT8 txAlloc;
int length;
A_BOOL disableCreditFlowCtrl = false;
A_UINT16 conn_flags;
A_UINT16 rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size;
A_UINT8 rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("+htc_connect_service, target:%p SvcID:0x%X\n", target,
pConnectReq->service_id));
do {
AR_DEBUG_ASSERT(pConnectReq->service_id != 0);
if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) {
/* special case for pseudo control service */
assignedEndpoint = ENDPOINT_0;
maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
txAlloc = 0;
} else {
txAlloc = htc_get_credit_allocation(target,
pConnectReq->service_id);
if (!txAlloc) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("Service %d does not allocate target credits!\n",
pConnectReq->service_id));
}
/* allocate a packet to send to the target */
pSendPacket = htc_alloc_control_tx_packet(target);
if (NULL == pSendPacket) {
AR_DEBUG_ASSERT(false);
status = A_NO_MEMORY;
break;
}
netbuf =
(cdf_nbuf_t)
GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
length =
sizeof(HTC_CONNECT_SERVICE_MSG) +
pConnectReq->MetaDataLength;
/* assemble connect service message */
cdf_nbuf_put_tail(netbuf, length);
pConnectMsg =
(HTC_CONNECT_SERVICE_MSG *) cdf_nbuf_data(netbuf);
if (NULL == pConnectMsg) {
AR_DEBUG_ASSERT(0);
status = A_EFAULT;
break;
}
A_MEMZERO(pConnectMsg, sizeof(HTC_CONNECT_SERVICE_MSG));
conn_flags =
(pConnectReq->
ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) |
HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc);
HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID);
HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
SERVICE_ID, pConnectReq->service_id);
HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG,
CONNECTIONFLAGS, conn_flags);
if (pConnectReq->
ConnectionFlags &
HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) {
disableCreditFlowCtrl = true;
}
#if defined(HIF_USB)
if (!htc_credit_flow) {
disableCreditFlowCtrl = true;
}
#else
/* Only enable credit for WMI service */
if (!htc_credit_flow
&& pConnectReq->service_id != WMI_CONTROL_SVC) {
disableCreditFlowCtrl = true;
}
#endif
/* check caller if it wants to transfer meta data */
if ((pConnectReq->pMetaData != NULL) &&
(pConnectReq->MetaDataLength <=
HTC_SERVICE_META_DATA_MAX_LENGTH)) {
/* copy meta data into message buffer (after header ) */
A_MEMCPY((A_UINT8 *) pConnectMsg +
sizeof(HTC_CONNECT_SERVICE_MSG),
pConnectReq->pMetaData,
pConnectReq->MetaDataLength);
HTC_SET_FIELD(pConnectMsg,
HTC_CONNECT_SERVICE_MSG,
SERVICEMETALENGTH,
pConnectReq->MetaDataLength);
}
SET_HTC_PACKET_INFO_TX(pSendPacket,
NULL,
(A_UINT8 *) pConnectMsg,
length,
ENDPOINT_0,
HTC_SERVICE_TX_PACKET_TAG);
status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
/* we don't own it anymore */
pSendPacket = NULL;
if (A_FAILED(status)) {
break;
}
/* wait for response */
status = htc_wait_recv_ctrl_message(target);
if (A_FAILED(status)) {
break;
}
/* we controlled the buffer creation so it has to be properly aligned */
pResponseMsg =
(HTC_CONNECT_SERVICE_RESPONSE_MSG *) target->
CtrlResponseBuffer;
rsp_msg_id = HTC_GET_FIELD(pResponseMsg,
HTC_CONNECT_SERVICE_RESPONSE_MSG,
MESSAGEID);
rsp_msg_serv_id =
HTC_GET_FIELD(pResponseMsg,
HTC_CONNECT_SERVICE_RESPONSE_MSG,
SERVICEID);
rsp_msg_status =
HTC_GET_FIELD(pResponseMsg,
HTC_CONNECT_SERVICE_RESPONSE_MSG,
STATUS);
rsp_msg_end_id =
HTC_GET_FIELD(pResponseMsg,
HTC_CONNECT_SERVICE_RESPONSE_MSG,
ENDPOINTID);
rsp_msg_max_msg_size =
HTC_GET_FIELD(pResponseMsg,
HTC_CONNECT_SERVICE_RESPONSE_MSG,
MAXMSGSIZE);
rsp_msg_serv_meta_len =
HTC_GET_FIELD(pResponseMsg,
HTC_CONNECT_SERVICE_RESPONSE_MSG,
SERVICEMETALENGTH);
if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID)
|| (target->CtrlResponseLength <
sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
/* this message is not valid */
AR_DEBUG_ASSERT(false);
status = A_EPROTO;
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n",
rsp_msg_serv_id, rsp_msg_status,
rsp_msg_end_id));
pConnectResp->ConnectRespCode = rsp_msg_status;
/* check response status */
if (rsp_msg_status != HTC_SERVICE_SUCCESS) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" Target failed service 0x%X connect request (status:%d)\n",
rsp_msg_serv_id,
rsp_msg_status));
status = A_EPROTO;
#ifdef QCA_TX_HTT2_SUPPORT
/* Keep work and not to block the control message. */
target->CtrlResponseProcessing = false;
#endif /* QCA_TX_HTT2_SUPPORT */
break;
}
assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id;
maxMsgSize = rsp_msg_max_msg_size;
if ((pConnectResp->pMetaData != NULL) &&
(rsp_msg_serv_meta_len > 0) &&
(rsp_msg_serv_meta_len <=
HTC_SERVICE_META_DATA_MAX_LENGTH)) {
/* caller supplied a buffer and the target responded with data */
int copyLength =
min((int)pConnectResp->BufferLength,
(int)rsp_msg_serv_meta_len);
/* copy the meta data */
A_MEMCPY(pConnectResp->pMetaData,
((A_UINT8 *) pResponseMsg) +
sizeof
(HTC_CONNECT_SERVICE_RESPONSE_MSG),
copyLength);
pConnectResp->ActualLength = copyLength;
}
/* done processing response buffer */
target->CtrlResponseProcessing = false;
}
/* the rest of these are parameter checks so set the error status */
status = A_EPROTO;
if (assignedEndpoint >= ENDPOINT_MAX) {
AR_DEBUG_ASSERT(false);
break;
}
if (0 == maxMsgSize) {
AR_DEBUG_ASSERT(false);
break;
}
pEndpoint = &target->endpoint[assignedEndpoint];
pEndpoint->Id = assignedEndpoint;
if (pEndpoint->service_id != 0) {
/* endpoint already in use! */
AR_DEBUG_ASSERT(false);
break;
}
/* return assigned endpoint to caller */
pConnectResp->Endpoint = assignedEndpoint;
pConnectResp->MaxMsgLength = maxMsgSize;
/* setup the endpoint */
/* service_id marks the endpoint in use */
pEndpoint->service_id = pConnectReq->service_id;
pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
pEndpoint->MaxMsgLength = maxMsgSize;
pEndpoint->TxCredits = txAlloc;
pEndpoint->TxCreditSize = target->TargetCreditSize;
pEndpoint->TxCreditsPerMaxMsg =
maxMsgSize / target->TargetCreditSize;
if (maxMsgSize % target->TargetCreditSize) {
pEndpoint->TxCreditsPerMaxMsg++;
}
#if DEBUG_CREDIT
cdf_print(" Endpoint%d initial credit:%d, size:%d.\n",
pEndpoint->Id, pEndpoint->TxCredits,
pEndpoint->TxCreditSize);
#endif
/* copy all the callbacks */
pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
status = hif_map_service_to_pipe(target->hif_dev,
pEndpoint->service_id,
&pEndpoint->UL_PipeID,
&pEndpoint->DL_PipeID,
&pEndpoint->ul_is_polled,
&pEndpoint->dl_is_polled);
if (A_FAILED(status)) {
break;
}
cdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */
if (pEndpoint->ul_is_polled) {
cdf_softirq_timer_init(target->osdev,
&pEndpoint->ul_poll_timer,
htc_send_complete_check_cleanup,
pEndpoint,
CDF_TIMER_TYPE_SW);
}
AR_DEBUG_PRINTF(ATH_DEBUG_SETUP,
("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n",
pEndpoint->service_id, pEndpoint->UL_PipeID,
pEndpoint->DL_PipeID, pEndpoint->Id));
if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) {
pEndpoint->TxCreditFlowEnabled = false;
AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
("HTC Service:0x%4.4X ep:%d TX flow control disabled\n",
pEndpoint->service_id,
assignedEndpoint));
}
} while (false);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service \n"));
return status;
}
void htc_set_credit_distribution(HTC_HANDLE HTCHandle,
void *pCreditDistContext,
HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
HTC_SERVICE_ID ServicePriorityOrder[],
int ListLength)
{
/* NOT Supported, this transport does not use a credit based flow control mechanism */
}
void htc_fw_event_handler(void *context, CDF_STATUS status)
{
HTC_TARGET *target = (HTC_TARGET *) context;
HTC_INIT_INFO *initInfo = &target->HTCInitInfo;
/* check if target failure handler exists and pass error code to it. */
if (target->HTCInitInfo.TargetFailure != NULL) {
initInfo->TargetFailure(initInfo->pContext, status);
}
}
/* Disable ASPM : disable PCIe low power */
void htc_disable_aspm(void)
{
hif_disable_aspm();
}