Add support for port start/stop and handle basic features
including mtu and link up/down.

Signed-off-by: Alfredo Cardigliano <cardigli...@ntop.org>
Reviewed-by: Shannon Nelson <snel...@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    4 
 drivers/net/ionic/ionic.h          |    1 
 drivers/net/ionic/ionic_dev.h      |    3 
 drivers/net/ionic/ionic_ethdev.c   |  315 ++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.c      |  268 +++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h      |    9 +
 drivers/net/ionic/ionic_osdep.h    |    2 
 7 files changed, 602 insertions(+)

diff --git a/doc/guides/nics/features/ionic.ini 
b/doc/guides/nics/features/ionic.ini
index 6915d9c42..c69e5cbed 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -4,6 +4,10 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Speed capabilities   = Y
+Link status          = Y
+Link status event    = Y
+MTU update           = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index 53836be64..05f1df061 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -54,6 +54,7 @@ struct ionic_adapter {
        uint32_t nlifs;
        uint32_t max_ntxqs_per_lif;
        uint32_t max_nrxqs_per_lif;
+       uint32_t max_mac_addrs;
        uint32_t link_speed;
        uint32_t nintrs;
        bool intrs[IONIC_INTR_CTRL_REGS_MAX];
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index ada07edff..02fcfdee8 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -20,6 +20,9 @@
  */
 #define IONIC_API_VERSION              "3"
 
+#define IONIC_MIN_MTU                  RTE_ETHER_MIN_MTU
+#define IONIC_MAX_MTU                  9194
+
 #define IONIC_MAX_RING_DESC            32768
 #define IONIC_MIN_RING_DESC            16
 
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 6e435fe89..fed332750 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -18,6 +18,17 @@
 
 static int  eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params);
 static int  eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev);
+static int  ionic_dev_info_get(struct rte_eth_dev *eth_dev,
+               struct rte_eth_dev_info *dev_info);
+static int  ionic_dev_configure(struct rte_eth_dev *dev);
+static int  ionic_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
+static int  ionic_dev_start(struct rte_eth_dev *dev);
+static void ionic_dev_stop(struct rte_eth_dev *dev);
+static void ionic_dev_close(struct rte_eth_dev *dev);
+static int  ionic_dev_set_link_up(struct rte_eth_dev *dev);
+static int  ionic_dev_set_link_down(struct rte_eth_dev *dev);
+static int  ionic_dev_link_update(struct rte_eth_dev *eth_dev,
+               int wait_to_complete);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -30,6 +41,15 @@ static const struct rte_pci_id pci_id_ionic_map[] = {
 };
 
 static const struct eth_dev_ops ionic_eth_dev_ops = {
+       .dev_infos_get          = ionic_dev_info_get,
+       .dev_configure          = ionic_dev_configure,
+       .mtu_set                = ionic_dev_mtu_set,
+       .dev_start              = ionic_dev_start,
+       .dev_stop               = ionic_dev_stop,
+       .dev_close              = ionic_dev_close,
+       .link_update            = ionic_dev_link_update,
+       .dev_set_link_up        = ionic_dev_set_link_up,
+       .dev_set_link_down      = ionic_dev_set_link_down,
 };
 
 /*
@@ -40,6 +60,104 @@ static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) 
ionic_pci_adapters =
                LIST_HEAD_INITIALIZER(ionic_pci_adapters);
 static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
 
+/*
+ * Set device link up, enable tx.
+ */
+static int
+ionic_dev_set_link_up(struct rte_eth_dev *eth_dev)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       struct ionic_adapter *adapter = lif->adapter;
+       struct ionic_dev *idev = &adapter->idev;
+       int err;
+
+       ionic_init_print_call();
+
+       ionic_dev_cmd_port_state(idev, IONIC_PORT_ADMIN_STATE_UP);
+
+       err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+       if (err) {
+               ionic_init_print(WARNING, "Failed to bring port UP\n");
+               return err;
+       }
+
+       return 0;
+}
+
+/*
+ * Set device link down, disable tx.
+ */
+static int
+ionic_dev_set_link_down(struct rte_eth_dev *eth_dev)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       struct ionic_adapter *adapter = lif->adapter;
+       struct ionic_dev *idev = &adapter->idev;
+       int err;
+
+       ionic_init_print_call();
+
+       ionic_dev_cmd_port_state(idev, IONIC_PORT_ADMIN_STATE_DOWN);
+
+       err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+       if (err) {
+               ionic_init_print(WARNING, "Failed to bring port DOWN\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int
+ionic_dev_link_update(struct rte_eth_dev *eth_dev,
+               int wait_to_complete __rte_unused)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       struct ionic_adapter *adapter = lif->adapter;
+       struct rte_eth_link link;
+
+       ionic_init_print_call();
+
+       /* Initialize */
+       memset(&link, 0, sizeof(link));
+       link.link_autoneg = ETH_LINK_AUTONEG;
+
+       if (!adapter->link_up) {
+               /* Interface is down */
+               link.link_status = ETH_LINK_DOWN;
+               link.link_duplex = ETH_LINK_HALF_DUPLEX;
+               link.link_speed = ETH_SPEED_NUM_NONE;
+       } else {
+               /* Interface is up */
+               link.link_status = ETH_LINK_UP;
+               link.link_duplex = ETH_LINK_FULL_DUPLEX;
+               switch (adapter->link_speed) {
+               case  10000:
+                       link.link_speed = ETH_SPEED_NUM_10G;
+                       break;
+               case  25000:
+                       link.link_speed = ETH_SPEED_NUM_25G;
+                       break;
+               case  40000:
+                       link.link_speed = ETH_SPEED_NUM_40G;
+                       break;
+               case  50000:
+                       link.link_speed = ETH_SPEED_NUM_50G;
+                       break;
+               case 100000:
+                       link.link_speed = ETH_SPEED_NUM_100G;
+                       break;
+               default:
+                       link.link_speed = ETH_SPEED_NUM_NONE;
+                       break;
+               }
+       }
+
+       return rte_eth_linkstatus_set(eth_dev, &link);
+}
+
 /**
  * Interrupt handler triggered by NIC for handling
  * specific interrupt.
@@ -64,6 +182,183 @@ ionic_dev_interrupt_handler(void *param)
        }
 }
 
+static int
+ionic_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       /*
+        * Size = MTU + Ethernet header + VLAN + QinQ
+        * Also add ETHER_CRC_LEN if the adapter is able to keep CRC
+        */
+       uint32_t frame_size = mtu + RTE_ETHER_HDR_LEN + 4 + 4;
+       int err;
+
+       ionic_init_print_call();
+
+       /* Check that mtu is within the allowed range */
+       if (mtu < IONIC_MIN_MTU || mtu > IONIC_MAX_MTU)
+               return -EINVAL;
+
+       err = ionic_lif_change_mtu(lif, mtu);
+
+       if (err)
+               return err;
+
+       /* Update max frame size */
+       eth_dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+
+       return 0;
+}
+
+static int
+ionic_dev_info_get(struct rte_eth_dev *eth_dev,
+               struct rte_eth_dev_info *dev_info)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       struct ionic_adapter *adapter = lif->adapter;
+       struct ionic_identity *ident = &adapter->ident;
+
+       ionic_init_print_call();
+
+       dev_info->max_rx_queues = (uint16_t)
+               ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ];
+       dev_info->max_tx_queues = (uint16_t)
+               ident->lif.eth.config.queue_count[IONIC_QTYPE_TXQ];
+       /* Also add ETHER_CRC_LEN if the adapter is able to keep CRC */
+       dev_info->min_rx_bufsize = IONIC_MIN_MTU + RTE_ETHER_HDR_LEN;
+       dev_info->max_rx_pktlen = IONIC_MAX_MTU + RTE_ETHER_HDR_LEN;
+       dev_info->max_mac_addrs = adapter->max_mac_addrs;
+
+       dev_info->speed_capa =
+               ETH_LINK_SPEED_10G |
+               ETH_LINK_SPEED_25G |
+               ETH_LINK_SPEED_40G |
+               ETH_LINK_SPEED_50G |
+               ETH_LINK_SPEED_100G;
+
+       return 0;
+}
+
+static int
+ionic_dev_configure(struct rte_eth_dev *eth_dev)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       int err;
+
+       ionic_init_print_call();
+
+       err = ionic_lif_configure(lif);
+
+       if (err) {
+               ionic_drv_print(ERR, "Cannot configure LIF: %d", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static inline uint32_t
+ionic_parse_link_speeds(uint16_t link_speeds)
+{
+       if (link_speeds & ETH_LINK_SPEED_100G)
+               return 100000;
+       else if (link_speeds & ETH_LINK_SPEED_50G)
+               return 50000;
+       else if (link_speeds & ETH_LINK_SPEED_40G)
+               return 40000;
+       else if (link_speeds & ETH_LINK_SPEED_25G)
+               return 25000;
+       else if (link_speeds & ETH_LINK_SPEED_10G)
+               return 10000;
+       else
+               return 0;
+}
+
+/*
+ * Configure device link speed and setup link.
+ * It returns 0 on success.
+ */
+static int
+ionic_dev_start(struct rte_eth_dev *eth_dev)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       struct ionic_adapter *adapter = lif->adapter;
+       struct ionic_dev *idev = &adapter->idev;
+       uint32_t allowed_speeds;
+       int err;
+
+       ionic_init_print_call();
+
+       err = ionic_lif_start(lif);
+
+       if (err) {
+               ionic_drv_print(ERR, "Cannot start LIF: %d", err);
+               return err;
+       }
+
+       if (eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
+               uint32_t speed = 
ionic_parse_link_speeds(eth_dev->data->dev_conf.link_speeds);
+
+               if (speed)
+                       ionic_dev_cmd_port_speed(idev, speed);
+       }
+
+       allowed_speeds =
+               ETH_LINK_SPEED_FIXED |
+               ETH_LINK_SPEED_10G |
+               ETH_LINK_SPEED_25G |
+               ETH_LINK_SPEED_40G |
+               ETH_LINK_SPEED_50G |
+               ETH_LINK_SPEED_100G;
+
+       if (eth_dev->data->dev_conf.link_speeds & ~allowed_speeds) {
+               ionic_init_print(ERR, "Invalid link setting");
+               return -EINVAL;
+       }
+
+       ionic_dev_link_update(eth_dev, 0);
+
+       return 0;
+}
+
+/*
+ * Stop device: disable rx and tx functions to allow for reconfiguring.
+ */
+static void
+ionic_dev_stop(struct rte_eth_dev *eth_dev)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       int err;
+
+       ionic_init_print_call();
+
+       err = ionic_lif_stop(lif);
+
+       if (err) {
+               ionic_drv_print(ERR, "Cannot stop LIF: %d", err);
+               return;
+       }
+}
+
+/*
+ * Reset and stop device.
+ */
+static void
+ionic_dev_close(struct rte_eth_dev *eth_dev)
+{
+       struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+       int err;
+
+       ionic_init_print_call();
+
+       err = ionic_lif_stop(lif);
+
+       if (err) {
+               ionic_drv_print(ERR, "Cannot stop LIF: %d", err);
+               return;
+       }
+}
+
 static int
 eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
 {
@@ -87,6 +382,20 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void 
*init_params)
        lif->adapter = adapter;
        adapter->lifs[adapter->nlifs] = lif;
 
+       ionic_init_print(DEBUG, "Up to %u MAC addresses supported",
+                       adapter->max_mac_addrs);
+
+       /* Allocate memory for storing MAC addresses */
+       eth_dev->data->mac_addrs = rte_zmalloc("ionic",
+                       RTE_ETHER_ADDR_LEN * adapter->max_mac_addrs, 0);
+
+       if (eth_dev->data->mac_addrs == NULL) {
+               ionic_init_print(ERR, "Failed to allocate %u bytes needed to "
+                               "store MAC addresses",
+                               RTE_ETHER_ADDR_LEN * adapter->max_mac_addrs);
+               return -ENOMEM;
+       }
+
        err = ionic_lif_alloc(lif);
 
        if (err) {
@@ -102,6 +411,10 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void 
*init_params)
                return err;
        }
 
+       /* Copy the MAC address */
+       rte_ether_addr_copy((struct rte_ether_addr *)lif->mac_addr,
+                       &eth_dev->data->mac_addrs[0]);
+
        ionic_init_print(DEBUG, "Port %u initialized", eth_dev->data->port_id);
 
        return 0;
@@ -297,6 +610,8 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv 
__rte_unused,
                return err;
        }
 
+       adapter->max_mac_addrs = adapter->ident.lif.eth.max_ucast_filters;
+
        adapter->nlifs = 0;
        for (i = 0; i < adapter->ident.dev.nlifs; i++) {
                snprintf(name, sizeof(name), "net_%s_lif_%lu",
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index 491db56d4..b6b730cef 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -10,6 +10,9 @@
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
 
+static int ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr);
+static int ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr);
+
 int
 ionic_qcq_enable(struct ionic_qcq *qcq)
 {
@@ -60,6 +63,105 @@ ionic_qcq_disable(struct ionic_qcq *qcq)
        return ionic_adminq_post_wait(lif, &ctx);
 }
 
+int
+ionic_lif_stop(struct ionic_lif *lif)
+{
+       /* Carrier OFF here */
+
+       return 0;
+}
+
+void
+ionic_lif_reset(struct ionic_lif *lif)
+{
+       struct ionic_dev *idev = &lif->adapter->idev;
+
+       ionic_drv_print_call();
+
+       ionic_dev_cmd_lif_reset(idev, lif->index);
+       ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+}
+
+static int
+ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr)
+{
+       ionic_init_print(INFO, "%s: stubbed\n", __func__);
+
+       return 0;
+}
+
+static int
+ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr)
+{
+       ionic_init_print(INFO, "%s: stubbed\n", __func__);
+
+       return 0;
+}
+
+static void
+ionic_lif_rx_mode(struct ionic_lif *lif, uint32_t rx_mode)
+{
+       struct ionic_admin_ctx ctx = {
+               .pending_work = true,
+               .cmd.rx_mode_set = {
+                       .opcode = IONIC_CMD_RX_MODE_SET,
+                       .lif_index = lif->index,
+                       .rx_mode = rx_mode,
+               },
+       };
+       int err;
+
+       if (rx_mode & IONIC_RX_MODE_F_UNICAST)
+               ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_UNICAST");
+       if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
+               ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_MULTICAST");
+       if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
+               ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_BROADCAST");
+       if (rx_mode & IONIC_RX_MODE_F_PROMISC)
+               ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_PROMISC");
+       if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
+               ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_ALLMULTI");
+
+       err = ionic_adminq_post_wait(lif, &ctx);
+
+       if (err)
+               ionic_init_print(ERR, "Failure setting RX mode");
+}
+
+static void
+ionic_set_rx_mode(struct ionic_lif *lif, uint32_t rx_mode)
+{
+       if (lif->rx_mode != rx_mode) {
+               lif->rx_mode = rx_mode;
+               ionic_lif_rx_mode(lif, rx_mode);
+       }
+}
+
+
+int
+ionic_lif_change_mtu(struct ionic_lif *lif, int new_mtu)
+{
+       struct ionic_admin_ctx ctx = {
+               .pending_work = true,
+               .cmd.lif_setattr = {
+                       .opcode = IONIC_CMD_LIF_SETATTR,
+                       .index = lif->index,
+                       .attr = IONIC_LIF_ATTR_MTU,
+                       .mtu = new_mtu,
+               },
+       };
+       int err;
+
+       err = ionic_adminq_post_wait(lif, &ctx);
+
+       if (err)
+               return err;
+
+       lif->mtu = new_mtu;
+
+       return 0;
+}
+
 int
 ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
 {
@@ -595,6 +697,124 @@ ionic_lif_notifyq_init(struct ionic_lif *lif)
        return 0;
 }
 
+int
+ionic_lif_set_features(struct ionic_lif *lif)
+{
+       struct ionic_admin_ctx ctx = {
+               .pending_work = true,
+               .cmd.lif_setattr = {
+                       .opcode = IONIC_CMD_LIF_SETATTR,
+                       .index = lif->index,
+                       .attr = IONIC_LIF_ATTR_FEATURES,
+                       .features = lif->features,
+               },
+       };
+       int err;
+
+       err = ionic_adminq_post_wait(lif, &ctx);
+       if (err)
+               return err;
+
+       lif->hw_features = (ctx.cmd.lif_setattr.features &
+                       ctx.comp.lif_setattr.features);
+
+       if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_VLAN_TX_TAG");
+       if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_VLAN_RX_STRIP");
+       if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_VLAN_RX_FILTER");
+       if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_RX_HASH");
+       if (lif->hw_features & IONIC_ETH_HW_TX_SG)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TX_SG");
+       if (lif->hw_features & IONIC_ETH_HW_RX_SG)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_RX_SG");
+       if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TX_CSUM");
+       if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_RX_CSUM");
+       if (lif->hw_features & IONIC_ETH_HW_TSO)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_IPV6");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_ECN");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_GRE");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_GRE_CSUM");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_IPXIP4");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_IPXIP6");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_UDP");
+       if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
+               ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_UDP_CSUM");
+
+       return 0;
+}
+
+static int
+ionic_station_set(struct ionic_lif *lif)
+{
+       struct ionic_admin_ctx ctx = {
+               .pending_work = true,
+               .cmd.lif_getattr = {
+                       .opcode = IONIC_CMD_LIF_GETATTR,
+                       .index = lif->index,
+                       .attr = IONIC_LIF_ATTR_MAC,
+               },
+       };
+       int err;
+
+       ionic_init_print_call();
+
+       err = ionic_adminq_post_wait(lif, &ctx);
+
+       if (err)
+               return err;
+
+       if (!rte_is_zero_ether_addr((struct rte_ether_addr *)
+                       lif->mac_addr)) {
+               ionic_init_print(INFO, "deleting station MAC addr");
+
+               ionic_lif_addr_del(lif, lif->mac_addr);
+       }
+
+       memcpy(lif->mac_addr, ctx.comp.lif_getattr.mac, ETH_ALEN);
+
+       if (rte_is_zero_ether_addr((struct rte_ether_addr *)lif->mac_addr)) {
+               ionic_init_print(NOTICE, "empty MAC addr (VF?)");
+               return 0;
+       }
+
+       ionic_init_print(DEBUG, "adding station MAC addr");
+
+       ionic_lif_addr_add(lif, lif->mac_addr);
+
+       return 0;
+}
+
+static void
+ionic_lif_set_name(struct ionic_lif *lif)
+{
+       struct ionic_admin_ctx ctx = {
+               .pending_work = true,
+               .cmd.lif_setattr = {
+                       .opcode = IONIC_CMD_LIF_SETATTR,
+                       .index = lif->index,
+                       .attr = IONIC_LIF_ATTR_NAME,
+               },
+       };
+
+       snprintf(ctx.cmd.lif_setattr.name, sizeof(ctx.cmd.lif_setattr.name),
+               "%d", lif->port_id);
+
+       ionic_adminq_post_wait(lif, &ctx);
+}
+
 int
 ionic_lif_init(struct ionic_lif *lif)
 {
@@ -620,10 +840,27 @@ ionic_lif_init(struct ionic_lif *lif)
        if (err)
                goto err_out_adminq_deinit;
 
+       lif->features = 0;
+
+       err = ionic_lif_set_features(lif);
+
+       if (err)
+               goto err_out_notifyq_deinit;
+
+       err = ionic_station_set(lif);
+
+       if (err)
+               goto err_out_notifyq_deinit;
+
+       ionic_lif_set_name(lif);
+
        lif->state |= IONIC_LIF_F_INITED;
 
        return 0;
 
+err_out_notifyq_deinit:
+       ionic_lif_qcq_deinit(lif, lif->notifyqcq);
+
 err_out_adminq_deinit:
        ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
@@ -642,6 +879,37 @@ ionic_lif_deinit(struct ionic_lif *lif)
        lif->state &= ~IONIC_LIF_F_INITED;
 }
 
+int
+ionic_lif_configure(struct ionic_lif *lif)
+{
+       lif->port_id = lif->eth_dev->data->port_id;
+
+       return 0;
+}
+
+int
+ionic_lif_start(struct ionic_lif *lif)
+{
+       uint32_t rx_mode = 0;
+
+       ionic_init_print(DEBUG, "Setting RX mode on port %u",
+               lif->port_id);
+
+       rx_mode |= IONIC_RX_MODE_F_UNICAST;
+       rx_mode |= IONIC_RX_MODE_F_MULTICAST;
+       rx_mode |= IONIC_RX_MODE_F_BROADCAST;
+
+       lif->rx_mode = 0; /* set by ionic_set_rx_mode */
+
+       ionic_set_rx_mode(lif, rx_mode);
+
+       ionic_link_status_check(lif);
+
+       /* Carrier ON here */
+
+       return 0;
+}
+
 int
 ionic_lif_identify(struct ionic_adapter *adapter)
 {
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index 326cb17d5..f7c51c9ec 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -44,6 +44,7 @@ struct ionic_lif {
        struct ionic_adapter *adapter;
        struct rte_eth_dev *eth_dev;
        uint16_t port_id;  /**< Device port identifier */
+       uint16_t mtu;
        uint32_t index;
        uint32_t hw_index;
        uint32_t state;
@@ -54,7 +55,11 @@ struct ionic_lif {
        struct ionic_qcq *notifyqcq;
        struct ionic_doorbell __iomem *kern_dbpage;
        uint64_t last_eid;
+       uint64_t features;
+       uint32_t hw_features;
+       uint32_t rx_mode;
        char name[IONIC_LIF_NAME_MAX_SZ];
+       uint8_t mac_addr[ETH_ALEN];
        uint32_t info_sz;
        struct ionic_lif_info *info;
        rte_iova_t info_pa;
@@ -84,11 +89,15 @@ bool ionic_adminq_service(struct ionic_cq *cq, uint32_t 
cq_desc_index,
 int ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
                void *cb_arg);
 
+int ionic_lif_change_mtu(struct ionic_lif *lif, int new_mtu);
+
 void ionic_qcq_free(struct ionic_qcq *qcq);
 
 int ionic_qcq_enable(struct ionic_qcq *qcq);
 int ionic_qcq_disable(struct ionic_qcq *qcq);
 
+int ionic_lif_set_features(struct ionic_lif *lif);
+
 int ionic_notifyq_handler(struct ionic_lif *lif, int budget);
 
 #endif /* _IONIC_LIF_H_ */
diff --git a/drivers/net/ionic/ionic_osdep.h b/drivers/net/ionic/ionic_osdep.h
index 5b8baa67b..39a9cefa9 100644
--- a/drivers/net/ionic/ionic_osdep.h
+++ b/drivers/net/ionic/ionic_osdep.h
@@ -28,6 +28,8 @@
 #define BIT_ULL(nr)        (1ULL << (nr))
 #define BITS_TO_LONGS(nr)  div_round_up(nr, 8 * sizeof(long))
 
+#define ETH_ALEN        6
+
 #ifndef PAGE_SHIFT
 #define PAGE_SHIFT      12
 #define PAGE_SIZE       (1 << PAGE_SHIFT)

Reply via email to