|
@@ -65,6 +65,10 @@
|
|
|
#define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000
|
|
|
#define MVPP2_RXQ_DISABLE_MASK BIT(31)
|
|
|
|
|
|
+/* Top Registers */
|
|
|
+#define MVPP2_MH_REG(port) (0x5040 + 4 * (port))
|
|
|
+#define MVPP2_DSA_EXTENDED BIT(5)
|
|
|
+
|
|
|
/* Parser Registers */
|
|
|
#define MVPP2_PRS_INIT_LOOKUP_REG 0x1000
|
|
|
#define MVPP2_PRS_PORT_LU_MAX 0xf
|
|
@@ -473,6 +477,7 @@
|
|
|
#define MVPP2_ETH_TYPE_LEN 2
|
|
|
#define MVPP2_PPPOE_HDR_SIZE 8
|
|
|
#define MVPP2_VLAN_TAG_LEN 4
|
|
|
+#define MVPP2_VLAN_TAG_EDSA_LEN 8
|
|
|
|
|
|
/* Lbtd 802.3 type */
|
|
|
#define MVPP2_IP_LBDT_TYPE 0xfffa
|
|
@@ -609,35 +614,64 @@ enum mvpp2_tag_type {
|
|
|
#define MVPP2_PRS_TCAM_LU_BYTE 20
|
|
|
#define MVPP2_PRS_TCAM_EN_OFFS(offs) ((offs) + 2)
|
|
|
#define MVPP2_PRS_TCAM_INV_WORD 5
|
|
|
+
|
|
|
+#define MVPP2_PRS_VID_TCAM_BYTE 2
|
|
|
+
|
|
|
+/* There is a TCAM range reserved for VLAN filtering entries, range size is 33
|
|
|
+ * 10 VLAN ID filter entries per port
|
|
|
+ * 1 default VLAN filter entry per port
|
|
|
+ * It is assumed that there are 3 ports for filter, not including loopback port
|
|
|
+ */
|
|
|
+#define MVPP2_PRS_VLAN_FILT_MAX 11
|
|
|
+#define MVPP2_PRS_VLAN_FILT_RANGE_SIZE 33
|
|
|
+
|
|
|
+#define MVPP2_PRS_VLAN_FILT_MAX_ENTRY (MVPP2_PRS_VLAN_FILT_MAX - 2)
|
|
|
+#define MVPP2_PRS_VLAN_FILT_DFLT_ENTRY (MVPP2_PRS_VLAN_FILT_MAX - 1)
|
|
|
+
|
|
|
/* Tcam entries ID */
|
|
|
#define MVPP2_PE_DROP_ALL 0
|
|
|
#define MVPP2_PE_FIRST_FREE_TID 1
|
|
|
-#define MVPP2_PE_LAST_FREE_TID (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
|
|
|
+
|
|
|
+/* VLAN filtering range */
|
|
|
+#define MVPP2_PE_VID_FILT_RANGE_END (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
|
|
|
+#define MVPP2_PE_VID_FILT_RANGE_START (MVPP2_PE_VID_FILT_RANGE_END - \
|
|
|
+ MVPP2_PRS_VLAN_FILT_RANGE_SIZE + 1)
|
|
|
+#define MVPP2_PE_LAST_FREE_TID (MVPP2_PE_VID_FILT_RANGE_START - 1)
|
|
|
#define MVPP2_PE_IP6_EXT_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 30)
|
|
|
#define MVPP2_PE_MAC_MC_IP6 (MVPP2_PRS_TCAM_SRAM_SIZE - 29)
|
|
|
#define MVPP2_PE_IP6_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 28)
|
|
|
#define MVPP2_PE_IP4_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 27)
|
|
|
#define MVPP2_PE_LAST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 26)
|
|
|
-#define MVPP2_PE_FIRST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 19)
|
|
|
-#define MVPP2_PE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 18)
|
|
|
-#define MVPP2_PE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 17)
|
|
|
-#define MVPP2_PE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 16)
|
|
|
-#define MVPP2_PE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 15)
|
|
|
-#define MVPP2_PE_ETYPE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 14)
|
|
|
-#define MVPP2_PE_ETYPE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 13)
|
|
|
-#define MVPP2_PE_ETYPE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 12)
|
|
|
-#define MVPP2_PE_ETYPE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 11)
|
|
|
-#define MVPP2_PE_MH_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 10)
|
|
|
-#define MVPP2_PE_DSA_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 9)
|
|
|
-#define MVPP2_PE_IP6_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 8)
|
|
|
-#define MVPP2_PE_IP4_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 7)
|
|
|
-#define MVPP2_PE_ETH_TYPE_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 6)
|
|
|
+#define MVPP2_PE_FIRST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 21)
|
|
|
+#define MVPP2_PE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 20)
|
|
|
+#define MVPP2_PE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 19)
|
|
|
+#define MVPP2_PE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 18)
|
|
|
+#define MVPP2_PE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 17)
|
|
|
+#define MVPP2_PE_ETYPE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 16)
|
|
|
+#define MVPP2_PE_ETYPE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 15)
|
|
|
+#define MVPP2_PE_ETYPE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 14)
|
|
|
+#define MVPP2_PE_ETYPE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 13)
|
|
|
+#define MVPP2_PE_MH_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 12)
|
|
|
+#define MVPP2_PE_DSA_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 11)
|
|
|
+#define MVPP2_PE_IP6_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 10)
|
|
|
+#define MVPP2_PE_IP4_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 9)
|
|
|
+#define MVPP2_PE_ETH_TYPE_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 8)
|
|
|
+#define MVPP2_PE_VID_FLTR_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 7)
|
|
|
+#define MVPP2_PE_VID_EDSA_FLTR_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 6)
|
|
|
#define MVPP2_PE_VLAN_DBL (MVPP2_PRS_TCAM_SRAM_SIZE - 5)
|
|
|
#define MVPP2_PE_VLAN_NONE (MVPP2_PRS_TCAM_SRAM_SIZE - 4)
|
|
|
#define MVPP2_PE_MAC_MC_ALL (MVPP2_PRS_TCAM_SRAM_SIZE - 3)
|
|
|
#define MVPP2_PE_MAC_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 2)
|
|
|
#define MVPP2_PE_MAC_NON_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 1)
|
|
|
|
|
|
+#define MVPP2_PRS_VID_PORT_FIRST(port) (MVPP2_PE_VID_FILT_RANGE_START + \
|
|
|
+ ((port) * MVPP2_PRS_VLAN_FILT_MAX))
|
|
|
+#define MVPP2_PRS_VID_PORT_LAST(port) (MVPP2_PRS_VID_PORT_FIRST(port) \
|
|
|
+ + MVPP2_PRS_VLAN_FILT_MAX_ENTRY)
|
|
|
+/* Index of default vid filter for given port */
|
|
|
+#define MVPP2_PRS_VID_PORT_DFLT(port) (MVPP2_PRS_VID_PORT_FIRST(port) \
|
|
|
+ + MVPP2_PRS_VLAN_FILT_DFLT_ENTRY)
|
|
|
+
|
|
|
/* Sram structure
|
|
|
* The fields are represented by MVPP2_PRS_TCAM_DATA_REG(3)->(0).
|
|
|
*/
|
|
@@ -725,6 +759,7 @@ enum mvpp2_tag_type {
|
|
|
#define MVPP2_PRS_IPV6_EXT_AH_L4_AI_BIT BIT(4)
|
|
|
#define MVPP2_PRS_SINGLE_VLAN_AI 0
|
|
|
#define MVPP2_PRS_DBL_VLAN_AI_BIT BIT(7)
|
|
|
+#define MVPP2_PRS_EDSA_VID_AI_BIT BIT(0)
|
|
|
|
|
|
/* DSA/EDSA type */
|
|
|
#define MVPP2_PRS_TAGGED true
|
|
@@ -747,6 +782,7 @@ enum mvpp2_prs_lookup {
|
|
|
MVPP2_PRS_LU_MAC,
|
|
|
MVPP2_PRS_LU_DSA,
|
|
|
MVPP2_PRS_LU_VLAN,
|
|
|
+ MVPP2_PRS_LU_VID,
|
|
|
MVPP2_PRS_LU_L2,
|
|
|
MVPP2_PRS_LU_PPPOE,
|
|
|
MVPP2_PRS_LU_IP4,
|
|
@@ -1662,6 +1698,14 @@ static void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset,
|
|
|
mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff);
|
|
|
}
|
|
|
|
|
|
+/* Set vid in tcam sw entry */
|
|
|
+static void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
|
|
|
+ unsigned short vid)
|
|
|
+{
|
|
|
+ mvpp2_prs_tcam_data_byte_set(pe, offset + 0, (vid & 0xf00) >> 8, 0xf);
|
|
|
+ mvpp2_prs_tcam_data_byte_set(pe, offset + 1, vid & 0xff, 0xff);
|
|
|
+}
|
|
|
+
|
|
|
/* Set bits in sram sw entry */
|
|
|
static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
|
|
|
int val)
|
|
@@ -2029,24 +2073,30 @@ static void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add,
|
|
|
mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
|
|
|
pe.index = tid;
|
|
|
|
|
|
- /* Shift 4 bytes if DSA tag or 8 bytes in case of EDSA tag*/
|
|
|
- mvpp2_prs_sram_shift_set(&pe, shift,
|
|
|
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
-
|
|
|
/* Update shadow table */
|
|
|
mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
|
|
|
|
|
|
if (tagged) {
|
|
|
/* Set tagged bit in DSA tag */
|
|
|
mvpp2_prs_tcam_data_byte_set(&pe, 0,
|
|
|
- MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
|
|
|
- MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
|
|
|
- /* Clear all ai bits for next iteration */
|
|
|
- mvpp2_prs_sram_ai_update(&pe, 0,
|
|
|
- MVPP2_PRS_SRAM_AI_MASK);
|
|
|
- /* If packet is tagged continue check vlans */
|
|
|
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
|
|
|
+ MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
|
|
|
+ MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
|
|
|
+
|
|
|
+ /* Set ai bits for next iteration */
|
|
|
+ if (extend)
|
|
|
+ mvpp2_prs_sram_ai_update(&pe, 1,
|
|
|
+ MVPP2_PRS_SRAM_AI_MASK);
|
|
|
+ else
|
|
|
+ mvpp2_prs_sram_ai_update(&pe, 0,
|
|
|
+ MVPP2_PRS_SRAM_AI_MASK);
|
|
|
+
|
|
|
+ /* If packet is tagged continue check vid filtering */
|
|
|
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
|
|
|
} else {
|
|
|
+ /* Shift 4 bytes for DSA tag or 8 bytes for EDSA tag*/
|
|
|
+ mvpp2_prs_sram_shift_set(&pe, shift,
|
|
|
+ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
+
|
|
|
/* Set result info bits to 'no vlans' */
|
|
|
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
|
|
|
MVPP2_PRS_RI_VLAN_MASK);
|
|
@@ -2231,10 +2281,9 @@ static int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
|
|
|
|
|
|
mvpp2_prs_match_etype(pe, 0, tpid);
|
|
|
|
|
|
- mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_L2);
|
|
|
- /* Shift 4 bytes - skip 1 vlan tag */
|
|
|
- mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN,
|
|
|
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
+ /* VLAN tag detected, proceed with VID filtering */
|
|
|
+ mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VID);
|
|
|
+
|
|
|
/* Clear all ai bits for next iteration */
|
|
|
mvpp2_prs_sram_ai_update(pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
|
|
|
@@ -2375,8 +2424,8 @@ static int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1,
|
|
|
mvpp2_prs_match_etype(pe, 4, tpid2);
|
|
|
|
|
|
mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VLAN);
|
|
|
- /* Shift 8 bytes - skip 2 vlan tags */
|
|
|
- mvpp2_prs_sram_shift_set(pe, 2 * MVPP2_VLAN_TAG_LEN,
|
|
|
+ /* Shift 4 bytes - skip outer vlan tag */
|
|
|
+ mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN,
|
|
|
MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_DOUBLE,
|
|
|
MVPP2_PRS_RI_VLAN_MASK);
|
|
@@ -2755,6 +2804,62 @@ static void mvpp2_prs_dsa_init(struct mvpp2 *priv)
|
|
|
mvpp2_prs_hw_write(priv, &pe);
|
|
|
}
|
|
|
|
|
|
+/* Initialize parser entries for VID filtering */
|
|
|
+static void mvpp2_prs_vid_init(struct mvpp2 *priv)
|
|
|
+{
|
|
|
+ struct mvpp2_prs_entry pe;
|
|
|
+
|
|
|
+ memset(&pe, 0, sizeof(pe));
|
|
|
+
|
|
|
+ /* Set default vid entry */
|
|
|
+ pe.index = MVPP2_PE_VID_FLTR_DEFAULT;
|
|
|
+ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
|
|
|
+
|
|
|
+ mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_EDSA_VID_AI_BIT);
|
|
|
+
|
|
|
+ /* Skip VLAN header - Set offset to 4 bytes */
|
|
|
+ mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
|
|
|
+ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
+
|
|
|
+ /* Clear all ai bits for next iteration */
|
|
|
+ mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
|
+
|
|
|
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
|
|
|
+
|
|
|
+ /* Unmask all ports */
|
|
|
+ mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
|
|
|
+
|
|
|
+ /* Update shadow table and hw entry */
|
|
|
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
|
|
|
+ mvpp2_prs_hw_write(priv, &pe);
|
|
|
+
|
|
|
+ /* Set default vid entry for extended DSA*/
|
|
|
+ memset(&pe, 0, sizeof(pe));
|
|
|
+
|
|
|
+ /* Set default vid entry */
|
|
|
+ pe.index = MVPP2_PE_VID_EDSA_FLTR_DEFAULT;
|
|
|
+ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
|
|
|
+
|
|
|
+ mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_EDSA_VID_AI_BIT,
|
|
|
+ MVPP2_PRS_EDSA_VID_AI_BIT);
|
|
|
+
|
|
|
+ /* Skip VLAN header - Set offset to 8 bytes */
|
|
|
+ mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_EDSA_LEN,
|
|
|
+ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
+
|
|
|
+ /* Clear all ai bits for next iteration */
|
|
|
+ mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
|
+
|
|
|
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
|
|
|
+
|
|
|
+ /* Unmask all ports */
|
|
|
+ mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
|
|
|
+
|
|
|
+ /* Update shadow table and hw entry */
|
|
|
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
|
|
|
+ mvpp2_prs_hw_write(priv, &pe);
|
|
|
+}
|
|
|
+
|
|
|
/* Match basic ethertypes */
|
|
|
static int mvpp2_prs_etype_init(struct mvpp2 *priv)
|
|
|
{
|
|
@@ -3023,7 +3128,8 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
|
|
|
mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
|
|
|
pe.index = MVPP2_PE_VLAN_DBL;
|
|
|
|
|
|
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
|
|
|
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
|
|
|
+
|
|
|
/* Clear ai for next iterations */
|
|
|
mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
|
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
|
|
@@ -3386,6 +3492,192 @@ static int mvpp2_prs_ip6_init(struct mvpp2 *priv)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* Find tcam entry with matched pair <vid,port> */
|
|
|
+static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid,
|
|
|
+ u16 mask)
|
|
|
+{
|
|
|
+ unsigned char byte[2], enable[2];
|
|
|
+ struct mvpp2_prs_entry pe;
|
|
|
+ u16 rvid, rmask;
|
|
|
+ int tid;
|
|
|
+
|
|
|
+ /* Go through the all entries with MVPP2_PRS_LU_VID */
|
|
|
+ for (tid = MVPP2_PE_VID_FILT_RANGE_START;
|
|
|
+ tid <= MVPP2_PE_VID_FILT_RANGE_END; tid++) {
|
|
|
+ if (!priv->prs_shadow[tid].valid ||
|
|
|
+ priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ pe.index = tid;
|
|
|
+
|
|
|
+ mvpp2_prs_hw_read(priv, &pe);
|
|
|
+ mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
|
|
|
+ mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
|
|
|
+
|
|
|
+ rvid = ((byte[0] & 0xf) << 8) + byte[1];
|
|
|
+ rmask = ((enable[0] & 0xf) << 8) + enable[1];
|
|
|
+
|
|
|
+ if (rvid != vid || rmask != mask)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ return tid;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Write parser entry for VID filtering */
|
|
|
+static int mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
|
|
|
+{
|
|
|
+ unsigned int vid_start = MVPP2_PE_VID_FILT_RANGE_START +
|
|
|
+ port->id * MVPP2_PRS_VLAN_FILT_MAX;
|
|
|
+ unsigned int mask = 0xfff, reg_val, shift;
|
|
|
+ struct mvpp2 *priv = port->priv;
|
|
|
+ struct mvpp2_prs_entry pe;
|
|
|
+ int tid;
|
|
|
+
|
|
|
+ /* Scan TCAM and see if entry with this <vid,port> already exist */
|
|
|
+ tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask);
|
|
|
+
|
|
|
+ reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
|
|
|
+ if (reg_val & MVPP2_DSA_EXTENDED)
|
|
|
+ shift = MVPP2_VLAN_TAG_EDSA_LEN;
|
|
|
+ else
|
|
|
+ shift = MVPP2_VLAN_TAG_LEN;
|
|
|
+
|
|
|
+ /* No such entry */
|
|
|
+ if (!tid) {
|
|
|
+ memset(&pe, 0, sizeof(pe));
|
|
|
+
|
|
|
+ /* Go through all entries from first to last in vlan range */
|
|
|
+ tid = mvpp2_prs_tcam_first_free(priv, vid_start,
|
|
|
+ vid_start +
|
|
|
+ MVPP2_PRS_VLAN_FILT_MAX_ENTRY);
|
|
|
+
|
|
|
+ /* There isn't room for a new VID filter */
|
|
|
+ if (tid < 0)
|
|
|
+ return tid;
|
|
|
+
|
|
|
+ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
|
|
|
+ pe.index = tid;
|
|
|
+
|
|
|
+ /* Mask all ports */
|
|
|
+ mvpp2_prs_tcam_port_map_set(&pe, 0);
|
|
|
+ } else {
|
|
|
+ mvpp2_prs_hw_read(priv, &pe);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Enable the current port */
|
|
|
+ mvpp2_prs_tcam_port_set(&pe, port->id, true);
|
|
|
+
|
|
|
+ /* Continue - set next lookup */
|
|
|
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
|
|
|
+
|
|
|
+ /* Skip VLAN header - Set offset to 4 or 8 bytes */
|
|
|
+ mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
+
|
|
|
+ /* Set match on VID */
|
|
|
+ mvpp2_prs_match_vid(&pe, MVPP2_PRS_VID_TCAM_BYTE, vid);
|
|
|
+
|
|
|
+ /* Clear all ai bits for next iteration */
|
|
|
+ mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
|
+
|
|
|
+ /* Update shadow table */
|
|
|
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
|
|
|
+ mvpp2_prs_hw_write(priv, &pe);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Write parser entry for VID filtering */
|
|
|
+static void mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
|
|
|
+{
|
|
|
+ struct mvpp2 *priv = port->priv;
|
|
|
+ int tid;
|
|
|
+
|
|
|
+ /* Scan TCAM and see if entry with this <vid,port> already exist */
|
|
|
+ tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff);
|
|
|
+
|
|
|
+ /* No such entry */
|
|
|
+ if (tid)
|
|
|
+ return;
|
|
|
+
|
|
|
+ mvpp2_prs_hw_inv(priv, tid);
|
|
|
+ priv->prs_shadow[tid].valid = false;
|
|
|
+}
|
|
|
+
|
|
|
+/* Remove all existing VID filters on this port */
|
|
|
+static void mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
|
|
|
+{
|
|
|
+ struct mvpp2 *priv = port->priv;
|
|
|
+ int tid;
|
|
|
+
|
|
|
+ for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
|
|
|
+ tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
|
|
|
+ if (priv->prs_shadow[tid].valid)
|
|
|
+ mvpp2_prs_vid_entry_remove(port, tid);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* Remove VID filering entry for this port */
|
|
|
+static void mvpp2_prs_vid_disable_filtering(struct mvpp2_port *port)
|
|
|
+{
|
|
|
+ unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
|
|
|
+ struct mvpp2 *priv = port->priv;
|
|
|
+
|
|
|
+ /* Invalidate the guard entry */
|
|
|
+ mvpp2_prs_hw_inv(priv, tid);
|
|
|
+
|
|
|
+ priv->prs_shadow[tid].valid = false;
|
|
|
+}
|
|
|
+
|
|
|
+/* Add guard entry that drops packets when no VID is matched on this port */
|
|
|
+static void mvpp2_prs_vid_enable_filtering(struct mvpp2_port *port)
|
|
|
+{
|
|
|
+ unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
|
|
|
+ struct mvpp2 *priv = port->priv;
|
|
|
+ unsigned int reg_val, shift;
|
|
|
+ struct mvpp2_prs_entry pe;
|
|
|
+
|
|
|
+ if (priv->prs_shadow[tid].valid)
|
|
|
+ return;
|
|
|
+
|
|
|
+ memset(&pe, 0, sizeof(pe));
|
|
|
+
|
|
|
+ pe.index = tid;
|
|
|
+
|
|
|
+ reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
|
|
|
+ if (reg_val & MVPP2_DSA_EXTENDED)
|
|
|
+ shift = MVPP2_VLAN_TAG_EDSA_LEN;
|
|
|
+ else
|
|
|
+ shift = MVPP2_VLAN_TAG_LEN;
|
|
|
+
|
|
|
+ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
|
|
|
+
|
|
|
+ /* Mask all ports */
|
|
|
+ mvpp2_prs_tcam_port_map_set(&pe, 0);
|
|
|
+
|
|
|
+ /* Update port mask */
|
|
|
+ mvpp2_prs_tcam_port_set(&pe, port->id, true);
|
|
|
+
|
|
|
+ /* Continue - set next lookup */
|
|
|
+ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
|
|
|
+
|
|
|
+ /* Skip VLAN header - Set offset to 4 or 8 bytes */
|
|
|
+ mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
|
+
|
|
|
+ /* Drop VLAN packets that don't belong to any VIDs on this port */
|
|
|
+ mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
|
|
|
+ MVPP2_PRS_RI_DROP_MASK);
|
|
|
+
|
|
|
+ /* Clear all ai bits for next iteration */
|
|
|
+ mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
|
+
|
|
|
+ /* Update shadow table */
|
|
|
+ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
|
|
|
+ mvpp2_prs_hw_write(priv, &pe);
|
|
|
+}
|
|
|
+
|
|
|
/* Parser default initialization */
|
|
|
static int mvpp2_prs_default_init(struct platform_device *pdev,
|
|
|
struct mvpp2 *priv)
|
|
@@ -3429,6 +3721,8 @@ static int mvpp2_prs_default_init(struct platform_device *pdev,
|
|
|
|
|
|
mvpp2_prs_dsa_init(priv);
|
|
|
|
|
|
+ mvpp2_prs_vid_init(priv);
|
|
|
+
|
|
|
err = mvpp2_prs_etype_init(priv);
|
|
|
if (err)
|
|
|
return err;
|
|
@@ -7153,6 +7447,12 @@ retry:
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /* Disable VLAN filtering in promiscuous mode */
|
|
|
+ if (dev->flags & IFF_PROMISC)
|
|
|
+ mvpp2_prs_vid_disable_filtering(port);
|
|
|
+ else
|
|
|
+ mvpp2_prs_vid_enable_filtering(port);
|
|
|
}
|
|
|
|
|
|
static int mvpp2_set_mac_address(struct net_device *dev, void *p)
|
|
@@ -7292,6 +7592,48 @@ static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int mvpp2_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
|
|
|
+{
|
|
|
+ struct mvpp2_port *port = netdev_priv(dev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = mvpp2_prs_vid_entry_add(port, vid);
|
|
|
+ if (ret)
|
|
|
+ netdev_err(dev, "rx-vlan-filter offloading cannot accept more than %d VIDs per port\n",
|
|
|
+ MVPP2_PRS_VLAN_FILT_MAX - 1);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int mvpp2_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
|
|
|
+{
|
|
|
+ struct mvpp2_port *port = netdev_priv(dev);
|
|
|
+
|
|
|
+ mvpp2_prs_vid_entry_remove(port, vid);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mvpp2_set_features(struct net_device *dev,
|
|
|
+ netdev_features_t features)
|
|
|
+{
|
|
|
+ netdev_features_t changed = dev->features ^ features;
|
|
|
+ struct mvpp2_port *port = netdev_priv(dev);
|
|
|
+
|
|
|
+ if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
|
|
|
+ if (features & NETIF_F_HW_VLAN_CTAG_FILTER) {
|
|
|
+ mvpp2_prs_vid_enable_filtering(port);
|
|
|
+ } else {
|
|
|
+ /* Invalidate all registered VID filters for this
|
|
|
+ * port
|
|
|
+ */
|
|
|
+ mvpp2_prs_vid_remove_all(port);
|
|
|
+
|
|
|
+ mvpp2_prs_vid_disable_filtering(port);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* Ethtool methods */
|
|
|
|
|
|
/* Set interrupt coalescing for ethtools */
|
|
@@ -7433,6 +7775,9 @@ static const struct net_device_ops mvpp2_netdev_ops = {
|
|
|
.ndo_change_mtu = mvpp2_change_mtu,
|
|
|
.ndo_get_stats64 = mvpp2_get_stats64,
|
|
|
.ndo_do_ioctl = mvpp2_ioctl,
|
|
|
+ .ndo_vlan_rx_add_vid = mvpp2_vlan_rx_add_vid,
|
|
|
+ .ndo_vlan_rx_kill_vid = mvpp2_vlan_rx_kill_vid,
|
|
|
+ .ndo_set_features = mvpp2_set_features,
|
|
|
};
|
|
|
|
|
|
static const struct ethtool_ops mvpp2_eth_tool_ops = {
|
|
@@ -7945,7 +8290,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
|
|
|
|
|
|
features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
|
|
|
dev->features = features | NETIF_F_RXCSUM;
|
|
|
- dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO;
|
|
|
+ dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO |
|
|
|
+ NETIF_F_HW_VLAN_CTAG_FILTER;
|
|
|
dev->vlan_features |= features;
|
|
|
dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
|
|
|
|