qcacmn: Genoa: SDIO: Handle Tx Padding & Credits
In Genoa SDIO ADMA implementation Host sends packets to FW in multiples of SDIO Block size. If the packet/bundle is not block aligned Host adds padding at the end of Packet/Bundle. If the TX packet plus padding exceeds one FW TX Buffer, Padding data will occupy the next FW TX buffer. Same applies for bundle TX packet. For above scenario, HTC_FLAGS_PADDING_CHECK of HTC header Flags is used to notify the FW that - Padding data follows the currentHTC packet Since the padding data will take one extra FW Tx Buffer, host need to handle the extra Tx credit being used by the padding data/buffer CRs-Fixed: 2516617 Change-Id: I1eb394859689b281653bfd6d681804eb016a14cf
This commit is contained in:
222
htc/htc_send.c
222
htc/htc_send.c
@@ -398,6 +398,103 @@ static QDF_STATUS htc_send_bundled_netbuf(HTC_TARGET *target,
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef QCA_TX_PADDING_CREDIT_SUPPORT
|
||||
#define SDIO_BLOCK_SIZE 512
|
||||
static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!ep || !ep->EpCallBacks.pContext ||
|
||||
!ep->EpCallBacks.ep_padding_credit_update)
|
||||
return 1;
|
||||
|
||||
ret = ep->EpCallBacks.ep_padding_credit_update(ep->EpCallBacks.pContext,
|
||||
0);
|
||||
|
||||
if (ret < 2)
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s ret %d\n", __func__, ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
|
||||
HTC_PACKET *p_last_htc_pkt,
|
||||
unsigned char *p_last_pkt_bundle_buffer,
|
||||
unsigned char **p_bundle_buffer,
|
||||
int tot_data_len)
|
||||
{
|
||||
bool extra_tx_credit = FALSE;
|
||||
HTC_FRAME_HDR *p_htc_hdr;
|
||||
int first_buf_bundled_len = 0, last_buf_len = 0;
|
||||
int sdio_pad = 0, free_space = 0;
|
||||
int (*update_ep_padding_credit)(void *, int);
|
||||
|
||||
update_ep_padding_credit = ep->EpCallBacks.ep_padding_credit_update;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("%s Tot data_len = %d\n", __func__, tot_data_len));
|
||||
|
||||
if (!p_last_htc_pkt)
|
||||
return extra_tx_credit;
|
||||
|
||||
last_buf_len = (p_last_htc_pkt->ActualLength + HTC_HDR_LENGTH);
|
||||
if (tot_data_len != last_buf_len) {
|
||||
first_buf_bundled_len = tot_data_len - ep->TxCreditSize;
|
||||
free_space = tot_data_len -
|
||||
(first_buf_bundled_len + last_buf_len);
|
||||
} else {
|
||||
free_space = ep->TxCreditSize - tot_data_len;
|
||||
}
|
||||
|
||||
sdio_pad = SDIO_BLOCK_SIZE - ((first_buf_bundled_len + last_buf_len) %
|
||||
SDIO_BLOCK_SIZE);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("%s first_buf_bundled_len = %d last_buf_len = %d\n",
|
||||
__func__, first_buf_bundled_len, last_buf_len));
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("%s sdio_pad = %d free_space = %d\n", __func__,
|
||||
sdio_pad, free_space));
|
||||
|
||||
if (sdio_pad <= free_space) {
|
||||
if (p_bundle_buffer && *p_bundle_buffer) {
|
||||
/* Align Tx bundled buf to avoid a extra Padding buf */
|
||||
*p_bundle_buffer -= (free_space - sdio_pad);
|
||||
}
|
||||
} else {
|
||||
/* Extra Padding Buffer needed, consume extra tx credit */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("%s Used a Tx credit for Padding Buffer\n",
|
||||
__func__));
|
||||
p_htc_hdr = (HTC_FRAME_HDR *)(p_last_pkt_bundle_buffer);
|
||||
p_htc_hdr->Flags |= HTC_FLAGS_PADDING_CHECK;
|
||||
extra_tx_credit = TRUE;
|
||||
if (ep->EpCallBacks.ep_padding_credit_update) {
|
||||
/* Decrement 1 credit at host,
|
||||
* due to extra tx credit consumed by padding buffer
|
||||
*/
|
||||
update_ep_padding_credit(ep->EpCallBacks.pContext, -1);
|
||||
}
|
||||
}
|
||||
return extra_tx_credit;
|
||||
}
|
||||
#else
|
||||
static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
|
||||
HTC_PACKET *p_last_htc_pkt,
|
||||
unsigned char *p_last_pkt_bundle_buffer,
|
||||
unsigned char **p_bundle_buffer,
|
||||
int tot_data_len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* htc_issue_packets_bundle() - HTC function to send bundle packets from a queue
|
||||
* @target: HTC target on which packets need to be sent
|
||||
@@ -419,6 +516,8 @@ static void htc_issue_packets_bundle(HTC_TARGET *target,
|
||||
int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining =
|
||||
0;
|
||||
HTC_PACKET_QUEUE *pQueueSave = NULL;
|
||||
HTC_PACKET *p_last_htc_pkt = NULL;
|
||||
unsigned char *p_last_pkt_bundle_buffer = NULL;
|
||||
|
||||
bundlesSpaceRemaining =
|
||||
target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize;
|
||||
@@ -434,6 +533,10 @@ static void htc_issue_packets_bundle(HTC_TARGET *target,
|
||||
pBundleBuffer = qdf_nbuf_data(bundleBuf);
|
||||
pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
|
||||
while (1) {
|
||||
if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
|
||||
if (htc_tx_pad_credit_avail(pEndpoint) < 1)
|
||||
break;
|
||||
}
|
||||
pPacket = htc_packet_dequeue(pPktQueue);
|
||||
if (!pPacket)
|
||||
break;
|
||||
@@ -451,6 +554,12 @@ static void htc_issue_packets_bundle(HTC_TARGET *target,
|
||||
}
|
||||
|
||||
if (bundlesSpaceRemaining < transferLength) {
|
||||
htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt,
|
||||
p_last_pkt_bundle_buffer,
|
||||
&pBundleBuffer,
|
||||
pBundleBuffer -
|
||||
qdf_nbuf_data(bundleBuf));
|
||||
|
||||
/* send out previous buffer */
|
||||
htc_send_bundled_netbuf(target, pEndpoint,
|
||||
pBundleBuffer - last_credit_pad,
|
||||
@@ -480,6 +589,9 @@ static void htc_issue_packets_bundle(HTC_TARGET *target,
|
||||
pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
|
||||
}
|
||||
|
||||
p_last_htc_pkt = pPacket;
|
||||
p_last_pkt_bundle_buffer = pBundleBuffer;
|
||||
|
||||
bundlesSpaceRemaining -= transferLength;
|
||||
netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
|
||||
|
||||
@@ -528,15 +640,41 @@ static void htc_issue_packets_bundle(HTC_TARGET *target,
|
||||
last_credit_pad = creditPad;
|
||||
}
|
||||
/* send out remaining buffer */
|
||||
if (pBundleBuffer != qdf_nbuf_data(bundleBuf))
|
||||
if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) {
|
||||
htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt,
|
||||
p_last_pkt_bundle_buffer,
|
||||
&pBundleBuffer,
|
||||
pBundleBuffer -
|
||||
qdf_nbuf_data(bundleBuf));
|
||||
|
||||
htc_send_bundled_netbuf(target, pEndpoint,
|
||||
pBundleBuffer - last_credit_pad,
|
||||
pPacketTx);
|
||||
else
|
||||
} else {
|
||||
free_htc_bundle_packet(target, pPacketTx);
|
||||
}
|
||||
}
|
||||
#endif /* ENABLE_BUNDLE_TX */
|
||||
#else
|
||||
static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
|
||||
HTC_PACKET *p_last_htc_pkt,
|
||||
unsigned char *p_last_pkt_bundle_buffer,
|
||||
unsigned char **p_bundle_buffer,
|
||||
int tot_data_len);
|
||||
bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
|
||||
HTC_PACKET *p_last_htc_pkt,
|
||||
unsigned char *p_last_pkt_bundle_buffer,
|
||||
unsigned char **p_bundle_buffer,
|
||||
int tot_data_len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void htc_issue_packets_bundle(HTC_TARGET *target,
|
||||
HTC_ENDPOINT *pEndpoint,
|
||||
HTC_PACKET_QUEUE *pPktQueue)
|
||||
@@ -565,6 +703,13 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
|
||||
enum qdf_bus_type bus_type;
|
||||
QDF_STATUS ret;
|
||||
bool rt_put = false;
|
||||
bool used_extra_tx_credit = false;
|
||||
uint8_t *buf = NULL;
|
||||
int (*update_ep_padding_credit)(void *, int);
|
||||
void *ctx = NULL;
|
||||
|
||||
update_ep_padding_credit =
|
||||
pEndpoint->EpCallBacks.ep_padding_credit_update;
|
||||
|
||||
bus_type = hif_get_bus_type(target->hif_dev);
|
||||
|
||||
@@ -579,6 +724,11 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
|
||||
case QDF_BUS_TYPE_SDIO:
|
||||
if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
|
||||
break;
|
||||
if (update_ep_padding_credit) {
|
||||
if (htc_tx_pad_credit_avail
|
||||
(pEndpoint) < 1)
|
||||
break;
|
||||
}
|
||||
case QDF_BUS_TYPE_USB:
|
||||
htc_issue_packets_bundle(target,
|
||||
pEndpoint,
|
||||
@@ -591,6 +741,13 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
|
||||
/* if not bundling or there was a packet that could not be
|
||||
* placed in a bundle, and send it by normal way
|
||||
*/
|
||||
if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
|
||||
if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
|
||||
status = QDF_STATUS_E_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pPacket = htc_packet_dequeue(pPktQueue);
|
||||
if (!pPacket) {
|
||||
/* local queue is fully drained */
|
||||
@@ -678,11 +835,26 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
|
||||
pEndpoint->TxCreditSize,
|
||||
HTC_HDR_LENGTH + pPacket->ActualLength);
|
||||
#endif
|
||||
buf = (uint8_t *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
|
||||
used_extra_tx_credit =
|
||||
htc_handle_extra_tx_credit(pEndpoint, pPacket, buf,
|
||||
NULL, pPacket->ActualLength +
|
||||
HTC_HDR_LENGTH);
|
||||
|
||||
status = hif_send_head(target->hif_dev,
|
||||
pEndpoint->UL_PipeID, pEndpoint->Id,
|
||||
HTC_HDR_LENGTH + pPacket->ActualLength,
|
||||
netbuf, data_attr);
|
||||
|
||||
if (status != QDF_STATUS_SUCCESS) {
|
||||
if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
|
||||
if (used_extra_tx_credit) {
|
||||
ctx = pEndpoint->EpCallBacks.pContext;
|
||||
update_ep_padding_credit(ctx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
htc_issue_tx_bundle_stats_inc(target);
|
||||
|
||||
target->ce_send_cnt++;
|
||||
@@ -1690,6 +1862,7 @@ QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
|
||||
int tx_resources;
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
uint32_t data_attr = 0;
|
||||
bool used_extra_tx_credit = false;
|
||||
|
||||
if (pPacket) {
|
||||
if ((pPacket->Endpoint >= ENDPOINT_MAX) ||
|
||||
@@ -1834,12 +2007,41 @@ QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
|
||||
HTC_MIN_MSG_PER_BUNDLE) &&
|
||||
(hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO ||
|
||||
hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) {
|
||||
if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
|
||||
if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
|
||||
status = QDF_STATUS_E_RESOURCES;
|
||||
/* put the sendQueue back at the front
|
||||
* of pEndpoint->TxQueue
|
||||
*/
|
||||
LOCK_HTC_TX(target);
|
||||
HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(
|
||||
&pEndpoint->TxQueue,
|
||||
&sendQueue);
|
||||
UNLOCK_HTC_TX(target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
htc_issue_packets_bundle(target, pEndpoint, &sendQueue);
|
||||
}
|
||||
if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
|
||||
if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
|
||||
status = QDF_STATUS_E_RESOURCES;
|
||||
/* put the sendQueue back at the front
|
||||
* of pEndpoint->TxQueue
|
||||
*/
|
||||
LOCK_HTC_TX(target);
|
||||
HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(
|
||||
&pEndpoint->TxQueue,
|
||||
&sendQueue);
|
||||
UNLOCK_HTC_TX(target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pPacket = htc_packet_dequeue(&sendQueue);
|
||||
if (!pPacket)
|
||||
break;
|
||||
netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
|
||||
pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
|
||||
|
||||
LOCK_HTC_TX(target);
|
||||
/* store in look up queue to match completions */
|
||||
@@ -1848,11 +2050,27 @@ QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
|
||||
pEndpoint->ul_outstanding_cnt++;
|
||||
UNLOCK_HTC_TX(target);
|
||||
|
||||
used_extra_tx_credit =
|
||||
htc_handle_extra_tx_credit(pEndpoint, pPacket,
|
||||
(uint8_t *)pHtcHdr,
|
||||
NULL,
|
||||
pPacket->ActualLength
|
||||
+ HTC_HDR_LENGTH);
|
||||
|
||||
status = hif_send_head(target->hif_dev,
|
||||
pEndpoint->UL_PipeID,
|
||||
pEndpoint->Id,
|
||||
HTC_HDR_LENGTH + pPacket->ActualLength,
|
||||
netbuf, data_attr);
|
||||
if (status != QDF_STATUS_SUCCESS) {
|
||||
if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
|
||||
if (used_extra_tx_credit) {
|
||||
pEndpoint->EpCallBacks.
|
||||
ep_padding_credit_update
|
||||
(pEndpoint->EpCallBacks.pContext, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if DEBUG_BUNDLE
|
||||
qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.",
|
||||
pEndpoint->Id,
|
||||
|
Reference in New Issue
Block a user