aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/cxgbe/t4_netmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/cxgbe/t4_netmap.c')
-rw-r--r--sys/dev/cxgbe/t4_netmap.c278
1 files changed, 201 insertions, 77 deletions
diff --git a/sys/dev/cxgbe/t4_netmap.c b/sys/dev/cxgbe/t4_netmap.c
index 9bc1e9d3a287..e3d1440d9461 100644
--- a/sys/dev/cxgbe/t4_netmap.c
+++ b/sys/dev/cxgbe/t4_netmap.c
@@ -347,6 +347,180 @@ free_nm_txq_hwq(struct vi_info *vi, struct sge_nm_txq *nm_txq)
}
static int
+cxgbe_netmap_simple_rss(struct adapter *sc, struct vi_info *vi,
+ struct ifnet *ifp, struct netmap_adapter *na)
+{
+ struct netmap_kring *kring;
+ struct sge_nm_rxq *nm_rxq;
+ int rc, i, j, nm_state, defq;
+ uint16_t *rss;
+
+ /*
+ * Check if there's at least one active (or about to go active) netmap
+ * rx queue.
+ */
+ defq = -1;
+ for_each_nm_rxq(vi, j, nm_rxq) {
+ nm_state = atomic_load_int(&nm_rxq->nm_state);
+ kring = na->rx_rings[nm_rxq->nid];
+ if ((nm_state != NM_OFF && !nm_kring_pending_off(kring)) ||
+ (nm_state == NM_OFF && nm_kring_pending_on(kring))) {
+ MPASS(nm_rxq->iq_cntxt_id != INVALID_NM_RXQ_CNTXT_ID);
+ if (defq == -1) {
+ defq = nm_rxq->iq_abs_id;
+ break;
+ }
+ }
+ }
+
+ if (defq == -1) {
+ /* No active netmap queues. Switch back to NIC queues. */
+ rss = vi->rss;
+ defq = vi->rss[0];
+ } else {
+ for (i = 0; i < vi->rss_size;) {
+ for_each_nm_rxq(vi, j, nm_rxq) {
+ nm_state = atomic_load_int(&nm_rxq->nm_state);
+ kring = na->rx_rings[nm_rxq->nid];
+ if ((nm_state != NM_OFF &&
+ !nm_kring_pending_off(kring)) ||
+ (nm_state == NM_OFF &&
+ nm_kring_pending_on(kring))) {
+ MPASS(nm_rxq->iq_cntxt_id !=
+ INVALID_NM_RXQ_CNTXT_ID);
+ vi->nm_rss[i++] = nm_rxq->iq_abs_id;
+ if (i == vi->rss_size)
+ break;
+ }
+ }
+ }
+ rss = vi->nm_rss;
+ }
+
+ rc = -t4_config_rss_range(sc, sc->mbox, vi->viid, 0, vi->rss_size, rss,
+ vi->rss_size);
+ if (rc != 0)
+ if_printf(ifp, "netmap rss_config failed: %d\n", rc);
+
+ rc = -t4_config_vi_rss(sc, sc->mbox, vi->viid, vi->hashen, defq, 0, 0);
+ if (rc != 0) {
+ if_printf(ifp, "netmap defaultq config failed: %d\n", rc);
+ }
+
+ return (rc);
+}
+
+/*
+ * Odd number of rx queues work best for split RSS mode as the first queue can
+ * be dedicated for non-RSS traffic and the rest divided into two equal halves.
+ */
+static int
+cxgbe_netmap_split_rss(struct adapter *sc, struct vi_info *vi,
+ struct ifnet *ifp, struct netmap_adapter *na)
+{
+ struct netmap_kring *kring;
+ struct sge_nm_rxq *nm_rxq;
+ int rc, i, j, nm_state, defq;
+ int nactive[2] = {0, 0};
+ int dq[2] = {-1, -1};
+ bool dq_norss; /* default queue should not be in RSS table. */
+
+ MPASS(nm_split_rss != 0);
+ MPASS(vi->nnmrxq > 1);
+
+ for_each_nm_rxq(vi, i, nm_rxq) {
+ j = i / ((vi->nnmrxq + 1) / 2);
+ nm_state = atomic_load_int(&nm_rxq->nm_state);
+ kring = na->rx_rings[nm_rxq->nid];
+ if ((nm_state != NM_OFF && !nm_kring_pending_off(kring)) ||
+ (nm_state == NM_OFF && nm_kring_pending_on(kring))) {
+ MPASS(nm_rxq->iq_cntxt_id != INVALID_NM_RXQ_CNTXT_ID);
+ nactive[j]++;
+ if (dq[j] == -1) {
+ dq[j] = nm_rxq->iq_abs_id;
+ break;
+ }
+ }
+ }
+
+ if (nactive[0] == 0 || nactive[1] == 0)
+ return (cxgbe_netmap_simple_rss(sc, vi, ifp, na));
+
+ MPASS(dq[0] != -1 && dq[1] != -1);
+ if (nactive[0] > nactive[1]) {
+ defq = dq[0];
+ dq_norss = true;
+ } else if (nactive[0] < nactive[1]) {
+ defq = dq[1];
+ dq_norss = true;
+ } else {
+ defq = dq[0];
+ dq_norss = false;
+ }
+
+ i = 0;
+ nm_rxq = &sc->sge.nm_rxq[vi->first_nm_rxq];
+ while (i < vi->rss_size / 2) {
+ for (j = 0; j < (vi->nnmrxq + 1) / 2; j++) {
+ nm_state = atomic_load_int(&nm_rxq[j].nm_state);
+ kring = na->rx_rings[nm_rxq[j].nid];
+ if ((nm_state == NM_OFF &&
+ !nm_kring_pending_on(kring)) ||
+ (nm_state == NM_ON &&
+ nm_kring_pending_off(kring))) {
+ continue;
+ }
+ MPASS(nm_rxq[j].iq_cntxt_id != INVALID_NM_RXQ_CNTXT_ID);
+ if (dq_norss && defq == nm_rxq[j].iq_abs_id)
+ continue;
+ vi->nm_rss[i++] = nm_rxq[j].iq_abs_id;
+ if (i == vi->rss_size / 2)
+ break;
+ }
+ }
+ while (i < vi->rss_size) {
+ for (j = (vi->nnmrxq + 1) / 2; j < vi->nnmrxq; j++) {
+ nm_state = atomic_load_int(&nm_rxq[j].nm_state);
+ kring = na->rx_rings[nm_rxq[j].nid];
+ if ((nm_state == NM_OFF &&
+ !nm_kring_pending_on(kring)) ||
+ (nm_state == NM_ON &&
+ nm_kring_pending_off(kring))) {
+ continue;
+ }
+ MPASS(nm_rxq[j].iq_cntxt_id != INVALID_NM_RXQ_CNTXT_ID);
+ if (dq_norss && defq == nm_rxq[j].iq_abs_id)
+ continue;
+ vi->nm_rss[i++] = nm_rxq[j].iq_abs_id;
+ if (i == vi->rss_size)
+ break;
+ }
+ }
+
+ rc = -t4_config_rss_range(sc, sc->mbox, vi->viid, 0, vi->rss_size,
+ vi->nm_rss, vi->rss_size);
+ if (rc != 0)
+ if_printf(ifp, "netmap split_rss_config failed: %d\n", rc);
+
+ rc = -t4_config_vi_rss(sc, sc->mbox, vi->viid, vi->hashen, defq, 0, 0);
+ if (rc != 0)
+ if_printf(ifp, "netmap defaultq config failed: %d\n", rc);
+
+ return (rc);
+}
+
+static inline int
+cxgbe_netmap_rss(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
+ struct netmap_adapter *na)
+{
+
+ if (nm_split_rss == 0 || vi->nnmrxq == 1)
+ return (cxgbe_netmap_simple_rss(sc, vi, ifp, na));
+ else
+ return (cxgbe_netmap_split_rss(sc, vi, ifp, na));
+}
+
+static int
cxgbe_netmap_on(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
struct netmap_adapter *na)
{
@@ -354,10 +528,12 @@ cxgbe_netmap_on(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
struct netmap_kring *kring;
struct sge_nm_rxq *nm_rxq;
struct sge_nm_txq *nm_txq;
- int rc, i, j, hwidx, defq, nrssq;
+ int i, j, hwidx;
struct rx_buf_info *rxb;
ASSERT_SYNCHRONIZED_OP(sc);
+ MPASS(vi->nnmrxq > 0);
+ MPASS(vi->nnmtxq > 0);
if ((vi->flags & VI_INIT_DONE) == 0 ||
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
@@ -430,72 +606,7 @@ cxgbe_netmap_on(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
M_ZERO | M_WAITOK);
}
- MPASS(vi->nnmrxq > 0);
- if (nm_split_rss == 0 || vi->nnmrxq == 1) {
- for (i = 0; i < vi->rss_size;) {
- for_each_nm_rxq(vi, j, nm_rxq) {
- vi->nm_rss[i++] = nm_rxq->iq_abs_id;
- if (i == vi->rss_size)
- break;
- }
- }
- defq = vi->nm_rss[0];
- } else {
- /* We have multiple queues and we want to split the table. */
- MPASS(nm_split_rss != 0);
- MPASS(vi->nnmrxq > 1);
-
- nm_rxq = &sc->sge.nm_rxq[vi->first_nm_rxq];
- nrssq = vi->nnmrxq;
- if (vi->nnmrxq & 1) {
- /*
- * Odd number of queues. The first rxq is designated the
- * default queue, the rest are split evenly.
- */
- defq = nm_rxq->iq_abs_id;
- nm_rxq++;
- nrssq--;
- } else {
- /*
- * Even number of queues split into two halves. The
- * first rxq in one of the halves is designated the
- * default queue.
- */
-#if 1
- /* First rxq in the first half. */
- defq = nm_rxq->iq_abs_id;
-#else
- /* First rxq in the second half. */
- defq = nm_rxq[vi->nnmrxq / 2].iq_abs_id;
-#endif
- }
-
- i = 0;
- while (i < vi->rss_size / 2) {
- for (j = 0; j < nrssq / 2; j++) {
- vi->nm_rss[i++] = nm_rxq[j].iq_abs_id;
- if (i == vi->rss_size / 2)
- break;
- }
- }
- while (i < vi->rss_size) {
- for (j = nrssq / 2; j < nrssq; j++) {
- vi->nm_rss[i++] = nm_rxq[j].iq_abs_id;
- if (i == vi->rss_size)
- break;
- }
- }
- }
- rc = -t4_config_rss_range(sc, sc->mbox, vi->viid, 0, vi->rss_size,
- vi->nm_rss, vi->rss_size);
- if (rc != 0)
- if_printf(ifp, "netmap rss_config failed: %d\n", rc);
-
- rc = -t4_config_vi_rss(sc, sc->mbox, vi->viid, vi->hashen, defq, 0, 0);
- if (rc != 0)
- if_printf(ifp, "netmap rss hash/defaultq config failed: %d\n", rc);
-
- return (rc);
+ return (cxgbe_netmap_rss(sc, vi, ifp, na));
}
static int
@@ -503,11 +614,13 @@ cxgbe_netmap_off(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
struct netmap_adapter *na)
{
struct netmap_kring *kring;
- int rc, i;
+ int rc, i, nm_state, nactive;
struct sge_nm_txq *nm_txq;
struct sge_nm_rxq *nm_rxq;
ASSERT_SYNCHRONIZED_OP(sc);
+ MPASS(vi->nnmrxq > 0);
+ MPASS(vi->nnmtxq > 0);
if (!nm_netmap_on(na))
return (0);
@@ -515,14 +628,10 @@ cxgbe_netmap_off(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
if ((vi->flags & VI_INIT_DONE) == 0)
return (0);
- rc = -t4_config_rss_range(sc, sc->mbox, vi->viid, 0, vi->rss_size,
- vi->rss, vi->rss_size);
- if (rc != 0)
- if_printf(ifp, "failed to restore RSS config: %d\n", rc);
- rc = -t4_config_vi_rss(sc, sc->mbox, vi->viid, vi->hashen, vi->rss[0], 0, 0);
+ /* First remove the queues that are stopping from the RSS table. */
+ rc = cxgbe_netmap_rss(sc, vi, ifp, na);
if (rc != 0)
- if_printf(ifp, "failed to restore RSS hash/defaultq: %d\n", rc);
- nm_clear_native_flags(na);
+ return (rc); /* error message logged already. */
for_each_nm_txq(vi, i, nm_txq) {
struct sge_qstat *spg = (void *)&nm_txq->desc[nm_txq->sidx];
@@ -541,18 +650,33 @@ cxgbe_netmap_off(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
pause("nmcidx", 1);
free_nm_txq_hwq(vi, nm_txq);
+
+ /* XXX: netmap, not the driver, should do this. */
+ kring->rhead = kring->rcur = kring->nr_hwcur = 0;
+ kring->rtail = kring->nr_hwtail = kring->nkr_num_slots - 1;
}
+ nactive = 0;
for_each_nm_rxq(vi, i, nm_rxq) {
+ nm_state = atomic_load_int(&nm_rxq->nm_state);
kring = na->rx_rings[nm_rxq->nid];
- if (!nm_kring_pending_off(kring) ||
- nm_rxq->iq_cntxt_id == INVALID_NM_RXQ_CNTXT_ID)
+ if (nm_state != NM_OFF && !nm_kring_pending_off(kring))
+ nactive++;
+ if (nm_state == NM_OFF || !nm_kring_pending_off(kring))
continue;
+ MPASS(nm_rxq->iq_cntxt_id != INVALID_NM_RXQ_CNTXT_ID);
while (!atomic_cmpset_int(&nm_rxq->nm_state, NM_ON, NM_OFF))
pause("nmst", 1);
free_nm_rxq_hwq(vi, nm_rxq);
+
+ /* XXX: netmap, not the driver, should do this. */
+ kring->rhead = kring->rcur = kring->nr_hwcur = 0;
+ kring->rtail = kring->nr_hwtail = 0;
}
+ netmap_krings_mode_commit(na, 0);
+ if (nactive == 0)
+ nm_clear_native_flags(na);
return (rc);
}