summaryrefslogtreecommitdiff
path: root/drivers/net/dsa/bcm_sf2_cfp.c
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2017-10-20 14:39:49 -0700
committerDavid S. Miller <davem@davemloft.net>2017-10-23 03:06:47 +0100
commitdd8eff68343d5ab6535fb05bc837a2f85434d506 (patch)
tree9da60c9ec6a4b5fee6a59507fedd712d8fc41aed /drivers/net/dsa/bcm_sf2_cfp.c
parentbc3fc44c12d6a4722b253f19423db1244175c18c (diff)
downloadlwn-dd8eff68343d5ab6535fb05bc837a2f85434d506.tar.gz
lwn-dd8eff68343d5ab6535fb05bc837a2f85434d506.zip
net: dsa: bcm_sf2: Allow matching arbitrary IPv6 masks/lengths
There is no reason why we should limit ourselves to matching only full IPv4 addresses (/32), the same logic applies between the DATA and MASK ports, so just make it more configurable to accept both. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa/bcm_sf2_cfp.c')
-rw-r--r--drivers/net/dsa/bcm_sf2_cfp.c113
1 files changed, 80 insertions, 33 deletions
diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c
index 043fd39793cc..4feb507eeee0 100644
--- a/drivers/net/dsa/bcm_sf2_cfp.c
+++ b/drivers/net/dsa/bcm_sf2_cfp.c
@@ -441,9 +441,10 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
const __be32 *ip6_addr, const __be16 port,
- unsigned int slice_num)
+ unsigned int slice_num,
+ bool mask)
{
- u32 reg, tmp, val;
+ u32 reg, tmp, val, offset;
/* C-Tag [31:24]
* UDF_n_B8 [23:8] (port)
@@ -451,7 +452,11 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
*/
reg = be32_to_cpu(ip6_addr[3]);
val = (u32)be16_to_cpu(port) << 8 | ((reg >> 8) & 0xff);
- core_writel(priv, val, CORE_CFP_DATA_PORT(4));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(4);
+ else
+ offset = CORE_CFP_DATA_PORT(4);
+ core_writel(priv, val, offset);
/* UDF_n_B7 (lower) [31:24] (addr[7:0])
* UDF_n_B6 [23:8] (addr[31:16])
@@ -460,7 +465,11 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
tmp = be32_to_cpu(ip6_addr[2]);
val = (u32)(reg & 0xff) << 24 | (u32)(reg >> 16) << 8 |
((tmp >> 8) & 0xff);
- core_writel(priv, val, CORE_CFP_DATA_PORT(3));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(3);
+ else
+ offset = CORE_CFP_DATA_PORT(3);
+ core_writel(priv, val, offset);
/* UDF_n_B5 (lower) [31:24] (addr[39:32])
* UDF_n_B4 [23:8] (addr[63:48])
@@ -469,7 +478,11 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
reg = be32_to_cpu(ip6_addr[1]);
val = (u32)(tmp & 0xff) << 24 | (u32)(tmp >> 16) << 8 |
((reg >> 8) & 0xff);
- core_writel(priv, val, CORE_CFP_DATA_PORT(2));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(2);
+ else
+ offset = CORE_CFP_DATA_PORT(2);
+ core_writel(priv, val, offset);
/* UDF_n_B3 (lower) [31:24] (addr[71:64])
* UDF_n_B2 [23:8] (addr[95:80])
@@ -478,7 +491,11 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
tmp = be32_to_cpu(ip6_addr[0]);
val = (u32)(reg & 0xff) << 24 | (u32)(reg >> 16) << 8 |
((tmp >> 8) & 0xff);
- core_writel(priv, val, CORE_CFP_DATA_PORT(1));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(1);
+ else
+ offset = CORE_CFP_DATA_PORT(1);
+ core_writel(priv, val, offset);
/* UDF_n_B1 (lower) [31:24] (addr[103:96])
* UDF_n_B0 [23:8] (addr[127:112])
@@ -488,14 +505,11 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
*/
reg = (u32)(tmp & 0xff) << 24 | (u32)(tmp >> 16) << 8 |
SLICE_NUM(slice_num) | SLICE_VALID;
- core_writel(priv, reg, CORE_CFP_DATA_PORT(0));
-
- /* All other UDFs should be matched with the filter */
- core_writel(priv, 0x00ffffff, CORE_CFP_MASK_PORT(4));
- core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(3));
- core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(2));
- core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(1));
- core_writel(priv, 0xffffff0f, CORE_CFP_MASK_PORT(0));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(0);
+ else
+ offset = CORE_CFP_DATA_PORT(0);
+ core_writel(priv, reg, offset);
}
static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
@@ -503,8 +517,8 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
unsigned int queue_num,
struct ethtool_rx_flow_spec *fs)
{
+ struct ethtool_tcpip6_spec *v6_spec, *v6_m_spec;
unsigned int slice_num, rule_index[2];
- struct ethtool_tcpip6_spec *v6_spec;
const struct cfp_udf_layout *layout;
u8 ip_proto, ip_frag;
int ret = 0;
@@ -515,10 +529,12 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
case TCP_V6_FLOW:
ip_proto = IPPROTO_TCP;
v6_spec = &fs->h_u.tcp_ip6_spec;
+ v6_m_spec = &fs->m_u.tcp_ip6_spec;
break;
case UDP_V6_FLOW:
ip_proto = IPPROTO_UDP;
v6_spec = &fs->h_u.udp_ip6_spec;
+ v6_m_spec = &fs->m_u.udp_ip6_spec;
break;
default:
return -EINVAL;
@@ -606,7 +622,10 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5));
/* Slice the IPv6 source address and port */
- bcm_sf2_cfp_slice_ipv6(priv, v6_spec->ip6src, v6_spec->psrc, slice_num);
+ bcm_sf2_cfp_slice_ipv6(priv, v6_spec->ip6src, v6_spec->psrc,
+ slice_num, false);
+ bcm_sf2_cfp_slice_ipv6(priv, v6_m_spec->ip6src, v6_m_spec->psrc,
+ slice_num, true);
/* Insert into TCAM now because we need to insert a second rule */
bcm_sf2_cfp_rule_addr_set(priv, rule_index[0]);
@@ -663,7 +682,10 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
/* Mask all */
core_writel(priv, 0, CORE_CFP_MASK_PORT(5));
- bcm_sf2_cfp_slice_ipv6(priv, v6_spec->ip6dst, v6_spec->pdst, slice_num);
+ bcm_sf2_cfp_slice_ipv6(priv, v6_spec->ip6dst, v6_spec->pdst, slice_num,
+ false);
+ bcm_sf2_cfp_slice_ipv6(priv, v6_m_spec->ip6dst, v6_m_spec->pdst,
+ SLICE_NUM_MASK, true);
/* Insert into TCAM now */
bcm_sf2_cfp_rule_addr_set(priv, rule_index[1]);
@@ -932,27 +954,33 @@ static int bcm_sf2_cfp_ipv4_rule_get(struct bcm_sf2_priv *priv, int port,
static int bcm_sf2_cfp_unslice_ipv6(struct bcm_sf2_priv *priv,
__be32 *ip6_addr, __be16 *port,
- __be32 *ip6_mask, __be16 *port_mask)
+ bool mask)
{
- u32 reg, tmp;
+ u32 reg, tmp, offset;
/* C-Tag [31:24]
* UDF_n_B8 [23:8] (port)
* UDF_n_B7 (upper) [7:0] (addr[15:8])
*/
- reg = core_readl(priv, CORE_CFP_DATA_PORT(4));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(4);
+ else
+ offset = CORE_CFP_DATA_PORT(4);
+ reg = core_readl(priv, offset);
*port = cpu_to_be32(reg) >> 8;
- *port_mask = cpu_to_be16(~0);
tmp = (u32)(reg & 0xff) << 8;
/* UDF_n_B7 (lower) [31:24] (addr[7:0])
* UDF_n_B6 [23:8] (addr[31:16])
* UDF_n_B5 (upper) [7:0] (addr[47:40])
*/
- reg = core_readl(priv, CORE_CFP_DATA_PORT(3));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(3);
+ else
+ offset = CORE_CFP_DATA_PORT(3);
+ reg = core_readl(priv, offset);
tmp |= (reg >> 24) & 0xff;
tmp |= (u32)((reg >> 8) << 16);
- ip6_mask[3] = cpu_to_be32(~0);
ip6_addr[3] = cpu_to_be32(tmp);
tmp = (u32)(reg & 0xff) << 8;
@@ -960,10 +988,13 @@ static int bcm_sf2_cfp_unslice_ipv6(struct bcm_sf2_priv *priv,
* UDF_n_B4 [23:8] (addr[63:48])
* UDF_n_B3 (upper) [7:0] (addr[79:72])
*/
- reg = core_readl(priv, CORE_CFP_DATA_PORT(2));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(2);
+ else
+ offset = CORE_CFP_DATA_PORT(2);
+ reg = core_readl(priv, offset);
tmp |= (reg >> 24) & 0xff;
tmp |= (u32)((reg >> 8) << 16);
- ip6_mask[2] = cpu_to_be32(~0);
ip6_addr[2] = cpu_to_be32(tmp);
tmp = (u32)(reg & 0xff) << 8;
@@ -971,10 +1002,13 @@ static int bcm_sf2_cfp_unslice_ipv6(struct bcm_sf2_priv *priv,
* UDF_n_B2 [23:8] (addr[95:80])
* UDF_n_B1 (upper) [7:0] (addr[111:104])
*/
- reg = core_readl(priv, CORE_CFP_DATA_PORT(1));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(1);
+ else
+ offset = CORE_CFP_DATA_PORT(1);
+ reg = core_readl(priv, offset);
tmp |= (reg >> 24) & 0xff;
tmp |= (u32)((reg >> 8) << 16);
- ip6_mask[1] = cpu_to_be32(~0);
ip6_addr[1] = cpu_to_be32(tmp);
tmp = (u32)(reg & 0xff) << 8;
@@ -984,13 +1018,16 @@ static int bcm_sf2_cfp_unslice_ipv6(struct bcm_sf2_priv *priv,
* Slice ID [3:2]
* Slice valid [1:0]
*/
- reg = core_readl(priv, CORE_CFP_DATA_PORT(0));
+ if (mask)
+ offset = CORE_CFP_MASK_PORT(0);
+ else
+ offset = CORE_CFP_DATA_PORT(0);
+ reg = core_readl(priv, offset);
tmp |= (reg >> 24) & 0xff;
tmp |= (u32)((reg >> 8) << 16);
- ip6_mask[0] = cpu_to_be32(~0);
ip6_addr[0] = cpu_to_be32(tmp);
- if (!(reg & SLICE_VALID))
+ if (!mask && !(reg & SLICE_VALID))
return -EINVAL;
return 0;
@@ -1012,7 +1049,12 @@ static int bcm_sf2_cfp_ipv6_rule_get(struct bcm_sf2_priv *priv, int port,
/* Read the second half first */
ret = bcm_sf2_cfp_unslice_ipv6(priv, v6_spec->ip6dst, &v6_spec->pdst,
- v6_m_spec->ip6dst, &v6_m_spec->pdst);
+ false);
+ if (ret)
+ return ret;
+
+ ret = bcm_sf2_cfp_unslice_ipv6(priv, v6_m_spec->ip6dst,
+ &v6_m_spec->pdst, true);
if (ret)
return ret;
@@ -1043,8 +1085,13 @@ static int bcm_sf2_cfp_ipv6_rule_get(struct bcm_sf2_priv *priv, int port,
return -EINVAL;
}
- return bcm_sf2_cfp_unslice_ipv6(priv, v6_spec->ip6src, &v6_spec->psrc,
- v6_m_spec->ip6src, &v6_m_spec->psrc);
+ ret = bcm_sf2_cfp_unslice_ipv6(priv, v6_spec->ip6src, &v6_spec->psrc,
+ false);
+ if (ret)
+ return ret;
+
+ return bcm_sf2_cfp_unslice_ipv6(priv, v6_m_spec->ip6src,
+ &v6_m_spec->psrc, true);
}
static int bcm_sf2_cfp_rule_get(struct bcm_sf2_priv *priv, int port,