xref: /openbmc/linux/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c (revision ea47eed33a3fe3d919e6e3cf4e4eb5507b817188)
1 /*
2  * RSS and Classifier helpers for Marvell PPv2 Network Controller
3  *
4  * Copyright (C) 2014 Marvell
5  *
6  * Marcin Wojtas <mw@semihalf.com>
7  *
8  * This file is licensed under the terms of the GNU General Public
9  * License version 2. This program is licensed "as is" without any
10  * warranty of any kind, whether express or implied.
11  */
12 
13 #include "mvpp2.h"
14 #include "mvpp2_cls.h"
15 
16 /* Update classification flow table registers */
17 static void mvpp2_cls_flow_write(struct mvpp2 *priv,
18 				 struct mvpp2_cls_flow_entry *fe)
19 {
20 	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, fe->index);
21 	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL0_REG,  fe->data[0]);
22 	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL1_REG,  fe->data[1]);
23 	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL2_REG,  fe->data[2]);
24 }
25 
26 /* Update classification lookup table register */
27 static void mvpp2_cls_lookup_write(struct mvpp2 *priv,
28 				   struct mvpp2_cls_lookup_entry *le)
29 {
30 	u32 val;
31 
32 	val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid;
33 	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);
34 	mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data);
35 }
36 
37 /* Classifier default initialization */
38 void mvpp2_cls_init(struct mvpp2 *priv)
39 {
40 	struct mvpp2_cls_lookup_entry le;
41 	struct mvpp2_cls_flow_entry fe;
42 	int index;
43 
44 	/* Enable classifier */
45 	mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
46 
47 	/* Clear classifier flow table */
48 	memset(&fe.data, 0, sizeof(fe.data));
49 	for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {
50 		fe.index = index;
51 		mvpp2_cls_flow_write(priv, &fe);
52 	}
53 
54 	/* Clear classifier lookup table */
55 	le.data = 0;
56 	for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) {
57 		le.lkpid = index;
58 		le.way = 0;
59 		mvpp2_cls_lookup_write(priv, &le);
60 
61 		le.way = 1;
62 		mvpp2_cls_lookup_write(priv, &le);
63 	}
64 }
65 
66 void mvpp2_cls_port_config(struct mvpp2_port *port)
67 {
68 	struct mvpp2_cls_lookup_entry le;
69 	u32 val;
70 
71 	/* Set way for the port */
72 	val = mvpp2_read(port->priv, MVPP2_CLS_PORT_WAY_REG);
73 	val &= ~MVPP2_CLS_PORT_WAY_MASK(port->id);
74 	mvpp2_write(port->priv, MVPP2_CLS_PORT_WAY_REG, val);
75 
76 	/* Pick the entry to be accessed in lookup ID decoding table
77 	 * according to the way and lkpid.
78 	 */
79 	le.lkpid = port->id;
80 	le.way = 0;
81 	le.data = 0;
82 
83 	/* Set initial CPU queue for receiving packets */
84 	le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;
85 	le.data |= port->first_rxq;
86 
87 	/* Disable classification engines */
88 	le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
89 
90 	/* Update lookup ID table entry */
91 	mvpp2_cls_lookup_write(port->priv, &le);
92 }
93 
94 /* Set CPU queue number for oversize packets */
95 void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port)
96 {
97 	u32 val;
98 
99 	mvpp2_write(port->priv, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->id),
100 		    port->first_rxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK);
101 
102 	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_P2HQ_REG(port->id),
103 		    (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS));
104 
105 	val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG);
106 	val |= MVPP2_CLS_SWFWD_PCTRL_MASK(port->id);
107 	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val);
108 }
109 
110 void mvpp22_init_rss(struct mvpp2_port *port)
111 {
112 	struct mvpp2 *priv = port->priv;
113 	int i;
114 
115 	/* Set the table width: replace the whole classifier Rx queue number
116 	 * with the ones configured in RSS table entries.
117 	 */
118 	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(0));
119 	mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);
120 
121 	/* Loop through the classifier Rx Queues and map them to a RSS table.
122 	 * Map them all to the first table (0) by default.
123 	 */
124 	for (i = 0; i < MVPP2_CLS_RX_QUEUES; i++) {
125 		mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(i));
126 		mvpp2_write(priv, MVPP22_RSS_TABLE,
127 			    MVPP22_RSS_TABLE_POINTER(0));
128 	}
129 
130 	/* Configure the first table to evenly distribute the packets across
131 	 * real Rx Queues. The table entries map a hash to an port Rx Queue.
132 	 */
133 	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) {
134 		u32 sel = MVPP22_RSS_INDEX_TABLE(0) |
135 			  MVPP22_RSS_INDEX_TABLE_ENTRY(i);
136 		mvpp2_write(priv, MVPP22_RSS_INDEX, sel);
137 
138 		mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY, i % port->nrxqs);
139 	}
140 
141 }
142