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:
208
htc/dl_list.h
Normale Datei
208
htc/dl_list.h
Normale Datei
@@ -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
881
htc/htc.c
Normale Datei
@@ -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
718
htc/htc_api.h
Normale Datei
@@ -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
50
htc/htc_debug.h
Normale Datei
@@ -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
317
htc/htc_internal.h
Normale Datei
@@ -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
280
htc/htc_packet.h
Normale Datei
@@ -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
749
htc/htc_recv.c
Normale Datei
@@ -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
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
369
htc/htc_services.c
Normale Datei
@@ -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();
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren