Skip to content

Commit a7e13ed

Browse files
Xiaoliang Yangdavem330
authored andcommitted
net: dsa: felix: restrict psfp rules on ingress port
PSFP rules take effect on the streams from any port of VSC9959 switch. This patch use ingress port to limit the rule only active on this port. Each stream can only match two ingress source ports in VSC9959. Streams from lowest port gets the configuration of SFID pointed by MAC Table lookup and streams from highest port gets the configuration of (SFID+1) pointed by MAC Table lookup. This patch defines the PSFP rule on highest port as dummy rule, which means that it does not modify the MAC table. Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 76c13ed commit a7e13ed

File tree

3 files changed

+163
-32
lines changed

3 files changed

+163
-32
lines changed

drivers/net/dsa/ocelot/felix_vsc9959.c

Lines changed: 160 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,9 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
13491349
struct felix_stream {
13501350
struct list_head list;
13511351
unsigned long id;
1352+
bool dummy;
1353+
int ports;
1354+
int port;
13521355
u8 dmac[ETH_ALEN];
13531356
u16 vid;
13541357
s8 prio;
@@ -1363,6 +1366,7 @@ struct felix_stream_filter {
13631366
refcount_t refcount;
13641367
u32 index;
13651368
u8 enable;
1369+
int portmask;
13661370
u8 sg_valid;
13671371
u32 sgid;
13681372
u8 fm_valid;
@@ -1505,10 +1509,12 @@ static int vsc9959_stream_table_add(struct ocelot *ocelot,
15051509

15061510
memcpy(stream_entry, stream, sizeof(*stream_entry));
15071511

1508-
ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack);
1509-
if (ret) {
1510-
kfree(stream_entry);
1511-
return ret;
1512+
if (!stream->dummy) {
1513+
ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack);
1514+
if (ret) {
1515+
kfree(stream_entry);
1516+
return ret;
1517+
}
15121518
}
15131519

15141520
list_add_tail(&stream_entry->list, stream_list);
@@ -1531,7 +1537,8 @@ vsc9959_stream_table_get(struct list_head *stream_list, unsigned long id)
15311537
static void vsc9959_stream_table_del(struct ocelot *ocelot,
15321538
struct felix_stream *stream)
15331539
{
1534-
vsc9959_mact_stream_set(ocelot, stream, NULL);
1540+
if (!stream->dummy)
1541+
vsc9959_mact_stream_set(ocelot, stream, NULL);
15351542

15361543
list_del(&stream->list);
15371544
kfree(stream);
@@ -1586,14 +1593,64 @@ static int vsc9959_psfp_sfi_set(struct ocelot *ocelot,
15861593
10, 100000);
15871594
}
15881595

1596+
static int vsc9959_psfp_sfidmask_set(struct ocelot *ocelot, u32 sfid, int ports)
1597+
{
1598+
u32 val;
1599+
1600+
ocelot_rmw(ocelot,
1601+
ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
1602+
ANA_TABLES_SFIDTIDX_SFID_INDEX_M,
1603+
ANA_TABLES_SFIDTIDX);
1604+
1605+
ocelot_write(ocelot,
1606+
ANA_TABLES_SFID_MASK_IGR_PORT_MASK(ports) |
1607+
ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA,
1608+
ANA_TABLES_SFID_MASK);
1609+
1610+
ocelot_rmw(ocelot,
1611+
ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
1612+
ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M,
1613+
ANA_TABLES_SFIDACCESS);
1614+
1615+
return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val,
1616+
(!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)),
1617+
10, 100000);
1618+
}
1619+
1620+
static int vsc9959_psfp_sfi_list_add(struct ocelot *ocelot,
1621+
struct felix_stream_filter *sfi,
1622+
struct list_head *pos)
1623+
{
1624+
struct felix_stream_filter *sfi_entry;
1625+
int ret;
1626+
1627+
sfi_entry = kzalloc(sizeof(*sfi_entry), GFP_KERNEL);
1628+
if (!sfi_entry)
1629+
return -ENOMEM;
1630+
1631+
memcpy(sfi_entry, sfi, sizeof(*sfi_entry));
1632+
refcount_set(&sfi_entry->refcount, 1);
1633+
1634+
ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry);
1635+
if (ret) {
1636+
kfree(sfi_entry);
1637+
return ret;
1638+
}
1639+
1640+
vsc9959_psfp_sfidmask_set(ocelot, sfi->index, sfi->portmask);
1641+
1642+
list_add(&sfi_entry->list, pos);
1643+
1644+
return 0;
1645+
}
1646+
15891647
static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot,
15901648
struct felix_stream_filter *sfi)
15911649
{
1592-
struct felix_stream_filter *sfi_entry, *tmp;
15931650
struct list_head *pos, *q, *last;
1651+
struct felix_stream_filter *tmp;
15941652
struct ocelot_psfp_list *psfp;
15951653
u32 insert = 0;
1596-
int ret;
15971654

15981655
psfp = &ocelot->psfp;
15991656
last = &psfp->sfi_list;
@@ -1602,6 +1659,7 @@ static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot,
16021659
tmp = list_entry(pos, struct felix_stream_filter, list);
16031660
if (sfi->sg_valid == tmp->sg_valid &&
16041661
sfi->fm_valid == tmp->fm_valid &&
1662+
sfi->portmask == tmp->portmask &&
16051663
tmp->sgid == sfi->sgid &&
16061664
tmp->fmid == sfi->fmid) {
16071665
sfi->index = tmp->index;
@@ -1616,22 +1674,40 @@ static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot,
16161674
}
16171675
sfi->index = insert;
16181676

1619-
sfi_entry = kzalloc(sizeof(*sfi_entry), GFP_KERNEL);
1620-
if (!sfi_entry)
1621-
return -ENOMEM;
1677+
return vsc9959_psfp_sfi_list_add(ocelot, sfi, last);
1678+
}
16221679

1623-
memcpy(sfi_entry, sfi, sizeof(*sfi_entry));
1624-
refcount_set(&sfi_entry->refcount, 1);
1680+
static int vsc9959_psfp_sfi_table_add2(struct ocelot *ocelot,
1681+
struct felix_stream_filter *sfi,
1682+
struct felix_stream_filter *sfi2)
1683+
{
1684+
struct felix_stream_filter *tmp;
1685+
struct list_head *pos, *q, *last;
1686+
struct ocelot_psfp_list *psfp;
1687+
u32 insert = 0;
1688+
int ret;
16251689

1626-
ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry);
1627-
if (ret) {
1628-
kfree(sfi_entry);
1629-
return ret;
1690+
psfp = &ocelot->psfp;
1691+
last = &psfp->sfi_list;
1692+
1693+
list_for_each_safe(pos, q, &psfp->sfi_list) {
1694+
tmp = list_entry(pos, struct felix_stream_filter, list);
1695+
/* Make sure that the index is increasing in order. */
1696+
if (tmp->index >= insert + 2)
1697+
break;
1698+
1699+
insert = tmp->index + 1;
1700+
last = pos;
16301701
}
1702+
sfi->index = insert;
1703+
1704+
ret = vsc9959_psfp_sfi_list_add(ocelot, sfi, last);
1705+
if (ret)
1706+
return ret;
16311707

1632-
list_add(&sfi_entry->list, last);
1708+
sfi2->index = insert + 1;
16331709

1634-
return 0;
1710+
return vsc9959_psfp_sfi_list_add(ocelot, sfi2, last->next);
16351711
}
16361712

16371713
static struct felix_stream_filter *
@@ -1832,10 +1908,11 @@ static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
18321908
SYS_STAT_CFG);
18331909
}
18341910

1835-
static int vsc9959_psfp_filter_add(struct ocelot *ocelot,
1911+
static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
18361912
struct flow_cls_offload *f)
18371913
{
18381914
struct netlink_ext_ack *extack = f->common.extack;
1915+
struct felix_stream_filter old_sfi, *sfi_entry;
18391916
struct felix_stream_filter sfi = {0};
18401917
const struct flow_action_entry *a;
18411918
struct felix_stream *stream_entry;
@@ -1896,21 +1973,61 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot,
18961973
}
18971974
}
18981975

1899-
/* Check if stream is set. */
1900-
stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream);
1901-
if (stream_entry) {
1902-
NL_SET_ERR_MSG_MOD(extack, "This stream is already added");
1903-
ret = -EEXIST;
1904-
goto err;
1905-
}
1976+
stream.ports = BIT(port);
1977+
stream.port = port;
19061978

1979+
sfi.portmask = stream.ports;
19071980
sfi.prio_valid = (stream.prio < 0 ? 0 : 1);
19081981
sfi.prio = (sfi.prio_valid ? stream.prio : 0);
19091982
sfi.enable = 1;
19101983

1911-
ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi);
1912-
if (ret)
1913-
goto err;
1984+
/* Check if stream is set. */
1985+
stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream);
1986+
if (stream_entry) {
1987+
if (stream_entry->ports & BIT(port)) {
1988+
NL_SET_ERR_MSG_MOD(extack,
1989+
"The stream is added on this port");
1990+
ret = -EEXIST;
1991+
goto err;
1992+
}
1993+
1994+
if (stream_entry->ports != BIT(stream_entry->port)) {
1995+
NL_SET_ERR_MSG_MOD(extack,
1996+
"The stream is added on two ports");
1997+
ret = -EEXIST;
1998+
goto err;
1999+
}
2000+
2001+
stream_entry->ports |= BIT(port);
2002+
stream.ports = stream_entry->ports;
2003+
2004+
sfi_entry = vsc9959_psfp_sfi_table_get(&psfp->sfi_list,
2005+
stream_entry->sfid);
2006+
memcpy(&old_sfi, sfi_entry, sizeof(old_sfi));
2007+
2008+
vsc9959_psfp_sfi_table_del(ocelot, stream_entry->sfid);
2009+
2010+
old_sfi.portmask = stream_entry->ports;
2011+
sfi.portmask = stream.ports;
2012+
2013+
if (stream_entry->port > port) {
2014+
ret = vsc9959_psfp_sfi_table_add2(ocelot, &sfi,
2015+
&old_sfi);
2016+
stream_entry->dummy = true;
2017+
} else {
2018+
ret = vsc9959_psfp_sfi_table_add2(ocelot, &old_sfi,
2019+
&sfi);
2020+
stream.dummy = true;
2021+
}
2022+
if (ret)
2023+
goto err;
2024+
2025+
stream_entry->sfid = old_sfi.index;
2026+
} else {
2027+
ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi);
2028+
if (ret)
2029+
goto err;
2030+
}
19142031

19152032
stream.sfid = sfi.index;
19162033
stream.sfid_valid = 1;
@@ -1936,9 +2053,9 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot,
19362053
static int vsc9959_psfp_filter_del(struct ocelot *ocelot,
19372054
struct flow_cls_offload *f)
19382055
{
2056+
struct felix_stream *stream, tmp, *stream_entry;
19392057
static struct felix_stream_filter *sfi;
19402058
struct ocelot_psfp_list *psfp;
1941-
struct felix_stream *stream;
19422059

19432060
psfp = &ocelot->psfp;
19442061

@@ -1958,9 +2075,22 @@ static int vsc9959_psfp_filter_del(struct ocelot *ocelot,
19582075

19592076
vsc9959_psfp_sfi_table_del(ocelot, stream->sfid);
19602077

2078+
memcpy(&tmp, stream, sizeof(tmp));
2079+
19612080
stream->sfid_valid = 0;
19622081
vsc9959_stream_table_del(ocelot, stream);
19632082

2083+
stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &tmp);
2084+
if (stream_entry) {
2085+
stream_entry->ports = BIT(stream_entry->port);
2086+
if (stream_entry->dummy) {
2087+
stream_entry->dummy = false;
2088+
vsc9959_mact_stream_set(ocelot, stream_entry, NULL);
2089+
}
2090+
vsc9959_psfp_sfidmask_set(ocelot, stream_entry->sfid,
2091+
stream_entry->ports);
2092+
}
2093+
19642094
return 0;
19652095
}
19662096

drivers/net/ethernet/mscc/ocelot_flower.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
837837
if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
838838
kfree(filter);
839839
if (ocelot->ops->psfp_filter_add)
840-
return ocelot->ops->psfp_filter_add(ocelot, f);
840+
return ocelot->ops->psfp_filter_add(ocelot, port, f);
841841

842842
NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
843843
return -EOPNOTSUPP;

include/soc/mscc/ocelot.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,8 @@ struct ocelot_ops {
556556
u16 (*wm_dec)(u16 value);
557557
void (*wm_stat)(u32 val, u32 *inuse, u32 *maxuse);
558558
void (*psfp_init)(struct ocelot *ocelot);
559-
int (*psfp_filter_add)(struct ocelot *ocelot, struct flow_cls_offload *f);
559+
int (*psfp_filter_add)(struct ocelot *ocelot, int port,
560+
struct flow_cls_offload *f);
560561
int (*psfp_filter_del)(struct ocelot *ocelot, struct flow_cls_offload *f);
561562
int (*psfp_stats_get)(struct ocelot *ocelot, struct flow_cls_offload *f,
562563
struct flow_stats *stats);

0 commit comments

Comments
 (0)