android_kernel_xiaomi_sm8350/core/htc/htc.c
Chandrasekaran, Manishekar 0d814c7b3e qcacld-3.0: Move cds_get_bin.c to concurrency management files
cds_get_bin.h and cds_get_bin.c were derived from qcacld-2.0
vos_get_bin.h and vos_get_bin.c.  These files got their names
since at one time they housed the wrappers used to retrieve
binary files nv.bin, cfg.dat, and firmware.  But over time the
functionality to actually retrieve binary files (get_bin) has
been removed, and almost all that is left is concurrency
management functions.  So, moving the .[ch] functionality to
the right files.

CRs-Fixed: 932777
Change-Id: I4a26c304cc6b6224d0839c365e4006fd32270961
2015-11-23 13:09:04 -08:00

817 lines
22 KiB
C

/*
* 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 "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"
#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));
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));
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->ServiceID = 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->ServiceID = WMI_DATA_BE_SVC;
pEntry->CreditAllocation = (credits >> 1);
pEntry++;
pEntry->ServiceID = 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].ServiceID != 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("HTC Service Index : %d TX : 0x%2.2X : alloc:%d \n",
i,
target->ServiceTxAllocTable[i].
ServiceID,
target->ServiceTxAllocTable[i].
CreditAllocation));
}
}
}
return status;
}
A_UINT8 htc_get_credit_allocation(HTC_TARGET *target, A_UINT16 ServiceID)
{
A_UINT8 allocation = 0;
int i;
for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
if (target->ServiceTxAllocTable[i].ServiceID == ServiceID) {
allocation =
target->ServiceTxAllocTable[i].CreditAllocation;
}
}
if (0 == allocation) {
AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
("HTC Service TX : 0x%2.2X : allocation is zero! \n",
ServiceID));
}
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.ServiceID = 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->ServiceID = 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"));
}
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->ServiceID) {
continue;
}
AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
("--- EP : %d ServiceID: 0x%X --------------\n",
pEndpoint->Id, pEndpoint->ServiceID));
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].EndPointStats,
sizeof(HTC_ENDPOINT_STATS));
}
if (clearStats) {
/* reset stats */
A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats,
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
void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle,
uint32_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 */