summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/pensando/ionic/ionic_txrx.c')
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_txrx.c188
1 files changed, 122 insertions, 66 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
index 85eb8f276a37..8107d32c2767 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
@@ -15,6 +15,10 @@ static void ionic_rx_clean(struct ionic_queue *q,
struct ionic_cq_info *cq_info,
void *cb_arg);
+static bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info);
+
+static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info);
+
static inline void ionic_txq_post(struct ionic_queue *q, bool ring_dbell,
ionic_desc_cb cb_func, void *cb_arg)
{
@@ -249,29 +253,13 @@ static bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info)
return true;
}
-static u32 ionic_rx_walk_cq(struct ionic_cq *rxcq, u32 limit)
-{
- u32 work_done = 0;
-
- while (ionic_rx_service(rxcq, rxcq->tail)) {
- if (rxcq->tail->last)
- rxcq->done_color = !rxcq->done_color;
- rxcq->tail = rxcq->tail->next;
- DEBUG_STATS_CQE_CNT(rxcq);
-
- if (++work_done >= limit)
- break;
- }
-
- return work_done;
-}
-
void ionic_rx_flush(struct ionic_cq *cq)
{
struct ionic_dev *idev = &cq->lif->ionic->idev;
u32 work_done;
- work_done = ionic_rx_walk_cq(cq, cq->num_descs);
+ work_done = ionic_cq_service(cq, cq->num_descs,
+ ionic_rx_service, NULL, NULL);
if (work_done)
ionic_intr_credits(idev->intr_ctrl, cq->bound_intr->index,
@@ -331,9 +319,6 @@ static void ionic_rx_page_free(struct ionic_queue *q, struct page *page,
__free_page(page);
}
-#define IONIC_RX_RING_DOORBELL_STRIDE ((1 << 5) - 1)
-#define IONIC_RX_RING_HEAD_BUF_SZ 2048
-
void ionic_rx_fill(struct ionic_queue *q)
{
struct net_device *netdev = q->lif->netdev;
@@ -345,7 +330,6 @@ void ionic_rx_fill(struct ionic_queue *q)
unsigned int remain_len;
unsigned int seg_len;
unsigned int nfrags;
- bool ring_doorbell;
unsigned int i, j;
unsigned int len;
@@ -360,9 +344,7 @@ void ionic_rx_fill(struct ionic_queue *q)
page_info = &desc_info->pages[0];
if (page_info->page) { /* recycle the buffer */
- ring_doorbell = ((q->head->index + 1) &
- IONIC_RX_RING_DOORBELL_STRIDE) == 0;
- ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, NULL);
+ ionic_rxq_post(q, false, ionic_rx_clean, NULL);
continue;
}
@@ -401,10 +383,11 @@ void ionic_rx_fill(struct ionic_queue *q)
page_info++;
}
- ring_doorbell = ((q->head->index + 1) &
- IONIC_RX_RING_DOORBELL_STRIDE) == 0;
- ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, NULL);
+ ionic_rxq_post(q, false, ionic_rx_clean, NULL);
}
+
+ ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
+ q->dbval | q->head->index);
}
static void ionic_rx_fill_cb(void *arg)
@@ -436,40 +419,117 @@ void ionic_rx_empty(struct ionic_queue *q)
}
}
+int ionic_tx_napi(struct napi_struct *napi, int budget)
+{
+ struct ionic_qcq *qcq = napi_to_qcq(napi);
+ struct ionic_cq *cq = napi_to_cq(napi);
+ struct ionic_dev *idev;
+ struct ionic_lif *lif;
+ u32 work_done = 0;
+ u32 flags = 0;
+
+ lif = cq->bound_q->lif;
+ idev = &lif->ionic->idev;
+
+ work_done = ionic_cq_service(cq, budget,
+ ionic_tx_service, NULL, NULL);
+
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
+ flags |= IONIC_INTR_CRED_UNMASK;
+ DEBUG_STATS_INTR_REARM(cq->bound_intr);
+ }
+
+ if (work_done || flags) {
+ flags |= IONIC_INTR_CRED_RESET_COALESCE;
+ ionic_intr_credits(idev->intr_ctrl,
+ cq->bound_intr->index,
+ work_done, flags);
+ }
+
+ DEBUG_STATS_NAPI_POLL(qcq, work_done);
+
+ return work_done;
+}
+
int ionic_rx_napi(struct napi_struct *napi, int budget)
{
struct ionic_qcq *qcq = napi_to_qcq(napi);
+ struct ionic_cq *cq = napi_to_cq(napi);
+ struct ionic_dev *idev;
+ struct ionic_lif *lif;
+ u32 work_done = 0;
+ u32 flags = 0;
+
+ lif = cq->bound_q->lif;
+ idev = &lif->ionic->idev;
+
+ work_done = ionic_cq_service(cq, budget,
+ ionic_rx_service, NULL, NULL);
+
+ if (work_done)
+ ionic_rx_fill(cq->bound_q);
+
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
+ flags |= IONIC_INTR_CRED_UNMASK;
+ DEBUG_STATS_INTR_REARM(cq->bound_intr);
+ }
+
+ if (work_done || flags) {
+ flags |= IONIC_INTR_CRED_RESET_COALESCE;
+ ionic_intr_credits(idev->intr_ctrl,
+ cq->bound_intr->index,
+ work_done, flags);
+ }
+
+ DEBUG_STATS_NAPI_POLL(qcq, work_done);
+
+ return work_done;
+}
+
+int ionic_txrx_napi(struct napi_struct *napi, int budget)
+{
+ struct ionic_qcq *qcq = napi_to_qcq(napi);
struct ionic_cq *rxcq = napi_to_cq(napi);
unsigned int qi = rxcq->bound_q->index;
struct ionic_dev *idev;
struct ionic_lif *lif;
struct ionic_cq *txcq;
+ u32 rx_work_done = 0;
+ u32 tx_work_done = 0;
u32 work_done = 0;
u32 flags = 0;
+ bool unmask;
lif = rxcq->bound_q->lif;
idev = &lif->ionic->idev;
txcq = &lif->txqcqs[qi].qcq->cq;
- ionic_tx_flush(txcq);
+ tx_work_done = ionic_cq_service(txcq, lif->tx_budget,
+ ionic_tx_service, NULL, NULL);
- work_done = ionic_rx_walk_cq(rxcq, budget);
-
- if (work_done)
+ rx_work_done = ionic_cq_service(rxcq, budget,
+ ionic_rx_service, NULL, NULL);
+ if (rx_work_done)
ionic_rx_fill_cb(rxcq->bound_q);
- if (work_done < budget && napi_complete_done(napi, work_done)) {
+ unmask = (rx_work_done < budget) && (tx_work_done < lif->tx_budget);
+
+ if (unmask && napi_complete_done(napi, rx_work_done)) {
flags |= IONIC_INTR_CRED_UNMASK;
DEBUG_STATS_INTR_REARM(rxcq->bound_intr);
+ work_done = rx_work_done;
+ } else {
+ work_done = budget;
}
if (work_done || flags) {
flags |= IONIC_INTR_CRED_RESET_COALESCE;
ionic_intr_credits(idev->intr_ctrl, rxcq->bound_intr->index,
- work_done, flags);
+ tx_work_done + rx_work_done, flags);
}
- DEBUG_STATS_NAPI_POLL(qcq, work_done);
+ DEBUG_STATS_NAPI_POLL(qcq, rx_work_done);
+ DEBUG_STATS_NAPI_POLL(qcq, tx_work_done);
return work_done;
}
@@ -557,43 +617,39 @@ static void ionic_tx_clean(struct ionic_queue *q,
}
}
-void ionic_tx_flush(struct ionic_cq *cq)
+static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info)
{
- struct ionic_txq_comp *comp = cq->tail->cq_desc;
- struct ionic_dev *idev = &cq->lif->ionic->idev;
+ struct ionic_txq_comp *comp = cq_info->cq_desc;
struct ionic_queue *q = cq->bound_q;
struct ionic_desc_info *desc_info;
- unsigned int work_done = 0;
-
- /* walk the completed cq entries */
- while (work_done < cq->num_descs &&
- color_match(comp->color, cq->done_color)) {
-
- /* clean the related q entries, there could be
- * several q entries completed for each cq completion
- */
- do {
- desc_info = q->tail;
- q->tail = desc_info->next;
- ionic_tx_clean(q, desc_info, cq->tail,
- desc_info->cb_arg);
- desc_info->cb = NULL;
- desc_info->cb_arg = NULL;
- } while (desc_info->index != le16_to_cpu(comp->comp_index));
-
- if (cq->tail->last)
- cq->done_color = !cq->done_color;
-
- cq->tail = cq->tail->next;
- comp = cq->tail->cq_desc;
- DEBUG_STATS_CQE_CNT(cq);
-
- work_done++;
- }
+ if (!color_match(comp->color, cq->done_color))
+ return false;
+
+ /* clean the related q entries, there could be
+ * several q entries completed for each cq completion
+ */
+ do {
+ desc_info = q->tail;
+ q->tail = desc_info->next;
+ ionic_tx_clean(q, desc_info, cq->tail, desc_info->cb_arg);
+ desc_info->cb = NULL;
+ desc_info->cb_arg = NULL;
+ } while (desc_info->index != le16_to_cpu(comp->comp_index));
+
+ return true;
+}
+
+void ionic_tx_flush(struct ionic_cq *cq)
+{
+ struct ionic_dev *idev = &cq->lif->ionic->idev;
+ u32 work_done;
+
+ work_done = ionic_cq_service(cq, cq->num_descs,
+ ionic_tx_service, NULL, NULL);
if (work_done)
ionic_intr_credits(idev->intr_ctrl, cq->bound_intr->index,
- work_done, 0);
+ work_done, IONIC_INTR_CRED_RESET_COALESCE);
}
void ionic_tx_empty(struct ionic_queue *q)