blob: 493ec501d87d0d04544ce3308bec197414086441 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "mvOs.h"
#include "mvCommon.h"
#include "mv802_3.h"
#ifndef CONFIG_OF
#include "ctrlEnv/mvCtrlEnvLib.h"
#endif
#include "gbe/mvNetaRegs.h"
#include "gbe/mvEthRegs.h"
#include "mvPnc.h"
#include "mvTcam.h"
/*
* PNC debug
*/
/*#define PNC_DBG mvOsPrintf*/
#define PNC_DBG(X...)
/*
* PNC errors
*/
#define PNC_ERR mvOsPrintf
/*#define PNC_ERR(X...)*/
/*
* Local variables
*/
static int pnc_inited = 0;
static int rxq_mac_bc = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_mac_mc = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_vlan = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_ip6 = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_ip4 = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_ip4_tcp = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_ip4_udp = CONFIG_MV_ETH_RXQ_DEF;
static int rxq_arp = CONFIG_MV_ETH_RXQ_DEF;
/* xlate gbe port number to port value in pnc entry */
struct gbe_pnc_port_mapping gbe_pnc_map[PORT_BITS];
struct gbe_pnc_port_mapping gbe_pnc_map_kw2[] = {
{.gbe_port = 0, .pnc_port = 2},
{.gbe_port = 1, .pnc_port = 4},
{.gbe_port = 2, .pnc_port = 0},
};
struct gbe_pnc_port_mapping gbe_pnc_map_axp[] = {
{.gbe_port = 0, .pnc_port = 0},
{.gbe_port = 1, .pnc_port = 4},
{.gbe_port = 2, .pnc_port = 2},
{.gbe_port = 3, .pnc_port = 3},
{.gbe_port = 0, .pnc_port = 1},
};
struct gbe_pnc_port_mapping gbe_pnc_map_38x[] = {
{.gbe_port = 0, .pnc_port = 0},
{.gbe_port = 1, .pnc_port = 2},
{.gbe_port = 2, .pnc_port = 4},
};
#ifdef CONFIG_OF
int pnc_gbe_port_map_init(unsigned int ctrl_model, unsigned int ctrl_rev)
{
memset(&gbe_pnc_map, 0xff, sizeof(gbe_pnc_map));
if (ctrl_model == MV78230_DEV_ID
|| ctrl_model == MV78260_DEV_ID
|| ctrl_model == MV78460_DEV_ID) {
/* Armada XP ID */
memcpy(&gbe_pnc_map, &gbe_pnc_map_axp, sizeof(gbe_pnc_map_axp));
} else if (ctrl_model == MV88F6510_DEV_ID
|| ctrl_model == MV88F6530_DEV_ID
|| ctrl_model == MV88F6601_DEV_ID
|| ctrl_model == MV88F6560_DEV_ID) {
/* Armada KW2 ID */
memcpy(&gbe_pnc_map, &gbe_pnc_map_kw2, sizeof(gbe_pnc_map_kw2));
} else if ((ctrl_model & ~0xFF) == MV_88F68XX) {
/* Armada A38x ID */
memcpy(&gbe_pnc_map, &gbe_pnc_map_38x, sizeof(gbe_pnc_map_38x));
} else {
mvOsPrintf("%s: ctrl_model=%x is not supported\n", __func__, ctrl_model);
return -1;
}
return 0;
}
#else
int pnc_gbe_port_map_init(unsigned int ctrl_model, unsigned int ctrl_rev)
{
memset(&gbe_pnc_map, 0xff, sizeof(gbe_pnc_map));
#ifdef CONFIG_ARCH_FEROCEON_KW2
/* Armada KW2 ID */
memcpy(&gbe_pnc_map, &gbe_pnc_map_kw2, sizeof(gbe_pnc_map_kw2));
#elif defined(CONFIG_ARCH_ARMADA38X)
/* Armada A38x ID */
memcpy(&gbe_pnc_map, &gbe_pnc_map_38x, sizeof(gbe_pnc_map_38x));
#else
/* Armada XP ID */
memcpy(&gbe_pnc_map, &gbe_pnc_map_axp, sizeof(gbe_pnc_map_axp));
#endif
return 0;
}
#endif
int pnc_port_map(int pnc_port)
{
int loop;
for (loop = 0; loop < PORT_BITS; loop++)
if (gbe_pnc_map[loop].pnc_port == pnc_port)
return gbe_pnc_map[loop].gbe_port;
mvOsPrintf("%s: pnc_port=%d is out of range\n", __func__, pnc_port);
return -1;
}
int pnc_eth_port_map(int eth_port)
{
int loop;
for (loop = 0; loop < PORT_BITS; loop++)
if (gbe_pnc_map[loop].gbe_port == eth_port)
return gbe_pnc_map[loop].pnc_port;
mvOsPrintf("%s: eth_port=%d is out of range\n", __func__, eth_port);
return -1;
}
int pnc_te_del(unsigned int tid)
{
PNC_DBG("%s [%d]\n", __func__, tid);
tcam_hw_inv(tid);
return 0;
}
/* pnc port setting: data: 0 for all bits, mask: 0 - for accepted ports, 1 - for rejected ports */
int pnc_port_mask_check(unsigned int mask, int eth_port)
{
int pnc_port = pnc_eth_port_map(eth_port);
if (pnc_port < 0)
return 0;
if (mask & (1 << pnc_port))
return 0;
return 1;
}
unsigned int pnc_port_mask_update(unsigned int mask, int eth_port, int add)
{
int pnc_port = pnc_eth_port_map(eth_port);
if (pnc_port < 0)
return mask;
if (add)
mask &= ~(1 << pnc_port);
else
mask |= (1 << pnc_port);
return mask;
}
unsigned int pnc_port_mask(int eth_port)
{
unsigned int mask;
int pnc_port = pnc_eth_port_map(eth_port);
if (pnc_port < 0)
return 0;
mask = (~(1 << pnc_port)) & PORT_MASK;
return mask;
}
/* Get TCAM entry if valid, NULL if invalid */
struct tcam_entry *pnc_tcam_entry_get(int tid)
{
struct tcam_entry *te;
te = tcam_sw_alloc(0);
tcam_hw_read(te, tid);
if (te->ctrl.flags & TCAM_F_INV) {
tcam_sw_free(te);
return NULL;
}
return te;
}
int pnc_tcam_port_update(int tid, int eth_port, int add)
{
struct tcam_entry *te;
unsigned int data, mask;
te = pnc_tcam_entry_get(tid);
if (te == NULL) {
mvOsPrintf("%s: TCAM entry #%d is invalid\n", __func__, tid);
return -1;
}
tcam_sw_get_port(te, &data, &mask);
mask = pnc_port_mask_update(mask, eth_port, add);
tcam_sw_set_port(te, data, mask);
tcam_hw_write(te, tid);
tcam_sw_free(te);
return 0;
}
/******************************************************************************
*
* MAC Address Section
*
******************************************************************************
*/
/*
* pnc_mac_fc_drop - Add Flow Control MAC address match rule to the MAC section
* to drop PAUSE frames arriving without Marvell Header on all ports
*/
static void pnc_mac_fc_drop(void)
{
struct tcam_entry *te = NULL;
unsigned char da[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 };
unsigned int len = MV_MAC_ADDR_SIZE;
te = tcam_sw_alloc(TCAM_LU_MAC);
/* set match on DA */
while (len--)
tcam_sw_set_byte(te, len, da[len]);
/* port id match */
tcam_sw_set_port(te, 0, 0); /* all ports */
/* result info bit */
sram_sw_set_rinfo(te, RI_DROP, RI_DROP);
tcam_sw_text(te, "flow control");
sram_sw_set_lookup_done(te, 1);
tcam_hw_write(te, TE_MAC_FLOW_CTRL);
tcam_sw_free(te);
}
/*
* pnc_mac_da - Add DA MAC address match rule to the MAC section
* @da: destination MAC address
* @len: destination MAC address length to match on: 0..6
* @port_mask: source port id: 0..1F or ANY
* @rxq: rx queue
* @rinfo: result info bits to set
*/
static struct tcam_entry *pnc_mac_da(unsigned char *da, unsigned int len,
unsigned int port_mask, int rxq, unsigned int rinfo)
{
struct tcam_entry *te = NULL;
if (len > MV_MAC_ADDR_SIZE)
goto out;
if (rinfo >= BIT24)
goto out;
te = tcam_sw_alloc(TCAM_LU_MAC);
/* set match on DA */
while (len--)
tcam_sw_set_byte(te, MV_ETH_MH_SIZE + len, da[len]);
/* port id match */
tcam_sw_set_port(te, 0, port_mask);
/* result info bit */
sram_sw_set_rinfo(te, rinfo, rinfo);
/* set rx queue */
sram_sw_set_rxq(te, rxq, 0);
/* shift to ethertype */
sram_sw_set_shift_update(te, 0, MV_ETH_MH_SIZE + 2 * MV_MAC_ADDR_SIZE);
sram_sw_set_next_lookup(te, TCAM_LU_L2);
out:
return te;
}
/*
* pnc_mac_me - Add DA MAC address of port
* @mac: destination MAC address or NULL for promiscuous
* @port: ingress giga port number
*/
int pnc_mac_me(unsigned int port, unsigned char *mac, int rxq)
{
struct tcam_entry *te;
int len = MV_MAC_ADDR_SIZE;
char text[TCAM_TEXT];
unsigned int port_mask = pnc_port_mask(port);
if (port_mask < 0)
return 1;
if (!mac)
len = 0;
te = pnc_mac_da(mac, len, port_mask, rxq, RI_DA_ME);
sprintf(text, "%s%d", "ucast_me", port);
tcam_sw_text(te, text);
tcam_hw_write(te, TE_MAC_ME + port);
tcam_sw_free(te);
return 0;
}
/*
* pnc_mcast_all - Accept all MAC multicast of port
* @port: ingress giga port number.
* @en: 1 - Accept ALL MCAST, 0 - Discard ALL MCAST
*/
int pnc_mcast_all(unsigned int port, int en)
{
struct tcam_entry *te;
unsigned int data, mask;
te = pnc_tcam_entry_get(TE_MAC_MC_ALL);
if (te == NULL) {
mvOsPrintf("%s: MC_ALL entry (tid=%d) is invalid\n", __func__, TE_MAC_MC_ALL);
return 1;
}
/* Update port mask */
tcam_sw_get_port(te, &data, &mask);
mask = pnc_port_mask_update(mask, port, en);
tcam_sw_set_port(te, data, mask);
tcam_sw_text(te, "mcast_all");
tcam_hw_write(te, TE_MAC_MC_ALL);
tcam_sw_free(te);
return 0;
}
/*
* pnc_mcast_me - Add DA MAC address of port
* @mac: Multicast MAC DA or NULL to delete all Multicast DAs for this port
* @port: ingress giga port number
*/
int pnc_mcast_me(unsigned int port, unsigned char *mac)
{
struct tcam_entry *te;
int tid, empty = -1;
unsigned int data, mask;
if (mac == NULL) {
/* Delete all Multicast addresses for this port */
for (tid = (TE_MAC_MC_ALL + 1); tid <= TE_MAC_MC_L; tid++) {
/* Check TCAM entry */
te = pnc_tcam_entry_get(tid);
if (te != NULL) {
/* delete entry if belong specific port */
tcam_sw_get_port(te, &data, &mask);
mask = pnc_port_mask_update(mask, port, 0);
if (mask == PORT_MASK) { /* No valid ports */
tcam_hw_inv(tid);
} else {
tcam_sw_set_port(te, data, mask);
tcam_hw_write(te, tid);
}
tcam_sw_free(te);
}
}
return 0;
}
/* Add new Multicast DA for this port */
for (tid = (TE_MAC_MC_ALL + 1); tid <= TE_MAC_MC_L; tid++) {
te = pnc_tcam_entry_get(tid);
/* Remember first Empty entry */
if (te == NULL) {
if (empty == -1)
empty = tid;
continue;
}
/* Find existing TCAM entry with this DA */
if (tcam_sw_cmp_bytes(te, MV_ETH_MH_SIZE, MV_MAC_ADDR_SIZE, mac) == 0) {
/* check and update port mask */
tcam_sw_get_port(te, &data, &mask);
mask = pnc_port_mask_update(mask, port, 1);
tcam_sw_set_port(te, data, mask);
tcam_hw_write(te, tid);
tcam_sw_free(te);
return 0;
}
tcam_sw_free(te);
}
/* Not found existing entry and no free TCAM entry - Failed */
if (empty == -1)
return 1;
/* Not found existing entry - add to free TCAM entry */
te = pnc_mac_da(mac, MV_MAC_ADDR_SIZE, pnc_port_mask(port), rxq_mac_mc, RI_DA_MC);
tcam_sw_text(te, "mcast_me");
tcam_hw_write(te, empty);
tcam_sw_free(te);
return 0;
}
/*
* pnc_mac_init - GE init phase configuration
*/
static int pnc_mac_init(void)
{
struct tcam_entry *te;
unsigned char da_mc[6] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
unsigned char da_bc[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
PNC_DBG("%s\n", __func__);
/* broadcast - for all ports */
te = pnc_mac_da(da_bc, 6, 0, rxq_mac_bc, RI_DA_BC);
tcam_sw_text(te, "bcast");
tcam_hw_write(te, TE_MAC_BC);
tcam_sw_free(te);
/* flow control PAUSE frames - discard for all ports by default */
pnc_mac_fc_drop();
/* All Multicast - no ports by default */
te = pnc_mac_da(da_mc, 1, PORT_MASK, rxq_mac_mc, RI_DA_MC);
tcam_sw_text(te, "mcast_all");
tcam_hw_write(te, TE_MAC_MC_ALL);
tcam_sw_free(te);
/* end of section */
te = tcam_sw_alloc(TCAM_LU_MAC);
sram_sw_set_flowid(te, FLOWID_EOF_LU_MAC, FLOWID_CTRL_LOW_HALF_MASK);
/* Non-promiscous mode - DROP unknown packets */
sram_sw_set_rinfo(te, RI_DROP, RI_DROP);
sram_sw_set_lookup_done(te, 1);
tcam_sw_text(te, "mac_eof");
tcam_hw_write(te, TE_MAC_EOF);
tcam_sw_free(te);
return 0;
}
/******************************************************************************
*
* L2 Section
*
******************************************************************************
*/
/*
* Helper: match ethertype
*/
static void pnc_match_etype(struct tcam_entry *te, unsigned short ethertype)
{
tcam_sw_set_byte(te, 0, ethertype >> 8);
tcam_sw_set_byte(te, 1, ethertype & 0xFF);
}
/* Set VLAN priority entry */
int pnc_vlan_prio_set(int port, int prio, int rxq)
{
#if (CONFIG_MV_ETH_PNC_VLAN_PRIO > 0)
struct tcam_entry *te;
unsigned int pdata, pmask;
int q, tid, empty = -1;
PNC_DBG("%s\n", __func__);
/* check validity */
if ((prio < 0) || (prio > 7))
return 1;
if ((rxq < -1) || (rxq > CONFIG_MV_ETH_RXQ))
return 1;
/* Find match TCAM entry */
for (tid = TE_VLAN_PRIO; tid <= TE_VLAN_PRIO_END; tid++) {
te = pnc_tcam_entry_get(tid);
/* Remember first Empty entry */
if (te == NULL) {
if (empty == -1)
empty = tid;
continue;
}
/* find VLAN entry with the same priority */
if (tcam_sw_cmp_byte(te, 2, ((unsigned char)prio << 5)) == 0) {
tcam_sw_get_port(te, &pdata, &pmask);
if (rxq == -1) {
if (!pnc_port_mask_check(pmask, port)) {
tcam_sw_free(te);
continue;
}
pmask = pnc_port_mask_update(pmask, port, 0);
if (pmask == PORT_MASK) { /* No valid ports */
tcam_hw_inv(tid);
} else {
tcam_sw_set_port(te, pdata, pmask);
tcam_hw_write(te, tid);
}
} else {
q = sram_sw_get_rxq(te, NULL);
if (rxq == q) {
/* Add port to this entry */
pmask = pnc_port_mask_update(pmask, port, 1);
tcam_sw_set_port(te, pdata, pmask);
tcam_hw_write(te, tid);
} else {
/* Update RXQ */
pmask = pnc_port_mask_update(pmask, port, 0);
if (pmask == PORT_MASK) {
/* No valid ports - use the same entry */
pmask = pnc_port_mask_update(pmask, port, 1);
tcam_sw_set_port(te, pdata, pmask);
sram_sw_set_rxq(te, rxq, 0);
tcam_hw_write(te, tid);
tcam_sw_free(te);
} else {
tcam_sw_free(te);
continue;
}
}
}
tcam_sw_free(te);
return 0;
}
tcam_sw_free(te);
}
if (rxq == -1) {
mvOsPrintf("%s: Entry not found - vprio=%d, rxq=%d\n",
__func__, prio, rxq);
return 1;
}
/* Not found existing entry and no free TCAM entry - Failed */
if (empty == -1) {
mvOsPrintf("%s: No free place - vprio=%d, rxq=%d\n",
__func__, prio, rxq);
return 1;
}
/* Not found existing entry - add to free TCAM entry */
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_VLAN_TYPE);
tcam_sw_set_byte(te, 2, prio << 5);
tcam_sw_set_mask(te, 2, 7 << 5);
tcam_sw_text(te, "vlan_prio");
sram_sw_set_rinfo(te, RI_VLAN, RI_VLAN);
sram_sw_set_next_lookup(te, TCAM_LU_L2);
sram_sw_set_shift_update(te, 0, MV_VLAN_HLEN);
sram_sw_set_rxq(te, rxq, 0);
/* single port mask */
pmask = pnc_port_mask(port);
tcam_sw_set_port(te, 0, pmask);
tcam_sw_text(te, "vlan_prio");
tcam_hw_write(te, empty);
tcam_sw_free(te);
return 0;
#else
return -1;
#endif /* CONFIG_MV_ETH_PNC_VLAN_PRIO > 0 */
}
int pnc_vlan_init(void)
{
struct tcam_entry *te;
int tid;
PNC_DBG("%s\n", __func__);
/* Set default VLAN entry */
tid = TE_VLAN_EOF;
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_VLAN_TYPE);
tcam_sw_set_mask(te, 2, 0);
tcam_sw_text(te, "vlan_def");
sram_sw_set_rxq(te, rxq_vlan, 0);
sram_sw_set_rinfo(te, RI_VLAN, RI_VLAN);
sram_sw_set_next_lookup(te, TCAM_LU_L2);
sram_sw_set_shift_update(te, 0, MV_VLAN_HLEN);
tcam_hw_write(te, tid);
tcam_sw_free(te);
return 0;
}
/******************************************************************************
*
* Ethertype Section
*
******************************************************************************
*/
/* match arp */
void pnc_etype_arp(int rxq)
{
struct tcam_entry *te;
rxq_arp = rxq;
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_IP_ARP_TYPE);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_rxq(te, rxq_arp, 0);
tcam_sw_text(te, "etype_arp");
tcam_hw_write(te, TE_ETYPE_ARP);
tcam_sw_free(te);
}
/* match ip4 */
static void pnc_etype_ip4(void)
{
struct tcam_entry *te;
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_IP_TYPE);
sram_sw_set_shift_update(te, 0, MV_ETH_TYPE_LEN);
sram_sw_set_rinfo(te, RI_L3_IP4, RI_L3_IP4);
sram_sw_set_next_lookup(te, TCAM_LU_IP4);
tcam_sw_text(te, "etype_ipv4");
tcam_hw_write(te, TE_ETYPE_IP4);
tcam_sw_free(te);
}
/* match ip6 */
static void pnc_etype_ip6(void)
{
struct tcam_entry *te;
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_IP6_TYPE);
sram_sw_set_shift_update(te, 0, MV_ETH_TYPE_LEN);
sram_sw_set_rinfo(te, RI_L3_IP6, RI_L3_IP6);
sram_sw_set_next_lookup(te, TCAM_LU_IP6);
tcam_sw_text(te, "etype_ipv6");
tcam_hw_write(te, TE_ETYPE_IP6);
tcam_sw_free(te);
}
/* match pppoe */
static void pnc_etype_pppoe(void)
{
struct tcam_entry *te;
/* IPv4 over PPPoE */
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_PPPOE_TYPE);
tcam_sw_set_byte(te, MV_PPPOE_HDR_SIZE, 0x00);
tcam_sw_set_byte(te, MV_PPPOE_HDR_SIZE + 1, 0x21);
sram_sw_set_shift_update(te, 0, MV_ETH_TYPE_LEN + MV_PPPOE_HDR_SIZE);
sram_sw_set_next_lookup(te, TCAM_LU_IP4);
sram_sw_set_rinfo(te, (RI_PPPOE | RI_L3_IP4), (RI_PPPOE | RI_L3_IP4));
tcam_sw_text(te, "pppoe_ip4");
tcam_hw_write(te, TE_PPPOE_IP4);
tcam_sw_free(te);
/* IPv6 over PPPoE */
te = tcam_sw_alloc(TCAM_LU_L2);
pnc_match_etype(te, MV_PPPOE_TYPE);
tcam_sw_set_byte(te, MV_PPPOE_HDR_SIZE, 0x00);
tcam_sw_set_byte(te, MV_PPPOE_HDR_SIZE + 1, 0x57);
sram_sw_set_shift_update(te, 0, MV_ETH_TYPE_LEN + MV_PPPOE_HDR_SIZE);
sram_sw_set_next_lookup(te, TCAM_LU_IP6);
sram_sw_set_rinfo(te, (RI_PPPOE | RI_L3_IP6), (RI_PPPOE | RI_L3_IP6));
tcam_sw_text(te, "pppoe_ip6");
tcam_hw_write(te, TE_PPPOE_IP6);
tcam_sw_free(te);
}
/*
* pnc_etype_init - match basic ethertypes
*/
static int pnc_etype_init(void)
{
struct tcam_entry *te;
int tid;
PNC_DBG("%s\n", __func__);
pnc_etype_arp(CONFIG_MV_ETH_RXQ_DEF);
pnc_etype_ip4();
pnc_etype_ip6();
pnc_etype_pppoe();
/* add custom ethertypes here */
tid = TE_ETYPE;
ERR_ON_OOR(--tid >= TE_ETYPE_EOF);
/* end of section */
te = tcam_sw_alloc(TCAM_LU_L2);
sram_sw_set_flowid(te, FLOWID_EOF_LU_L2, FLOWID_CTRL_LOW_HALF_MASK);
sram_sw_set_rxq(te, CONFIG_MV_ETH_RXQ_DEF, 0);
sram_sw_set_lookup_done(te, 1);
tcam_sw_text(te, "etype_eof");
tcam_hw_write(te, TE_ETYPE_EOF);
tcam_sw_free(te);
return 0;
}
/******************************************************************************
*
* IPv4 Section
*
******************************************************************************
*/
static void pnc_ip4_flow_next_lookup_set(struct tcam_entry *te)
{
#ifdef CONFIG_MV_ETH_PNC_L3_FLOW
sram_sw_set_next_lookup(te, TCAM_LU_FLOW_IP4);
#else
sram_sw_set_next_lookup(te, TCAM_LU_L4);
#endif /* CONFIG_MV_ETH_PNC_L3_FLOW */
}
/*
* pnc_ip4_tos - Add TOS priority rules
*/
int pnc_ip4_dscp(int port, unsigned char dscp, unsigned char mask, int rxq)
{
#if (CONFIG_MV_ETH_PNC_DSCP_PRIO > 0)
struct tcam_entry *te;
unsigned int pdata, pmask;
int tid, q, empty = -1;
if ((rxq < -1) || (rxq > CONFIG_MV_ETH_RXQ))
return 1;
for (tid = TE_IP4_DSCP; tid <= TE_IP4_DSCP_END; tid++) {
PNC_DBG("%s: tid=%d, dscp=0x%02x, mask=0x%02x, rxq=%d\n", __func__, tid, dscp, mask, rxq);
te = pnc_tcam_entry_get(tid);
/* Remember first Empty entry */
if (te == NULL) {
if (empty == -1)
empty = tid;
continue;
}
/* Find existing entry for this TOS */
if (tcam_sw_cmp_bytes(te, 1, 1, &dscp) == 0) {
tcam_sw_get_port(te, &pdata, &pmask);
if (rxq == -1) {
if (!pnc_port_mask_check(pmask, port)) {
tcam_sw_free(te);
continue;
}
pmask = pnc_port_mask_update(pmask, port, 0);
if (pmask == PORT_MASK) { /* No valid ports */
tcam_hw_inv(tid);
} else {
tcam_sw_set_port(te, pdata, pmask);
tcam_hw_write(te, tid);
}
} else {
q = sram_sw_get_rxq(te, NULL);
if (rxq == q) {
/* Add port to this entry */
pmask = pnc_port_mask_update(pmask, port, 1);
tcam_sw_set_port(te, pdata, pmask);
tcam_hw_write(te, tid);
} else {
/* Update RXQ */
pmask = pnc_port_mask_update(pmask, port, 0);
if (pmask == PORT_MASK) {
/* No valid ports - use the same entry */
pmask = pnc_port_mask_update(pmask, port, 1);
tcam_sw_set_port(te, pdata, pmask);
sram_sw_set_rxq(te, rxq, 0);
tcam_hw_write(te, tid);
} else {
tcam_sw_free(te);
continue;
}
}
}
tcam_sw_free(te);
return 0;
}
tcam_sw_free(te);
}
if (rxq == -1) {
mvOsPrintf("%s: Entry not found - tos=0x%x, rxq=%d\n",
__func__, dscp, rxq);
return 1;
}
/* Not found existing entry and no free TCAM entry - Failed */
if (empty == -1) {
mvOsPrintf("%s: No free place - tos=0x%x, rxq=%d\n",
__func__, dscp, rxq);
return 1;
}
/* Not found existing entry - add to free TCAM entry */
te = tcam_sw_alloc(TCAM_LU_IP4);
tcam_sw_set_byte(te, 1, (MV_U8) dscp);
tcam_sw_set_mask(te, 1, (MV_U8) mask);
sram_sw_set_rxq(te, rxq, 0);
pmask = pnc_port_mask(port);
tcam_sw_set_port(te, 0, pmask);
sram_sw_set_next_lookup(te, TCAM_LU_IP4);
tcam_sw_set_ainfo(te, 0, AI_DONE_MASK);
sram_sw_set_ainfo(te, AI_DONE_MASK, AI_DONE_MASK);
tcam_sw_text(te, "ipv4_tos");
tcam_hw_write(te, empty);
tcam_sw_free(te);
return 0;
#else
return -1;
#endif /* (CONFIG_MV_ETH_PNC_DSCP_PRIO > 0) */
}
/* IPv4/TCP header parsing for fragmentation and L4 offset. */
void pnc_ip4_tcp(int rxq)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
rxq_ip4_tcp = rxq;
/* TCP, FRAG=0 normal */
te = tcam_sw_alloc(TCAM_LU_IP4);
tcam_sw_set_byte(te, 9, MV_IP_PROTO_TCP);
tcam_sw_set_byte(te, 6, 0x00);
tcam_sw_set_mask(te, 6, 0x3F);
tcam_sw_set_byte(te, 7, 0x00);
tcam_sw_set_mask(te, 7, 0xFF);
sram_sw_set_shift_update(te, 1, SHIFT_IP4_HLEN);
sram_sw_set_rinfo(te, RI_L4_TCP, RI_L4_TCP);
sram_sw_set_rxq(te, rxq_ip4_tcp, 0);
sram_sw_set_ainfo(te, 0, AI_DONE_MASK);
pnc_ip4_flow_next_lookup_set(te);
tcam_sw_text(te, "ipv4_tcp");
tcam_hw_write(te, TE_IP4_TCP);
tcam_sw_free(te);
/* TCP, FRAG=1 any */
te = tcam_sw_alloc(TCAM_LU_IP4);
tcam_sw_set_byte(te, 9, MV_IP_PROTO_TCP);
sram_sw_set_shift_update(te, 1, SHIFT_IP4_HLEN);
sram_sw_set_rinfo(te, (RI_L3_IP4_FRAG | RI_L4_TCP), (RI_L3_IP4 | RI_L3_IP4_FRAG | RI_L4_TCP));
sram_sw_set_rxq(te, rxq_ip4_tcp, 0);
sram_sw_set_ainfo(te, 0, AI_DONE_MASK);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_L4, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "ipv4_tcp_fr");
tcam_hw_write(te, TE_IP4_TCP_FRAG);
tcam_sw_free(te);
}
/* IPv4/UDP header parsing for fragmentation and L4 offset. */
void pnc_ip4_udp(int rxq)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
rxq_ip4_udp = rxq;
/* UDP, FRAG=0 normal */
te = tcam_sw_alloc(TCAM_LU_IP4);
tcam_sw_set_byte(te, 9, MV_IP_PROTO_UDP);
tcam_sw_set_byte(te, 6, 0x00);
tcam_sw_set_mask(te, 6, 0x3F);
tcam_sw_set_byte(te, 7, 0x00);
tcam_sw_set_mask(te, 7, 0xFF);
sram_sw_set_shift_update(te, 1, SHIFT_IP4_HLEN);
sram_sw_set_rinfo(te, RI_L4_UDP, RI_L4_UDP);
sram_sw_set_rxq(te, rxq_ip4_udp, 0);
sram_sw_set_ainfo(te, 0, AI_DONE_MASK);
pnc_ip4_flow_next_lookup_set(te);
tcam_sw_text(te, "ipv4_udp");
tcam_hw_write(te, TE_IP4_UDP);
tcam_sw_free(te);
/* UDP, FRAG=1 any */
te = tcam_sw_alloc(TCAM_LU_IP4);
tcam_sw_set_byte(te, 9, MV_IP_PROTO_UDP);
sram_sw_set_shift_update(te, 1, SHIFT_IP4_HLEN);
sram_sw_set_rinfo(te, (RI_L3_IP4_FRAG | RI_L4_UDP), (RI_L3_IP4 | RI_L3_IP4_FRAG | RI_L4_UDP));
sram_sw_set_rxq(te, rxq_ip4_udp, 0);
sram_sw_set_ainfo(te, 0, AI_DONE_MASK);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_L4, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "ipv4_udp_fr");
tcam_hw_write(te, TE_IP4_UDP_FRAG);
tcam_sw_free(te);
}
/* IPv4 - end of section */
static void pnc_ip4_end(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
te = tcam_sw_alloc(TCAM_LU_IP4);
sram_sw_set_rinfo(te, RI_L4_UN, RI_L4_UN);
sram_sw_set_rxq(te, rxq_ip4, 0);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_IP4, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "ipv4_eof");
tcam_hw_write(te, TE_IP4_EOF);
tcam_sw_free(te);
}
int pnc_ip4_init(void)
{
PNC_DBG("%s\n", __func__);
pnc_ip4_tcp(CONFIG_MV_ETH_RXQ_DEF);
pnc_ip4_udp(CONFIG_MV_ETH_RXQ_DEF);
/*pnc_ip4_esp();*/
pnc_ip4_end();
return 0;
}
/******************************************************************************
*
* IPv6 Section
*
*******************************************************************************
*/
static void pnc_ip6_flow_next_lookup_set(struct tcam_entry *te)
{
#ifdef CONFIG_MV_ETH_PNC_L3_FLOW
sram_sw_set_next_lookup(te, TCAM_LU_FLOW_IP6_A);
#else
sram_sw_set_next_lookup(te, TCAM_LU_L4);
#endif /* CONFIG_MV_ETH_PNC_L3_FLOW */
}
/* IPv6 - detect TCP */
static void pnc_ip6_tcp(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
/* TCP without extension headers */
te = tcam_sw_alloc(TCAM_LU_IP6);
tcam_sw_set_byte(te, 6, MV_IP_PROTO_TCP);
sram_sw_set_shift_update(te, 1, SHIFT_IP6_FIRST_PHASE);
sram_sw_set_next_lookup_shift(te, 1);
sram_sw_set_next_lookup(te, TCAM_LU_IP6);
sram_sw_set_rinfo(te, RI_L4_TCP, RI_L4_TCP);
sram_sw_set_rxq(te, rxq_ip6, 0);
tcam_sw_text(te, "ipv6_tcp");
tcam_sw_set_ainfo(te, 0, (AI_IP6_L4_TCP_UDP_MASK | AI_IP6_L4_NOTHING_MASK));
sram_sw_set_ainfo(te, AI_IP6_L4_TCP_UDP_MASK, AI_IP6_L4_TCP_UDP_MASK);
tcam_hw_write(te, TE_IP6_TCP);
tcam_sw_free(te);
}
/* IPv6 - detect UDP */
static void pnc_ip6_udp(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
/* UDP without extension headers */
te = tcam_sw_alloc(TCAM_LU_IP6);
tcam_sw_set_byte(te, 6, MV_IP_PROTO_UDP);
sram_sw_set_shift_update(te, 1, SHIFT_IP6_FIRST_PHASE);
sram_sw_set_next_lookup_shift(te, 1);
sram_sw_set_next_lookup(te, TCAM_LU_IP6);
sram_sw_set_rinfo(te, RI_L4_UDP, RI_L4_UDP);
sram_sw_set_rxq(te, rxq_ip6, 0);
tcam_sw_set_ainfo(te, 0, (AI_IP6_L4_TCP_UDP_MASK | AI_IP6_L4_NOTHING_MASK));
sram_sw_set_ainfo(te, AI_IP6_L4_TCP_UDP_MASK, AI_IP6_L4_TCP_UDP_MASK);
tcam_sw_text(te, "ipv6_udp");
tcam_hw_write(te, TE_IP6_UDP);
tcam_sw_free(te);
}
/* IPv6 - second phase */
static void pnc_ip6_end(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
/* IPv6 - second phase, TCP/UDP part */
te = tcam_sw_alloc(TCAM_LU_IP6);
sram_sw_set_shift_update(te, 1, SHIFT_IP6_SECOND_PHASE);
sram_sw_set_next_lookup_shift(te, 1);
tcam_sw_text(te, "ipv6_2nd_tcp_udp");
tcam_sw_set_ainfo(te, AI_IP6_L4_TCP_UDP_MASK, AI_IP6_L4_TCP_UDP_MASK);
pnc_ip6_flow_next_lookup_set(te);
tcam_hw_write(te, TE_IP6_2ND_PHASE_TCP_UDP);
tcam_sw_free(te);
/* IPv6 - second phase, unknown L4 part */
te = tcam_sw_alloc(TCAM_LU_IP6);
sram_sw_set_shift_update(te, 1, SHIFT_IP6_SECOND_PHASE);
sram_sw_set_next_lookup_shift(te, 1);
tcam_sw_text(te, "ipv6_2nd_unknown_l4");
tcam_sw_set_ainfo(te, AI_IP6_L4_NOTHING_MASK, AI_IP6_L4_NOTHING_MASK);
pnc_ip6_flow_next_lookup_set(te);
tcam_hw_write(te, TE_IP6_2ND_PHASE_UNKNOWN_L4);
tcam_sw_free(te);
}
static void pnc_ip6_unknown_l4(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
te = tcam_sw_alloc(TCAM_LU_IP6);
sram_sw_set_shift_update(te, 1, SHIFT_IP6_FIRST_PHASE);
sram_sw_set_next_lookup_shift(te, 1);
sram_sw_set_rinfo(te, RI_L4_UN, RI_L4_UN);
sram_sw_set_rxq(te, rxq_ip6, 0);
sram_sw_set_next_lookup(te, TCAM_LU_IP6);
sram_sw_set_flowid(te, FLOWID_EOF_LU_IP6, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "ipv6_unknown_l4");
tcam_sw_set_ainfo(te, 0, (AI_IP6_L4_TCP_UDP_MASK | AI_IP6_L4_NOTHING_MASK));
sram_sw_set_ainfo(te, AI_IP6_L4_NOTHING_MASK, AI_IP6_L4_NOTHING_MASK);
tcam_hw_write(te, TE_IP6_UNKNOWN_L4);
tcam_sw_free(te);
}
int pnc_ip6_init(void)
{
PNC_DBG("%s\n", __func__);
pnc_ip6_tcp();
pnc_ip6_udp();
pnc_ip6_unknown_l4();
pnc_ip6_end();
return 0;
}
#ifdef CONFIG_MV_ETH_PNC_L3_FLOW
/******************************************************************************
*
* L3 Flows Section
*
******************************************************************************
*/
static int pnc_flow_init(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
/* end of section for IPv4 */
te = tcam_sw_alloc(TCAM_LU_FLOW_IP4);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_FLOW_IP4, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "flow_ip4_eof");
tcam_hw_write(te, TE_FLOW_IP4_EOF);
tcam_sw_free(te);
/* end of section for IPv6_A */
te = tcam_sw_alloc(TCAM_LU_FLOW_IP6_A);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_FLOW_IP6_A, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "flow_ip6_A_eof");
tcam_hw_write(te, TE_FLOW_IP6_A_EOF);
tcam_sw_free(te);
/* end of section for IPv6_B */
te = tcam_sw_alloc(TCAM_LU_FLOW_IP6_B);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_FLOW_IP6_B, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "flow_ip6_B_eof");
tcam_hw_write(te, TE_FLOW_IP6_B_EOF);
tcam_sw_free(te);
return 0;
}
/* require 2 TCAM entries for macth */
int pnc_ipv6_2_tuples_add(unsigned int tid1, unsigned int tid2, unsigned int flow_id,
MV_U8 unique, MV_U8 *sip, MV_U8 *dip, unsigned int rxq)
{
struct tcam_entry *te;
int i;
if ((tid1 < TE_FLOW_L3) || (tid1 > TE_FLOW_L3_END))
ERR_ON_OOR(1);
if ((tid2 < TE_FLOW_L3) || (tid2 > TE_FLOW_L3_END))
ERR_ON_OOR(2);
te = tcam_sw_alloc(TCAM_LU_FLOW_IP6_A);
for (i = 0; i < 16; i++)
tcam_sw_set_byte(te, 8+i, sip[i]);
sram_sw_set_shift_update(te, 2, 24);
sram_sw_set_next_lookup_shift(te, 2);
sram_sw_set_next_lookup(te, TCAM_LU_FLOW_IP6_B);
sram_sw_set_ainfo(te, unique, AI_MASK);
tcam_sw_text(te, "ipv6_2t_A");
tcam_hw_write(te, tid1);
tcam_sw_free(te);
te = tcam_sw_alloc(TCAM_LU_FLOW_IP6_B);
for (i = 0; i < 16; i++)
tcam_sw_set_byte(te, i, dip[i]);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, flow_id, FLOWID_CTRL_FULL_MASK);
if (PNC_FLOWID_IS_HWF(flow_id)) {
/* Overwrite RXQ - FIXME */
sram_sw_set_rxq(te, rxq, 1);
} else {
sram_sw_set_rxq(te, rxq, 0);
}
sram_sw_set_rinfo(te, RI_L3_FLOW, RI_L3_FLOW);
tcam_sw_set_ainfo(te, unique, AI_MASK);
tcam_sw_text(te, "ipv6_2t_B");
tcam_hw_write(te, tid2);
tcam_sw_free(te);
return 0;
}
int pnc_ipv4_2_tuples_add(unsigned int tid, unsigned int flow_id, unsigned int sip, unsigned int dip, unsigned int rxq)
{
struct tcam_entry *te;
PNC_DBG("%s [%d] flow=%d " MV_IPQUAD_FMT "->" MV_IPQUAD_FMT "\n",
__func__, tid, flow_id, MV_IPQUAD(((MV_U8 *)&sip)), MV_IPQUAD(((MV_U8 *)&dip)));
if (tid < TE_FLOW_L3)
ERR_ON_OOR(1);
if (tid > TE_FLOW_L3_END)
ERR_ON_OOR(1);
te = tcam_sw_alloc(TCAM_LU_FLOW_IP4);
tcam_sw_set_byte(te, 12, (sip >> 0) & 0xFF);
tcam_sw_set_byte(te, 13, (sip >> 8) & 0xFF);
tcam_sw_set_byte(te, 14, (sip >> 16) & 0xFF);
tcam_sw_set_byte(te, 15, (sip >> 24) & 0xFF);
tcam_sw_set_byte(te, 16, (dip >> 0) & 0xFF);
tcam_sw_set_byte(te, 17, (dip >> 8) & 0xFF);
tcam_sw_set_byte(te, 18, (dip >> 16) & 0xFF);
tcam_sw_set_byte(te, 19, (dip >> 24) & 0xFF);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, flow_id, FLOWID_CTRL_FULL_MASK);
sram_sw_set_rxq(te, rxq, 0);
sram_sw_set_rinfo(te, RI_L3_FLOW, RI_L3_FLOW);
tcam_sw_text(te, "ipv4_2t");
tcam_hw_write(te, tid);
tcam_sw_free(te);
#ifdef MV_ETH_PNC_AGING
mvPncAgingCntrGroupSet(tid, 3);
#endif
return 0;
}
int pnc_ipv4_5_tuples_add(unsigned int tid, unsigned int flow_id,
unsigned int sip, unsigned int dip, unsigned int proto, unsigned int ports, unsigned int rxq)
{
struct tcam_entry *te;
PNC_DBG("%s [%d] flow=%d " MV_IPQUAD_FMT "->" MV_IPQUAD_FMT ", ports=0x%x, proto=%d\n",
__func__, tid, flow_id, MV_IPQUAD(((MV_U8 *)&sip)), MV_IPQUAD(((MV_U8 *)&dip)), ports, proto);
if (tid < TE_FLOW_L3)
ERR_ON_OOR(1);
if (tid > TE_FLOW_L3_END)
ERR_ON_OOR(1);
/* sanity check */
te = tcam_sw_alloc(TCAM_LU_FLOW_IP4);
tcam_sw_set_byte(te, 9, proto);
tcam_sw_set_byte(te, 12, (sip >> 0) & 0xFF);
tcam_sw_set_byte(te, 13, (sip >> 8) & 0xFF);
tcam_sw_set_byte(te, 14, (sip >> 16) & 0xFF);
tcam_sw_set_byte(te, 15, (sip >> 24) & 0xFF);
tcam_sw_set_byte(te, 16, (dip >> 0) & 0xFF);
tcam_sw_set_byte(te, 17, (dip >> 8) & 0xFF);
tcam_sw_set_byte(te, 18, (dip >> 16) & 0xFF);
tcam_sw_set_byte(te, 19, (dip >> 24) & 0xFF);
tcam_sw_set_byte(te, 20, (ports >> 0) & 0xFF);
tcam_sw_set_byte(te, 21, (ports >> 8) & 0xFF);
tcam_sw_set_byte(te, 22, (ports >> 16) & 0xFF);
tcam_sw_set_byte(te, 23, (ports >> 24) & 0xFF);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, flow_id, FLOWID_CTRL_FULL_MASK);
sram_sw_set_rxq(te, rxq, 0);
sram_sw_set_rinfo(te, RI_L3_FLOW, RI_L3_FLOW);
tcam_sw_text(te, "ipv4_5t");
tcam_hw_write(te, tid);
tcam_sw_free(te);
#ifdef MV_ETH_PNC_AGING
mvPncAgingCntrGroupSet(tid, 2);
#endif
return 0;
}
#else
int pnc_l4_end(void)
{
struct tcam_entry *te;
PNC_DBG("%s\n", __func__);
te = tcam_sw_alloc(TCAM_LU_L4);
sram_sw_set_lookup_done(te, 1);
sram_sw_set_flowid(te, FLOWID_EOF_LU_L4, FLOWID_CTRL_LOW_HALF_MASK);
tcam_sw_text(te, "l4_eof");
tcam_hw_write(te, TE_L4_EOF);
tcam_sw_free(te);
return 0;
}
#endif /* CONFIG_MV_ETH_PNC_L3_FLOW */
/******************************************************************************
*
* PnC Init
*
******************************************************************************
*/
int pnc_default_init(void)
{
int rc, port;
MV_U32 regVal = 0;
PNC_DBG("%s\n", __func__);
rc = tcam_hw_init();
if (rc)
goto out;
/* Mask all interrupts */
MV_REG_WRITE(MV_PNC_MASK_REG, 0xffffffff);
/* Clear all interrupts */
MV_REG_WRITE(MV_PNC_CAUSE_REG, 0x0);
/* Always start from lookup = 0 */
for (port = 0; port < PORT_BITS; port++)
regVal |= MV_PNC_PORT_LU_INIT_VAL(port, TCAM_LU_MAC);
MV_REG_WRITE(MV_PNC_INIT_LOOKUP_REG, regVal);
rc = pnc_mac_init();
if (rc)
goto out;
rc = pnc_vlan_init();
if (rc)
goto out;
rc = pnc_etype_init();
if (rc)
goto out;
rc = pnc_ip4_init();
if (rc)
goto out;
rc = pnc_ip6_init();
if (rc)
goto out;
#ifdef CONFIG_MV_ETH_PNC_L3_FLOW
rc = pnc_flow_init();
if (rc)
goto out;
#else
rc = pnc_l4_end();
if (rc)
goto out;
#endif /* CONFIG_MV_ETH_PNC_L3_FLOW */
#ifdef CONFIG_MV_ETH_PNC_WOL
mv_pnc_wol_init();
#endif /* CONFIG_MV_ETH_PNC_WOL */
pnc_inited = 1;
out:
return rc;
}
static void pnc_port_sprintf(struct tcam_entry *te, char *buf)
{
int p, offs;
unsigned int data, mask;
tcam_sw_get_port(te, &data, &mask);
if (mask == PORT_MASK)
mvOsSPrintf(buf, "None");
else if (mask == 0)
mvOsSPrintf(buf, "All");
else {
offs = 0;
for (p = 0; p < PORT_BITS; p++) {
if ((mask & (1 << p)) == 0)
offs += mvOsSPrintf(buf + offs, " %d,", pnc_port_map(p));
}
}
}
void pnc_vlan_prio_show(int port)
{
#if (CONFIG_MV_ETH_PNC_VLAN_PRIO > 0)
struct tcam_entry *te;
int tid;
unsigned char prio;
char buf[16];
mvOsPrintf("Prio Mask Ports RXQ Name\n");
for (tid = TE_VLAN_PRIO; tid <= TE_VLAN_PRIO_END; tid++) {
te = pnc_tcam_entry_get(tid);
if (te) {
prio = *(te->data.u.byte + 2);
mvOsPrintf("0x%02x", prio >> 5);
prio = *(te->mask.u.byte + 2);
mvOsPrintf(" 0x%02x", prio >> 5);
pnc_port_sprintf(te, buf);
mvOsPrintf(" %12s", buf);
mvOsPrintf(" %d", sram_sw_get_rxq(te, NULL));
mvOsPrintf(" %s\n", te->ctrl.text);
tcam_sw_free(te);
}
}
#endif /* (CONFIG_MV_ETH_PNC_VLAN_PRIO > 0) */
return;
}
void pnc_ipv4_dscp_show(int port)
{
#if (CONFIG_MV_ETH_PNC_DSCP_PRIO > 0)
struct tcam_entry *te;
int tid;
unsigned char tos;
char buf[16];
mvOsPrintf("TOS Mask Ports RXQ Name\n");
for (tid = TE_IP4_DSCP; tid <= TE_IP4_DSCP_END; tid++) {
te = pnc_tcam_entry_get(tid);
if (te) {
tos = *(te->data.u.byte + 1);
mvOsPrintf("0x%02x", tos);
tos = *(te->mask.u.byte + 1);
mvOsPrintf(" 0x%02x", tos);
pnc_port_sprintf(te, buf);
mvOsPrintf(" %10s", buf);
mvOsPrintf(" %d", sram_sw_get_rxq(te, NULL));
mvOsPrintf(" %s\n", te->ctrl.text);
tcam_sw_free(te);
}
}
#endif /* CONFIG_MV_ETH_PNC_DSCP_PRIO > 0 */
return;
}
void pnc_mac_show(void)
{
int tid;
struct tcam_entry *te;
char *mac;
char buf[16];
mvOsPrintf(" Addr Mask Ports RXQ Name\n");
for (tid = TE_MAC_BC; tid < TE_MAC_EOF; tid++) {
te = pnc_tcam_entry_get(tid);
if (te) {
mac = te->data.u.byte + MV_ETH_MH_SIZE;
mvOsPrintf(MV_MACQUAD_FMT, MV_MACQUAD(mac));
mac = te->mask.u.byte + MV_ETH_MH_SIZE;
mvOsPrintf(" " MV_MACQUAD_FMT, MV_MACQUAD(mac));
pnc_port_sprintf(te, buf);
mvOsPrintf(" %10s", buf);
mvOsPrintf(" %d", sram_sw_get_rxq(te, NULL));
mvOsPrintf(" %s\n", te->ctrl.text);
tcam_sw_free(te);
}
}
}