ixgbe: fix vf irq storm when running on Xen Dom0.
[dpdk.git] / lib / librte_pmd_ixgbe / ixgbe_ethdev.c
index b826008..d413792 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  * 
- *   Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
  *   All rights reserved.
  * 
  *   Redistribution and use in source and binary forms, with or without
@@ -711,7 +711,8 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                        hw->mac.num_rar_entries, 0);
        if (eth_dev->data->mac_addrs == NULL) {
                PMD_INIT_LOG(ERR,
-                       "Failed to allocate %d bytes needed to store MAC addresses",
+                       "Failed to allocate %u bytes needed to store "
+                       "MAC addresses",
                        ETHER_ADDR_LEN * hw->mac.num_rar_entries);
                return -ENOMEM;
        }
@@ -771,6 +772,21 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        return 0;
 }
 
+static void ixgbevf_get_queue_num(struct ixgbe_hw *hw)
+{
+       /* Traffic classes are not supported by now */
+       unsigned int tcs, tc;
+
+       /*
+        * Must let PF know we are at mailbox API version 1.1.
+        * Otherwise PF won't answer properly.
+        * In case that PF fails to provide Rx/Tx queue number,
+        * max_tx_queues and max_rx_queues remain to be 1.
+        */
+       if (!ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_11))
+               ixgbevf_get_queues(hw, &tcs, &tc);
+}
+
 /*
  * Virtual Function device init
  */
@@ -839,12 +855,16 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                return (diag);
        }
 
+       /* Get Rx/Tx queue count via mailbox, which is ready after reset_hw */
+       ixgbevf_get_queue_num(hw);
+
        /* Allocate memory for storing MAC addresses */
        eth_dev->data->mac_addrs = rte_zmalloc("ixgbevf", ETHER_ADDR_LEN *
                        hw->mac.num_rar_entries, 0);
        if (eth_dev->data->mac_addrs == NULL) {
                PMD_INIT_LOG(ERR,
-                       "Failed to allocate %d bytes needed to store MAC addresses",
+                       "Failed to allocate %u bytes needed to store "
+                       "MAC addresses",
                        ETHER_ADDR_LEN * hw->mac.num_rar_entries);
                return -ENOMEM;
        }
@@ -1245,7 +1265,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        /* IXGBE devices don't support half duplex */
        if ((dev->data->dev_conf.link_duplex != ETH_LINK_AUTONEG_DUPLEX) &&
                        (dev->data->dev_conf.link_duplex != ETH_LINK_FULL_DUPLEX)) {
-               PMD_INIT_LOG(ERR, "Invalid link_duplex (%u) for port %u\n",
+               PMD_INIT_LOG(ERR, "Invalid link_duplex (%hu) for port %hhu\n",
                                dev->data->dev_conf.link_duplex,
                                dev->data->port_id);
                return -EINVAL;
@@ -1286,6 +1306,11 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        /* Turn on the laser */
        ixgbe_enable_tx_laser(hw);
 
+       /* Skip link setup if loopback mode is enabled for 82599. */
+       if (hw->mac.type == ixgbe_mac_82599EB &&
+                       dev->data->dev_conf.lpbk_mode == IXGBE_LPBK_82599_TX_RX)
+               goto skip_link_setup;
+
        err = ixgbe_check_link(hw, &speed, &link_up, 0);
        if (err)
                goto error;
@@ -1313,8 +1338,9 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
                speed = IXGBE_LINK_SPEED_10GB_FULL;
                break;
        default:
-               PMD_INIT_LOG(ERR, "Invalid link_speed (%u) for port %u\n",
-                               dev->data->dev_conf.link_speed, dev->data->port_id);
+               PMD_INIT_LOG(ERR, "Invalid link_speed (%hu) for port %hhu\n",
+                               dev->data->dev_conf.link_speed,
+                               dev->data->port_id);
                goto error;
        }
 
@@ -1322,6 +1348,8 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        if (err)
                goto error;
 
+skip_link_setup:
+
        /* check if lsc interrupt is enabled */
        if (dev->data->dev_conf.intr_conf.lsc != 0)
                ixgbe_dev_lsc_interrupt_setup(dev);
@@ -1366,6 +1394,9 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
        struct rte_eth_link link;
        struct ixgbe_hw *hw =
                IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_vf_info *vfinfo = 
+               *IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private);
+       int vf;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -1379,6 +1410,10 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
        /* stop adapter */
        ixgbe_stop_adapter(hw);
 
+       for (vf = 0; vfinfo != NULL && 
+                    vf < dev->pci_dev->max_vfs; vf++)
+               vfinfo[vf].clear_to_send = false;
+
        /* Turn off the laser */
        ixgbe_disable_tx_laser(hw);
 
@@ -2028,6 +2063,7 @@ ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
        int err;
        uint32_t rx_buf_size;
        uint32_t max_high_water;
+       uint32_t mflcn;
        enum ixgbe_fc_mode rte_fcmode_2_ixgbe_fcmode[] = {
                ixgbe_fc_none,
                ixgbe_fc_rx_pause,
@@ -2060,8 +2096,24 @@ ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
        hw->fc.send_xon       = fc_conf->send_xon;
 
        err = ixgbe_fc_enable(hw);
+
        /* Not negotiated is not an error case */
        if ((err == IXGBE_SUCCESS) || (err == IXGBE_ERR_FC_NOT_NEGOTIATED)) {
+
+               /* check if we want to forward MAC frames - driver doesn't have native
+                * capability to do that, so we'll write the registers ourselves */
+
+               mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+
+               /* set or clear MFLCN.PMCF bit depending on configuration */
+               if (fc_conf->mac_ctrl_frame_fwd != 0)
+                       mflcn |= IXGBE_MFLCN_PMCF;
+               else
+                       mflcn &= ~IXGBE_MFLCN_PMCF;
+
+               IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn);
+               IXGBE_WRITE_FLUSH(hw);
+
                return 0;
        }