Commit c67939ef authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'prestera-router-driver'



Yevhen Orlov says:

====================
prestera: add basic router driver support

Add initial router support for Marvell Prestera driver.
Subscribe on inetaddr notifications. TRAP packets, that has to be routed
(if packet has router's destination MAC address).

Add features:
 - Support ip address adding on port.
   e.g.: "ip address add PORT 1.1.1.1/24"

Limitations:
 - Only regular port supported. Vlan will be added soon.
 - It is routing through CPU. Offloading will be added in
   next patches.

Co-developed-by: default avatarTaras Chornyi <tchornyi@marvell.com>
Signed-off-by: default avatarTaras Chornyi <tchornyi@marvell.com>
Co-developed-by: default avatarOleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: default avatarOleksandr Mazur <oleksandr.mazur@plvision.eu>
Signed-off-by: default avatarYevhen Orlov <yevhen.orlov@plvision.eu>

Changes for v2:
* Remove useless assignment
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 47869e82 15fa9e8c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ obj-$(CONFIG_PRESTERA) += prestera.o
prestera-objs		:= prestera_main.o prestera_hw.o prestera_dsa.o \
			   prestera_rxtx.o prestera_devlink.o prestera_ethtool.o \
			   prestera_switchdev.o prestera_acl.o prestera_flow.o \
			   prestera_flower.o prestera_span.o prestera_counter.o
			   prestera_flower.o prestera_span.o prestera_counter.o \
			   prestera_router.o prestera_router_hw.o

obj-$(CONFIG_PRESTERA_PCI)	+= prestera_pci.o
+38 −0
Original line number Diff line number Diff line
@@ -225,6 +225,29 @@ struct prestera_event {
	};
};

enum prestera_if_type {
	/* the interface is of port type (dev,port) */
	PRESTERA_IF_PORT_E = 0,

	/* the interface is of lag type (lag-id) */
	PRESTERA_IF_LAG_E = 1,

	/* the interface is of Vid type (vlan-id) */
	PRESTERA_IF_VID_E = 3,
};

struct prestera_iface {
	enum prestera_if_type type;
	struct {
		u32 hw_dev_num;
		u32 port_num;
	} dev_port;
	u32 hw_dev_num;
	u16 vr_id;
	u16 lag_id;
	u16 vlan_id;
};

struct prestera_switchdev;
struct prestera_span;
struct prestera_rxtx;
@@ -247,12 +270,22 @@ struct prestera_switch {
	u32 mtu_min;
	u32 mtu_max;
	u8 id;
	struct prestera_router *router;
	struct prestera_lag *lags;
	struct prestera_counter *counter;
	u8 lag_member_max;
	u8 lag_max;
};

struct prestera_router {
	struct prestera_switch *sw;
	struct list_head vr_list;
	struct list_head rif_entry_list;
	struct notifier_block inetaddr_nb;
	struct notifier_block inetaddr_valid_nb;
	bool aborted;
};

struct prestera_rxtx_params {
	bool use_sdma;
	u32 map_addr;
@@ -280,6 +313,9 @@ struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,

int prestera_port_autoneg_set(struct prestera_port *port, u64 link_modes);

int prestera_router_init(struct prestera_switch *sw);
void prestera_router_fini(struct prestera_switch *sw);

struct prestera_port *prestera_find_port(struct prestera_switch *sw, u32 id);

int prestera_port_cfg_mac_read(struct prestera_port *port,
@@ -294,6 +330,8 @@ int prestera_port_pvid_set(struct prestera_port *port, u16 vid);

bool prestera_netdev_check(const struct net_device *dev);

int prestera_is_valid_mac_addr(struct prestera_port *port, const u8 *addr);

bool prestera_port_is_lag_member(const struct prestera_port *port);

struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);
+139 −0
Original line number Diff line number Diff line
@@ -53,6 +53,11 @@ enum prestera_cmd_type_t {
	PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND = 0x560,
	PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND = 0x561,

	PRESTERA_CMD_TYPE_ROUTER_RIF_CREATE = 0x600,
	PRESTERA_CMD_TYPE_ROUTER_RIF_DELETE = 0x601,
	PRESTERA_CMD_TYPE_ROUTER_VR_CREATE = 0x630,
	PRESTERA_CMD_TYPE_ROUTER_VR_DELETE = 0x631,

	PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,

	PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,
@@ -480,6 +485,48 @@ struct prestera_msg_rxtx_resp {
	__le32 map_addr;
};

struct prestera_msg_iface {
	union {
		struct {
			__le32 dev;
			__le32 port;
		};
		__le16 lag_id;
	};
	__le16 vr_id;
	__le16 vid;
	u8 type;
	u8 __pad[3];
};

struct prestera_msg_rif_req {
	struct prestera_msg_cmd cmd;
	struct prestera_msg_iface iif;
	__le32 mtu;
	__le16 rif_id;
	__le16 __reserved;
	u8 mac[ETH_ALEN];
	u8 __pad[2];
};

struct prestera_msg_rif_resp {
	struct prestera_msg_ret ret;
	__le16 rif_id;
	u8 __pad[2];
};

struct prestera_msg_vr_req {
	struct prestera_msg_cmd cmd;
	__le16 vr_id;
	u8 __pad[2];
};

struct prestera_msg_vr_resp {
	struct prestera_msg_ret ret;
	__le16 vr_id;
	u8 __pad[2];
};

struct prestera_msg_lag_req {
	struct prestera_msg_cmd cmd;
	__le32 port;
@@ -549,6 +596,11 @@ static void prestera_hw_build_tests(void)
	BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32);
	BUILD_BUG_ON(sizeof(struct prestera_msg_counter_req) != 16);
	BUILD_BUG_ON(sizeof(struct prestera_msg_counter_stats) != 16);
	BUILD_BUG_ON(sizeof(struct prestera_msg_rif_req) != 36);
	BUILD_BUG_ON(sizeof(struct prestera_msg_vr_req) != 8);

	/*  structure that are part of req/resp fw messages */
	BUILD_BUG_ON(sizeof(struct prestera_msg_iface) != 16);

	/* check responses */
	BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8);
@@ -561,6 +613,8 @@ static void prestera_hw_build_tests(void)
	BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12);
	BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16);
	BUILD_BUG_ON(sizeof(struct prestera_msg_counter_resp) != 24);
	BUILD_BUG_ON(sizeof(struct prestera_msg_rif_resp) != 12);
	BUILD_BUG_ON(sizeof(struct prestera_msg_vr_resp) != 12);

	/* check events */
	BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20);
@@ -1752,6 +1806,91 @@ int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id)
			    &req.cmd, sizeof(req));
}

static int prestera_iface_to_msg(struct prestera_iface *iface,
				 struct prestera_msg_iface *msg_if)
{
	switch (iface->type) {
	case PRESTERA_IF_PORT_E:
	case PRESTERA_IF_VID_E:
		msg_if->port = __cpu_to_le32(iface->dev_port.port_num);
		msg_if->dev = __cpu_to_le32(iface->dev_port.hw_dev_num);
		break;
	case PRESTERA_IF_LAG_E:
		msg_if->lag_id = __cpu_to_le16(iface->lag_id);
		break;
	default:
		return -EOPNOTSUPP;
	}

	msg_if->vr_id = __cpu_to_le16(iface->vr_id);
	msg_if->vid = __cpu_to_le16(iface->vlan_id);
	msg_if->type = iface->type;
	return 0;
}

int prestera_hw_rif_create(struct prestera_switch *sw,
			   struct prestera_iface *iif, u8 *mac, u16 *rif_id)
{
	struct prestera_msg_rif_req req;
	struct prestera_msg_rif_resp resp;
	int err;

	memcpy(req.mac, mac, ETH_ALEN);

	err = prestera_iface_to_msg(iif, &req.iif);
	if (err)
		return err;

	err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ROUTER_RIF_CREATE,
			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
	if (err)
		return err;

	*rif_id = __le16_to_cpu(resp.rif_id);
	return err;
}

int prestera_hw_rif_delete(struct prestera_switch *sw, u16 rif_id,
			   struct prestera_iface *iif)
{
	struct prestera_msg_rif_req req = {
		.rif_id = __cpu_to_le16(rif_id),
	};
	int err;

	err = prestera_iface_to_msg(iif, &req.iif);
	if (err)
		return err;

	return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_RIF_DELETE, &req.cmd,
			    sizeof(req));
}

int prestera_hw_vr_create(struct prestera_switch *sw, u16 *vr_id)
{
	int err;
	struct prestera_msg_vr_resp resp;
	struct prestera_msg_vr_req req;

	err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ROUTER_VR_CREATE,
			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
	if (err)
		return err;

	*vr_id = __le16_to_cpu(resp.vr_id);
	return err;
}

int prestera_hw_vr_delete(struct prestera_switch *sw, u16 vr_id)
{
	struct prestera_msg_vr_req req = {
		.vr_id = __cpu_to_le16(vr_id),
	};

	return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_VR_DELETE, &req.cmd,
			    sizeof(req));
}

int prestera_hw_rxtx_init(struct prestera_switch *sw,
			  struct prestera_rxtx_params *params)
{
+11 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct prestera_rxtx_params;
struct prestera_acl_hw_action_info;
struct prestera_acl_iface;
struct prestera_counter_stats;
struct prestera_iface;

/* Switch API */
int prestera_hw_switch_init(struct prestera_switch *sw);
@@ -238,6 +239,16 @@ int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id);
int prestera_hw_span_unbind(const struct prestera_port *port);
int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id);

/* Router API */
int prestera_hw_rif_create(struct prestera_switch *sw,
			   struct prestera_iface *iif, u8 *mac, u16 *rif_id);
int prestera_hw_rif_delete(struct prestera_switch *sw, u16 rif_id,
			   struct prestera_iface *iif);

/* Virtual Router API */
int prestera_hw_vr_create(struct prestera_switch *sw, u16 *vr_id);
int prestera_hw_vr_delete(struct prestera_switch *sw, u16 vr_id);

/* Event handlers */
int prestera_hw_event_handler_register(struct prestera_switch *sw,
				       enum prestera_event_type type,
+7 −1
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ static netdev_tx_t prestera_port_xmit(struct sk_buff *skb,
	return prestera_rxtx_xmit(netdev_priv(dev), skb);
}

static int prestera_is_valid_mac_addr(struct prestera_port *port, u8 *addr)
int prestera_is_valid_mac_addr(struct prestera_port *port, const u8 *addr)
{
	if (!is_valid_ether_addr(addr))
		return -EADDRNOTAVAIL;
@@ -902,6 +902,10 @@ static int prestera_switch_init(struct prestera_switch *sw)
	if (err)
		return err;

	err = prestera_router_init(sw);
	if (err)
		goto err_router_init;

	err = prestera_switchdev_init(sw);
	if (err)
		goto err_swdev_register;
@@ -958,6 +962,8 @@ static int prestera_switch_init(struct prestera_switch *sw)
err_rxtx_register:
	prestera_switchdev_fini(sw);
err_swdev_register:
	prestera_router_fini(sw);
err_router_init:
	prestera_netdev_event_handler_unregister(sw);
	prestera_hw_switch_fini(sw);

Loading