| /* |
| * RSS and Classifier helpers for Marvell PPv2 Network Controller |
| * |
| * Copyright (C) 2014 Marvell |
| * |
| * Marcin Wojtas <mw@semihalf.com> |
| * |
| * This file is licensed under the terms of the GNU General Public |
| * License version 2. This program is licensed "as is" without any |
| * warranty of any kind, whether express or implied. |
| */ |
| |
| #include "mvpp2.h" |
| #include "mvpp2_cls.h" |
| |
| /* Update classification flow table registers */ |
| static void mvpp2_cls_flow_write(struct mvpp2 *priv, |
| struct mvpp2_cls_flow_entry *fe) |
| { |
| mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, fe->index); |
| mvpp2_write(priv, MVPP2_CLS_FLOW_TBL0_REG, fe->data[0]); |
| mvpp2_write(priv, MVPP2_CLS_FLOW_TBL1_REG, fe->data[1]); |
| mvpp2_write(priv, MVPP2_CLS_FLOW_TBL2_REG, fe->data[2]); |
| } |
| |
| /* Update classification lookup table register */ |
| static void mvpp2_cls_lookup_write(struct mvpp2 *priv, |
| struct mvpp2_cls_lookup_entry *le) |
| { |
| u32 val; |
| |
| val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid; |
| mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val); |
| mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data); |
| } |
| |
| /* Classifier default initialization */ |
| void mvpp2_cls_init(struct mvpp2 *priv) |
| { |
| struct mvpp2_cls_lookup_entry le; |
| struct mvpp2_cls_flow_entry fe; |
| int index; |
| |
| /* Enable classifier */ |
| mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK); |
| |
| /* Clear classifier flow table */ |
| memset(&fe.data, 0, sizeof(fe.data)); |
| for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) { |
| fe.index = index; |
| mvpp2_cls_flow_write(priv, &fe); |
| } |
| |
| /* Clear classifier lookup table */ |
| le.data = 0; |
| for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) { |
| le.lkpid = index; |
| le.way = 0; |
| mvpp2_cls_lookup_write(priv, &le); |
| |
| le.way = 1; |
| mvpp2_cls_lookup_write(priv, &le); |
| } |
| } |
| |
| void mvpp2_cls_port_config(struct mvpp2_port *port) |
| { |
| struct mvpp2_cls_lookup_entry le; |
| u32 val; |
| |
| /* Set way for the port */ |
| val = mvpp2_read(port->priv, MVPP2_CLS_PORT_WAY_REG); |
| val &= ~MVPP2_CLS_PORT_WAY_MASK(port->id); |
| mvpp2_write(port->priv, MVPP2_CLS_PORT_WAY_REG, val); |
| |
| /* Pick the entry to be accessed in lookup ID decoding table |
| * according to the way and lkpid. |
| */ |
| le.lkpid = port->id; |
| le.way = 0; |
| le.data = 0; |
| |
| /* Set initial CPU queue for receiving packets */ |
| le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK; |
| le.data |= port->first_rxq; |
| |
| /* Disable classification engines */ |
| le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK; |
| |
| /* Update lookup ID table entry */ |
| mvpp2_cls_lookup_write(port->priv, &le); |
| } |
| |
| /* Set CPU queue number for oversize packets */ |
| void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) |
| { |
| u32 val; |
| |
| mvpp2_write(port->priv, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->id), |
| port->first_rxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK); |
| |
| mvpp2_write(port->priv, MVPP2_CLS_SWFWD_P2HQ_REG(port->id), |
| (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS)); |
| |
| val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG); |
| val |= MVPP2_CLS_SWFWD_PCTRL_MASK(port->id); |
| mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val); |
| } |
| |
| void mvpp22_init_rss(struct mvpp2_port *port) |
| { |
| struct mvpp2 *priv = port->priv; |
| int i; |
| |
| /* Set the table width: replace the whole classifier Rx queue number |
| * with the ones configured in RSS table entries. |
| */ |
| mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(0)); |
| mvpp2_write(priv, MVPP22_RSS_WIDTH, 8); |
| |
| /* Loop through the classifier Rx Queues and map them to a RSS table. |
| * Map them all to the first table (0) by default. |
| */ |
| for (i = 0; i < MVPP2_CLS_RX_QUEUES; i++) { |
| mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(i)); |
| mvpp2_write(priv, MVPP22_RSS_TABLE, |
| MVPP22_RSS_TABLE_POINTER(0)); |
| } |
| |
| /* Configure the first table to evenly distribute the packets across |
| * real Rx Queues. The table entries map a hash to an port Rx Queue. |
| */ |
| for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) { |
| u32 sel = MVPP22_RSS_INDEX_TABLE(0) | |
| MVPP22_RSS_INDEX_TABLE_ENTRY(i); |
| mvpp2_write(priv, MVPP22_RSS_INDEX, sel); |
| |
| mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY, i % port->nrxqs); |
| } |
| |
| } |