From 7da9ffee83aef5261db9c6a332a2adc1d2c19d37 Mon Sep 17 00:00:00 2001 From: Intel Date: Thu, 20 Dec 2012 00:00:00 +0100 Subject: [PATCH] e1000: add vlan offload support Signed-off-by: Intel --- lib/librte_pmd_e1000/e1000_ethdev.h | 6 +- lib/librte_pmd_e1000/igb_ethdev.c | 153 +++++++++++++++++++++++----- lib/librte_pmd_e1000/igb_rxtx.c | 3 +- 3 files changed, 131 insertions(+), 31 deletions(-) diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h b/lib/librte_pmd_e1000/e1000_ethdev.h index f7b49892af..a342f237d0 100644 --- a/lib/librte_pmd_e1000/e1000_ethdev.h +++ b/lib/librte_pmd_e1000/e1000_ethdev.h @@ -49,8 +49,8 @@ #define E1000_RXD_ERR_CKSUM_BIT 29 #define E1000_RXD_ERR_CKSUM_MSK 3 #define E1000_ADVTXD_MACLEN_SHIFT 9 /* Bit shift for l2_len */ - -#define E1000_VFTA_SIZE 128 +#define E1000_CTRL_EXT_EXTEND_VLAN (1<<26) /* EXTENDED VLAN */ +#define IGB_VFTA_SIZE 128 /* structure for interrupt relative data */ struct e1000_interrupt { @@ -59,7 +59,7 @@ struct e1000_interrupt { /* local vfta copy */ struct e1000_vfta { - uint32_t vfta[E1000_VFTA_SIZE]; + uint32_t vfta[IGB_VFTA_SIZE]; }; /* diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c index 26f87881e7..1732c79a05 100644 --- a/lib/librte_pmd_e1000/igb_ethdev.c +++ b/lib/librte_pmd_e1000/igb_ethdev.c @@ -85,11 +85,19 @@ static void igb_hw_control_acquire(struct e1000_hw *hw); static void igb_hw_control_release(struct e1000_hw *hw); static void igb_init_manageability(struct e1000_hw *hw); static void igb_release_manageability(struct e1000_hw *hw); -static void igb_vlan_hw_support_enable(struct rte_eth_dev *dev); -static void igb_vlan_hw_support_disable(struct rte_eth_dev *dev); -static void eth_igb_vlan_filter_set(struct rte_eth_dev *dev, - uint16_t vlan_id, - int on); + +static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev, + uint16_t vlan_id, int on); +static void eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid_id); +static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask); + +static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev); +static void igb_vlan_hw_filter_disable(struct rte_eth_dev *dev); +static void igb_vlan_hw_strip_enable(struct rte_eth_dev *dev); +static void igb_vlan_hw_strip_disable(struct rte_eth_dev *dev); +static void igb_vlan_hw_extend_enable(struct rte_eth_dev *dev); +static void igb_vlan_hw_extend_disable(struct rte_eth_dev *dev); + static int eth_igb_led_on(struct rte_eth_dev *dev); static int eth_igb_led_off(struct rte_eth_dev *dev); @@ -166,6 +174,8 @@ static struct eth_dev_ops eth_igb_ops = { .stats_reset = eth_igb_stats_reset, .dev_infos_get = eth_igb_infos_get, .vlan_filter_set = eth_igb_vlan_filter_set, + .vlan_tpid_set = eth_igb_vlan_tpid_set, + .vlan_offload_set = eth_igb_vlan_offload_set, .rx_queue_setup = eth_igb_rx_queue_setup, .tx_queue_setup = eth_igb_tx_queue_setup, .dev_led_on = eth_igb_led_on, @@ -576,13 +586,11 @@ eth_igb_start(struct rte_eth_dev *dev) e1000_clear_hw_cntrs_base_generic(hw); /* - * If VLAN filtering is enabled, set up VLAN tag offload and filtering - * and restore the VFTA. + * VLAN Offload Settings */ - if (dev->data->dev_conf.rxmode.hw_vlan_filter) - igb_vlan_hw_support_enable(dev); - else - igb_vlan_hw_support_disable(dev); + mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \ + ETH_VLAN_EXTEND_MASK; + eth_igb_vlan_offload_set(dev, mask); /* * Configure the Interrupt Moderation register (EITR) with the maximum @@ -1258,7 +1266,7 @@ eth_igb_allmulticast_disable(struct rte_eth_dev *dev) E1000_WRITE_REG(hw, E1000_RCTL, rctl); } -static void +static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) { struct e1000_hw *hw = @@ -1281,10 +1289,37 @@ eth_igb_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 +eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t reg = ETHER_TYPE_VLAN ; + + reg |= (tpid << 16); + E1000_WRITE_REG(hw, E1000_VET, reg); +} + +static void +igb_vlan_hw_filter_disable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t reg; + + /* Filter Table Disable */ + reg = E1000_READ_REG(hw, E1000_RCTL); + reg &= ~E1000_RCTL_CFIEN; + reg &= ~E1000_RCTL_VFE; + E1000_WRITE_REG(hw, E1000_RCTL, reg); } static void -igb_vlan_hw_support_enable(struct rte_eth_dev *dev) +igb_vlan_hw_filter_enable(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); @@ -1293,38 +1328,102 @@ igb_vlan_hw_support_enable(struct rte_eth_dev *dev) uint32_t reg; int i; - /* VLAN Mode Enable */ - reg = E1000_READ_REG(hw, E1000_CTRL); - reg |= E1000_CTRL_VME; - E1000_WRITE_REG(hw, E1000_CTRL, reg); - - /* Filter Table Enable */ + /* Filter Table Enable, CFI not used for packet acceptance */ reg = E1000_READ_REG(hw, E1000_RCTL); reg &= ~E1000_RCTL_CFIEN; reg |= E1000_RCTL_VFE; E1000_WRITE_REG(hw, E1000_RCTL, reg); - /* Update maximum frame size */ - reg = E1000_READ_REG(hw, E1000_RLPML); - reg += VLAN_TAG_SIZE; - E1000_WRITE_REG(hw, E1000_RLPML, reg); - /* restore VFTA table */ - for (i = 0; i < E1000_VFTA_SIZE; i++) + for (i = 0; i < IGB_VFTA_SIZE; i++) E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, i, shadow_vfta->vfta[i]); } static void -igb_vlan_hw_support_disable(struct rte_eth_dev *dev) +igb_vlan_hw_strip_disable(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); uint32_t reg; - /* VLAN Mode disable */ + /* VLAN Mode Disable */ reg = E1000_READ_REG(hw, E1000_CTRL); reg &= ~E1000_CTRL_VME; E1000_WRITE_REG(hw, E1000_CTRL, reg); + + /* Update maximum frame size */ + E1000_WRITE_REG(hw, E1000_RLPML, + dev->data->dev_conf.rxmode.max_rx_pkt_len + VLAN_TAG_SIZE); +} + +static void +igb_vlan_hw_strip_enable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t reg; + + /* VLAN Mode Enable */ + reg = E1000_READ_REG(hw, E1000_CTRL); + reg |= E1000_CTRL_VME; + E1000_WRITE_REG(hw, E1000_CTRL, reg); + + /* Update maximum frame size */ + E1000_WRITE_REG(hw, E1000_RLPML, + dev->data->dev_conf.rxmode.max_rx_pkt_len); + +} + +static void +igb_vlan_hw_extend_disable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t reg; + + /* CTRL_EXT: Extended VLAN */ + reg = E1000_READ_REG(hw, E1000_CTRL_EXT); + reg &= ~E1000_CTRL_EXT_EXTEND_VLAN; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + +} + +static void +igb_vlan_hw_extend_enable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t reg; + + /* CTRL_EXT: Extended VLAN */ + reg = E1000_READ_REG(hw, E1000_CTRL_EXT); + reg |= E1000_CTRL_EXT_EXTEND_VLAN; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); +} + +static void +eth_igb_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) + igb_vlan_hw_strip_enable(dev); + else + igb_vlan_hw_strip_disable(dev); + } + + if(mask & ETH_VLAN_FILTER_MASK){ + if (dev->data->dev_conf.rxmode.hw_vlan_filter) + igb_vlan_hw_filter_enable(dev); + else + igb_vlan_hw_filter_disable(dev); + } + + if(mask & ETH_VLAN_EXTEND_MASK){ + if (dev->data->dev_conf.rxmode.hw_vlan_extend) + igb_vlan_hw_extend_enable(dev); + else + igb_vlan_hw_extend_disable(dev); + } } static void diff --git a/lib/librte_pmd_e1000/igb_rxtx.c b/lib/librte_pmd_e1000/igb_rxtx.c index a600ff7d4c..b59e1aa7d7 100644 --- a/lib/librte_pmd_e1000/igb_rxtx.c +++ b/lib/librte_pmd_e1000/igb_rxtx.c @@ -1691,7 +1691,8 @@ eth_igb_rx_init(struct rte_eth_dev *dev) E1000_SRRCTL_BSIZEPKT_MASK) << E1000_SRRCTL_BSIZEPKT_SHIFT); - if (dev->data->dev_conf.rxmode.max_rx_pkt_len > buf_size){ + if (dev->data->dev_conf.rxmode.max_rx_pkt_len + VLAN_TAG_SIZE + > buf_size){ dev->rx_pkt_burst = eth_igb_recv_scattered_pkts; dev->data->scattered_rx = 1; } -- 2.20.1