Merge "qca-wifi: Fix monitor mode ppdu id mismatch issue for qcn9000"

このコミットが含まれているのは:
Linux Build Service Account
2020-05-07 11:40:34 -07:00
committed by Gerrit - the friendly Code Review server
コミット 051a4a29e0

ファイルの表示

@@ -34,6 +34,184 @@ dp_rx_mon_status_process(struct dp_soc *soc,
uint32_t mac_id,
uint32_t quota);
/*
* dp_rx_mon_status_buf_validate () - Validate first monitor status buffer addr
* against status buf addr given in monitor destination ring
*
* @pdev: DP pdev handle
* @mac_id: lmac id
*
* Return: QDF_STATUS
*/
static inline QDF_STATUS
dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t mac_id)
{
struct dp_soc *soc = pdev->soc;
hal_soc_handle_t hal_soc;
void *mon_status_srng;
void *ring_entry;
uint32_t rx_buf_cookie;
qdf_nbuf_t status_nbuf;
struct dp_rx_desc *rx_desc;
uint64_t buf_paddr;
struct rx_desc_pool *rx_desc_pool;
uint32_t tlv_tag;
void *rx_tlv;
struct hal_rx_ppdu_info *ppdu_info;
QDF_STATUS status = QDF_STATUS_E_FAILURE;
QDF_STATUS buf_status;
mon_status_srng = soc->rxdma_mon_status_ring[mac_id].hal_srng;
qdf_assert(mon_status_srng);
if (!mon_status_srng || !hal_srng_initialized(mon_status_srng)) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
"%s %d : HAL Monitor Status Ring Init Failed -- %pK",
__func__, __LINE__, mon_status_srng);
return status;
}
hal_soc = soc->hal_soc;
qdf_assert(hal_soc);
if (qdf_unlikely(hal_srng_access_start(hal_soc, mon_status_srng))) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
"%s %d : HAL SRNG access Failed -- %pK",
__func__, __LINE__, mon_status_srng);
return status;
}
ring_entry = hal_srng_src_peek_n_get_next(hal_soc, mon_status_srng);
if (!ring_entry) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
"%s %d : HAL SRNG entry is NULL srng:-- %pK",
__func__, __LINE__, mon_status_srng);
goto done;
}
ppdu_info = &pdev->ppdu_info;
rx_desc_pool = &soc->rx_desc_status[mac_id];
buf_paddr = (HAL_RX_BUFFER_ADDR_31_0_GET(ring_entry) |
((uint64_t)(HAL_RX_BUFFER_ADDR_39_32_GET(ring_entry)) << 32));
if (!buf_paddr) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
"%s %d : buf addr is NULL -- %pK",
__func__, __LINE__, mon_status_srng);
goto done;
}
rx_buf_cookie = HAL_RX_BUF_COOKIE_GET(ring_entry);
rx_desc = dp_rx_cookie_2_va_mon_status(soc, rx_buf_cookie);
qdf_assert(rx_desc);
status_nbuf = rx_desc->nbuf;
qdf_nbuf_sync_for_cpu(soc->osdev, status_nbuf,
QDF_DMA_FROM_DEVICE);
rx_tlv = qdf_nbuf_data(status_nbuf);
buf_status = hal_get_rx_status_done(rx_tlv);
/* If status buffer DMA is not done,
* hold on to mon destination ring.
*/
if (buf_status != QDF_STATUS_SUCCESS) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor status ring: DMA is not done "
"for nbuf: %pK buf_addr: %llx"),
status_nbuf, buf_paddr);
pdev->rx_mon_stats.tlv_tag_status_err++;
pdev->hold_mon_dest_ring = true;
goto done;
}
qdf_nbuf_unmap_nbytes_single(soc->osdev, status_nbuf,
QDF_DMA_FROM_DEVICE,
rx_desc_pool->buf_size);
rx_tlv = hal_rx_status_get_next_tlv(rx_tlv);
tlv_tag = HAL_RX_GET_USER_TLV32_TYPE(rx_tlv);
if (tlv_tag == WIFIRX_PPDU_START_E) {
rx_tlv = (uint8_t *)rx_tlv + HAL_RX_TLV32_HDR_SIZE;
ppdu_info->com_info.ppdu_id = HAL_RX_GET(rx_tlv,
RX_PPDU_START_0,
PHY_PPDU_ID);
pdev->status_buf_addr = buf_paddr;
}
/* If Monitor destination ring is on hold and ppdu id matches,
* deliver PPDU data which was on hold.
*/
if (pdev->hold_mon_dest_ring &&
(pdev->mon_desc->ppdu_id == pdev->ppdu_info.com_info.ppdu_id)) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor destination was on Hold "
"PPDU id matched"));
pdev->hold_mon_dest_ring = false;
goto done;
}
if ((pdev->mon_desc->status_buf.paddr != buf_paddr) ||
(pdev->mon_desc->ppdu_id != pdev->ppdu_info.com_info.ppdu_id)) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor: PPDU id or status buf_addr mismatch "
"status_ppdu_id: %d dest_ppdu_id: %d "
"status_addr: %llx status_buf_cookie: %d "
"dest_addr: %llx tlv_tag: %d"
" status_nbuf: %pK"),
pdev->ppdu_info.com_info.ppdu_id,
pdev->mon_desc->ppdu_id, pdev->status_buf_addr,
rx_buf_cookie,
pdev->mon_desc->status_buf.paddr, tlv_tag,
status_nbuf);
}
/* Monitor Status ring is reaped in two cases:
* a. If first status buffer's buf_addr_info matches
* with latched status buffer addr info in monitor
* destination ring.
* b. If monitor status ring is lagging behind
* monitor destination ring. Hold on to monitor
* destination ring in this case until status ring
* and destination ring ppdu id matches.
*/
if ((pdev->mon_desc->status_buf.paddr == buf_paddr) ||
(pdev->mon_desc->ppdu_id > pdev->ppdu_info.com_info.ppdu_id)) {
if (pdev->mon_desc->ppdu_id >
pdev->ppdu_info.com_info.ppdu_id) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor status ring is lagging behind "
"monitor destination ring "
"status_ppdu_id: %d dest_ppdu_id: %d "
"status_nbuf: %pK tlv_tag: %d "
"status_addr: %llx dest_addr: %llx "),
ppdu_info->com_info.ppdu_id,
pdev->mon_desc->ppdu_id,
status_nbuf, tlv_tag,
pdev->status_buf_addr,
pdev->mon_desc->status_buf.paddr);
pdev->rx_mon_stats.ppdu_id_mismatch++;
pdev->rx_mon_stats.status_ppdu_drop++;
pdev->hold_mon_dest_ring = true;
}
status = QDF_STATUS_SUCCESS;
}
done:
hal_srng_access_end(hal_soc, mon_status_srng);
return status;
}
/*
* dp_rx_mon_prepare_mon_mpdu () - API to prepare dp_mon_mpdu object
*
@@ -52,7 +230,7 @@ dp_rx_mon_prepare_mon_mpdu(struct dp_pdev *pdev,
mon_mpdu = qdf_mem_malloc(sizeof(struct dp_mon_mpdu));
if (!mon_mpdu) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor MPDU object allocation failed -- %pK"),
pdev);
qdf_assert_always(0);
@@ -69,6 +247,40 @@ dp_rx_mon_prepare_mon_mpdu(struct dp_pdev *pdev,
return mon_mpdu;
}
static inline void
dp_rx_mon_drop_ppdu(struct dp_pdev *pdev, uint32_t mac_id)
{
struct dp_mon_mpdu *mpdu = NULL;
struct dp_mon_mpdu *temp_mpdu = NULL;
qdf_nbuf_t mon_skb, skb_next;
if (!TAILQ_EMPTY(&pdev->mon_mpdu_q)) {
TAILQ_FOREACH_SAFE(mpdu,
&pdev->mon_mpdu_q,
mpdu_list_elem,
temp_mpdu) {
TAILQ_REMOVE(&pdev->mon_mpdu_q,
mpdu, mpdu_list_elem);
mon_skb = mpdu->head;
while (mon_skb) {
skb_next = qdf_nbuf_next(mon_skb);
QDF_TRACE(QDF_MODULE_ID_DP,
QDF_TRACE_LEVEL_DEBUG,
"[%s][%d] mon_skb=%pK len %u"
" __func__, __LINE__",
mon_skb, mon_skb->len);
qdf_nbuf_free(mon_skb);
mon_skb = skb_next;
}
qdf_mem_free(mpdu);
}
}
}
/*
* dp_rx_monitor_deliver_ppdu () - API to deliver all MPDU for a MPDU
* to upper layer stack
@@ -128,21 +340,39 @@ dp_rx_mon_reap_status_ring(struct dp_soc *soc,
uint32_t work_done = 0;
status_buf_count = desc_info->status_buf_count;
desc_info->drop_ppdu = false;
status_reap:
work_done += dp_rx_mon_status_process(soc, mac_id, status_buf_count);
if (dp_rx_mon_status_buf_validate(pdev, mac_id) == QDF_STATUS_SUCCESS)
work_done = dp_rx_mon_status_process(soc,
mac_id,
status_buf_count);
if (desc_info->ppdu_id != pdev->ppdu_info.com_info.ppdu_id) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor: PPDU id mismatch "
"status_ppdu_id: %d dest_ppdu_id: %d "
"status_addr: %llx dest_addr: %llx "
"count: %d quota: %d work_done: %d "),
pdev->ppdu_info.com_info.ppdu_id,
pdev->mon_desc->ppdu_id, pdev->status_buf_addr,
pdev->mon_desc->status_buf.paddr,
status_buf_count, quota, work_done);
}
if (desc_info->ppdu_id < pdev->ppdu_info.com_info.ppdu_id) {
pdev->rx_mon_stats.ppdu_id_mismatch++;
desc_info->drop_ppdu = true;
pdev->rx_mon_stats.dest_ppdu_drop++;
qdf_err("count: %d quota: %d work_done: %d status_ppdu_id: %d"
"dest_ppdu_id: %d ", status_buf_count, quota,
work_done,
pdev->ppdu_info.com_info.ppdu_id,
desc_info->ppdu_id);
if (desc_info->ppdu_id > pdev->ppdu_info.com_info.ppdu_id)
goto status_reap;
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Monitor destination ring is lagging behind "
"monitor status ring "
"status_ppdu_id: %d dest_ppdu_id: %d "
"status_addr: %llx dest_addr: %llx "),
pdev->ppdu_info.com_info.ppdu_id,
pdev->mon_desc->ppdu_id,
pdev->status_buf_addr,
pdev->mon_desc->status_buf.paddr);
}
return work_done;
@@ -347,6 +577,63 @@ next_msdu:
return rx_buf_reaped;
}
/*
* dp_rx_mon_deliver_prev_ppdu () - Deliver previous PPDU
*
* @pdev: DP pdev handle
* @mac_id: lmac id
* @quota: quota
*
* Return: remaining qouta
*/
static inline uint32_t
dp_rx_mon_deliver_prev_ppdu(struct dp_pdev *pdev,
uint32_t mac_id,
uint32_t quota)
{
struct dp_soc *soc = pdev->soc;
struct hal_rx_mon_desc_info *desc_info = pdev->mon_desc;
uint32_t work_done = 0;
bool hold_mon_dest_ring = false;
while (pdev->hold_mon_dest_ring) {
if (dp_rx_mon_status_buf_validate(pdev, mac_id) == QDF_STATUS_SUCCESS) {
work_done = dp_rx_mon_status_process(soc, mac_id, 1);
}
quota -= work_done;
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
FL("Hold on Monitor destination ring "
"work_done: %d quota: %d status_ppdu_id: %d "
"dest_ppdu_id: %d s_addr: %llx d_addr: %llx "),
work_done, quota,
pdev->ppdu_info.com_info.ppdu_id,
desc_info->ppdu_id, pdev->status_buf_addr,
desc_info->status_buf.paddr);
hold_mon_dest_ring = true;
if (!quota)
return quota;
}
if (hold_mon_dest_ring) {
if (quota >= desc_info->status_buf_count) {
qdf_err("DEBUG:");
work_done = dp_rx_mon_status_process(soc, mac_id,
desc_info->status_buf_count);
dp_rx_monitor_deliver_ppdu(soc, mac_id);
hold_mon_dest_ring = false;
} else {
pdev->hold_mon_dest_ring = true;
return quota;
}
quota -= work_done;
}
return quota;
}
/**
* dp_rx_mon_process () - Core brain processing for monitor mode
*
@@ -375,30 +662,42 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
struct hal_rx_mon_desc_info *desc_info;
int mac_for_pdev = mac_id;
QDF_STATUS status;
uint32_t work_done = 0;
if (qdf_unlikely(!dp_soc_is_full_mon_enable(pdev)))
return dp_rx_mon_status_process(soc, mac_id, quota);
qdf_spin_lock_bh(&pdev->mon_lock);
if (qdf_unlikely(!dp_soc_is_full_mon_enable(pdev))) {
quota -= dp_rx_mon_status_process(soc, mac_id, quota);
qdf_spin_unlock_bh(&pdev->mon_lock);
return quota;
}
desc_info = pdev->mon_desc;
quota = dp_rx_mon_deliver_prev_ppdu(pdev, mac_id, quota);
/* Do not proceed if quota expires */
if (!quota || pdev->hold_mon_dest_ring) {
qdf_spin_unlock_bh(&pdev->mon_lock);
return quota;
}
mon_dest_srng = dp_rxdma_get_mon_dst_ring(pdev, mac_for_pdev);
if (qdf_unlikely(!mon_dest_srng ||
!hal_srng_initialized(mon_dest_srng))) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
FL("HAL Monitor Destination Ring Init Failed -- %pK"),
mon_dest_srng);
goto done;
goto done1;
}
hal_soc = soc->hal_soc;
qdf_assert_always(hal_soc && pdev);
qdf_spin_lock_bh(&pdev->mon_lock);
desc_info = pdev->mon_desc;
if (qdf_unlikely(hal_srng_access_start(hal_soc, mon_dest_srng))) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
FL("HAL Monitor Destination Ring access Failed -- %pK"),
mon_dest_srng);
goto done1;
@@ -473,7 +772,7 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
head_msdu,
tail_msdu);
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
FL("Dest_srng: %pK MPDU_OBJ: %pK "
"head_msdu: %pK tail_msdu: %pK -- "),
mon_dest_srng,
@@ -501,70 +800,16 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
*/
rx_mon_stats->dest_ppdu_done++;
#if 0
if (pdev->ppdu_info.com_info.ppdu_id !=
pdev->mon_desc->ppdu_id) {
pdev->rx_mon_stats.ppdu_id_mismatch++;
qdf_err("PPDU id mismatch, status_ppdu_id: %d"
"dest_ppdu_id: %d status_ppdu_done: %d "
"dest_ppdu_done: %d ppdu_id_mismatch_cnt: %u"
"dest_mpdu_drop: %u",
pdev->ppdu_info.com_info.ppdu_id,
pdev->mon_desc->ppdu_id,
pdev->rx_mon_stats.status_ppdu_done,
pdev->rx_mon_stats.dest_ppdu_done,
pdev->rx_mon_stats.ppdu_id_mismatch,
pdev->rx_mon_stats.dest_mpdu_drop);
/* WAR: It is observed that in some cases, status ring ppdu_id
* and destination ring ppdu_id doesn't match.
* Following WAR is added to fix it.
* a. If status ppdu_id is less than destination ppdu_id,
* hold onto destination ring until ppdu_id matches
* b. If status ppdu_id is greater than destination ring
* ppdu_Id, move tp in destination ring.
*/
if (pdev->ppdu_info.com_info.ppdu_id <
pdev->mon_desc->ppdu_id) {
break;
} else {
ring_desc = hal_srng_dst_get_next(hal_soc,
mon_dest_srng);
continue;
}
}
/*
* At this point, end_of_ppdu is one here,
* When 'end_of_ppdu' is one, status buffer_count and
* status_buf_addr must be valid.
*
* Assert if
* a. status_buf_count is zero
* b. status_buf.paddr is NULL
*/
if (!pdev->mon_desc->status_buf_count ||
!pdev->mon_desc->status_buf.paddr) {
qdf_assert_always(0);
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
FL("Status buffer info is NULL"
"status_buf_count: %d"
"status_buf_addr: %pK"
"ring_desc: %pK-- "),
pdev->mon_desc->status_buf_count,
pdev->mon_desc->status_buf.paddr,
ring_desc);
goto done2;
}
#endif
quota -= dp_rx_mon_reap_status_ring(soc, mac_id,
work_done = dp_rx_mon_reap_status_ring(soc, mac_id,
quota, desc_info);
/* Deliver all MPDUs for a PPDU */
dp_rx_monitor_deliver_ppdu(soc, mac_id);
if (desc_info->drop_ppdu)
dp_rx_mon_drop_ppdu(pdev, mac_id);
else if (!pdev->hold_mon_dest_ring)
dp_rx_monitor_deliver_ppdu(soc, mac_id);
hal_srng_dst_get_next(hal_soc, mon_dest_srng);
quota -= work_done;
break;
}
@@ -573,7 +818,6 @@ uint32_t dp_rx_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
done1:
qdf_spin_unlock_bh(&pdev->mon_lock);
done:
return quota;
}