net: mvpp2: use classifier to assign default rx queue
authorMaxime Chevallier <maxime.chevallier@bootlin.com>
Thu, 12 Jul 2018 11:54:24 +0000 (13:54 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 13 Jul 2018 00:30:49 +0000 (17:30 -0700)
The PPv2 Controller has a classifier, that can perform multiple lookup
operations for each packet, using different engines.

One of these engines is the C2 engine, which performs TCAM based lookups
on data extracted from the packet header. When a packet matches an
entry, the engine sets various attributes, used to perform
classification operations.

One of these attributes is the rx queue in which the packet should be sent.
The current code uses the lookup_id table (also called decoding table)
to assign the rx queue. However, this only works if we use one entry per
port in the decoding table, which won't be the case once we add RSS
lookups.

This patch uses the C2 engine to assign the rx queue to each packet.

The C2 engine is used through the flow table, which dictates what
classification operations are done for a given flow.

Right now, we have one flow per port, which contains every ingress
packet for this port.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/mvpp2/mvpp2.h
drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h

index 2afbbf5e71e2cdab87f028a1ad06dfe6c1424a4c..749d9720bf5e36c42154fe440e970a01627c9732 100644 (file)
 #define     MVPP2_CLS_LKP_INDEX_WAY_OFFS       6
 #define MVPP2_CLS_LKP_TBL_REG                  0x1818
 #define     MVPP2_CLS_LKP_TBL_RXQ_MASK         0xff
+#define     MVPP2_CLS_LKP_FLOW_PTR(flow)       ((flow) << 16)
 #define     MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK   BIT(25)
 #define MVPP2_CLS_FLOW_INDEX_REG               0x1820
 #define MVPP2_CLS_FLOW_TBL0_REG                        0x1824
+#define     MVPP2_CLS_FLOW_TBL0_LAST           BIT(0)
+#define     MVPP2_CLS_FLOW_TBL0_ENG_MASK       0x7
+#define     MVPP2_CLS_FLOW_TBL0_OFFS           1
+#define     MVPP2_CLS_FLOW_TBL0_ENG(x)         ((x) << 1)
+#define     MVPP2_CLS_FLOW_TBL0_PORT_ID_MASK   0xff
+#define     MVPP2_CLS_FLOW_TBL0_PORT_ID(port)  ((port) << 4)
+#define     MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL    BIT(23)
 #define MVPP2_CLS_FLOW_TBL1_REG                        0x1828
+#define     MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK  0x7
+#define     MVPP2_CLS_FLOW_TBL1_N_FIELDS(x)    (x)
+#define     MVPP2_CLS_FLOW_TBL1_PRIO_MASK      0x3f
+#define     MVPP2_CLS_FLOW_TBL1_PRIO(x)                ((x) << 9)
+#define     MVPP2_CLS_FLOW_TBL1_SEQ_MASK       0x7
+#define     MVPP2_CLS_FLOW_TBL1_SEQ(x)         ((x) << 15)
 #define MVPP2_CLS_FLOW_TBL2_REG                        0x182c
+#define     MVPP2_CLS_FLOW_TBL2_FLD_MASK       0x3f
+#define     MVPP2_CLS_FLOW_TBL2_FLD_OFFS(n)    ((n) * 6)
+#define     MVPP2_CLS_FLOW_TBL2_FLD(n, x)      ((x) << ((n) * 6))
 #define MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port)   (0x1980 + ((port) * 4))
 #define     MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS    3
 #define     MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK    0x7
 #define MVPP2_CLS_SWFWD_PCTRL_REG              0x19d0
 #define     MVPP2_CLS_SWFWD_PCTRL_MASK(port)   (1 << (port))
 
+/* Classifier C2 engine Registers */
+#define MVPP22_CLS_C2_TCAM_IDX                 0x1b00
+#define MVPP22_CLS_C2_TCAM_DATA0               0x1b10
+#define MVPP22_CLS_C2_TCAM_DATA1               0x1b14
+#define MVPP22_CLS_C2_TCAM_DATA2               0x1b18
+#define MVPP22_CLS_C2_TCAM_DATA3               0x1b1c
+#define MVPP22_CLS_C2_TCAM_DATA4               0x1b20
+#define     MVPP22_CLS_C2_PORT_ID(port)                ((port) << 8)
+#define MVPP22_CLS_C2_ACT                      0x1b60
+#define     MVPP22_CLS_C2_ACT_RSS_EN(act)      (((act) & 0x3) << 19)
+#define     MVPP22_CLS_C2_ACT_FWD(act)         (((act) & 0x7) << 13)
+#define     MVPP22_CLS_C2_ACT_QHIGH(act)       (((act) & 0x3) << 11)
+#define     MVPP22_CLS_C2_ACT_QLOW(act)                (((act) & 0x3) << 9)
+#define MVPP22_CLS_C2_ATTR0                    0x1b64
+#define     MVPP22_CLS_C2_ATTR0_QHIGH(qh)      (((qh) & 0x1f) << 24)
+#define     MVPP22_CLS_C2_ATTR0_QHIGH_MASK     0x1f
+#define     MVPP22_CLS_C2_ATTR0_QLOW(ql)       (((ql) & 0x7) << 21)
+#define     MVPP22_CLS_C2_ATTR0_QLOW_MASK      0x7
+#define MVPP22_CLS_C2_ATTR1                    0x1b68
+#define MVPP22_CLS_C2_ATTR2                    0x1b6c
+#define     MVPP22_CLS_C2_ATTR2_RSS_EN         BIT(30)
+#define MVPP22_CLS_C2_ATTR3                    0x1b70
+
 /* Descriptor Manager Top Registers */
 #define MVPP2_RXQ_NUM_REG                      0x2040
 #define MVPP2_RXQ_DESC_ADDR_REG                        0x2044
index 66160b9b8a9a61061d2f427a0b178d5dd2c54362..7cee117efb4fbddd5584c7d68de5990d5df8ad87 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "mvpp2.h"
 #include "mvpp2_cls.h"
+#include "mvpp2_prs.h"
 
 /* Update classification flow table registers */
 static void mvpp2_cls_flow_write(struct mvpp2 *priv,
@@ -34,6 +35,151 @@ static void mvpp2_cls_lookup_write(struct mvpp2 *priv,
        mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data);
 }
 
+static void mvpp2_cls_flow_eng_set(struct mvpp2_cls_flow_entry *fe,
+                                  int engine)
+{
+       fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_ENG(MVPP2_CLS_FLOW_TBL0_ENG_MASK);
+       fe->data[0] |= MVPP2_CLS_FLOW_TBL0_ENG(engine);
+}
+
+static void mvpp2_cls_flow_port_id_sel(struct mvpp2_cls_flow_entry *fe,
+                                      bool from_packet)
+{
+       if (from_packet)
+               fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
+       else
+               fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
+}
+
+static void mvpp2_cls_flow_seq_set(struct mvpp2_cls_flow_entry *fe, u32 seq)
+{
+       fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_SEQ(MVPP2_CLS_FLOW_TBL1_SEQ_MASK);
+       fe->data[1] |= MVPP2_CLS_FLOW_TBL1_SEQ(seq);
+}
+
+static void mvpp2_cls_flow_last_set(struct mvpp2_cls_flow_entry *fe,
+                                   bool is_last)
+{
+       fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_LAST;
+       fe->data[0] |= !!is_last;
+}
+
+static void mvpp2_cls_flow_pri_set(struct mvpp2_cls_flow_entry *fe, int prio)
+{
+       fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_PRIO(MVPP2_CLS_FLOW_TBL1_PRIO_MASK);
+       fe->data[1] |= MVPP2_CLS_FLOW_TBL1_PRIO(prio);
+}
+
+static void mvpp2_cls_flow_port_add(struct mvpp2_cls_flow_entry *fe,
+                                   u32 port)
+{
+       fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port);
+}
+
+/* Initialize the Lookup Id table entry for the given flow */
+static void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv, int port_id)
+{
+       struct mvpp2_cls_lookup_entry le;
+
+       le.way = 0;
+       le.lkpid = port_id;
+
+       /* The default RxQ for this port is set in the C2 lookup */
+       le.data = 0;
+
+       le.data |= MVPP2_CLS_LKP_FLOW_PTR(port_id);
+       le.data |= MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
+
+       mvpp2_cls_lookup_write(priv, &le);
+}
+
+/* Initialize the flow table entries for the given flow */
+static void mvpp2_cls_flow_init(struct mvpp2 *priv, int port_id)
+{
+       struct mvpp2_cls_flow_entry fe;
+       int i;
+
+       /* C2 lookup */
+       memset(&fe, 0, sizeof(fe));
+       fe.index = port_id;
+
+       mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C2);
+       mvpp2_cls_flow_port_id_sel(&fe, true);
+       mvpp2_cls_flow_last_set(&fe, 1);
+       mvpp2_cls_flow_pri_set(&fe, 0);
+       mvpp2_cls_flow_seq_set(&fe, MVPP2_CLS_FLOW_SEQ_LAST);
+
+       /* Add all ports */
+       for (i = 0; i < MVPP2_MAX_PORTS; i++)
+               mvpp2_cls_flow_port_add(&fe, BIT(i));
+
+       mvpp2_cls_flow_write(priv, &fe);
+}
+
+static void mvpp2_cls_port_init_flows(struct mvpp2 *priv)
+{
+       int i;
+
+       for (i = 0; i < MVPP2_MAX_PORTS; i++) {
+               mvpp2_cls_flow_lkp_init(priv, i);
+               mvpp2_cls_flow_init(priv, i);
+       }
+}
+
+static void mvpp2_cls_c2_write(struct mvpp2 *priv,
+                              struct mvpp2_cls_c2_entry *c2)
+{
+       mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2->index);
+
+       /* Write TCAM */
+       mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA0, c2->tcam[0]);
+       mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA1, c2->tcam[1]);
+       mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA2, c2->tcam[2]);
+       mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA3, c2->tcam[3]);
+       mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA4, c2->tcam[4]);
+
+       mvpp2_write(priv, MVPP22_CLS_C2_ACT, c2->act);
+
+       mvpp2_write(priv, MVPP22_CLS_C2_ATTR0, c2->attr[0]);
+       mvpp2_write(priv, MVPP22_CLS_C2_ATTR1, c2->attr[1]);
+       mvpp2_write(priv, MVPP22_CLS_C2_ATTR2, c2->attr[2]);
+       mvpp2_write(priv, MVPP22_CLS_C2_ATTR3, c2->attr[3]);
+}
+
+static void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
+{
+       struct mvpp2_cls_c2_entry c2;
+       u8 qh, ql, pmap;
+
+       memset(&c2, 0, sizeof(c2));
+
+       c2.index = MVPP22_CLS_C2_RSS_ENTRY(port->id);
+
+       pmap = BIT(port->id);
+       c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);
+       c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));
+
+       /* Update RSS status after matching this entry */
+       c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
+
+       /* Mark packet as "forwarded to software", needed for RSS */
+       c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);
+
+       /* Configure the default rx queue : Update Queue Low and Queue High, but
+        * don't lock, since the rx queue selection might be overridden by RSS
+        */
+       c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD) |
+                  MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD);
+
+       qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
+       ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
+
+       c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
+                     MVPP22_CLS_C2_ATTR0_QLOW(ql);
+
+       mvpp2_cls_c2_write(port->priv, &c2);
+}
+
 /* Classifier default initialization */
 void mvpp2_cls_init(struct mvpp2 *priv)
 {
@@ -61,6 +207,8 @@ void mvpp2_cls_init(struct mvpp2 *priv)
                le.way = 1;
                mvpp2_cls_lookup_write(priv, &le);
        }
+
+       mvpp2_cls_port_init_flows(priv);
 }
 
 void mvpp2_cls_port_config(struct mvpp2_port *port)
@@ -89,6 +237,8 @@ void mvpp2_cls_port_config(struct mvpp2_port *port)
 
        /* Update lookup ID table entry */
        mvpp2_cls_lookup_write(port->priv, &le);
+
+       mvpp2_port_c2_cls_init(port);
 }
 
 /* Set CPU queue number for oversize packets */
index 38a8cf1172df524fd0d78dcfdbf99bb312369ede..ee4933ca7ed8e74b04e211be0b2e582c1aeb31f6 100644 (file)
@@ -14,6 +14,7 @@
 #define _MVPP2_CLS_H_
 
 #include "mvpp2.h"
+#include "mvpp2_prs.h"
 
 /* Classifier constants */
 #define MVPP2_CLS_FLOWS_TBL_SIZE       512
 #define MVPP2_CLS_LKP_TBL_SIZE         64
 #define MVPP2_CLS_RX_QUEUES            256
 
+/* Classifier flow constants */
+enum mvpp2_cls_engine {
+       MVPP22_CLS_ENGINE_C2 = 1,
+       MVPP22_CLS_ENGINE_C3A,
+       MVPP22_CLS_ENGINE_C3B,
+       MVPP22_CLS_ENGINE_C4,
+       MVPP22_CLS_ENGINE_C3HA = 6,
+       MVPP22_CLS_ENGINE_C3HB = 7,
+};
+
+enum mvpp2_cls_flow_seq {
+       MVPP2_CLS_FLOW_SEQ_NORMAL = 0,
+       MVPP2_CLS_FLOW_SEQ_FIRST1,
+       MVPP2_CLS_FLOW_SEQ_FIRST2,
+       MVPP2_CLS_FLOW_SEQ_LAST,
+       MVPP2_CLS_FLOW_SEQ_MIDDLE
+};
+
+/* Classifier C2 engine constants */
+#define MVPP22_CLS_C2_TCAM_EN(data)            ((data) << 16)
+
+enum mvpp22_cls_c2_action {
+       MVPP22_C2_NO_UPD = 0,
+       MVPP22_C2_NO_UPD_LOCK,
+       MVPP22_C2_UPD,
+       MVPP22_C2_UPD_LOCK,
+};
+
+enum mvpp22_cls_c2_fwd_action {
+       MVPP22_C2_FWD_NO_UPD = 0,
+       MVPP22_C2_FWD_NO_UPD_LOCK,
+       MVPP22_C2_FWD_SW,
+       MVPP22_C2_FWD_SW_LOCK,
+       MVPP22_C2_FWD_HW,
+       MVPP22_C2_FWD_HW_LOCK,
+       MVPP22_C2_FWD_HW_LOW_LAT,
+       MVPP22_C2_FWD_HW_LOW_LAT_LOCK,
+};
+
+#define MVPP2_CLS_C2_TCAM_WORDS                        5
+#define MVPP2_CLS_C2_ATTR_WORDS                        5
+
+struct mvpp2_cls_c2_entry {
+       u32 index;
+       u32 tcam[MVPP2_CLS_C2_TCAM_WORDS];
+       u32 act;
+       u32 attr[MVPP2_CLS_C2_ATTR_WORDS];
+};
+
+/* Classifier C2 engine entries */
+#define MVPP22_CLS_C2_RSS_ENTRY(port)  (port)
+#define MVPP22_CLS_C2_N_ENTRIES                MVPP2_MAX_PORTS
+
+#define MVPP22_RSS_FLOW_C2_OFFS                0
+
 struct mvpp2_cls_flow_entry {
        u32 index;
        u32 data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS];