1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00

modules/mqnic: Register ports with devlink

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich 2023-09-13 16:40:27 -07:00
parent a9800099e3
commit 54d0165f68
7 changed files with 82 additions and 69 deletions

View File

@ -20,6 +20,7 @@
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <net/devlink.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
@ -151,8 +152,7 @@ struct mqnic_dev {
struct mqnic_reg_block *clk_info_rb; struct mqnic_reg_block *clk_info_rb;
struct mqnic_reg_block *phc_rb; struct mqnic_reg_block *phc_rb;
int dev_port_max; int phys_port_max;
int dev_port_limit;
u32 fpga_id; u32 fpga_id;
u32 fw_id; u32 fw_id;
@ -349,8 +349,11 @@ struct mqnic_port {
struct mqnic_reg_block *port_ctrl_rb; struct mqnic_reg_block *port_ctrl_rb;
int index; int index;
int phys_index;
u32 port_features; u32 port_features;
struct devlink_port dl_port;
}; };
struct mqnic_sched_block { struct mqnic_sched_block {
@ -380,10 +383,6 @@ struct mqnic_if {
int index; int index;
int dev_port_base;
int dev_port_max;
int dev_port_limit;
u32 if_features; u32 if_features;
u32 max_tx_mtu; u32 max_tx_mtu;
@ -423,6 +422,7 @@ struct mqnic_if {
struct mqnic_priv { struct mqnic_priv {
struct device *dev; struct device *dev;
struct net_device *ndev; struct net_device *ndev;
struct devlink_port *dl_port;
struct mqnic_dev *mdev; struct mqnic_dev *mdev;
struct mqnic_if *interface; struct mqnic_if *interface;
@ -449,11 +449,8 @@ struct mqnic_priv {
struct rw_semaphore rxq_table_sem; struct rw_semaphore rxq_table_sem;
struct radix_tree_root rxq_table; struct radix_tree_root rxq_table;
u32 sched_block_count; struct mqnic_sched_block *sched_block;
struct mqnic_sched_block *sched_block[MQNIC_MAX_PORTS]; struct mqnic_port *port;
u32 port_count;
struct mqnic_port *port[MQNIC_MAX_PORTS];
u32 max_desc_block_size; u32 max_desc_block_size;
@ -508,7 +505,7 @@ void mqnic_interface_set_rx_queue_map_indir_table(struct mqnic_if *interface, in
// mqnic_port.c // mqnic_port.c
struct mqnic_port *mqnic_create_port(struct mqnic_if *interface, int index, struct mqnic_port *mqnic_create_port(struct mqnic_if *interface, int index,
struct mqnic_reg_block *port_rb); int phys_index, struct mqnic_reg_block *port_rb);
void mqnic_destroy_port(struct mqnic_port *port); void mqnic_destroy_port(struct mqnic_port *port);
u32 mqnic_port_get_tx_ctrl(struct mqnic_port *port); u32 mqnic_port_get_tx_ctrl(struct mqnic_port *port);
void mqnic_port_set_tx_ctrl(struct mqnic_port *port, u32 val); void mqnic_port_set_tx_ctrl(struct mqnic_port *port, u32 val);
@ -526,7 +523,8 @@ int mqnic_start_port(struct net_device *ndev);
void mqnic_stop_port(struct net_device *ndev); void mqnic_stop_port(struct net_device *ndev);
int mqnic_update_indir_table(struct net_device *ndev); int mqnic_update_indir_table(struct net_device *ndev);
void mqnic_update_stats(struct net_device *ndev); void mqnic_update_stats(struct net_device *ndev);
struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index, int dev_port); struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index,
struct mqnic_port *port, struct mqnic_sched_block *sched_block);
void mqnic_destroy_netdev(struct net_device *ndev); void mqnic_destroy_netdev(struct net_device *ndev);
// mqnic_sched_block.c // mqnic_sched_block.c

View File

@ -6,7 +6,6 @@
#include "mqnic.h" #include "mqnic.h"
#include <linux/version.h> #include <linux/version.h>
#include <net/devlink.h>
static int mqnic_devlink_info_get(struct devlink *devlink, static int mqnic_devlink_info_get(struct devlink *devlink,
struct devlink_info_req *req, struct netlink_ext_ack *extack) struct devlink_info_req *req, struct netlink_ext_ack *extack)

View File

@ -143,7 +143,7 @@ static void mqnic_get_pauseparam(struct net_device *ndev,
if (!(priv->if_features & MQNIC_IF_FEATURE_LFC)) if (!(priv->if_features & MQNIC_IF_FEATURE_LFC))
return; return;
val = mqnic_port_get_lfc_ctrl(priv->port[0]); val = mqnic_port_get_lfc_ctrl(priv->port);
param->rx_pause = !!(val & MQNIC_PORT_LFC_CTRL_RX_LFC_EN); param->rx_pause = !!(val & MQNIC_PORT_LFC_CTRL_RX_LFC_EN);
param->tx_pause = !!(val & MQNIC_PORT_LFC_CTRL_TX_LFC_EN); param->tx_pause = !!(val & MQNIC_PORT_LFC_CTRL_TX_LFC_EN);
@ -161,7 +161,7 @@ static int mqnic_set_pauseparam(struct net_device *ndev,
if (param->autoneg) if (param->autoneg)
return -EINVAL; return -EINVAL;
val = mqnic_port_get_lfc_ctrl(priv->port[0]); val = mqnic_port_get_lfc_ctrl(priv->port);
if (param->rx_pause) if (param->rx_pause)
val |= MQNIC_PORT_LFC_CTRL_RX_LFC_EN; val |= MQNIC_PORT_LFC_CTRL_RX_LFC_EN;
@ -173,7 +173,7 @@ static int mqnic_set_pauseparam(struct net_device *ndev,
else else
val &= ~MQNIC_PORT_LFC_CTRL_TX_LFC_EN; val &= ~MQNIC_PORT_LFC_CTRL_TX_LFC_EN;
mqnic_port_set_lfc_ctrl(priv->port[0], val); mqnic_port_set_lfc_ctrl(priv->port, val);
return 0; return 0;
} }

View File

@ -221,7 +221,7 @@ struct mqnic_if *mqnic_create_interface(struct mqnic_dev *mdev, int index, u8 __
goto fail; goto fail;
} }
port = mqnic_create_port(interface, k, port_rb); port = mqnic_create_port(interface, k, mdev->phys_port_max++, port_rb);
if (IS_ERR_OR_NULL(port)) { if (IS_ERR_OR_NULL(port)) {
ret = PTR_ERR(port); ret = PTR_ERR(port);
goto fail; goto fail;
@ -267,12 +267,10 @@ struct mqnic_if *mqnic_create_interface(struct mqnic_dev *mdev, int index, u8 __
} }
// create net_devices // create net_devices
interface->dev_port_base = mdev->dev_port_max;
interface->dev_port_max = mdev->dev_port_max;
interface->ndev_count = 1; interface->ndev_count = 1;
for (k = 0; k < interface->ndev_count; k++) { for (k = 0; k < interface->ndev_count; k++) {
struct net_device *ndev = mqnic_create_netdev(interface, k, interface->dev_port_max++); struct net_device *ndev = mqnic_create_netdev(interface, k,
interface->port[k], interface->sched_block[k]);
if (IS_ERR_OR_NULL(ndev)) { if (IS_ERR_OR_NULL(ndev)) {
ret = PTR_ERR(ndev); ret = PTR_ERR(ndev);
goto fail; goto fail;

View File

@ -9,7 +9,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <net/devlink.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
@ -364,8 +363,7 @@ static int mqnic_common_probe(struct mqnic_dev *mqnic)
mutex_init(&mqnic->state_lock); mutex_init(&mqnic->state_lock);
// Set up interfaces // Set up interfaces
mqnic->dev_port_max = 0; mqnic->phys_port_max = 0;
mqnic->dev_port_limit = MQNIC_MAX_IF;
mqnic->if_count = min_t(u32, mqnic->if_count, MQNIC_MAX_IF); mqnic->if_count = min_t(u32, mqnic->if_count, MQNIC_MAX_IF);
@ -378,7 +376,6 @@ static int mqnic_common_probe(struct mqnic_dev *mqnic)
goto fail_create_if; goto fail_create_if;
} }
mqnic->interface[k] = interface; mqnic->interface[k] = interface;
mqnic->dev_port_max = mqnic->interface[k]->dev_port_max;
} }
// pass module I2C clients to interface instances // pass module I2C clients to interface instances

View File

@ -159,11 +159,10 @@ int mqnic_start_port(struct net_device *ndev)
} }
up_read(&priv->rxq_table_sem); up_read(&priv->rxq_table_sem);
// enable first scheduler mqnic_port_set_tx_ctrl(priv->port, MQNIC_PORT_TX_CTRL_EN);
mqnic_activate_sched_block(priv->sched_block[0]);
// enable first port // enable scheduler
mqnic_port_set_tx_ctrl(priv->port[0], MQNIC_PORT_TX_CTRL_EN); mqnic_activate_sched_block(priv->sched_block);
netif_tx_start_all_queues(ndev); netif_tx_start_all_queues(ndev);
netif_device_attach(ndev); netif_device_attach(ndev);
@ -176,7 +175,7 @@ int mqnic_start_port(struct net_device *ndev)
netif_carrier_on(ndev); netif_carrier_on(ndev);
} }
mqnic_port_set_rx_ctrl(priv->port[0], MQNIC_PORT_RX_CTRL_EN); mqnic_port_set_rx_ctrl(priv->port, MQNIC_PORT_RX_CTRL_EN);
return 0; return 0;
@ -191,7 +190,6 @@ void mqnic_stop_port(struct net_device *ndev)
struct mqnic_cq *cq; struct mqnic_cq *cq;
struct radix_tree_iter iter; struct radix_tree_iter iter;
void **slot; void **slot;
int k;
netdev_info(ndev, "%s on interface %d netdev %d", __func__, netdev_info(ndev, "%s on interface %d netdev %d", __func__,
priv->interface->index, priv->index); priv->interface->index, priv->index);
@ -199,7 +197,7 @@ void mqnic_stop_port(struct net_device *ndev)
if (mqnic_link_status_poll) if (mqnic_link_status_poll)
del_timer_sync(&priv->link_status_timer); del_timer_sync(&priv->link_status_timer);
mqnic_port_set_rx_ctrl(priv->port[0], 0); mqnic_port_set_rx_ctrl(priv->port, 0);
netif_tx_lock_bh(ndev); netif_tx_lock_bh(ndev);
// if (detach) // if (detach)
@ -214,9 +212,8 @@ void mqnic_stop_port(struct net_device *ndev)
mqnic_update_stats(ndev); mqnic_update_stats(ndev);
spin_unlock_bh(&priv->stats_lock); spin_unlock_bh(&priv->stats_lock);
// disable schedulers // disable scheduler
for (k = 0; k < priv->sched_block_count; k++) mqnic_deactivate_sched_block(priv->sched_block);
mqnic_deactivate_sched_block(priv->sched_block[k]);
// disable TX and RX queues // disable TX and RX queues
down_read(&priv->txq_table_sem); down_read(&priv->txq_table_sem);
@ -237,7 +234,7 @@ void mqnic_stop_port(struct net_device *ndev)
msleep(20); msleep(20);
mqnic_port_set_tx_ctrl(priv->port[0], 0); mqnic_port_set_tx_ctrl(priv->port, 0);
priv->port_up = false; priv->port_up = false;
@ -481,6 +478,14 @@ static int mqnic_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
} }
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
static struct devlink_port *mqnic_get_devlink_port(struct net_device *ndev)
{
struct mqnic_priv *priv = netdev_priv(ndev);
return priv->dl_port;
}
#endif
static const struct net_device_ops mqnic_netdev_ops = { static const struct net_device_ops mqnic_netdev_ops = {
.ndo_open = mqnic_open, .ndo_open = mqnic_open,
.ndo_stop = mqnic_close, .ndo_stop = mqnic_close,
@ -493,34 +498,29 @@ static const struct net_device_ops mqnic_netdev_ops = {
#else #else
.ndo_do_ioctl = mqnic_ioctl, .ndo_do_ioctl = mqnic_ioctl,
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
.ndo_get_devlink_port = mqnic_get_devlink_port,
#endif
}; };
static void mqnic_link_status_timeout(struct timer_list *timer) static void mqnic_link_status_timeout(struct timer_list *timer)
{ {
struct mqnic_priv *priv = from_timer(priv, timer, link_status_timer); struct mqnic_priv *priv = from_timer(priv, timer, link_status_timer);
int k; unsigned int up = 1;
unsigned int up;
// "combine" all TX/RX status signals of all ports of this netdev if (!(mqnic_port_get_tx_ctrl(priv->port) & MQNIC_PORT_TX_CTRL_STATUS))
for (k = 0, up = 0; k < priv->port_count; k++) { up = 0;
if (!(mqnic_port_get_tx_ctrl(priv->port[k]) & MQNIC_PORT_TX_CTRL_STATUS)) if (!(mqnic_port_get_rx_ctrl(priv->port) & MQNIC_PORT_RX_CTRL_STATUS))
continue; up = 0;
if (!(mqnic_port_get_rx_ctrl(priv->port[k]) & MQNIC_PORT_RX_CTRL_STATUS))
continue;
up++; if (up) {
} if (!priv->link_status) {
netif_carrier_on(priv->ndev);
if (up < priv->port_count) {
// report carrier off, as soon as a one port's TX/RX status is deasserted
if (priv->link_status) {
netif_carrier_off(priv->ndev);
priv->link_status = !priv->link_status; priv->link_status = !priv->link_status;
} }
} else { } else {
// report carrier on, as soon as all ports' TX/RX status is asserted if (priv->link_status) {
if (!priv->link_status) { netif_carrier_off(priv->ndev);
netif_carrier_on(priv->ndev);
priv->link_status = !priv->link_status; priv->link_status = !priv->link_status;
} }
} }
@ -528,7 +528,8 @@ static void mqnic_link_status_timeout(struct timer_list *timer)
mod_timer(&priv->link_status_timer, jiffies + msecs_to_jiffies(mqnic_link_status_poll)); mod_timer(&priv->link_status_timer, jiffies + msecs_to_jiffies(mqnic_link_status_poll));
} }
struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index, int dev_port) struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index,
struct mqnic_port *port, struct mqnic_sched_block *sched_block)
{ {
struct mqnic_dev *mdev = interface->mdev; struct mqnic_dev *mdev = interface->mdev;
struct device *dev = interface->dev; struct device *dev = interface->dev;
@ -546,7 +547,10 @@ struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index, in
} }
SET_NETDEV_DEV(ndev, dev); SET_NETDEV_DEV(ndev, dev);
ndev->dev_port = dev_port; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0)
SET_NETDEV_DEVLINK_PORT(ndev, &port->dl_port);
#endif
ndev->dev_port = port->phys_index;
// init private data // init private data
priv = netdev_priv(ndev); priv = netdev_priv(ndev);
@ -556,10 +560,13 @@ struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index, in
priv->ndev = ndev; priv->ndev = ndev;
priv->mdev = interface->mdev; priv->mdev = interface->mdev;
priv->dl_port = &port->dl_port;
priv->interface = interface; priv->interface = interface;
priv->dev = dev; priv->dev = dev;
priv->index = index; priv->index = index;
priv->port = port;
priv->port_up = false; priv->port_up = false;
priv->sched_block = sched_block;
// associate interface resources // associate interface resources
priv->if_features = interface->if_features; priv->if_features = interface->if_features;
@ -578,28 +585,20 @@ struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index, in
init_rwsem(&priv->rxq_table_sem); init_rwsem(&priv->rxq_table_sem);
INIT_RADIX_TREE(&priv->rxq_table, GFP_KERNEL); INIT_RADIX_TREE(&priv->rxq_table, GFP_KERNEL);
priv->sched_block_count = interface->sched_block_count;
for (k = 0; k < interface->sched_block_count; k++)
priv->sched_block[k] = interface->sched_block[k];
priv->port_count = interface->port_count;
for (k = 0; k < interface->port_count; k++)
priv->port[k] = interface->port[k];
netif_set_real_num_tx_queues(ndev, priv->txq_count); netif_set_real_num_tx_queues(ndev, priv->txq_count);
netif_set_real_num_rx_queues(ndev, priv->rxq_count); netif_set_real_num_rx_queues(ndev, priv->rxq_count);
// set MAC // set MAC
ndev->addr_len = ETH_ALEN; ndev->addr_len = ETH_ALEN;
if (dev_port >= mdev->mac_count) { if (ndev->dev_port >= mdev->mac_count) {
dev_warn(dev, "Exhausted permanent MAC addresses; using random MAC"); dev_warn(dev, "Exhausted permanent MAC addresses; using random MAC");
eth_hw_addr_random(ndev); eth_hw_addr_random(ndev);
} else { } else {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
eth_hw_addr_set(ndev, mdev->mac_list[dev_port]); eth_hw_addr_set(ndev, mdev->mac_list[ndev->dev_port]);
#else #else
memcpy(ndev->dev_addr, mdev->mac_list[dev_port], ETH_ALEN); memcpy(ndev->dev_addr, mdev->mac_list[ndev->dev_port], ETH_ALEN);
#endif #endif
if (!is_valid_ether_addr(ndev->dev_addr)) { if (!is_valid_ether_addr(ndev->dev_addr)) {
@ -657,6 +656,10 @@ struct net_device *mqnic_create_netdev(struct mqnic_if *interface, int index, in
goto fail; goto fail;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
devlink_port_type_eth_set(&port->dl_port, ndev);
#endif
priv->registered = 1; priv->registered = 1;
return ndev; return ndev;
@ -675,5 +678,9 @@ void mqnic_destroy_netdev(struct net_device *ndev)
kfree(priv->rx_queue_map_indir_table); kfree(priv->rx_queue_map_indir_table);
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
devlink_port_type_clear(priv->dl_port);
#endif
free_netdev(ndev); free_netdev(ndev);
} }

View File

@ -6,9 +6,11 @@
#include "mqnic.h" #include "mqnic.h"
struct mqnic_port *mqnic_create_port(struct mqnic_if *interface, int index, struct mqnic_port *mqnic_create_port(struct mqnic_if *interface, int index,
struct mqnic_reg_block *port_rb) int phys_index, struct mqnic_reg_block *port_rb)
{ {
struct device *dev = interface->dev; struct device *dev = interface->dev;
struct devlink *devlink = priv_to_devlink(interface->mdev);
struct devlink_port_attrs attrs = {};
struct mqnic_port *port; struct mqnic_port *port;
struct mqnic_reg_block *rb; struct mqnic_reg_block *rb;
u32 offset; u32 offset;
@ -19,6 +21,16 @@ struct mqnic_port *mqnic_create_port(struct mqnic_if *interface, int index,
if (!port) if (!port)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
attrs.phys.port_number = phys_index;
devlink_port_attrs_set(&port->dl_port, &attrs);
ret = devlink_port_register(devlink, &port->dl_port, phys_index);
if (ret) {
kfree(port);
return ERR_PTR(ret);
}
port->dev = dev; port->dev = dev;
port->interface = interface; port->interface = interface;
@ -75,6 +87,8 @@ void mqnic_destroy_port(struct mqnic_port *port)
if (port->rb_list) if (port->rb_list)
mqnic_free_reg_block_list(port->rb_list); mqnic_free_reg_block_list(port->rb_list);
devlink_port_unregister(&port->dl_port);
kfree(port); kfree(port);
} }