Skip to content

Commit

Permalink
rocker: use FIB notifications instead of switchdev calls
Browse files Browse the repository at this point in the history
Until now, in order to offload a FIB entry to HW we use switchdev op.
Use the newly introduced FIB notifier infrasturucture to process
FIB entries to offload the in HW.
Abort mechanism is now handled within the rocker driver.

Signed-off-by: Jiri Pirko <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jpirko authored and davem330 committed Sep 28, 2016
1 parent b45f64d commit 936bd48
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 65 deletions.
15 changes: 10 additions & 5 deletions drivers/net/ethernet/rocker/rocker.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/notifier.h>
#include <net/neighbour.h>
#include <net/switchdev.h>

Expand Down Expand Up @@ -52,6 +53,9 @@ struct rocker_port {
struct rocker_dma_ring_info rx_ring;
};

struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
struct rocker *rocker);

struct rocker_world_ops;

struct rocker {
Expand All @@ -66,6 +70,7 @@ 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 notifier_block fib_nb;
struct rocker_world_ops *wops;
void *wpriv;
};
Expand Down Expand Up @@ -117,11 +122,6 @@ struct rocker_world_ops {
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);
Expand All @@ -141,6 +141,11 @@ struct rocker_world_ops {
int (*port_ev_mac_vlan_seen)(struct rocker_port *rocker_port,
const unsigned char *addr,
__be16 vlan_id);
int (*fib4_add)(struct rocker *rocker,
const struct fib_entry_notifier_info *fen_info);
int (*fib4_del)(struct rocker *rocker,
const struct fib_entry_notifier_info *fen_info);
void (*fib4_abort)(struct rocker *rocker);
};

extern struct rocker_world_ops rocker_ofdpa_ops;
Expand Down
120 changes: 88 additions & 32 deletions drivers/net/ethernet/rocker/rocker_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1624,29 +1624,6 @@ rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port,
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 -EOPNOTSUPP;
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 -EOPNOTSUPP;
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,
Expand Down Expand Up @@ -1733,6 +1710,34 @@ static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
}

static int rocker_world_fib4_add(struct rocker *rocker,
const struct fib_entry_notifier_info *fen_info)
{
struct rocker_world_ops *wops = rocker->wops;

if (!wops->fib4_add)
return 0;
return wops->fib4_add(rocker, fen_info);
}

static int rocker_world_fib4_del(struct rocker *rocker,
const struct fib_entry_notifier_info *fen_info)
{
struct rocker_world_ops *wops = rocker->wops;

if (!wops->fib4_del)
return 0;
return wops->fib4_del(rocker, fen_info);
}

static void rocker_world_fib4_abort(struct rocker *rocker)
{
struct rocker_world_ops *wops = rocker->wops;

if (wops->fib4_abort)
wops->fib4_abort(rocker);
}

/*****************
* Net device ops
*****************/
Expand Down Expand Up @@ -2096,11 +2101,6 @@ static int rocker_port_obj_add(struct net_device *dev,
SWITCHDEV_OBJ_PORT_VLAN(obj),
trans);
break;
case SWITCHDEV_OBJ_ID_IPV4_FIB:
err = rocker_world_port_obj_fib4_add(rocker_port,
SWITCHDEV_OBJ_IPV4_FIB(obj),
trans);
break;
case SWITCHDEV_OBJ_ID_PORT_FDB:
err = rocker_world_port_obj_fdb_add(rocker_port,
SWITCHDEV_OBJ_PORT_FDB(obj),
Expand All @@ -2125,10 +2125,6 @@ static int rocker_port_obj_del(struct net_device *dev,
err = rocker_world_port_obj_vlan_del(rocker_port,
SWITCHDEV_OBJ_PORT_VLAN(obj));
break;
case SWITCHDEV_OBJ_ID_IPV4_FIB:
err = rocker_world_port_obj_fib4_del(rocker_port,
SWITCHDEV_OBJ_IPV4_FIB(obj));
break;
case SWITCHDEV_OBJ_ID_PORT_FDB:
err = rocker_world_port_obj_fdb_del(rocker_port,
SWITCHDEV_OBJ_PORT_FDB(obj));
Expand Down Expand Up @@ -2175,6 +2171,31 @@ static const struct switchdev_ops rocker_port_switchdev_ops = {
.switchdev_port_obj_dump = rocker_port_obj_dump,
};

static int rocker_router_fib_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct rocker *rocker = container_of(nb, struct rocker, fib_nb);
struct fib_entry_notifier_info *fen_info = ptr;
int err;

switch (event) {
case FIB_EVENT_ENTRY_ADD:
err = rocker_world_fib4_add(rocker, fen_info);
if (err)
rocker_world_fib4_abort(rocker);
else
break;
case FIB_EVENT_ENTRY_DEL:
rocker_world_fib4_del(rocker, fen_info);
break;
case FIB_EVENT_RULE_ADD: /* fall through */
case FIB_EVENT_RULE_DEL:
rocker_world_fib4_abort(rocker);
break;
}
return NOTIFY_DONE;
}

/********************
* ethtool interface
********************/
Expand Down Expand Up @@ -2740,6 +2761,9 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_probe_ports;
}

rocker->fib_nb.notifier_call = rocker_router_fib_event;
register_fib_notifier(&rocker->fib_nb);

dev_info(&pdev->dev, "Rocker switch with id %*phN\n",
(int)sizeof(rocker->hw.id), &rocker->hw.id);

Expand Down Expand Up @@ -2771,6 +2795,7 @@ static void rocker_remove(struct pci_dev *pdev)
{
struct rocker *rocker = pci_get_drvdata(pdev);

unregister_fib_notifier(&rocker->fib_nb);
rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
rocker_remove_ports(rocker);
free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
Expand Down Expand Up @@ -2799,6 +2824,37 @@ static bool rocker_port_dev_check(const struct net_device *dev)
return dev->netdev_ops == &rocker_port_netdev_ops;
}

static bool rocker_port_dev_check_under(const struct net_device *dev,
struct rocker *rocker)
{
struct rocker_port *rocker_port;

if (!rocker_port_dev_check(dev))
return false;

rocker_port = netdev_priv(dev);
if (rocker_port->rocker != rocker)
return false;

return true;
}

struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
struct rocker *rocker)
{
struct net_device *lower_dev;
struct list_head *iter;

if (rocker_port_dev_check_under(dev, rocker))
return netdev_priv(dev);

netdev_for_each_all_lower_dev(dev, lower_dev, iter) {
if (rocker_port_dev_check_under(lower_dev, rocker))
return netdev_priv(lower_dev);
}
return NULL;
}

static int rocker_netdevice_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
Expand Down
Loading

0 comments on commit 936bd48

Please sign in to comment.