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