Commit e420114e authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

rocker: introduce worlds infrastructure

This is another step on the way to per-world clean cut. Introduce world
ops hooks which each world can implement in world-specific way.
Also introduce world infrastructure along with OF-DPA world stub.
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0514c4e8
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
# #
obj-$(CONFIG_ROCKER) += rocker.o obj-$(CONFIG_ROCKER) += rocker.o
rocker-y := rocker_main.o rocker_tlv.o rocker-y := rocker_main.o rocker_tlv.o rocker_ofdpa.o
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
#ifndef _ROCKER_H #ifndef _ROCKER_H
#define _ROCKER_H #define _ROCKER_H
#include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/netdevice.h>
#include <net/neighbour.h>
#include <net/switchdev.h>
#include "rocker_hw.h" #include "rocker_hw.h"
...@@ -57,6 +61,7 @@ struct rocker_port { ...@@ -57,6 +61,7 @@ struct rocker_port {
struct net_device *dev; struct net_device *dev;
struct net_device *bridge_dev; struct net_device *bridge_dev;
struct rocker *rocker; struct rocker *rocker;
void *wpriv;
unsigned int port_number; unsigned int port_number;
u32 pport; u32 pport;
__be16 internal_vlan_id; __be16 internal_vlan_id;
...@@ -71,6 +76,8 @@ struct rocker_port { ...@@ -71,6 +76,8 @@ struct rocker_port {
struct rocker_dma_ring_info rx_ring; struct rocker_dma_ring_info rx_ring;
}; };
struct rocker_world_ops;
struct rocker { struct rocker {
struct pci_dev *pdev; struct pci_dev *pdev;
u8 __iomem *hw_addr; u8 __iomem *hw_addr;
...@@ -83,6 +90,8 @@ struct rocker { ...@@ -83,6 +90,8 @@ struct rocker {
spinlock_t cmd_ring_lock; /* for cmd ring accesses */ spinlock_t cmd_ring_lock; /* for cmd ring accesses */
struct rocker_dma_ring_info cmd_ring; struct rocker_dma_ring_info cmd_ring;
struct rocker_dma_ring_info event_ring; struct rocker_dma_ring_info event_ring;
struct rocker_world_ops *wops;
void *wpriv;
DECLARE_HASHTABLE(flow_tbl, 16); DECLARE_HASHTABLE(flow_tbl, 16);
spinlock_t flow_tbl_lock; /* for flow tbl accesses */ spinlock_t flow_tbl_lock; /* for flow tbl accesses */
u64 flow_tbl_next_cookie; u64 flow_tbl_next_cookie;
...@@ -99,4 +108,64 @@ struct rocker { ...@@ -99,4 +108,64 @@ struct rocker {
u32 neigh_tbl_next_index; u32 neigh_tbl_next_index;
}; };
struct rocker_world_ops {
const char *kind;
size_t priv_size;
size_t port_priv_size;
u8 mode;
int (*init)(struct rocker *rocker);
void (*fini)(struct rocker *rocker);
int (*port_pre_init)(struct rocker_port *rocker_port);
int (*port_init)(struct rocker_port *rocker_port);
void (*port_fini)(struct rocker_port *rocker_port);
void (*port_post_fini)(struct rocker_port *rocker_port);
int (*port_open)(struct rocker_port *rocker_port);
void (*port_stop)(struct rocker_port *rocker_port);
int (*port_attr_stp_state_set)(struct rocker_port *rocker_port,
u8 state,
struct switchdev_trans *trans);
int (*port_attr_bridge_flags_set)(struct rocker_port *rocker_port,
unsigned long brport_flags,
struct switchdev_trans *trans);
int (*port_attr_bridge_flags_get)(const struct rocker_port *rocker_port,
unsigned long *p_brport_flags);
int (*port_attr_bridge_ageing_time_set)(struct rocker_port *rocker_port,
u32 ageing_time,
struct switchdev_trans *trans);
int (*port_obj_vlan_add)(struct rocker_port *rocker_port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans);
int (*port_obj_vlan_del)(struct rocker_port *rocker_port,
const struct switchdev_obj_port_vlan *vlan);
int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port,
struct switchdev_obj_port_vlan *vlan,
switchdev_obj_dump_cb_t *cb);
int (*port_obj_fib4_add)(struct rocker_port *rocker_port,
const struct switchdev_obj_ipv4_fib *fib4,
struct switchdev_trans *trans);
int (*port_obj_fib4_del)(struct rocker_port *rocker_port,
const struct switchdev_obj_ipv4_fib *fib4);
int (*port_obj_fdb_add)(struct rocker_port *rocker_port,
const struct switchdev_obj_port_fdb *fdb,
struct switchdev_trans *trans);
int (*port_obj_fdb_del)(struct rocker_port *rocker_port,
const struct switchdev_obj_port_fdb *fdb);
int (*port_obj_fdb_dump)(const struct rocker_port *rocker_port,
struct switchdev_obj_port_fdb *fdb,
switchdev_obj_dump_cb_t *cb);
int (*port_master_linked)(struct rocker_port *rocker_port,
struct net_device *master);
int (*port_master_unlinked)(struct rocker_port *rocker_port,
struct net_device *master);
int (*port_neigh_update)(struct rocker_port *rocker_port,
struct neighbour *n);
int (*port_neigh_destroy)(struct rocker_port *rocker_port,
struct neighbour *n);
int (*port_ev_mac_vlan_seen)(struct rocker_port *rocker_port,
const unsigned char *addr,
__be16 vlan_id);
};
extern struct rocker_world_ops rocker_ofdpa_ops;
#endif #endif
...@@ -1164,6 +1164,9 @@ static int rocker_port_fdb(struct rocker_port *rocker_port, ...@@ -1164,6 +1164,9 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
struct switchdev_trans *trans, struct switchdev_trans *trans,
const unsigned char *addr, const unsigned char *addr,
__be16 vlan_id, int flags); __be16 vlan_id, int flags);
static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
const unsigned char *addr,
__be16 vlan_id);
static int rocker_event_mac_vlan_seen(const struct rocker *rocker, static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
const struct rocker_tlv *info) const struct rocker_tlv *info)
...@@ -1174,6 +1177,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker, ...@@ -1174,6 +1177,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
const unsigned char *addr; const unsigned char *addr;
int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED; int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
__be16 vlan_id; __be16 vlan_id;
int err;
rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info); rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] || if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] ||
...@@ -1190,6 +1194,10 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker, ...@@ -1190,6 +1194,10 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
rocker_port = rocker->ports[port_number]; rocker_port = rocker->ports[port_number];
err = rocker_world_port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
if (err)
return err;
if (rocker_port->stp_state != BR_STATE_LEARNING && if (rocker_port->stp_state != BR_STATE_LEARNING &&
rocker_port->stp_state != BR_STATE_FORWARDING) rocker_port->stp_state != BR_STATE_FORWARDING)
return 0; return 0;
...@@ -1651,6 +1659,335 @@ static int rocker_port_set_learning(struct rocker_port *rocker_port, ...@@ -1651,6 +1659,335 @@ static int rocker_port_set_learning(struct rocker_port *rocker_port,
NULL, NULL, NULL); NULL, NULL, NULL);
} }
/**********************
* Worlds manipulation
**********************/
static struct rocker_world_ops *rocker_world_ops[] = {
&rocker_ofdpa_ops,
};
#define ROCKER_WORLD_OPS_LEN ARRAY_SIZE(rocker_world_ops)
static struct rocker_world_ops *rocker_world_ops_find(u8 mode)
{
int i;
for (i = 0; i < ROCKER_WORLD_OPS_LEN; i++)
if (rocker_world_ops[i]->mode == mode)
return rocker_world_ops[i];
return NULL;
}
static int rocker_world_init(struct rocker *rocker, u8 mode)
{
struct rocker_world_ops *wops;
int err;
wops = rocker_world_ops_find(mode);
if (!wops) {
dev_err(&rocker->pdev->dev, "port mode \"%d\" is not supported\n",
mode);
return -EINVAL;
}
rocker->wops = wops;
rocker->wpriv = kzalloc(wops->priv_size, GFP_KERNEL);
if (!rocker->wpriv)
return -ENOMEM;
if (!wops->init)
return 0;
err = wops->init(rocker);
if (err)
kfree(rocker->wpriv);
return err;
}
static void rocker_world_fini(struct rocker *rocker)
{
struct rocker_world_ops *wops = rocker->wops;
if (!wops || !wops->fini)
return;
wops->fini(rocker);
kfree(rocker->wpriv);
}
static int rocker_world_check_init(struct rocker_port *rocker_port)
{
struct rocker *rocker = rocker_port->rocker;
u8 mode;
int err;
err = rocker_cmd_get_port_settings_mode(rocker_port, &mode);
if (err) {
dev_err(&rocker->pdev->dev, "failed to get port mode\n");
return err;
}
if (rocker->wops) {
if (rocker->wops->mode != mode) {
dev_err(&rocker->pdev->dev, "hardware has ports in different worlds, which is not supported\n");
return err;
}
return 0;
}
return rocker_world_init(rocker, mode);
}
static int rocker_world_port_pre_init(struct rocker_port *rocker_port)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
int err;
rocker_port->wpriv = kzalloc(wops->port_priv_size, GFP_KERNEL);
if (!rocker_port->wpriv)
return -ENOMEM;
if (!wops->port_pre_init)
return 0;
err = wops->port_pre_init(rocker_port);
if (err)
kfree(rocker_port->wpriv);
return 0;
}
static int rocker_world_port_init(struct rocker_port *rocker_port)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_init)
return 0;
return wops->port_init(rocker_port);
}
static void rocker_world_port_fini(struct rocker_port *rocker_port)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_fini)
return;
wops->port_fini(rocker_port);
}
static void rocker_world_port_post_fini(struct rocker_port *rocker_port)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_post_fini)
return;
wops->port_post_fini(rocker_port);
kfree(rocker_port->wpriv);
}
static int rocker_world_port_open(struct rocker_port *rocker_port)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_open)
return 0;
return wops->port_open(rocker_port);
}
static void rocker_world_port_stop(struct rocker_port *rocker_port)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_stop)
return;
wops->port_stop(rocker_port);
}
static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port,
u8 state,
struct switchdev_trans *trans)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_stp_state_set)
return 0;
return wops->port_attr_stp_state_set(rocker_port, state, trans);
}
static int
rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
unsigned long brport_flags,
struct switchdev_trans *trans)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_bridge_flags_set)
return 0;
return wops->port_attr_bridge_flags_set(rocker_port, brport_flags,
trans);
}
static int
rocker_world_port_attr_bridge_flags_get(const struct rocker_port *rocker_port,
unsigned long *p_brport_flags)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_bridge_flags_get)
return 0;
return wops->port_attr_bridge_flags_get(rocker_port, p_brport_flags);
}
static int
rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
u32 ageing_time,
struct switchdev_trans *trans)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_bridge_ageing_time_set)
return 0;
return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time,
trans);
}
static int
rocker_world_port_obj_vlan_add(struct rocker_port *rocker_port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_vlan_add)
return 0;
return wops->port_obj_vlan_add(rocker_port, vlan, trans);
}
static int
rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port,
const struct switchdev_obj_port_vlan *vlan)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_vlan_del)
return 0;
return wops->port_obj_vlan_del(rocker_port, vlan);
}
static int
rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port,
struct switchdev_obj_port_vlan *vlan,
switchdev_obj_dump_cb_t *cb)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_vlan_dump)
return 0;
return wops->port_obj_vlan_dump(rocker_port, vlan, cb);
}
static int
rocker_world_port_obj_fib4_add(struct rocker_port *rocker_port,
const struct switchdev_obj_ipv4_fib *fib4,
struct switchdev_trans *trans)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_fib4_add)
return 0;
return wops->port_obj_fib4_add(rocker_port, fib4, trans);
}
static int
rocker_world_port_obj_fib4_del(struct rocker_port *rocker_port,
const struct switchdev_obj_ipv4_fib *fib4)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_fib4_del)
return 0;
return wops->port_obj_fib4_del(rocker_port, fib4);
}
static int
rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port,
const struct switchdev_obj_port_fdb *fdb,
struct switchdev_trans *trans)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_fdb_add)
return 0;
return wops->port_obj_fdb_add(rocker_port, fdb, trans);
}
static int
rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port,
const struct switchdev_obj_port_fdb *fdb)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_fdb_del)
return 0;
return wops->port_obj_fdb_del(rocker_port, fdb);
}
static int
rocker_world_port_obj_fdb_dump(const struct rocker_port *rocker_port,
struct switchdev_obj_port_fdb *fdb,
switchdev_obj_dump_cb_t *cb)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_obj_fdb_dump)
return 0;
return wops->port_obj_fdb_dump(rocker_port, fdb, cb);
}
static int rocker_world_port_master_linked(struct rocker_port *rocker_port,
struct net_device *master)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_master_linked)
return 0;
return wops->port_master_linked(rocker_port, master);
}
static int rocker_world_port_master_unlinked(struct rocker_port *rocker_port,
struct net_device *master)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_master_unlinked)
return 0;
return wops->port_master_unlinked(rocker_port, master);
}
static int rocker_world_port_neigh_update(struct rocker_port *rocker_port,
struct neighbour *n)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_neigh_update)
return 0;
return wops->port_neigh_update(rocker_port, n);
}
static int rocker_world_port_neigh_destroy(struct rocker_port *rocker_port,
struct neighbour *n)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_neigh_destroy)
return 0;
return wops->port_neigh_destroy(rocker_port, n);
}
static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
const unsigned char *addr,
__be16 vlan_id)
{
struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_ev_mac_vlan_seen)
return 0;
return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
}
static int static int
rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info, rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
const struct rocker_flow_tbl_entry *entry) const struct rocker_flow_tbl_entry *entry)
...@@ -3799,6 +4136,12 @@ static int rocker_port_open(struct net_device *dev) ...@@ -3799,6 +4136,12 @@ static int rocker_port_open(struct net_device *dev)
goto err_request_rx_irq; goto err_request_rx_irq;
} }
err = rocker_world_port_open(rocker_port);
if (err) {
netdev_err(rocker_port->dev, "cannot open port in world\n");
goto err_world_port_open;
}
err = rocker_port_fwd_enable(rocker_port, NULL, 0); err = rocker_port_fwd_enable(rocker_port, NULL, 0);
if (err) if (err)
goto err_fwd_enable; goto err_fwd_enable;
...@@ -3811,6 +4154,7 @@ static int rocker_port_open(struct net_device *dev) ...@@ -3811,6 +4154,7 @@ static int rocker_port_open(struct net_device *dev)
return 0; return 0;
err_fwd_enable: err_fwd_enable:
err_world_port_open:
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port); free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
err_request_rx_irq: err_request_rx_irq:
free_irq(rocker_msix_tx_vector(rocker_port), rocker_port); free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
...@@ -3827,6 +4171,7 @@ static int rocker_port_stop(struct net_device *dev) ...@@ -3827,6 +4171,7 @@ static int rocker_port_stop(struct net_device *dev)
rocker_port_set_enable(rocker_port, false); rocker_port_set_enable(rocker_port, false);
napi_disable(&rocker_port->napi_rx); napi_disable(&rocker_port->napi_rx);
napi_disable(&rocker_port->napi_tx); napi_disable(&rocker_port->napi_tx);
rocker_world_port_stop(rocker_port);
rocker_port_fwd_disable(rocker_port, NULL, rocker_port_fwd_disable(rocker_port, NULL,
ROCKER_OP_FLAG_NOWAIT); ROCKER_OP_FLAG_NOWAIT);
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port); free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
...@@ -4037,9 +4382,14 @@ static void rocker_port_neigh_destroy(struct neighbour *n) ...@@ -4037,9 +4382,14 @@ static void rocker_port_neigh_destroy(struct neighbour *n)
struct rocker_port *rocker_port = netdev_priv(n->dev); struct rocker_port *rocker_port = netdev_priv(n->dev);
int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT; int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT;
__be32 ip_addr = *(__be32 *)n->primary_key; __be32 ip_addr = *(__be32 *)n->primary_key;
int err;
rocker_port_ipv4_neigh(rocker_port, NULL, rocker_port_ipv4_neigh(rocker_port, NULL,
flags, ip_addr, n->ha); flags, ip_addr, n->ha);
err = rocker_world_port_neigh_destroy(rocker_port, n);
if (err)
netdev_warn(rocker_port->dev, "failed to handle neigh destroy (err %d)\n",
err);
} }
static const struct net_device_ops rocker_port_netdev_ops = { static const struct net_device_ops rocker_port_netdev_ops = {
...@@ -4068,6 +4418,7 @@ static int rocker_port_attr_get(struct net_device *dev, ...@@ -4068,6 +4418,7 @@ static int rocker_port_attr_get(struct net_device *dev,
{ {
const struct rocker_port *rocker_port = netdev_priv(dev); const struct rocker_port *rocker_port = netdev_priv(dev);
const struct rocker *rocker = rocker_port->rocker; const struct rocker *rocker = rocker_port->rocker;
int err = 0;
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
...@@ -4076,12 +4427,14 @@ static int rocker_port_attr_get(struct net_device *dev, ...@@ -4076,12 +4427,14 @@ static int rocker_port_attr_get(struct net_device *dev,
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
attr->u.brport_flags = rocker_port->brport_flags; attr->u.brport_flags = rocker_port->brport_flags;
err = rocker_world_port_attr_bridge_flags_get(rocker_port,
&attr->u.brport_flags);
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
return 0; return err;
} }
static int rocker_port_brport_flags_set(struct rocker_port *rocker_port, static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
...@@ -4125,14 +4478,29 @@ static int rocker_port_attr_set(struct net_device *dev, ...@@ -4125,14 +4478,29 @@ static int rocker_port_attr_set(struct net_device *dev,
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
err = rocker_port_stp_update(rocker_port, trans, 0, err = rocker_port_stp_update(rocker_port, trans, 0,
attr->u.stp_state); attr->u.stp_state);
if (err)
break;
err = rocker_world_port_attr_stp_state_set(rocker_port,
attr->u.stp_state,
trans);
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = rocker_port_brport_flags_set(rocker_port, trans, err = rocker_port_brport_flags_set(rocker_port, trans,
attr->u.brport_flags); attr->u.brport_flags);
if (err)
break;
err = rocker_world_port_attr_bridge_flags_set(rocker_port,
attr->u.brport_flags,
trans);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
err = rocker_port_bridge_ageing_time(rocker_port, trans, err = rocker_port_bridge_ageing_time(rocker_port, trans,
attr->u.ageing_time); attr->u.ageing_time);
if (err)
break;
err = rocker_world_port_attr_bridge_ageing_time_set(rocker_port,
attr->u.ageing_time,
trans);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -4204,16 +4572,31 @@ static int rocker_port_obj_add(struct net_device *dev, ...@@ -4204,16 +4572,31 @@ static int rocker_port_obj_add(struct net_device *dev,
case SWITCHDEV_OBJ_ID_PORT_VLAN: case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = rocker_port_vlans_add(rocker_port, trans, err = rocker_port_vlans_add(rocker_port, trans,
SWITCHDEV_OBJ_PORT_VLAN(obj)); SWITCHDEV_OBJ_PORT_VLAN(obj));
if (err)
break;
err = rocker_world_port_obj_vlan_add(rocker_port,
SWITCHDEV_OBJ_PORT_VLAN(obj),
trans);
break; break;
case SWITCHDEV_OBJ_ID_IPV4_FIB: case SWITCHDEV_OBJ_ID_IPV4_FIB:
fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
err = rocker_port_fib_ipv4(rocker_port, trans, err = rocker_port_fib_ipv4(rocker_port, trans,
htonl(fib4->dst), fib4->dst_len, htonl(fib4->dst), fib4->dst_len,
&fib4->fi, fib4->tb_id, 0); &fib4->fi, fib4->tb_id, 0);
if (err)
break;
err = rocker_world_port_obj_fib4_add(rocker_port,
SWITCHDEV_OBJ_IPV4_FIB(obj),
trans);
break; break;
case SWITCHDEV_OBJ_ID_PORT_FDB: case SWITCHDEV_OBJ_ID_PORT_FDB:
err = rocker_port_fdb_add(rocker_port, trans, err = rocker_port_fdb_add(rocker_port, trans,
SWITCHDEV_OBJ_PORT_FDB(obj)); SWITCHDEV_OBJ_PORT_FDB(obj));
if (err)
break;
err = rocker_world_port_obj_fdb_add(rocker_port,
SWITCHDEV_OBJ_PORT_FDB(obj),
trans);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -4276,6 +4659,10 @@ static int rocker_port_obj_del(struct net_device *dev, ...@@ -4276,6 +4659,10 @@ static int rocker_port_obj_del(struct net_device *dev,
case SWITCHDEV_OBJ_ID_PORT_VLAN: case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = rocker_port_vlans_del(rocker_port, err = rocker_port_vlans_del(rocker_port,
SWITCHDEV_OBJ_PORT_VLAN(obj)); SWITCHDEV_OBJ_PORT_VLAN(obj));
if (err)
break;
err = rocker_world_port_obj_vlan_del(rocker_port,
SWITCHDEV_OBJ_PORT_VLAN(obj));
break; break;
case SWITCHDEV_OBJ_ID_IPV4_FIB: case SWITCHDEV_OBJ_ID_IPV4_FIB:
fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
...@@ -4283,10 +4670,18 @@ static int rocker_port_obj_del(struct net_device *dev, ...@@ -4283,10 +4670,18 @@ static int rocker_port_obj_del(struct net_device *dev,
htonl(fib4->dst), fib4->dst_len, htonl(fib4->dst), fib4->dst_len,
&fib4->fi, fib4->tb_id, &fib4->fi, fib4->tb_id,
ROCKER_OP_FLAG_REMOVE); ROCKER_OP_FLAG_REMOVE);
if (err)
break;
err = rocker_world_port_obj_fib4_del(rocker_port,
SWITCHDEV_OBJ_IPV4_FIB(obj));
break; break;
case SWITCHDEV_OBJ_ID_PORT_FDB: case SWITCHDEV_OBJ_ID_PORT_FDB:
err = rocker_port_fdb_del(rocker_port, NULL, err = rocker_port_fdb_del(rocker_port, NULL,
SWITCHDEV_OBJ_PORT_FDB(obj)); SWITCHDEV_OBJ_PORT_FDB(obj));
if (err)
break;
err = rocker_world_port_obj_fdb_del(rocker_port,
SWITCHDEV_OBJ_PORT_FDB(obj));
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -4358,10 +4753,20 @@ static int rocker_port_obj_dump(struct net_device *dev, ...@@ -4358,10 +4753,20 @@ static int rocker_port_obj_dump(struct net_device *dev,
case SWITCHDEV_OBJ_ID_PORT_FDB: case SWITCHDEV_OBJ_ID_PORT_FDB:
err = rocker_port_fdb_dump(rocker_port, err = rocker_port_fdb_dump(rocker_port,
SWITCHDEV_OBJ_PORT_FDB(obj), cb); SWITCHDEV_OBJ_PORT_FDB(obj), cb);
if (err)
break;
err = rocker_world_port_obj_fdb_dump(rocker_port,
SWITCHDEV_OBJ_PORT_FDB(obj),
cb);
break; break;
case SWITCHDEV_OBJ_ID_PORT_VLAN: case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = rocker_port_vlan_dump(rocker_port, err = rocker_port_vlan_dump(rocker_port,
SWITCHDEV_OBJ_PORT_VLAN(obj), cb); SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
if (err)
break;
err = rocker_world_port_obj_vlan_dump(rocker_port,
SWITCHDEV_OBJ_PORT_VLAN(obj),
cb);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -4687,7 +5092,7 @@ static void rocker_carrier_init(const struct rocker_port *rocker_port) ...@@ -4687,7 +5092,7 @@ static void rocker_carrier_init(const struct rocker_port *rocker_port)
netif_carrier_off(rocker_port->dev); netif_carrier_off(rocker_port->dev);
} }
static void rocker_remove_ports(const struct rocker *rocker) static void rocker_remove_ports(struct rocker *rocker)
{ {
struct rocker_port *rocker_port; struct rocker_port *rocker_port;
int i; int i;
...@@ -4697,9 +5102,12 @@ static void rocker_remove_ports(const struct rocker *rocker) ...@@ -4697,9 +5102,12 @@ static void rocker_remove_ports(const struct rocker *rocker)
if (!rocker_port) if (!rocker_port)
continue; continue;
rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE); rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
rocker_world_port_fini(rocker_port);
unregister_netdev(rocker_port->dev); unregister_netdev(rocker_port->dev);
rocker_world_port_post_fini(rocker_port);
free_netdev(rocker_port->dev); free_netdev(rocker_port->dev);
} }
rocker_world_fini(rocker);
kfree(rocker->ports); kfree(rocker->ports);
} }
...@@ -4736,6 +5144,12 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -4736,6 +5144,12 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC; rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
rocker_port->ageing_time = BR_DEFAULT_AGEING_TIME; rocker_port->ageing_time = BR_DEFAULT_AGEING_TIME;
err = rocker_world_check_init(rocker_port);
if (err) {
dev_err(&pdev->dev, "world init failed\n");
goto err_world_check_init;
}
rocker_port_dev_addr_init(rocker_port); rocker_port_dev_addr_init(rocker_port);
dev->netdev_ops = &rocker_port_netdev_ops; dev->netdev_ops = &rocker_port_netdev_ops;
dev->ethtool_ops = &rocker_port_ethtool_ops; dev->ethtool_ops = &rocker_port_ethtool_ops;
...@@ -4748,6 +5162,11 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -4748,6 +5162,11 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_SG; dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_SG;
err = rocker_world_port_pre_init(rocker_port);
if (err) {
dev_err(&pdev->dev, "port world pre-init failed\n");
goto err_world_port_pre_init;
}
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
dev_err(&pdev->dev, "register_netdev failed\n"); dev_err(&pdev->dev, "register_netdev failed\n");
...@@ -4755,6 +5174,12 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -4755,6 +5174,12 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
} }
rocker->ports[port_number] = rocker_port; rocker->ports[port_number] = rocker_port;
err = rocker_world_port_init(rocker_port);
if (err) {
dev_err(&pdev->dev, "port world init failed\n");
goto err_world_port_init;
}
switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false); switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false);
rocker_port_set_learning(rocker_port, NULL); rocker_port_set_learning(rocker_port, NULL);
...@@ -4779,9 +5204,14 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) ...@@ -4779,9 +5204,14 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
err_untagged_vlan: err_untagged_vlan:
rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE); rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
err_port_ig_tbl: err_port_ig_tbl:
rocker_world_port_fini(rocker_port);
err_world_port_init:
rocker->ports[port_number] = NULL; rocker->ports[port_number] = NULL;
unregister_netdev(dev); unregister_netdev(dev);
err_register_netdev: err_register_netdev:
rocker_world_port_post_fini(rocker_port);
err_world_port_pre_init:
err_world_check_init:
free_netdev(dev); free_netdev(dev);
return err; return err;
} }
...@@ -5132,12 +5562,22 @@ static int rocker_netdevice_event(struct notifier_block *unused, ...@@ -5132,12 +5562,22 @@ static int rocker_netdevice_event(struct notifier_block *unused,
goto out; goto out;
rocker_port = netdev_priv(dev); rocker_port = netdev_priv(dev);
if (info->linking) { if (info->linking) {
err = rocker_world_port_master_linked(rocker_port,
info->upper_dev);
if (err)
netdev_warn(dev, "failed to reflect master linked (err %d)\n",
err);
err = rocker_port_master_linked(rocker_port, err = rocker_port_master_linked(rocker_port,
info->upper_dev); info->upper_dev);
if (err) if (err)
netdev_warn(dev, "failed to reflect master linked (err %d)\n", netdev_warn(dev, "failed to reflect master linked (err %d)\n",
err); err);
} else { } else {
err = rocker_world_port_master_unlinked(rocker_port,
info->upper_dev);
if (err)
netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",
err);
err = rocker_port_master_unlinked(rocker_port); err = rocker_port_master_unlinked(rocker_port);
if (err) if (err)
netdev_warn(dev, "failed to reflect master unlinked (err %d)\n", netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",
...@@ -5170,6 +5610,7 @@ static int rocker_neigh_update(struct net_device *dev, struct neighbour *n) ...@@ -5170,6 +5610,7 @@ static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
static int rocker_netevent_event(struct notifier_block *unused, static int rocker_netevent_event(struct notifier_block *unused,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
struct rocker_port *rocker_port;
struct net_device *dev; struct net_device *dev;
struct neighbour *n = ptr; struct neighbour *n = ptr;
int err; int err;
...@@ -5181,6 +5622,11 @@ static int rocker_netevent_event(struct notifier_block *unused, ...@@ -5181,6 +5622,11 @@ static int rocker_netevent_event(struct notifier_block *unused,
dev = n->dev; dev = n->dev;
if (!rocker_port_dev_check(dev)) if (!rocker_port_dev_check(dev))
return NOTIFY_DONE; return NOTIFY_DONE;
rocker_port = netdev_priv(dev);
err = rocker_world_port_neigh_update(rocker_port, n);
if (err)
netdev_warn(dev, "failed to handle neigh update (err %d)\n",
err);
err = rocker_neigh_update(dev, n); err = rocker_neigh_update(dev, n);
if (err) if (err)
netdev_warn(dev, netdev_warn(dev,
......
/*
* drivers/net/ethernet/rocker/rocker_ofdpa.c - Rocker switch OF-DPA-like
* implementation
* Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
* Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include "rocker.h"
struct ofdpa {
};
struct ofdpa_port {
};
struct rocker_world_ops rocker_ofdpa_ops = {
.kind = "ofdpa",
.priv_size = sizeof(struct ofdpa),
.port_priv_size = sizeof(struct ofdpa_port),
.mode = ROCKER_PORT_MODE_OF_DPA,
};
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