Skip to content

Commit bc3fc44

Browse files
ffainellidavem330
authored andcommitted
net: dsa: bcm_sf2: Allow matching arbitrary IPv4 mask 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>
1 parent ba0696c commit bc3fc44

File tree

2 files changed

+149
-88
lines changed

2 files changed

+149
-88
lines changed

drivers/net/dsa/bcm_sf2_cfp.c

Lines changed: 148 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,84 @@ static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv,
250250
return 0;
251251
}
252252

253+
static void bcm_sf2_cfp_slice_ipv4(struct bcm_sf2_priv *priv,
254+
struct ethtool_tcpip4_spec *v4_spec,
255+
unsigned int slice_num,
256+
bool mask)
257+
{
258+
u32 reg, offset;
259+
260+
/* C-Tag [31:24]
261+
* UDF_n_A8 [23:8]
262+
* UDF_n_A7 [7:0]
263+
*/
264+
reg = 0;
265+
if (mask)
266+
offset = CORE_CFP_MASK_PORT(4);
267+
else
268+
offset = CORE_CFP_DATA_PORT(4);
269+
core_writel(priv, reg, offset);
270+
271+
/* UDF_n_A7 [31:24]
272+
* UDF_n_A6 [23:8]
273+
* UDF_n_A5 [7:0]
274+
*/
275+
reg = be16_to_cpu(v4_spec->pdst) >> 8;
276+
if (mask)
277+
offset = CORE_CFP_MASK_PORT(3);
278+
else
279+
offset = CORE_CFP_DATA_PORT(3);
280+
core_writel(priv, reg, offset);
281+
282+
/* UDF_n_A5 [31:24]
283+
* UDF_n_A4 [23:8]
284+
* UDF_n_A3 [7:0]
285+
*/
286+
reg = (be16_to_cpu(v4_spec->pdst) & 0xff) << 24 |
287+
(u32)be16_to_cpu(v4_spec->psrc) << 8 |
288+
(be32_to_cpu(v4_spec->ip4dst) & 0x0000ff00) >> 8;
289+
if (mask)
290+
offset = CORE_CFP_MASK_PORT(2);
291+
else
292+
offset = CORE_CFP_DATA_PORT(2);
293+
core_writel(priv, reg, offset);
294+
295+
/* UDF_n_A3 [31:24]
296+
* UDF_n_A2 [23:8]
297+
* UDF_n_A1 [7:0]
298+
*/
299+
reg = (u32)(be32_to_cpu(v4_spec->ip4dst) & 0xff) << 24 |
300+
(u32)(be32_to_cpu(v4_spec->ip4dst) >> 16) << 8 |
301+
(be32_to_cpu(v4_spec->ip4src) & 0x0000ff00) >> 8;
302+
if (mask)
303+
offset = CORE_CFP_MASK_PORT(1);
304+
else
305+
offset = CORE_CFP_DATA_PORT(1);
306+
core_writel(priv, reg, offset);
307+
308+
/* UDF_n_A1 [31:24]
309+
* UDF_n_A0 [23:8]
310+
* Reserved [7:4]
311+
* Slice ID [3:2]
312+
* Slice valid [1:0]
313+
*/
314+
reg = (u32)(be32_to_cpu(v4_spec->ip4src) & 0xff) << 24 |
315+
(u32)(be32_to_cpu(v4_spec->ip4src) >> 16) << 8 |
316+
SLICE_NUM(slice_num) | SLICE_VALID;
317+
if (mask)
318+
offset = CORE_CFP_MASK_PORT(0);
319+
else
320+
offset = CORE_CFP_DATA_PORT(0);
321+
core_writel(priv, reg, offset);
322+
}
323+
253324
static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
254325
unsigned int port_num,
255326
unsigned int queue_num,
256327
struct ethtool_rx_flow_spec *fs)
257328
{
329+
struct ethtool_tcpip4_spec *v4_spec, *v4_m_spec;
258330
const struct cfp_udf_layout *layout;
259-
struct ethtool_tcpip4_spec *v4_spec;
260331
unsigned int slice_num, rule_index;
261332
u8 ip_proto, ip_frag;
262333
u8 num_udf;
@@ -267,10 +338,12 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
267338
case TCP_V4_FLOW:
268339
ip_proto = IPPROTO_TCP;
269340
v4_spec = &fs->h_u.tcp_ip4_spec;
341+
v4_m_spec = &fs->m_u.tcp_ip4_spec;
270342
break;
271343
case UDP_V4_FLOW:
272344
ip_proto = IPPROTO_UDP;
273345
v4_spec = &fs->h_u.udp_ip4_spec;
346+
v4_m_spec = &fs->m_u.udp_ip4_spec;
274347
break;
275348
default:
276349
return -EINVAL;
@@ -321,69 +394,22 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
321394
udf_upper_bits(num_udf),
322395
CORE_CFP_DATA_PORT(6));
323396

397+
/* Mask with the specific layout for IPv4 packets */
398+
core_writel(priv, layout->udfs[slice_num].mask_value |
399+
udf_upper_bits(num_udf), CORE_CFP_MASK_PORT(6));
400+
324401
/* UDF_Valid[7:0] [31:24]
325402
* S-Tag [23:8]
326403
* C-Tag [7:0]
327404
*/
328405
core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5));
329406

330-
/* C-Tag [31:24]
331-
* UDF_n_A8 [23:8]
332-
* UDF_n_A7 [7:0]
333-
*/
334-
core_writel(priv, 0, CORE_CFP_DATA_PORT(4));
335-
336-
/* UDF_n_A7 [31:24]
337-
* UDF_n_A6 [23:8]
338-
* UDF_n_A5 [7:0]
339-
*/
340-
core_writel(priv, be16_to_cpu(v4_spec->pdst) >> 8,
341-
CORE_CFP_DATA_PORT(3));
342-
343-
/* UDF_n_A5 [31:24]
344-
* UDF_n_A4 [23:8]
345-
* UDF_n_A3 [7:0]
346-
*/
347-
reg = (be16_to_cpu(v4_spec->pdst) & 0xff) << 24 |
348-
(u32)be16_to_cpu(v4_spec->psrc) << 8 |
349-
(be32_to_cpu(v4_spec->ip4dst) & 0x0000ff00) >> 8;
350-
core_writel(priv, reg, CORE_CFP_DATA_PORT(2));
351-
352-
/* UDF_n_A3 [31:24]
353-
* UDF_n_A2 [23:8]
354-
* UDF_n_A1 [7:0]
355-
*/
356-
reg = (u32)(be32_to_cpu(v4_spec->ip4dst) & 0xff) << 24 |
357-
(u32)(be32_to_cpu(v4_spec->ip4dst) >> 16) << 8 |
358-
(be32_to_cpu(v4_spec->ip4src) & 0x0000ff00) >> 8;
359-
core_writel(priv, reg, CORE_CFP_DATA_PORT(1));
360-
361-
/* UDF_n_A1 [31:24]
362-
* UDF_n_A0 [23:8]
363-
* Reserved [7:4]
364-
* Slice ID [3:2]
365-
* Slice valid [1:0]
366-
*/
367-
reg = (u32)(be32_to_cpu(v4_spec->ip4src) & 0xff) << 24 |
368-
(u32)(be32_to_cpu(v4_spec->ip4src) >> 16) << 8 |
369-
SLICE_NUM(slice_num) | SLICE_VALID;
370-
core_writel(priv, reg, CORE_CFP_DATA_PORT(0));
371-
372-
/* Mask with the specific layout for IPv4 packets */
373-
core_writel(priv, layout->udfs[slice_num].mask_value |
374-
udf_upper_bits(num_udf), CORE_CFP_MASK_PORT(6));
375-
376407
/* Mask all but valid UDFs */
377408
core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5));
378409

379-
/* Mask all */
380-
core_writel(priv, 0, CORE_CFP_MASK_PORT(4));
381-
382-
/* All other UDFs should be matched with the filter */
383-
core_writel(priv, 0xff, CORE_CFP_MASK_PORT(3));
384-
core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(2));
385-
core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(1));
386-
core_writel(priv, 0xffffff0f, CORE_CFP_MASK_PORT(0));
410+
/* Program the match and the mask */
411+
bcm_sf2_cfp_slice_ipv4(priv, v4_spec, slice_num, false);
412+
bcm_sf2_cfp_slice_ipv4(priv, v4_m_spec, SLICE_NUM_MASK, true);
387413

388414
/* Insert into TCAM now */
389415
bcm_sf2_cfp_rule_addr_set(priv, rule_index);
@@ -802,73 +828,108 @@ static void bcm_sf2_invert_masks(struct ethtool_rx_flow_spec *flow)
802828
flow->m_ext.data[1] ^= cpu_to_be32(~0);
803829
}
804830

805-
static int bcm_sf2_cfp_ipv4_rule_get(struct bcm_sf2_priv *priv, int port,
806-
struct ethtool_rx_flow_spec *fs)
831+
static int bcm_sf2_cfp_unslice_ipv4(struct bcm_sf2_priv *priv,
832+
struct ethtool_tcpip4_spec *v4_spec,
833+
bool mask)
807834
{
808-
struct ethtool_tcpip4_spec *v4_spec = NULL, *v4_m_spec = NULL;
835+
u32 reg, offset, ipv4;
809836
u16 src_dst_port;
810-
u32 reg, ipv4;
811-
812-
reg = core_readl(priv, CORE_CFP_DATA_PORT(6));
813837

814-
switch ((reg & IPPROTO_MASK) >> IPPROTO_SHIFT) {
815-
case IPPROTO_TCP:
816-
fs->flow_type = TCP_V4_FLOW;
817-
v4_spec = &fs->h_u.tcp_ip4_spec;
818-
v4_m_spec = &fs->m_u.tcp_ip4_spec;
819-
break;
820-
case IPPROTO_UDP:
821-
fs->flow_type = UDP_V4_FLOW;
822-
v4_spec = &fs->h_u.udp_ip4_spec;
823-
v4_m_spec = &fs->m_u.udp_ip4_spec;
824-
break;
825-
default:
826-
return -EINVAL;
827-
}
828-
829-
fs->m_ext.data[0] = cpu_to_be32((reg >> IP_FRAG_SHIFT) & 1);
830-
v4_spec->tos = (reg >> IPTOS_SHIFT) & IPTOS_MASK;
838+
if (mask)
839+
offset = CORE_CFP_MASK_PORT(3);
840+
else
841+
offset = CORE_CFP_DATA_PORT(3);
831842

832-
reg = core_readl(priv, CORE_CFP_DATA_PORT(3));
843+
reg = core_readl(priv, offset);
833844
/* src port [15:8] */
834845
src_dst_port = reg << 8;
835846

836-
reg = core_readl(priv, CORE_CFP_DATA_PORT(2));
847+
if (mask)
848+
offset = CORE_CFP_MASK_PORT(2);
849+
else
850+
offset = CORE_CFP_DATA_PORT(2);
851+
852+
reg = core_readl(priv, offset);
837853
/* src port [7:0] */
838854
src_dst_port |= (reg >> 24);
839855

840856
v4_spec->pdst = cpu_to_be16(src_dst_port);
841-
v4_m_spec->pdst = cpu_to_be16(~0);
842857
v4_spec->psrc = cpu_to_be16((u16)(reg >> 8));
843-
v4_m_spec->psrc = cpu_to_be16(~0);
844858

845859
/* IPv4 dst [15:8] */
846860
ipv4 = (reg & 0xff) << 8;
847-
reg = core_readl(priv, CORE_CFP_DATA_PORT(1));
861+
862+
if (mask)
863+
offset = CORE_CFP_MASK_PORT(1);
864+
else
865+
offset = CORE_CFP_DATA_PORT(1);
866+
867+
reg = core_readl(priv, offset);
848868
/* IPv4 dst [31:16] */
849869
ipv4 |= ((reg >> 8) & 0xffff) << 16;
850870
/* IPv4 dst [7:0] */
851871
ipv4 |= (reg >> 24) & 0xff;
852872
v4_spec->ip4dst = cpu_to_be32(ipv4);
853-
v4_m_spec->ip4dst = cpu_to_be32(~0);
854873

855874
/* IPv4 src [15:8] */
856875
ipv4 = (reg & 0xff) << 8;
857-
reg = core_readl(priv, CORE_CFP_DATA_PORT(0));
858876

859-
if (!(reg & SLICE_VALID))
877+
if (mask)
878+
offset = CORE_CFP_MASK_PORT(0);
879+
else
880+
offset = CORE_CFP_DATA_PORT(0);
881+
reg = core_readl(priv, offset);
882+
883+
/* Once the TCAM is programmed, the mask reflects the slice number
884+
* being matched, don't bother checking it when reading back the
885+
* mask spec
886+
*/
887+
if (!mask && !(reg & SLICE_VALID))
860888
return -EINVAL;
861889

862890
/* IPv4 src [7:0] */
863891
ipv4 |= (reg >> 24) & 0xff;
864892
/* IPv4 src [31:16] */
865893
ipv4 |= ((reg >> 8) & 0xffff) << 16;
866894
v4_spec->ip4src = cpu_to_be32(ipv4);
867-
v4_m_spec->ip4src = cpu_to_be32(~0);
868895

869896
return 0;
870897
}
871898

899+
static int bcm_sf2_cfp_ipv4_rule_get(struct bcm_sf2_priv *priv, int port,
900+
struct ethtool_rx_flow_spec *fs)
901+
{
902+
struct ethtool_tcpip4_spec *v4_spec = NULL, *v4_m_spec = NULL;
903+
u32 reg;
904+
int ret;
905+
906+
reg = core_readl(priv, CORE_CFP_DATA_PORT(6));
907+
908+
switch ((reg & IPPROTO_MASK) >> IPPROTO_SHIFT) {
909+
case IPPROTO_TCP:
910+
fs->flow_type = TCP_V4_FLOW;
911+
v4_spec = &fs->h_u.tcp_ip4_spec;
912+
v4_m_spec = &fs->m_u.tcp_ip4_spec;
913+
break;
914+
case IPPROTO_UDP:
915+
fs->flow_type = UDP_V4_FLOW;
916+
v4_spec = &fs->h_u.udp_ip4_spec;
917+
v4_m_spec = &fs->m_u.udp_ip4_spec;
918+
break;
919+
default:
920+
return -EINVAL;
921+
}
922+
923+
fs->m_ext.data[0] = cpu_to_be32((reg >> IP_FRAG_SHIFT) & 1);
924+
v4_spec->tos = (reg >> IPTOS_SHIFT) & IPTOS_MASK;
925+
926+
ret = bcm_sf2_cfp_unslice_ipv4(priv, v4_spec, false);
927+
if (ret)
928+
return ret;
929+
930+
return bcm_sf2_cfp_unslice_ipv4(priv, v4_m_spec, true);
931+
}
932+
872933
static int bcm_sf2_cfp_unslice_ipv6(struct bcm_sf2_priv *priv,
873934
__be32 *ip6_addr, __be16 *port,
874935
__be32 *ip6_mask, __be16 *port_mask)

drivers/net/dsa/bcm_sf2_regs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ enum bcm_sf2_reg_offs {
313313
#define SLICE_VALID 3
314314
#define SLICE_NUM_SHIFT 2
315315
#define SLICE_NUM(x) ((x) << SLICE_NUM_SHIFT)
316-
#define SLICE_NUM_MASK 0xff
316+
#define SLICE_NUM_MASK 0x3
317317

318318
#define CORE_CFP_MASK_PORT_0 0x280c0
319319

0 commit comments

Comments
 (0)