ixgbe: add vlan offload support
authorIntel <intel.com>
Wed, 19 Dec 2012 23:00:00 +0000 (00:00 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Thu, 25 Jul 2013 13:40:56 +0000 (15:40 +0200)
Signed-off-by: Intel
lib/librte_pmd_ixgbe/ixgbe_ethdev.c
lib/librte_pmd_ixgbe/ixgbe_ethdev.h

index d8642a0..bbe92e3 100644 (file)
@@ -108,9 +108,23 @@ static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
                                             uint8_t is_rx);
 static void ixgbe_dev_info_get(struct rte_eth_dev *dev,
                                struct rte_eth_dev_info *dev_info);
-static void ixgbe_vlan_filter_set(struct rte_eth_dev *dev,
-                                 uint16_t vlan_id,
+static int ixgbe_vlan_filter_set(struct rte_eth_dev *dev,
+               uint16_t vlan_id, int on);
+static void ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid_id);
+static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev, 
+               uint16_t queue, bool on);
+static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue,
                                  int on);
+static void ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static void ixgbe_vlan_hw_filter_enable(struct rte_eth_dev *dev);
+static void ixgbe_vlan_hw_filter_disable(struct rte_eth_dev *dev);
+static void ixgbe_vlan_hw_strip_enable_all(struct rte_eth_dev *dev);
+static void ixgbe_vlan_hw_strip_disable_all(struct rte_eth_dev *dev);
+static void ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue);
+static void ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue);
+static void ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev);
+static void ixgbe_vlan_hw_extend_disable(struct rte_eth_dev *dev);
+
 static int ixgbe_dev_led_on(struct rte_eth_dev *dev);
 static int ixgbe_dev_led_off(struct rte_eth_dev *dev);
 static int  ixgbe_flow_ctrl_set(struct rte_eth_dev *dev,
@@ -135,6 +149,13 @@ static void ixgbevf_dev_stop(struct rte_eth_dev *dev);
 static void ixgbevf_intr_disable(struct ixgbe_hw *hw);
 static void ixgbevf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
 static void ixgbevf_dev_stats_reset(struct rte_eth_dev *dev);
+static int ixgbevf_vlan_filter_set(struct rte_eth_dev *dev, 
+               uint16_t vlan_id, int on);
+static void ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev,
+               uint16_t queue, int on);
+static void ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+
 
 /*
  *  * Define VF Stats MACRO for Non "cleared on read" register
@@ -155,6 +176,24 @@ static void ixgbevf_dev_stats_reset(struct rte_eth_dev *dev);
        last = latest;                                           \
 }
 
+#define IXGBE_SET_HWSTRIP(h, q) do{\
+               uint32_t idx = (q) / (sizeof ((h)->bitmap[0]) * NBBY); \
+               uint32_t bit = (q) % (sizeof ((h)->bitmap[0]) * NBBY); \
+               (h)->bitmap[idx] |= 1 << bit;\
+       }while(0)
+       
+#define IXGBE_CLEAR_HWSTRIP(h, q) do{\
+               uint32_t idx = (q) / (sizeof ((h)->bitmap[0]) * NBBY); \
+               uint32_t bit = (q) % (sizeof ((h)->bitmap[0]) * NBBY); \
+               (h)->bitmap[idx] &= ~(1 << bit);\
+       }while(0)
+#define IXGBE_GET_HWSTRIP(h, q, r) do{\
+               uint32_t idx = (q) / (sizeof ((h)->bitmap[0]) * NBBY); \
+               uint32_t bit = (q) % (sizeof ((h)->bitmap[0]) * NBBY); \
+               (r) = (h)->bitmap[idx] >> bit & 1;\
+       }while(0)
+
 /*
  * The set of PCI devices this driver supports
  */
@@ -196,6 +235,9 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = {
        .queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set,
        .dev_infos_get        = ixgbe_dev_info_get,
        .vlan_filter_set      = ixgbe_vlan_filter_set,
+       .vlan_tpid_set        = ixgbe_vlan_tpid_set,
+       .vlan_offload_set     = ixgbe_vlan_offload_set,
+       .vlan_strip_queue_set = ixgbe_vlan_strip_queue_set,
        .rx_queue_setup       = ixgbe_dev_rx_queue_setup,
        .rx_queue_release     = ixgbe_dev_rx_queue_release,
        .tx_queue_setup       = ixgbe_dev_tx_queue_setup,
@@ -230,6 +272,9 @@ static struct eth_dev_ops ixgbevf_eth_dev_ops = {
        .dev_close            = ixgbevf_dev_stop,
 
        .dev_infos_get        = ixgbe_dev_info_get,
+       .vlan_filter_set      = ixgbevf_vlan_filter_set,
+       .vlan_strip_queue_set = ixgbevf_vlan_strip_queue_set,
+       .vlan_offload_set     = ixgbevf_vlan_offload_set,
        .rx_queue_setup       = ixgbe_dev_rx_queue_setup,
        .rx_queue_release     = ixgbe_dev_rx_queue_release,
        .tx_queue_setup       = ixgbe_dev_tx_queue_setup,
@@ -439,6 +484,10 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
        struct ixgbe_vfta * shadow_vfta =
                IXGBE_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private);
+       struct ixgbe_hwstrip *hwstrip = 
+               IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(eth_dev->data->dev_private);
+       struct ixgbe_dcb_config *dcb_config =
+               IXGBE_DEV_PRIVATE_TO_DCB_CFG(eth_dev->data->dev_private);
        uint32_t ctrl_ext;
        uint16_t csum;
        int diag, i;
@@ -541,6 +590,9 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        /* initialize the vfta */
        memset(shadow_vfta, 0, sizeof(*shadow_vfta));
 
+       /* initialize the hw strip bitmap*/
+       memset(hwstrip, 0, sizeof(*hwstrip));
+
        /* let hardware know driver is loaded */
        ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
        ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
@@ -575,6 +627,10 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        struct rte_pci_device *pci_dev;
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
        int diag;
+       struct ixgbe_vfta * shadow_vfta =
+               IXGBE_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private);
+       struct ixgbe_hwstrip *hwstrip = 
+               IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(eth_dev->data->dev_private);
 
        PMD_INIT_LOG(DEBUG, "eth_ixgbevf_dev_init");
 
@@ -585,6 +641,12 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        hw->vendor_id = pci_dev->id.vendor_id;
        hw->hw_addr = (void *)pci_dev->mem_resource.addr;
 
+       /* initialize the vfta */
+       memset(shadow_vfta, 0, sizeof(*shadow_vfta));
+
+       /* initialize the hw strip bitmap*/
+       memset(hwstrip, 0, sizeof(*hwstrip));
+
        /* Initialize the shared code */
        diag = ixgbe_init_shared_code(hw);
        if (diag != IXGBE_SUCCESS) {
@@ -683,7 +745,7 @@ rte_ixgbevf_pmd_init(void)
        return (0);
 }
 
-static void
+static int
 ixgbe_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 {
        struct ixgbe_hw *hw =
@@ -705,16 +767,35 @@ ixgbe_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 
        /* update local VFTA copy */
        shadow_vfta->vfta[vid_idx] = vfta;
+
+       return 0;
+}
+
+static void
+ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on)
+{
+       if (on)
+               ixgbe_vlan_hw_strip_enable(dev, queue);
+       else
+               ixgbe_vlan_hw_strip_disable(dev, queue);
+}
+
+static void
+ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /* Only the high 16-bits is valid */
+       IXGBE_WRITE_REG(hw, IXGBE_EXVET, tpid << 16);
 }
 
 static void
-ixgbe_vlan_hw_support_disable(struct rte_eth_dev *dev)
+ixgbe_vlan_hw_filter_disable(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw =
                IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        uint32_t vlnctrl;
-       uint32_t rxdctl;
-       uint16_t i;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -722,28 +803,17 @@ ixgbe_vlan_hw_support_disable(struct rte_eth_dev *dev)
        vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
        vlnctrl &= ~IXGBE_VLNCTRL_VFE;
 
-       if (hw->mac.type == ixgbe_mac_82598EB)
-               vlnctrl &= ~IXGBE_VLNCTRL_VME;
-       else {
-               /* On 82599 the VLAN enable is per/queue in RXDCTL */
-               for (i = 0; i < dev->data->nb_rx_queues; i++) {
-                       rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
-                       rxdctl &= ~IXGBE_RXDCTL_VME;
-                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl);
-               }
-       }
        IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 }
 
 static void
-ixgbe_vlan_hw_support_enable(struct rte_eth_dev *dev)
+ixgbe_vlan_hw_filter_enable(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw =
                IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct ixgbe_vfta * shadow_vfta =
                IXGBE_DEV_PRIVATE_TO_VFTA(dev->data->dev_private);
        uint32_t vlnctrl;
-       uint32_t rxdctl;
        uint16_t i;
 
        PMD_INIT_FUNC_TRACE();
@@ -753,16 +823,6 @@ ixgbe_vlan_hw_support_enable(struct rte_eth_dev *dev)
        vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
        vlnctrl |= IXGBE_VLNCTRL_VFE;
 
-       if (hw->mac.type == ixgbe_mac_82598EB)
-               vlnctrl |= IXGBE_VLNCTRL_VME;
-       else {
-               /* On 82599 the VLAN enable is per/queue in RXDCTL */
-               for (i = 0; i < dev->data->nb_rx_queues; i++) {
-                       rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
-                       rxdctl |= IXGBE_RXDCTL_VME;
-                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl);
-               }
-       }
        IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 
        /* write whatever is in local vfta copy */
@@ -770,18 +830,203 @@ ixgbe_vlan_hw_support_enable(struct rte_eth_dev *dev)
                IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), shadow_vfta->vfta[i]);
 }
 
-static int
-ixgbe_dev_configure(struct rte_eth_dev *dev, uint16_t nb_rx_q, uint16_t nb_tx_q)
+static void 
+ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev, uint16_t queue, bool on)
 {
-       struct ixgbe_interrupt *intr =
-               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-       int diag;
+       struct ixgbe_hwstrip *hwstrip = 
+               IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(dev->data->dev_private);
+
+       if(queue >= IXGBE_MAX_RX_QUEUE_NUM)
+               return;
+
+       if (on)
+               IXGBE_SET_HWSTRIP(hwstrip, queue);
+       else
+               IXGBE_CLEAR_HWSTRIP(hwstrip, queue);
+}
+
+static void
+ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
 
        PMD_INIT_FUNC_TRACE();
 
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               /* No queue level support */
+               PMD_INIT_LOG(INFO, "82598EB not support queue level hw strip");
+               return;
+       }
+       else {
+               /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */
+               ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(queue));
+               ctrl &= ~IXGBE_RXDCTL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(queue), ctrl);
        }
+       /* record those setting for HW strip per queue */
+       ixgbe_vlan_hw_strip_bitmap_set(dev, queue, 0);
+}
+
+static void
+ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
 
+       PMD_INIT_FUNC_TRACE();
+
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               /* No queue level supported */
+               PMD_INIT_LOG(INFO, "82598EB not support queue level hw strip");
+               return;
+       }
+       else {
+               /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */
+               ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(queue));
+               ctrl |= IXGBE_RXDCTL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(queue), ctrl);
        }
+       /* record those setting for HW strip per queue */
+       ixgbe_vlan_hw_strip_bitmap_set(dev, queue, 1);
+}
+
+static void
+ixgbe_vlan_hw_strip_disable_all(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
+       uint16_t i;
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+               ctrl &= ~IXGBE_VLNCTRL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
+       }
+       else {
+               /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */
+               for (i = 0; i < dev->data->nb_rx_queues; i++) {
+                       ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+                       ctrl &= ~IXGBE_RXDCTL_VME;
+                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl);
+
+                       /* record those setting for HW strip per queue */
+                       ixgbe_vlan_hw_strip_bitmap_set(dev, i, 0);
+               }
+       }
+}
+
+static void
+ixgbe_vlan_hw_strip_enable_all(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
+       uint16_t i;
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+               ctrl |= IXGBE_VLNCTRL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
+       }
+       else {
+               /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */
+               for (i = 0; i < dev->data->nb_rx_queues; i++) {
+                       ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+                       ctrl |= IXGBE_RXDCTL_VME;
+                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl);
+
+                       /* record those setting for HW strip per queue */
+                       ixgbe_vlan_hw_strip_bitmap_set(dev, i, 1);                      
+               }
+       }
+}
+
+static void
+ixgbe_vlan_hw_extend_disable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
+
+       PMD_INIT_FUNC_TRACE();
+
+       /* DMATXCTRL: Geric Double VLAN Disable */
+       ctrl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+       ctrl &= ~IXGBE_DMATXCTL_GDV;
+       IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, ctrl);
+
+       /* CTRL_EXT: Global Double VLAN Disable */
+       ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+       ctrl &= ~IXGBE_EXTENDED_VLAN;
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl);
+
+}
+
+static void
+ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
+
+       PMD_INIT_FUNC_TRACE();
+
+       /* DMATXCTRL: Geric Double VLAN Enable */
+       ctrl  = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+       ctrl |= IXGBE_DMATXCTL_GDV;
+       IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, ctrl);
+
+       /* CTRL_EXT: Global Double VLAN Enable */
+       ctrl  = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+       ctrl |= IXGBE_EXTENDED_VLAN;
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl);
+
+       /*
+        * VET EXT field in the EXVET register = 0x8100 by default
+        * So no need to change. Same to VT field of DMATXCTL register
+        */
+}
+
+static void
+ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+       if(mask & ETH_VLAN_STRIP_MASK){
+               if (dev->data->dev_conf.rxmode.hw_vlan_strip)
+                       ixgbe_vlan_hw_strip_enable_all(dev);
+               else
+                       ixgbe_vlan_hw_strip_disable_all(dev);
+       }
+
+       if(mask & ETH_VLAN_FILTER_MASK){
+               if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+                       ixgbe_vlan_hw_filter_enable(dev);
+               else
+                       ixgbe_vlan_hw_filter_disable(dev);
+       }
+
+       if(mask & ETH_VLAN_EXTEND_MASK){
+               if (dev->data->dev_conf.rxmode.hw_vlan_extend)
+                       ixgbe_vlan_hw_extend_enable(dev);
+               else
+                       ixgbe_vlan_hw_extend_disable(dev);
+       }
+}
+
+static int
+ixgbe_dev_configure(struct rte_eth_dev *dev)
+{
+       struct ixgbe_interrupt *intr =
+               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+
+       PMD_INIT_FUNC_TRACE();
 
        /* set flag to update link status after init */
        intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -885,14 +1130,9 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
                        goto error;
        }
 
-       /*
-        * If VLAN filtering is enabled, set up VLAN tag offload and filtering
-        * and restore VFTA.
-        */
-       if (dev->data->dev_conf.rxmode.hw_vlan_filter)
-               ixgbe_vlan_hw_support_enable(dev);
-       else
-               ixgbe_vlan_hw_support_disable(dev);
+       mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
+               ETH_VLAN_EXTEND_MASK;
+       ixgbe_vlan_offload_set(dev, mask);
 
        if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_NONE) {
                err = ixgbe_fdir_configure(dev);
@@ -1659,6 +1899,15 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
                PMD_INIT_LOG(ERR,"Unable to initialize RX hardware\n");
                return err;
        }
+       
+       /* Set vfta */
+       ixgbevf_set_vfta_all(dev,1);
+
+       /* Set HW strip */
+       mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
+               ETH_VLAN_EXTEND_MASK;
+       ixgbevf_vlan_offload_set(dev, mask);
+
        ixgbevf_dev_rxtx_start(dev);
 
        return 0;
@@ -1677,3 +1926,94 @@ ixgbevf_dev_stop(struct rte_eth_dev *dev)
        /* reprogram the RAR[0] in case user changed it. */
        ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
 }
+
+static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_vfta * shadow_vfta =
+               IXGBE_DEV_PRIVATE_TO_VFTA(dev->data->dev_private);
+       int i = 0, j = 0, vfta = 0, mask = 1;
+
+       for (i = 0; i < IXGBE_VFTA_SIZE; i++){
+               vfta = shadow_vfta->vfta[i];
+               if(vfta){
+                       mask = 1;
+                       for (j = 0; j < 32; j++){
+                               if(vfta & mask)
+                                       ixgbe_set_vfta(hw, (i<<5)+j, 0, on);
+                               mask<<=1;
+                       }
+               }
+       }
+
+}
+
+static int
+ixgbevf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_vfta * shadow_vfta =
+               IXGBE_DEV_PRIVATE_TO_VFTA(dev->data->dev_private);
+       uint32_t vid_idx = 0;
+       uint32_t vid_bit = 0;
+       int ret = 0;
+       
+       PMD_INIT_FUNC_TRACE();
+
+       /* vind is not used in VF driver, set to 0, check ixgbe_set_vfta_vf */
+       ret = ixgbe_set_vfta(hw, vlan_id, 0, !!on);
+       if(ret){
+               PMD_INIT_LOG(ERR, "Unable to set VF vlan");
+               return ret;
+       }
+       vid_idx = (uint32_t) ((vlan_id >> 5) & 0x7F);
+       vid_bit = (uint32_t) (1 << (vlan_id & 0x1F));
+
+       /* Save what we set and retore it after device reset */
+       if (on)
+               shadow_vfta->vfta[vid_idx] |= vid_bit;
+       else
+               shadow_vfta->vfta[vid_idx] &= ~vid_bit;
+
+       return 0;
+}
+
+static void
+ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ctrl;
+
+       PMD_INIT_FUNC_TRACE();
+       
+       if(queue >= hw->mac.max_rx_queues)
+               return;
+
+       ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(queue));
+       if(on)
+               ctrl |= IXGBE_RXDCTL_VME;
+       else 
+               ctrl &= ~IXGBE_RXDCTL_VME;
+       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(queue), ctrl);
+
+       ixgbe_vlan_hw_strip_bitmap_set( dev, queue, on);
+}
+
+static void
+ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t i, on = 0;
+
+       /* VF function only support hw strip feature, others are not support */
+       if(mask & ETH_VLAN_STRIP_MASK){
+               on = !!(dev->data->dev_conf.rxmode.hw_vlan_strip);
+
+               for(i=0; i < hw->mac.max_rx_queues; i++)
+                       ixgbevf_vlan_strip_queue_set(dev,i,on);
+       }
+}
+
index e03f28f..14271ac 100644 (file)
 #define IXGBE_RXDADV_ERR_CKSUM_MSK  3
 #define IXGBE_ADVTXD_MACLEN_SHIFT   9          /* Bit shift for l2_len */
 #define IXGBE_NB_STAT_MAPPING_REGS  32
+#define IXGBE_EXTENDED_VLAN      (uint32_t)(1 << 26) /* EXTENDED VLAN ENABLE */
 #define IXGBE_VFTA_SIZE 128
+#define IXGBE_HWSTRIP_BITMAP_SIZE (IXGBE_MAX_RX_QUEUE_NUM / (sizeof(uint32_t) * NBBY))
+
 
 /*
  * Information about the fdir mode.
@@ -75,11 +78,14 @@ struct ixgbe_stat_mapping_registers {
        uint32_t rqsmr[IXGBE_NB_STAT_MAPPING_REGS];
 };
 
-/* local VFTA copy */
 struct ixgbe_vfta {
        uint32_t vfta[IXGBE_VFTA_SIZE];
 };
 
+struct ixgbe_hwstrip {
+       uint32_t bitmap[IXGBE_HWSTRIP_BITMAP_SIZE];
+};
+
 /*
  * Structure to store private data for each driver instance (for each port).
  */
@@ -90,6 +96,7 @@ struct ixgbe_adapter {
        struct ixgbe_interrupt      intr;
        struct ixgbe_stat_mapping_registers stat_mappings;
        struct ixgbe_vfta           shadow_vfta;
+       struct ixgbe_hwstrip            hwstrip;
 };
 
 #define IXGBE_DEV_PRIVATE_TO_HW(adapter)\
@@ -110,6 +117,8 @@ struct ixgbe_adapter {
 #define IXGBE_DEV_PRIVATE_TO_VFTA(adapter) \
        (&((struct ixgbe_adapter *)adapter)->shadow_vfta)
 
+#define IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(adapter) \
+       (&((struct ixgbe_adapter *)adapter)->hwstrip)
 
 /*
  * RX/TX function prototypes