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/ptp_clock_kernel.h>
#include <linux/timer.h>
#include <net/devlink.h>
#include <linux/i2c.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 *phc_rb;
int dev_port_max;
int dev_port_limit;
int phys_port_max;
u32 fpga_id;
u32 fw_id;
@ -349,8 +349,11 @@ struct mqnic_port {
struct mqnic_reg_block *port_ctrl_rb;
int index;
int phys_index;
u32 port_features;
struct devlink_port dl_port;
};
struct mqnic_sched_block {
@ -380,10 +383,6 @@ struct mqnic_if {
int index;
int dev_port_base;
int dev_port_max;
int dev_port_limit;
u32 if_features;
u32 max_tx_mtu;
@ -423,6 +422,7 @@ struct mqnic_if {
struct mqnic_priv {
struct device *dev;
struct net_device *ndev;
struct devlink_port *dl_port;
struct mqnic_dev *mdev;
struct mqnic_if *interface;
@ -449,11 +449,8 @@ struct mqnic_priv {
struct rw_semaphore rxq_table_sem;
struct radix_tree_root rxq_table;
u32 sched_block_count;
struct mqnic_sched_block *sched_block[MQNIC_MAX_PORTS];
u32 port_count;
struct mqnic_port *port[MQNIC_MAX_PORTS];
struct mqnic_sched_block *sched_block;
struct mqnic_port *port;
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
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);
u32 mqnic_port_get_tx_ctrl(struct mqnic_port *port);
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);
int mqnic_update_indir_table(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);
// mqnic_sched_block.c

View File

@ -6,7 +6,6 @@
#include "mqnic.h"
#include <linux/version.h>
#include <net/devlink.h>
static int mqnic_devlink_info_get(struct devlink *devlink,
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))
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->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)
return -EINVAL;
val = mqnic_port_get_lfc_ctrl(priv->port[0]);
val = mqnic_port_get_lfc_ctrl(priv->port);
if (param->rx_pause)
val |= MQNIC_PORT_LFC_CTRL_RX_LFC_EN;
@ -173,7 +173,7 @@ static int mqnic_set_pauseparam(struct net_device *ndev,
else
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;
}

View File

@ -221,7 +221,7 @@ struct mqnic_if *mqnic_create_interface(struct mqnic_dev *mdev, int index, u8 __
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)) {
ret = PTR_ERR(port);
goto fail;
@ -267,12 +267,10 @@ struct mqnic_if *mqnic_create_interface(struct mqnic_dev *mdev, int index, u8 __
}
// create net_devices
interface->dev_port_base = mdev->dev_port_max;
interface->dev_port_max = mdev->dev_port_max;
interface->ndev_count = 1;
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)) {
ret = PTR_ERR(ndev);
goto fail;

View File

@ -9,7 +9,6 @@
#include <linux/delay.h>
#include <linux/reset.h>
#include <linux/rtc.h>
#include <net/devlink.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
#include <linux/pci-aspm.h>
@ -364,8 +363,7 @@ static int mqnic_common_probe(struct mqnic_dev *mqnic)
mutex_init(&mqnic->state_lock);
// Set up interfaces
mqnic->dev_port_max = 0;
mqnic->dev_port_limit = MQNIC_MAX_IF;
mqnic->phys_port_max = 0;
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;
}
mqnic->interface[k] = interface;
mqnic->dev_port_max = mqnic->interface[k]->dev_port_max;
}
// 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);
// enable first scheduler
mqnic_activate_sched_block(priv->sched_block[0]);
mqnic_port_set_tx_ctrl(priv->port, MQNIC_PORT_TX_CTRL_EN);
// enable first port
mqnic_port_set_tx_ctrl(priv->port[0], MQNIC_PORT_TX_CTRL_EN);
// enable scheduler
mqnic_activate_sched_block(priv->sched_block);
netif_tx_start_all_queues(ndev);
netif_device_attach(ndev);
@ -176,7 +175,7 @@ int mqnic_start_port(struct net_device *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;
@ -191,7 +190,6 @@ void mqnic_stop_port(struct net_device *ndev)
struct mqnic_cq *cq;
struct radix_tree_iter iter;
void **slot;
int k;
netdev_info(ndev, "%s on interface %d netdev %d", __func__,
priv->interface->index, priv->index);
@ -199,7 +197,7 @@ void mqnic_stop_port(struct net_device *ndev)
if (mqnic_link_status_poll)
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);
// if (detach)
@ -214,9 +212,8 @@ void mqnic_stop_port(struct net_device *ndev)
mqnic_update_stats(ndev);
spin_unlock_bh(&priv->stats_lock);
// disable schedulers
for (k = 0; k < priv->sched_block_count; k++)
mqnic_deactivate_sched_block(priv->sched_block[k]);
// disable scheduler
mqnic_deactivate_sched_block(priv->sched_block);
// disable TX and RX queues
down_read(&priv->txq_table_sem);
@ -237,7 +234,7 @@ void mqnic_stop_port(struct net_device *ndev)
msleep(20);
mqnic_port_set_tx_ctrl(priv->port[0], 0);
mqnic_port_set_tx_ctrl(priv->port, 0);
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 = {
.ndo_open = mqnic_open,
.ndo_stop = mqnic_close,
@ -493,34 +498,29 @@ static const struct net_device_ops mqnic_netdev_ops = {
#else
.ndo_do_ioctl = mqnic_ioctl,
#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)
{
struct mqnic_priv *priv = from_timer(priv, timer, link_status_timer);
int k;
unsigned int up;
unsigned int up = 1;
// "combine" all TX/RX status signals of all ports of this netdev
for (k = 0, up = 0; k < priv->port_count; k++) {
if (!(mqnic_port_get_tx_ctrl(priv->port[k]) & MQNIC_PORT_TX_CTRL_STATUS))
continue;
if (!(mqnic_port_get_rx_ctrl(priv->port[k]) & MQNIC_PORT_RX_CTRL_STATUS))
continue;
if (!(mqnic_port_get_tx_ctrl(priv->port) & MQNIC_PORT_TX_CTRL_STATUS))
up = 0;
if (!(mqnic_port_get_rx_ctrl(priv->port) & MQNIC_PORT_RX_CTRL_STATUS))
up = 0;
up++;
}
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);
if (up) {
if (!priv->link_status) {
netif_carrier_on(priv->ndev);
priv->link_status = !priv->link_status;
}
} else {
// report carrier on, as soon as all ports' TX/RX status is asserted
if (!priv->link_status) {
netif_carrier_on(priv->ndev);
if (priv->link_status) {
netif_carrier_off(priv->ndev);
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));
}
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 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);
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
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->mdev = interface->mdev;
priv->dl_port = &port->dl_port;
priv->interface = interface;
priv->dev = dev;
priv->index = index;
priv->port = port;
priv->port_up = false;
priv->sched_block = sched_block;
// associate interface resources
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_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_rx_queues(ndev, priv->rxq_count);
// set MAC
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");
eth_hw_addr_random(ndev);
} else {
#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
memcpy(ndev->dev_addr, mdev->mac_list[dev_port], ETH_ALEN);
memcpy(ndev->dev_addr, mdev->mac_list[ndev->dev_port], ETH_ALEN);
#endif
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;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
devlink_port_type_eth_set(&port->dl_port, ndev);
#endif
priv->registered = 1;
return ndev;
@ -675,5 +678,9 @@ void mqnic_destroy_netdev(struct net_device *ndev)
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);
}

View File

@ -6,9 +6,11 @@
#include "mqnic.h"
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 devlink *devlink = priv_to_devlink(interface->mdev);
struct devlink_port_attrs attrs = {};
struct mqnic_port *port;
struct mqnic_reg_block *rb;
u32 offset;
@ -19,6 +21,16 @@ struct mqnic_port *mqnic_create_port(struct mqnic_if *interface, int index,
if (!port)
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->interface = interface;
@ -75,6 +87,8 @@ void mqnic_destroy_port(struct mqnic_port *port)
if (port->rb_list)
mqnic_free_reg_block_list(port->rb_list);
devlink_port_unregister(&port->dl_port);
kfree(port);
}