diff --git a/modules/mqnic/mqnic.h b/modules/mqnic/mqnic.h index 7039bdd86..d501c832e 100644 --- a/modules/mqnic/mqnic.h +++ b/modules/mqnic/mqnic.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -66,10 +67,15 @@ #define MQNIC_PROP_MODULE_EEPROM "module-eeproms" #endif +// default interval to poll port TX/RX status, in ms +#define MQNIC_LINK_STATUS_POLL_MS 1000 + extern unsigned int mqnic_num_ev_queue_entries; extern unsigned int mqnic_num_tx_queue_entries; extern unsigned int mqnic_num_rx_queue_entries; +extern unsigned int mqnic_link_status_poll; + struct mqnic_dev; struct mqnic_if; @@ -456,6 +462,9 @@ struct mqnic_priv { u32 if_features; + unsigned int link_status; + struct timer_list link_status_timer; + u32 event_queue_count; struct mqnic_eq_ring *event_ring[MQNIC_MAX_EVENT_RINGS]; diff --git a/modules/mqnic/mqnic_main.c b/modules/mqnic/mqnic_main.c index 289029d28..a696239d1 100644 --- a/modules/mqnic/mqnic_main.c +++ b/modules/mqnic/mqnic_main.c @@ -59,6 +59,13 @@ MODULE_PARM_DESC(num_tx_queue_entries, "number of entries to allocate per transm module_param_named(num_rx_queue_entries, mqnic_num_rx_queue_entries, uint, 0444); MODULE_PARM_DESC(num_rx_queue_entries, "number of entries to allocate per receive queue (default: 1024)"); +unsigned int mqnic_link_status_poll = MQNIC_LINK_STATUS_POLL_MS; + +module_param_named(link_status_poll, mqnic_link_status_poll, uint, 0444); +MODULE_PARM_DESC(link_status_poll, + "link status polling interval, in ms (default: 1000; 0 to turn off)"); + + #ifdef CONFIG_PCI static const struct pci_device_id mqnic_pci_id_table[] = { {PCI_DEVICE(0x1234, 0x1001)}, diff --git a/modules/mqnic/mqnic_netdev.c b/modules/mqnic/mqnic_netdev.c index f529b3078..06568af9d 100644 --- a/modules/mqnic/mqnic_netdev.c +++ b/modules/mqnic/mqnic_netdev.c @@ -99,8 +99,11 @@ static int mqnic_start_port(struct net_device *ndev) netif_tx_start_all_queues(ndev); netif_device_attach(ndev); - //netif_carrier_off(ndev); - netif_carrier_on(ndev); // TODO link status monitoring + if (mqnic_link_status_poll) + mod_timer(&priv->link_status_timer, + jiffies + msecs_to_jiffies(mqnic_link_status_poll)); + else + netif_carrier_on(ndev); return 0; } @@ -114,6 +117,9 @@ static int mqnic_stop_port(struct net_device *ndev) dev_info(mdev->dev, "%s on interface %d netdev %d", __func__, priv->interface->index, priv->index); + if (mqnic_link_status_poll) + del_timer_sync(&priv->link_status_timer); + netif_tx_lock_bh(ndev); // if (detach) // netif_device_detach(ndev); @@ -359,6 +365,40 @@ static const struct net_device_ops mqnic_netdev_ops = { #endif }; +static void mqnic_link_status_timeout(struct timer_list *timer) +{ + struct mqnic_priv *priv = from_timer(priv, timer, link_status_timer); + struct mqnic_if *interface = priv->interface; + int k; + unsigned int up; + + // "combine" all TX/RX status signals of all ports of this interface + for (k = 0, up = 0; k < interface->port_count; k++) { + if (!(mqnic_port_get_tx_status(interface->port[k]) & 0x1)) + continue; + if (!(mqnic_port_get_rx_status(interface->port[k]) & 0x1)) + continue; + + up++; + } + + if (up < interface->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; + } + } else { + // report carrier on, as soon as all ports' TX/RX status is asserted + if (!priv->link_status) { + netif_carrier_on(priv->ndev); + priv->link_status = !priv->link_status; + } + } + + mod_timer(&priv->link_status_timer, jiffies + msecs_to_jiffies(mqnic_link_status_poll)); +} + int mqnic_create_netdev(struct mqnic_if *interface, struct net_device **ndev_ptr, int index, int dev_port) { @@ -502,6 +542,10 @@ int mqnic_create_netdev(struct mqnic_if *interface, struct net_device **ndev_ptr ndev->max_mtu = min(interface->max_tx_mtu, interface->max_rx_mtu) - ETH_HLEN; netif_carrier_off(ndev); + if (mqnic_link_status_poll) { + priv->link_status = false; + timer_setup(&priv->link_status_timer, mqnic_link_status_timeout, 0); + } ret = register_netdev(ndev); if (ret) {