mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-15 20:56:44 +07:00
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: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0514c4e809
commit
e420114eef
@ -3,4 +3,4 @@
|
||||
#
|
||||
|
||||
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 @@
|
||||
#ifndef _ROCKER_H
|
||||
#define _ROCKER_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "rocker_hw.h"
|
||||
|
||||
@ -57,6 +61,7 @@ struct rocker_port {
|
||||
struct net_device *dev;
|
||||
struct net_device *bridge_dev;
|
||||
struct rocker *rocker;
|
||||
void *wpriv;
|
||||
unsigned int port_number;
|
||||
u32 pport;
|
||||
__be16 internal_vlan_id;
|
||||
@ -71,6 +76,8 @@ struct rocker_port {
|
||||
struct rocker_dma_ring_info rx_ring;
|
||||
};
|
||||
|
||||
struct rocker_world_ops;
|
||||
|
||||
struct rocker {
|
||||
struct pci_dev *pdev;
|
||||
u8 __iomem *hw_addr;
|
||||
@ -83,6 +90,8 @@ struct rocker {
|
||||
spinlock_t cmd_ring_lock; /* for cmd ring accesses */
|
||||
struct rocker_dma_ring_info cmd_ring;
|
||||
struct rocker_dma_ring_info event_ring;
|
||||
struct rocker_world_ops *wops;
|
||||
void *wpriv;
|
||||
DECLARE_HASHTABLE(flow_tbl, 16);
|
||||
spinlock_t flow_tbl_lock; /* for flow tbl accesses */
|
||||
u64 flow_tbl_next_cookie;
|
||||
@ -99,4 +108,64 @@ struct rocker {
|
||||
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
|
||||
|
@ -1164,6 +1164,9 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
|
||||
struct switchdev_trans *trans,
|
||||
const unsigned char *addr,
|
||||
__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,
|
||||
const struct rocker_tlv *info)
|
||||
@ -1174,6 +1177,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
|
||||
const unsigned char *addr;
|
||||
int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
|
||||
__be16 vlan_id;
|
||||
int err;
|
||||
|
||||
rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
|
||||
if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] ||
|
||||
@ -1190,6 +1194,10 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
|
||||
|
||||
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 &&
|
||||
rocker_port->stp_state != BR_STATE_FORWARDING)
|
||||
return 0;
|
||||
@ -1651,6 +1659,335 @@ static int rocker_port_set_learning(struct rocker_port *rocker_port,
|
||||
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
|
||||
rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
|
||||
const struct rocker_flow_tbl_entry *entry)
|
||||
@ -3799,6 +4136,12 @@ static int rocker_port_open(struct net_device *dev)
|
||||
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);
|
||||
if (err)
|
||||
goto err_fwd_enable;
|
||||
@ -3811,6 +4154,7 @@ static int rocker_port_open(struct net_device *dev)
|
||||
return 0;
|
||||
|
||||
err_fwd_enable:
|
||||
err_world_port_open:
|
||||
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
|
||||
err_request_rx_irq:
|
||||
free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
|
||||
@ -3827,6 +4171,7 @@ static int rocker_port_stop(struct net_device *dev)
|
||||
rocker_port_set_enable(rocker_port, false);
|
||||
napi_disable(&rocker_port->napi_rx);
|
||||
napi_disable(&rocker_port->napi_tx);
|
||||
rocker_world_port_stop(rocker_port);
|
||||
rocker_port_fwd_disable(rocker_port, NULL,
|
||||
ROCKER_OP_FLAG_NOWAIT);
|
||||
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
|
||||
@ -4037,9 +4382,14 @@ static void rocker_port_neigh_destroy(struct neighbour *n)
|
||||
struct rocker_port *rocker_port = netdev_priv(n->dev);
|
||||
int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT;
|
||||
__be32 ip_addr = *(__be32 *)n->primary_key;
|
||||
int err;
|
||||
|
||||
rocker_port_ipv4_neigh(rocker_port, NULL,
|
||||
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 = {
|
||||
@ -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 *rocker = rocker_port->rocker;
|
||||
int err = 0;
|
||||
|
||||
switch (attr->id) {
|
||||
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
|
||||
@ -4076,12 +4427,14 @@ static int rocker_port_attr_get(struct net_device *dev,
|
||||
break;
|
||||
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
|
||||
attr->u.brport_flags = rocker_port->brport_flags;
|
||||
err = rocker_world_port_attr_bridge_flags_get(rocker_port,
|
||||
&attr->u.brport_flags);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
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,
|
||||
case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
|
||||
err = rocker_port_stp_update(rocker_port, trans, 0,
|
||||
attr->u.stp_state);
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_attr_stp_state_set(rocker_port,
|
||||
attr->u.stp_state,
|
||||
trans);
|
||||
break;
|
||||
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
|
||||
err = rocker_port_brport_flags_set(rocker_port, trans,
|
||||
attr->u.brport_flags);
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_attr_bridge_flags_set(rocker_port,
|
||||
attr->u.brport_flags,
|
||||
trans);
|
||||
break;
|
||||
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
|
||||
err = rocker_port_bridge_ageing_time(rocker_port, trans,
|
||||
attr->u.ageing_time);
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_attr_bridge_ageing_time_set(rocker_port,
|
||||
attr->u.ageing_time,
|
||||
trans);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
@ -4204,16 +4572,31 @@ static int rocker_port_obj_add(struct net_device *dev,
|
||||
case SWITCHDEV_OBJ_ID_PORT_VLAN:
|
||||
err = rocker_port_vlans_add(rocker_port, trans,
|
||||
SWITCHDEV_OBJ_PORT_VLAN(obj));
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_obj_vlan_add(rocker_port,
|
||||
SWITCHDEV_OBJ_PORT_VLAN(obj),
|
||||
trans);
|
||||
break;
|
||||
case SWITCHDEV_OBJ_ID_IPV4_FIB:
|
||||
fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
|
||||
err = rocker_port_fib_ipv4(rocker_port, trans,
|
||||
htonl(fib4->dst), fib4->dst_len,
|
||||
&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;
|
||||
case SWITCHDEV_OBJ_ID_PORT_FDB:
|
||||
err = rocker_port_fdb_add(rocker_port, trans,
|
||||
SWITCHDEV_OBJ_PORT_FDB(obj));
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_obj_fdb_add(rocker_port,
|
||||
SWITCHDEV_OBJ_PORT_FDB(obj),
|
||||
trans);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
@ -4276,6 +4659,10 @@ static int rocker_port_obj_del(struct net_device *dev,
|
||||
case SWITCHDEV_OBJ_ID_PORT_VLAN:
|
||||
err = rocker_port_vlans_del(rocker_port,
|
||||
SWITCHDEV_OBJ_PORT_VLAN(obj));
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_obj_vlan_del(rocker_port,
|
||||
SWITCHDEV_OBJ_PORT_VLAN(obj));
|
||||
break;
|
||||
case SWITCHDEV_OBJ_ID_IPV4_FIB:
|
||||
fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
|
||||
@ -4283,10 +4670,18 @@ static int rocker_port_obj_del(struct net_device *dev,
|
||||
htonl(fib4->dst), fib4->dst_len,
|
||||
&fib4->fi, fib4->tb_id,
|
||||
ROCKER_OP_FLAG_REMOVE);
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_obj_fib4_del(rocker_port,
|
||||
SWITCHDEV_OBJ_IPV4_FIB(obj));
|
||||
break;
|
||||
case SWITCHDEV_OBJ_ID_PORT_FDB:
|
||||
err = rocker_port_fdb_del(rocker_port, NULL,
|
||||
SWITCHDEV_OBJ_PORT_FDB(obj));
|
||||
if (err)
|
||||
break;
|
||||
err = rocker_world_port_obj_fdb_del(rocker_port,
|
||||
SWITCHDEV_OBJ_PORT_FDB(obj));
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
@ -4358,10 +4753,20 @@ static int rocker_port_obj_dump(struct net_device *dev,
|
||||
case SWITCHDEV_OBJ_ID_PORT_FDB:
|
||||
err = rocker_port_fdb_dump(rocker_port,
|
||||
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;
|
||||
case SWITCHDEV_OBJ_ID_PORT_VLAN:
|
||||
err = rocker_port_vlan_dump(rocker_port,
|
||||
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;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
@ -4687,7 +5092,7 @@ static void rocker_carrier_init(const struct rocker_port *rocker_port)
|
||||
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;
|
||||
int i;
|
||||
@ -4697,9 +5102,12 @@ static void rocker_remove_ports(const struct rocker *rocker)
|
||||
if (!rocker_port)
|
||||
continue;
|
||||
rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
|
||||
rocker_world_port_fini(rocker_port);
|
||||
unregister_netdev(rocker_port->dev);
|
||||
rocker_world_port_post_fini(rocker_port);
|
||||
free_netdev(rocker_port->dev);
|
||||
}
|
||||
rocker_world_fini(rocker);
|
||||
kfree(rocker->ports);
|
||||
}
|
||||
|
||||
@ -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->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);
|
||||
dev->netdev_ops = &rocker_port_netdev_ops;
|
||||
dev->ethtool_ops = &rocker_port_ethtool_ops;
|
||||
@ -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;
|
||||
|
||||
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);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "register_netdev failed\n");
|
||||
@ -4755,6 +5174,12 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
||||
}
|
||||
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);
|
||||
|
||||
rocker_port_set_learning(rocker_port, NULL);
|
||||
@ -4779,9 +5204,14 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
||||
err_untagged_vlan:
|
||||
rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
|
||||
err_port_ig_tbl:
|
||||
rocker_world_port_fini(rocker_port);
|
||||
err_world_port_init:
|
||||
rocker->ports[port_number] = NULL;
|
||||
unregister_netdev(dev);
|
||||
err_register_netdev:
|
||||
rocker_world_port_post_fini(rocker_port);
|
||||
err_world_port_pre_init:
|
||||
err_world_check_init:
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
}
|
||||
@ -5132,12 +5562,22 @@ static int rocker_netdevice_event(struct notifier_block *unused,
|
||||
goto out;
|
||||
rocker_port = netdev_priv(dev);
|
||||
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,
|
||||
info->upper_dev);
|
||||
if (err)
|
||||
netdev_warn(dev, "failed to reflect master linked (err %d)\n",
|
||||
err);
|
||||
} 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);
|
||||
if (err)
|
||||
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)
|
||||
static int rocker_netevent_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct rocker_port *rocker_port;
|
||||
struct net_device *dev;
|
||||
struct neighbour *n = ptr;
|
||||
int err;
|
||||
@ -5181,6 +5622,11 @@ static int rocker_netevent_event(struct notifier_block *unused,
|
||||
dev = n->dev;
|
||||
if (!rocker_port_dev_check(dev))
|
||||
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);
|
||||
if (err)
|
||||
netdev_warn(dev,
|
||||
|
27
drivers/net/ethernet/rocker/rocker_ofdpa.c
Normal file
27
drivers/net/ethernet/rocker/rocker_ofdpa.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
Loading…
Reference in New Issue
Block a user