igb: avoid enabling interrupt with zero vector
[dpdk.git] / drivers / net / e1000 / igb_ethdev.c
index 7ed7fb3..76d2acc 100644 (file)
@@ -152,7 +152,10 @@ static int igbvf_dev_start(struct rte_eth_dev *dev);
 static void igbvf_dev_stop(struct rte_eth_dev *dev);
 static void igbvf_dev_close(struct rte_eth_dev *dev);
 static int eth_igbvf_link_update(struct e1000_hw *hw);
-static void eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats);
+static void eth_igbvf_stats_get(struct rte_eth_dev *dev,
+                               struct rte_eth_stats *rte_stats);
+static int eth_igbvf_xstats_get(struct rte_eth_dev *dev,
+                               struct rte_eth_xstats *xstats, unsigned n);
 static void eth_igbvf_stats_reset(struct rte_eth_dev *dev);
 static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
                uint16_t vlan_id, int on);
@@ -359,7 +362,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
        .dev_close            = igbvf_dev_close,
        .link_update          = eth_igb_link_update,
        .stats_get            = eth_igbvf_stats_get,
+       .xstats_get           = eth_igbvf_xstats_get,
        .stats_reset          = eth_igbvf_stats_reset,
+       .xstats_reset         = eth_igbvf_stats_reset,
        .vlan_filter_set      = igbvf_vlan_filter_set,
        .dev_infos_get        = eth_igbvf_infos_get,
        .rx_queue_setup       = eth_igb_rx_queue_setup,
@@ -444,6 +449,17 @@ static const struct rte_igb_xstats_name_off rte_igb_stats_strings[] = {
 #define IGB_NB_XSTATS (sizeof(rte_igb_stats_strings) / \
                sizeof(rte_igb_stats_strings[0]))
 
+static const struct rte_igb_xstats_name_off rte_igbvf_stats_strings[] = {
+       {"rx_multicast_packets", offsetof(struct e1000_vf_stats, mprc)},
+       {"rx_good_loopback_packets", offsetof(struct e1000_vf_stats, gprlbc)},
+       {"tx_good_loopback_packets", offsetof(struct e1000_vf_stats, gptlbc)},
+       {"rx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gorlbc)},
+       {"tx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gotlbc)},
+};
+
+#define IGBVF_NB_XSTATS (sizeof(rte_igbvf_stats_strings) / \
+               sizeof(rte_igbvf_stats_strings[0]))
+
 /**
  * Atomically reads the link status information from global
  * structure rte_eth_dev.
@@ -621,6 +637,9 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
        uint32_t ctrl_ext;
 
        pci_dev = eth_dev->pci_dev;
+
+       rte_eth_copy_pci_info(eth_dev, pci_dev);
+
        eth_dev->dev_ops = &eth_igb_ops;
        eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;
        eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
@@ -829,6 +848,8 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 
        pci_dev = eth_dev->pci_dev;
 
+       rte_eth_copy_pci_info(eth_dev, pci_dev);
+
        hw->device_id = pci_dev->id.device_id;
        hw->vendor_id = pci_dev->id.vendor_id;
        hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
@@ -1101,11 +1122,11 @@ eth_igb_start(struct rte_eth_dev *dev)
        igb_pf_host_configure(dev);
 
        /* check and configure queue intr-vector mapping */
-       if (dev->data->dev_conf.intr_conf.rxq != 0)
+       if (dev->data->dev_conf.intr_conf.rxq != 0) {
                intr_vector = dev->data->nb_rx_queues;
-
-       if (rte_intr_efd_enable(intr_handle, intr_vector))
-               return -1;
+               if (rte_intr_efd_enable(intr_handle, intr_vector))
+                       return -1;
+       }
 
        if (rte_intr_dp_is_en(intr_handle)) {
                intr_handle->intr_vec =
@@ -1632,12 +1653,8 @@ eth_igb_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
 }
 
 static void
-eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
+igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
 {
-       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct e1000_vf_stats *hw_stats = (struct e1000_vf_stats*)
-                         E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
-
        /* Good Rx packets, include VF loopback */
        UPDATE_VF_STAT(E1000_VFGPRC,
            hw_stats->last_gprc, hw_stats->gprc);
@@ -1673,6 +1690,43 @@ eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        /* Good Tx loopback octets */
        UPDATE_VF_STAT(E1000_VFGOTLBC,
            hw_stats->last_gotlbc, hw_stats->gotlbc);
+}
+
+static int
+eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
+                    unsigned n)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_vf_stats *hw_stats = (struct e1000_vf_stats *)
+                       E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+       unsigned i;
+
+       if (n < IGBVF_NB_XSTATS)
+               return IGBVF_NB_XSTATS;
+
+       igbvf_read_stats_registers(hw, hw_stats);
+
+       if (!xstats)
+               return 0;
+
+       for (i = 0; i < IGBVF_NB_XSTATS; i++) {
+               snprintf(xstats[i].name, sizeof(xstats[i].name), "%s",
+                        rte_igbvf_stats_strings[i].name);
+               xstats[i].value = *(uint64_t *)(((char *)hw_stats) +
+                       rte_igbvf_stats_strings[i].offset);
+       }
+
+       return IGBVF_NB_XSTATS;
+}
+
+static void
+eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_vf_stats *hw_stats = (struct e1000_vf_stats *)
+                         E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+
+       igbvf_read_stats_registers(hw, hw_stats);
 
        if (rte_stats == NULL)
                return;
@@ -1700,7 +1754,6 @@ eth_igbvf_stats_reset(struct rte_eth_dev *dev)
        /* reset HW current stats*/
        memset(&hw_stats->gprc, 0, sizeof(*hw_stats) -
               offsetof(struct e1000_vf_stats, gprc));
-
 }
 
 static void
@@ -4442,7 +4495,10 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
        uint32_t tmpval, regval, intr_mask;
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint32_t vec = 0;
+       uint32_t vec = E1000_MISC_VEC_ID;
+       uint32_t base = E1000_MISC_VEC_ID;
+       uint32_t misc_shift = 0;
+
        struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
 
        /* won't configure msix register if no mapping is done
@@ -4451,6 +4507,11 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
        if (!rte_intr_dp_is_en(intr_handle))
                return;
 
+       if (rte_intr_allow_others(intr_handle)) {
+               vec = base = E1000_RX_VEC_START;
+               misc_shift = 1;
+       }
+
        /* set interrupt vector for other causes */
        if (hw->mac.type == e1000_82575) {
                tmpval = E1000_READ_REG(hw, E1000_CTRL_EXT);
@@ -4479,8 +4540,8 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
                E1000_WRITE_REG(hw, E1000_GPIE, E1000_GPIE_MSIX_MODE |
                                        E1000_GPIE_PBA | E1000_GPIE_EIAME |
                                        E1000_GPIE_NSICR);
-
-               intr_mask = (1 << intr_handle->max_intr) - 1;
+               intr_mask = RTE_LEN2MASK(intr_handle->nb_efd, uint32_t) <<
+                       misc_shift;
                regval = E1000_READ_REG(hw, E1000_EIAC);
                E1000_WRITE_REG(hw, E1000_EIAC, regval | intr_mask);
 
@@ -4494,14 +4555,15 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
        /* use EIAM to auto-mask when MSI-X interrupt
         * is asserted, this saves a register write for every interrupt
         */
-       intr_mask = (1 << intr_handle->nb_efd) - 1;
+       intr_mask = RTE_LEN2MASK(intr_handle->nb_efd, uint32_t) <<
+               misc_shift;
        regval = E1000_READ_REG(hw, E1000_EIAM);
        E1000_WRITE_REG(hw, E1000_EIAM, regval | intr_mask);
 
        for (queue_id = 0; queue_id < dev->data->nb_rx_queues; queue_id++) {
                eth_igb_assign_msix_vector(hw, 0, queue_id, vec);
                intr_handle->intr_vec[queue_id] = vec;
-               if (vec < intr_handle->nb_efd - 1)
+               if (vec < base + intr_handle->nb_efd - 1)
                        vec++;
        }