From patchwork Sun Feb 15 04:07:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jingjing Wu X-Patchwork-Id: 3356 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 58E0CB52C; Sun, 15 Feb 2015 05:07:58 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id E6E07B52A for ; Sun, 15 Feb 2015 05:07:55 +0100 (CET) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga103.jf.intel.com with ESMTP; 14 Feb 2015 20:02:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.09,579,1418112000"; d="scan'208";a="666550561" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by fmsmga001.fm.intel.com with ESMTP; 14 Feb 2015 20:07:44 -0800 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id t1F47gZd031338; Sun, 15 Feb 2015 12:07:42 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id t1F47eYv000653; Sun, 15 Feb 2015 12:07:42 +0800 Received: (from wujingji@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id t1F47duE000649; Sun, 15 Feb 2015 12:07:39 +0800 From: Jingjing Wu To: dev@dpdk.org Date: Sun, 15 Feb 2015 12:07:31 +0800 Message-Id: <1423973254-605-3-git-send-email-jingjing.wu@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1423973254-605-1-git-send-email-jingjing.wu@intel.com> References: <1422593303-15308-1-git-send-email-zhida.zang@intel.com> <1423973254-605-1-git-send-email-jingjing.wu@intel.com> Subject: [dpdk-dev] [PATCH v2 2/5] e1000: new functions replace old ones for flex filter X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch defines new functions dealing with flex filter. It removes old functions of flex filter in igb driver. Syn filter is dealt with through entrance eth_igb_filter_ctrl. Signed-off-by: Jingjing Wu --- lib/librte_pmd_e1000/e1000_ethdev.h | 27 ++- lib/librte_pmd_e1000/igb_ethdev.c | 332 ++++++++++++++++++++++-------------- 2 files changed, 231 insertions(+), 128 deletions(-) diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h b/lib/librte_pmd_e1000/e1000_ethdev.h index d155e77..b91fcad 100644 --- a/lib/librte_pmd_e1000/e1000_ethdev.h +++ b/lib/librte_pmd_e1000/e1000_ethdev.h @@ -78,11 +78,16 @@ #define E1000_MAX_TTQF_FILTERS 8 #define E1000_2TUPLE_MAX_PRI 7 -#define E1000_MAX_FLEXIBLE_FILTERS 8 +#define E1000_MAX_FLEX_FILTERS 8 #define E1000_MAX_FHFT 4 #define E1000_MAX_FHFT_EXT 4 +#define E1000_FHFT_SIZE_IN_DWD 64 #define E1000_MAX_FLEX_FILTER_PRI 7 #define E1000_MAX_FLEX_FILTER_LEN 128 +#define E1000_MAX_FLEX_FILTER_DWDS \ + (E1000_MAX_FLEX_FILTER_LEN / sizeof(uint32_t)) +#define E1000_FLEX_FILTERS_MASK_SIZE \ + (E1000_MAX_FLEX_FILTER_DWDS / 4) #define E1000_FHFT_QUEUEING_LEN 0x0000007F #define E1000_FHFT_QUEUEING_QUEUE 0x00000700 #define E1000_FHFT_QUEUEING_PRIO 0x00070000 @@ -131,6 +136,24 @@ struct e1000_vf_info { uint16_t tx_rate; }; +TAILQ_HEAD(e1000_flex_filter_list, e1000_flex_filter); + +struct e1000_flex_filter_info { + uint16_t len; + uint32_t dwords[E1000_MAX_FLEX_FILTER_DWDS]; /* flex bytes in dword. */ + /* if mask bit is 1b, do not compare corresponding byte in dwords. */ + uint8_t mask[E1000_FLEX_FILTERS_MASK_SIZE]; + uint8_t priority; +}; + +/* Flex filter structure */ +struct e1000_flex_filter { + TAILQ_ENTRY(e1000_flex_filter) entries; + uint16_t index; /* index of flex filter */ + struct e1000_flex_filter_info filter_info; + uint16_t queue; /* rx queue assigned to */ +}; + /* * Structure to store filters' info. */ @@ -138,6 +161,8 @@ struct e1000_filter_info { uint8_t ethertype_mask; /* Bit mask for every used ethertype filter */ /* store used ethertype filters*/ uint16_t ethertype_filters[E1000_MAX_ETQF_FILTERS]; + uint8_t flex_mask; /* Bit mask for every used flex filter */ + struct e1000_flex_filter_list flex_list; }; /* diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c index 2a268b8..6e9240e 100644 --- a/lib/librte_pmd_e1000/igb_ethdev.c +++ b/lib/librte_pmd_e1000/igb_ethdev.c @@ -162,14 +162,14 @@ static int eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev, static int eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_2tuple_filter *filter, uint16_t *rx_queue); -static int eth_igb_add_flex_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_flex_filter *filter, uint16_t rx_queue); -static int eth_igb_remove_flex_filter(struct rte_eth_dev *dev, - uint16_t index); +static int eth_igb_add_del_flex_filter(struct rte_eth_dev *dev, + struct rte_eth_flex_filter *filter, + bool add); static int eth_igb_get_flex_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_flex_filter *filter, uint16_t *rx_queue); + struct rte_eth_flex_filter *filter); +static int eth_igb_flex_filter_handle(struct rte_eth_dev *dev, + enum rte_filter_op filter_op, + void *arg); static int eth_igb_add_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_5tuple_filter *filter, uint16_t rx_queue); @@ -271,9 +271,6 @@ static struct eth_dev_ops eth_igb_ops = { .add_2tuple_filter = eth_igb_add_2tuple_filter, .remove_2tuple_filter = eth_igb_remove_2tuple_filter, .get_2tuple_filter = eth_igb_get_2tuple_filter, - .add_flex_filter = eth_igb_add_flex_filter, - .remove_flex_filter = eth_igb_remove_flex_filter, - .get_flex_filter = eth_igb_get_flex_filter, .add_5tuple_filter = eth_igb_add_5tuple_filter, .remove_5tuple_filter = eth_igb_remove_5tuple_filter, .get_5tuple_filter = eth_igb_get_5tuple_filter, @@ -470,6 +467,8 @@ eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); struct e1000_vfta * shadow_vfta = E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private); uint32_t ctrl_ext; pci_dev = eth_dev->pci_dev; @@ -601,6 +600,9 @@ eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, /* enable support intr */ igb_intr_enable(eth_dev); + TAILQ_INIT(&filter_info->flex_list); + filter_info->flex_mask = 0; + return 0; err_late: @@ -926,7 +928,10 @@ static void eth_igb_stop(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); struct rte_eth_link link; + struct e1000_flex_filter *p_flex; igb_intr_disable(hw); igb_pf_reset_hw(hw); @@ -949,6 +954,13 @@ eth_igb_stop(struct rte_eth_dev *dev) /* clear the recorded link status */ memset(&link, 0, sizeof(link)); rte_igb_dev_atomic_write_link_status(dev, &link); + + /* Remove all flex filters of the device */ + while ((p_flex = TAILQ_FIRST(&filter_info->flex_list))) { + TAILQ_REMOVE(&filter_info->flex_list, p_flex, entries); + rte_free(p_flex); + } + filter_info->flex_mask = 0; } static void @@ -2652,161 +2664,224 @@ eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, return -ENOENT; } -/* - * add a flex filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that will be added. - * rx_queue: the queue id the filter assigned to. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ -static int -eth_igb_add_flex_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_flex_filter *filter, uint16_t rx_queue) +static inline struct e1000_flex_filter * +eth_igb_flex_filter_lookup(struct e1000_flex_filter_list *filter_list, + struct e1000_flex_filter_info *key) { - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t wufc, en_bits = 0; - uint32_t queueing = 0; - uint32_t reg_off = 0; - uint8_t i, j = 0; - - MAC_TYPE_FILTER_SUP_EXT(hw->mac.type); - - if (index >= E1000_MAX_FLEXIBLE_FILTERS) - return -EINVAL; /* filter index is out of range. */ - - if (filter->len == 0 || filter->len > E1000_MAX_FLEX_FILTER_LEN || - filter->len % 8 != 0 || - filter->priority > E1000_MAX_FLEX_FILTER_PRI) - return -EINVAL; - - wufc = E1000_READ_REG(hw, E1000_WUFC); - en_bits = E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index); - if ((wufc & en_bits) == en_bits) - return -EINVAL; /* the filter is in use. */ + struct e1000_flex_filter *it; - E1000_WRITE_REG(hw, E1000_WUFC, - wufc | E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index)); + TAILQ_FOREACH(it, filter_list, entries) { + if (memcmp(key, &it->filter_info, + sizeof(struct e1000_flex_filter_info)) == 0) + return it; + } - j = 0; - if (index < E1000_MAX_FHFT) - reg_off = E1000_FHFT(index); - else - reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT); - - for (i = 0; i < 16; i++) { - E1000_WRITE_REG(hw, reg_off + i*4*4, filter->dwords[j]); - E1000_WRITE_REG(hw, reg_off + (i*4+1)*4, filter->dwords[++j]); - E1000_WRITE_REG(hw, reg_off + (i*4+2)*4, - (uint32_t)filter->mask[i]); - ++j; - } - queueing |= filter->len | - (rx_queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) | - (filter->priority << E1000_FHFT_QUEUEING_PRIO_SHIFT); - E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET, queueing); - return 0; + return NULL; } -/* - * remove a flex filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ static int -eth_igb_remove_flex_filter(struct rte_eth_dev *dev, - uint16_t index) +eth_igb_add_del_flex_filter(struct rte_eth_dev *dev, + struct rte_eth_flex_filter *filter, + bool add) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t wufc, reg_off = 0; - uint8_t i; - - MAC_TYPE_FILTER_SUP_EXT(hw->mac.type); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_flex_filter *flex_filter, *it; + uint32_t wufc, queueing, mask; + uint32_t reg_off; + uint8_t shift, i, j = 0; + + flex_filter = rte_zmalloc("e1000_flex_filter", + sizeof(struct e1000_flex_filter), 0); + if (flex_filter == NULL) + return -ENOMEM; - if (index >= E1000_MAX_FLEXIBLE_FILTERS) - return -EINVAL; /* filter index is out of range. */ + flex_filter->filter_info.len = filter->len; + flex_filter->filter_info.priority = filter->priority; + memcpy(flex_filter->filter_info.dwords, filter->bytes, filter->len); + for (i = 0; i < RTE_ALIGN(filter->len, CHAR_BIT) / CHAR_BIT; i++) { + mask = 0; + /* reverse bits in flex filter's mask*/ + for (shift = 0; shift < CHAR_BIT; shift++) { + if (filter->mask[i] & (0x01 << shift)) + mask |= (0x80 >> shift); + } + flex_filter->filter_info.mask[i] = mask; + } wufc = E1000_READ_REG(hw, E1000_WUFC); - E1000_WRITE_REG(hw, E1000_WUFC, wufc & (~(E1000_WUFC_FLX0 << index))); - - if (index < E1000_MAX_FHFT) - reg_off = E1000_FHFT(index); + if (flex_filter->index < E1000_MAX_FHFT) + reg_off = E1000_FHFT(flex_filter->index); else - reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT); + reg_off = E1000_FHFT_EXT(flex_filter->index - E1000_MAX_FHFT); + + if (add) { + if (eth_igb_flex_filter_lookup(&filter_info->flex_list, + &flex_filter->filter_info) != NULL) { + PMD_DRV_LOG(ERR, "filter exists."); + rte_free(flex_filter); + return -EEXIST; + } + flex_filter->queue = filter->queue; + /* + * look for an unused flex filter index + * and insert the filter into the list. + */ + for (i = 0; i < E1000_MAX_FLEX_FILTERS; i++) { + if (!(filter_info->flex_mask & (1 << i))) { + filter_info->flex_mask |= 1 << i; + flex_filter->index = i; + TAILQ_INSERT_TAIL(&filter_info->flex_list, + flex_filter, + entries); + break; + } + } + if (i >= E1000_MAX_FLEX_FILTERS) { + PMD_DRV_LOG(ERR, "flex filters are full."); + rte_free(flex_filter); + return -ENOSYS; + } + + E1000_WRITE_REG(hw, E1000_WUFC, wufc | E1000_WUFC_FLEX_HQ | + (E1000_WUFC_FLX0 << flex_filter->index)); + queueing = filter->len | + (filter->queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) | + (filter->priority << E1000_FHFT_QUEUEING_PRIO_SHIFT); + E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET, + queueing); + for (i = 0; i < E1000_FLEX_FILTERS_MASK_SIZE; i++) { + E1000_WRITE_REG(hw, reg_off, + flex_filter->filter_info.dwords[j]); + reg_off += sizeof(uint32_t); + E1000_WRITE_REG(hw, reg_off, + flex_filter->filter_info.dwords[++j]); + reg_off += sizeof(uint32_t); + E1000_WRITE_REG(hw, reg_off, + (uint32_t)flex_filter->filter_info.mask[i]); + reg_off += sizeof(uint32_t) * 2; + ++j; + } + } else { + it = eth_igb_flex_filter_lookup(&filter_info->flex_list, + &flex_filter->filter_info); + if (it == NULL) { + PMD_DRV_LOG(ERR, "filter doesn't exist."); + rte_free(flex_filter); + return -ENOENT; + } + + for (i = 0; i < E1000_FHFT_SIZE_IN_DWD; i++) + E1000_WRITE_REG(hw, reg_off + i * sizeof(uint32_t), 0); + E1000_WRITE_REG(hw, E1000_WUFC, wufc & + (~(E1000_WUFC_FLX0 << it->index))); + + filter_info->flex_mask &= ~(1 << it->index); + TAILQ_REMOVE(&filter_info->flex_list, it, entries); + rte_free(it); + rte_free(flex_filter); + } - for (i = 0; i < 64; i++) - E1000_WRITE_REG(hw, reg_off + i*4, 0); return 0; } -/* - * get a flex filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that returns. - * *rx_queue: the pointer of the queue id the filter assigned to. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ static int -eth_igb_get_flex_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_flex_filter *filter, uint16_t *rx_queue) +eth_igb_get_flex_filter(struct rte_eth_dev *dev, + struct rte_eth_flex_filter *filter) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + struct e1000_flex_filter flex_filter, *it; uint32_t wufc, queueing, wufc_en = 0; - uint8_t i, j; - MAC_TYPE_FILTER_SUP_EXT(hw->mac.type); - - if (index >= E1000_MAX_FLEXIBLE_FILTERS) - return -EINVAL; /* filter index is out of range. */ + memset(&flex_filter, 0, sizeof(struct e1000_flex_filter)); + flex_filter.filter_info.len = filter->len; + flex_filter.filter_info.priority = filter->priority; + memcpy(flex_filter.filter_info.dwords, filter->bytes, filter->len); + memcpy(flex_filter.filter_info.mask, filter->mask, + RTE_ALIGN(filter->len, sizeof(char)) / sizeof(char)); + + it = eth_igb_flex_filter_lookup(&filter_info->flex_list, + &flex_filter.filter_info); + if (it == NULL) { + PMD_DRV_LOG(ERR, "filter doesn't exist."); + return -ENOENT; + } wufc = E1000_READ_REG(hw, E1000_WUFC); - wufc_en = E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index); + wufc_en = E1000_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << it->index); if ((wufc & wufc_en) == wufc_en) { uint32_t reg_off = 0; - j = 0; - if (index < E1000_MAX_FHFT) - reg_off = E1000_FHFT(index); + if (it->index < E1000_MAX_FHFT) + reg_off = E1000_FHFT(it->index); else - reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT); - - for (i = 0; i < 16; i++, j = i * 2) { - filter->dwords[j] = - E1000_READ_REG(hw, reg_off + i*4*4); - filter->dwords[j+1] = - E1000_READ_REG(hw, reg_off + (i*4+1)*4); - filter->mask[i] = - E1000_READ_REG(hw, reg_off + (i*4+2)*4); - } + reg_off = E1000_FHFT_EXT(it->index - E1000_MAX_FHFT); + queueing = E1000_READ_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET); filter->len = queueing & E1000_FHFT_QUEUEING_LEN; filter->priority = (queueing & E1000_FHFT_QUEUEING_PRIO) >> E1000_FHFT_QUEUEING_PRIO_SHIFT; - *rx_queue = (queueing & E1000_FHFT_QUEUEING_QUEUE) >> + filter->queue = (queueing & E1000_FHFT_QUEUEING_QUEUE) >> E1000_FHFT_QUEUEING_QUEUE_SHIFT; return 0; } return -ENOENT; } +static int +eth_igb_flex_filter_handle(struct rte_eth_dev *dev, + enum rte_filter_op filter_op, + void *arg) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_eth_flex_filter *filter; + int ret = 0; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (filter_op == RTE_ETH_FILTER_NOP) + return ret; + + if (arg == NULL) { + PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u", + filter_op); + return -EINVAL; + } + + filter = (struct rte_eth_flex_filter *)arg; + if (filter->len == 0 || filter->len > E1000_MAX_FLEX_FILTER_LEN + || filter->len % sizeof(uint64_t) != 0) { + PMD_DRV_LOG(ERR, "filter's length is out of range"); + return -EINVAL; + } + if (filter->priority > E1000_MAX_FLEX_FILTER_PRI) { + PMD_DRV_LOG(ERR, "filter's priority is out of range"); + return -EINVAL; + } + + switch (filter_op) { + case RTE_ETH_FILTER_ADD: + ret = eth_igb_add_del_flex_filter(dev, filter, TRUE); + break; + case RTE_ETH_FILTER_DELETE: + ret = eth_igb_add_del_flex_filter(dev, filter, FALSE); + break; + case RTE_ETH_FILTER_GET: + ret = eth_igb_get_flex_filter(dev, filter); + break; + default: + PMD_DRV_LOG(ERR, "unsupported operation %u", filter_op); + ret = -EINVAL; + break; + } + + return ret; +} + /* * add a 5tuple filter * @@ -3237,6 +3312,9 @@ eth_igb_filter_ctrl(struct rte_eth_dev *dev, case RTE_ETH_FILTER_ETHERTYPE: ret = igb_ethertype_filter_handle(dev, filter_op, arg); break; + case RTE_ETH_FILTER_FLEXIBLE: + ret = eth_igb_flex_filter_handle(dev, filter_op, arg); + break; default: PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", filter_type);