Commit d8ea7ff3 authored by Horatiu Vultur's avatar Horatiu Vultur Committed by David S. Miller

net: mscc: ocelot: Add support for MRP

Add basic support for MRP. The HW will just trap all MRP frames on the
ring ports to CPU and allow the SW to process them. In this way it is
possible to for this node to behave both as MRM and MRC.

Current limitations are:
- it doesn't support Interconnect roles.
- it supports only a single ring.
- the HW should be able to do forwarding of MRP Test frames so the SW
  will not need to do this. So it would be able to have the role MRC
  without SW support.
Signed-off-by: default avatarHoratiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cd605d45
...@@ -8,6 +8,7 @@ mscc_ocelot_switch_lib-y := \ ...@@ -8,6 +8,7 @@ mscc_ocelot_switch_lib-y := \
ocelot_flower.o \ ocelot_flower.o \
ocelot_ptp.o \ ocelot_ptp.o \
ocelot_devlink.o ocelot_devlink.o
mscc_ocelot_switch_lib-$(CONFIG_BRIDGE_MRP) += ocelot_mrp.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
mscc_ocelot-y := \ mscc_ocelot-y := \
ocelot_vsc7514.o \ ocelot_vsc7514.o \
......
...@@ -687,7 +687,7 @@ static int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp, u32 *xfh) ...@@ -687,7 +687,7 @@ static int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp, u32 *xfh)
int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb) int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)
{ {
struct skb_shared_hwtstamps *shhwtstamps; struct skb_shared_hwtstamps *shhwtstamps;
u64 tod_in_ns, full_ts_in_ns; u64 tod_in_ns, full_ts_in_ns, cpuq;
u64 timestamp, src_port, len; u64 timestamp, src_port, len;
u32 xfh[OCELOT_TAG_LEN / 4]; u32 xfh[OCELOT_TAG_LEN / 4];
struct net_device *dev; struct net_device *dev;
...@@ -704,6 +704,7 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb) ...@@ -704,6 +704,7 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)
ocelot_xfh_get_src_port(xfh, &src_port); ocelot_xfh_get_src_port(xfh, &src_port);
ocelot_xfh_get_len(xfh, &len); ocelot_xfh_get_len(xfh, &len);
ocelot_xfh_get_rew_val(xfh, &timestamp); ocelot_xfh_get_rew_val(xfh, &timestamp);
ocelot_xfh_get_cpuq(xfh, &cpuq);
if (WARN_ON(src_port >= ocelot->num_phys_ports)) if (WARN_ON(src_port >= ocelot->num_phys_ports))
return -EINVAL; return -EINVAL;
...@@ -770,6 +771,13 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb) ...@@ -770,6 +771,13 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **nskb)
skb->offload_fwd_mark = 1; skb->offload_fwd_mark = 1;
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
#if IS_ENABLED(CONFIG_BRIDGE_MRP)
if (skb->protocol == cpu_to_be16(ETH_P_MRP) &&
cpuq & BIT(OCELOT_MRP_CPUQ))
skb->offload_fwd_mark = 0;
#endif
*nskb = skb; *nskb = skb;
return 0; return 0;
......
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Microsemi Ocelot Switch driver
*
* This contains glue logic between the switchdev driver operations and the
* mscc_ocelot_switch_lib.
*
* Copyright (c) 2017, 2019 Microsemi Corporation
* Copyright 2020-2021 NXP Semiconductors
*/
#include <linux/if_bridge.h>
#include <linux/mrp_bridge.h>
#include <soc/mscc/ocelot_vcap.h>
#include <uapi/linux/mrp_bridge.h>
#include "ocelot.h"
#include "ocelot_vcap.h"
static int ocelot_mrp_del_vcap(struct ocelot *ocelot, int port)
{
struct ocelot_vcap_block *block_vcap_is2;
struct ocelot_vcap_filter *filter;
block_vcap_is2 = &ocelot->block[VCAP_IS2];
filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, port,
false);
if (!filter)
return 0;
return ocelot_vcap_filter_del(ocelot, filter);
}
int ocelot_mrp_add(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
struct ocelot_port_private *priv;
struct net_device *dev;
if (!ocelot_port)
return -EOPNOTSUPP;
priv = container_of(ocelot_port, struct ocelot_port_private, port);
dev = priv->dev;
if (mrp->p_port != dev && mrp->s_port != dev)
return 0;
if (ocelot->mrp_ring_id != 0 &&
ocelot->mrp_s_port &&
ocelot->mrp_p_port)
return -EINVAL;
if (mrp->p_port == dev)
ocelot->mrp_p_port = dev;
if (mrp->s_port == dev)
ocelot->mrp_s_port = dev;
ocelot->mrp_ring_id = mrp->ring_id;
return 0;
}
EXPORT_SYMBOL(ocelot_mrp_add);
int ocelot_mrp_del(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
struct ocelot_port_private *priv;
struct net_device *dev;
if (!ocelot_port)
return -EOPNOTSUPP;
priv = container_of(ocelot_port, struct ocelot_port_private, port);
dev = priv->dev;
if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev)
return 0;
if (ocelot->mrp_ring_id == 0 &&
!ocelot->mrp_s_port &&
!ocelot->mrp_p_port)
return -EINVAL;
if (ocelot_mrp_del_vcap(ocelot, priv->chip_port))
return -EINVAL;
if (ocelot->mrp_p_port == dev)
ocelot->mrp_p_port = NULL;
if (ocelot->mrp_s_port == dev)
ocelot->mrp_s_port = NULL;
ocelot->mrp_ring_id = 0;
return 0;
}
EXPORT_SYMBOL(ocelot_mrp_del);
int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port,
const struct switchdev_obj_ring_role_mrp *mrp)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
struct ocelot_vcap_filter *filter;
struct ocelot_port_private *priv;
struct net_device *dev;
int err;
if (!ocelot_port)
return -EOPNOTSUPP;
priv = container_of(ocelot_port, struct ocelot_port_private, port);
dev = priv->dev;
if (ocelot->mrp_ring_id != mrp->ring_id)
return -EINVAL;
if (!mrp->sw_backup)
return -EOPNOTSUPP;
if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev)
return 0;
filter = kzalloc(sizeof(*filter), GFP_ATOMIC);
if (!filter)
return -ENOMEM;
filter->key_type = OCELOT_VCAP_KEY_ETYPE;
filter->prio = 1;
filter->id.cookie = priv->chip_port;
filter->id.tc_offload = false;
filter->block_id = VCAP_IS2;
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
filter->ingress_port_mask = BIT(priv->chip_port);
*(__be16 *)filter->key.etype.etype.value = htons(ETH_P_MRP);
*(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
filter->action.port_mask = 0x0;
filter->action.cpu_copy_ena = true;
filter->action.cpu_qu_num = OCELOT_MRP_CPUQ;
err = ocelot_vcap_filter_add(ocelot, filter, NULL);
if (err)
kfree(filter);
return err;
}
EXPORT_SYMBOL(ocelot_mrp_add_ring_role);
int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port,
const struct switchdev_obj_ring_role_mrp *mrp)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
struct ocelot_port_private *priv;
struct net_device *dev;
if (!ocelot_port)
return -EOPNOTSUPP;
priv = container_of(ocelot_port, struct ocelot_port_private, port);
dev = priv->dev;
if (ocelot->mrp_ring_id != mrp->ring_id)
return -EINVAL;
if (!mrp->sw_backup)
return -EOPNOTSUPP;
if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev)
return 0;
return ocelot_mrp_del_vcap(ocelot, priv->chip_port);
}
EXPORT_SYMBOL(ocelot_mrp_del_ring_role);
...@@ -1010,6 +1010,52 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev, ...@@ -1010,6 +1010,52 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev,
return ocelot_port_mdb_del(ocelot, port, mdb); return ocelot_port_mdb_del(ocelot, port, mdb);
} }
static int ocelot_port_obj_mrp_add(struct net_device *dev,
const struct switchdev_obj_mrp *mrp)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_mrp_add(ocelot, port, mrp);
}
static int ocelot_port_obj_mrp_del(struct net_device *dev,
const struct switchdev_obj_mrp *mrp)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_mrp_del(ocelot, port, mrp);
}
static int
ocelot_port_obj_mrp_add_ring_role(struct net_device *dev,
const struct switchdev_obj_ring_role_mrp *mrp)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_mrp_add_ring_role(ocelot, port, mrp);
}
static int
ocelot_port_obj_mrp_del_ring_role(struct net_device *dev,
const struct switchdev_obj_ring_role_mrp *mrp)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_mrp_del_ring_role(ocelot, port, mrp);
}
static int ocelot_port_obj_add(struct net_device *dev, static int ocelot_port_obj_add(struct net_device *dev,
const struct switchdev_obj *obj, const struct switchdev_obj *obj,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -1024,6 +1070,13 @@ static int ocelot_port_obj_add(struct net_device *dev, ...@@ -1024,6 +1070,13 @@ static int ocelot_port_obj_add(struct net_device *dev,
case SWITCHDEV_OBJ_ID_PORT_MDB: case SWITCHDEV_OBJ_ID_PORT_MDB:
ret = ocelot_port_obj_add_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); ret = ocelot_port_obj_add_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
break; break;
case SWITCHDEV_OBJ_ID_MRP:
ret = ocelot_port_obj_mrp_add(dev, SWITCHDEV_OBJ_MRP(obj));
break;
case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
ret = ocelot_port_obj_mrp_add_ring_role(dev,
SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -1044,6 +1097,13 @@ static int ocelot_port_obj_del(struct net_device *dev, ...@@ -1044,6 +1097,13 @@ static int ocelot_port_obj_del(struct net_device *dev,
case SWITCHDEV_OBJ_ID_PORT_MDB: case SWITCHDEV_OBJ_ID_PORT_MDB:
ret = ocelot_port_obj_del_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); ret = ocelot_port_obj_del_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
break; break;
case SWITCHDEV_OBJ_ID_MRP:
ret = ocelot_port_obj_mrp_del(dev, SWITCHDEV_OBJ_MRP(obj));
break;
case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
ret = ocelot_port_obj_mrp_del_ring_role(dev,
SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -160,6 +160,11 @@ static inline void ocelot_xfh_get_src_port(void *extraction, u64 *src_port) ...@@ -160,6 +160,11 @@ static inline void ocelot_xfh_get_src_port(void *extraction, u64 *src_port)
packing(extraction, src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0); packing(extraction, src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
} }
static inline void ocelot_xfh_get_cpuq(void *extraction, u64 *cpuq)
{
packing(extraction, cpuq, 28, 20, OCELOT_TAG_LEN, UNPACK, 0);
}
static inline void ocelot_xfh_get_qos_class(void *extraction, u64 *qos_class) static inline void ocelot_xfh_get_qos_class(void *extraction, u64 *qos_class)
{ {
packing(extraction, qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0); packing(extraction, qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
......
...@@ -112,6 +112,8 @@ ...@@ -112,6 +112,8 @@
#define REG_RESERVED_ADDR 0xffffffff #define REG_RESERVED_ADDR 0xffffffff
#define REG_RESERVED(reg) REG(reg, REG_RESERVED_ADDR) #define REG_RESERVED(reg) REG(reg, REG_RESERVED_ADDR)
#define OCELOT_MRP_CPUQ 7
enum ocelot_target { enum ocelot_target {
ANA = 1, ANA = 1,
QS, QS,
...@@ -677,6 +679,12 @@ struct ocelot { ...@@ -677,6 +679,12 @@ struct ocelot {
/* Protects the PTP clock */ /* Protects the PTP clock */
spinlock_t ptp_clock_lock; spinlock_t ptp_clock_lock;
struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM]; struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM];
#if IS_ENABLED(CONFIG_BRIDGE_MRP)
u16 mrp_ring_id;
struct net_device *mrp_p_port;
struct net_device *mrp_s_port;
#endif
}; };
struct ocelot_policer { struct ocelot_policer {
...@@ -874,4 +882,41 @@ int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port, ...@@ -874,4 +882,41 @@ int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
enum devlink_sb_pool_type pool_type, enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max); u32 *p_cur, u32 *p_max);
#if IS_ENABLED(CONFIG_BRIDGE_MRP)
int ocelot_mrp_add(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp);
int ocelot_mrp_del(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp);
int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port,
const struct switchdev_obj_ring_role_mrp *mrp);
int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port,
const struct switchdev_obj_ring_role_mrp *mrp);
#else
static inline int ocelot_mrp_add(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp)
{
return -EOPNOTSUPP;
}
static inline int ocelot_mrp_del(struct ocelot *ocelot, int port,
const struct switchdev_obj_mrp *mrp)
{
return -EOPNOTSUPP;
}
static inline int
ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port,
const struct switchdev_obj_ring_role_mrp *mrp)
{
return -EOPNOTSUPP;
}
static inline int
ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port,
const struct switchdev_obj_ring_role_mrp *mrp)
{
return -EOPNOTSUPP;
}
#endif
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment