From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 1AA525960 for ; Thu, 12 Feb 2015 11:00:53 +0100 (CET) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP; 12 Feb 2015 02:00:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.09,564,1418112000"; d="scan'208";a="665320938" Received: from pgsmsx105.gar.corp.intel.com ([10.221.44.96]) by fmsmga001.fm.intel.com with ESMTP; 12 Feb 2015 02:00:50 -0800 Received: from shsmsx104.ccr.corp.intel.com (10.239.4.70) by PGSMSX105.gar.corp.intel.com (10.221.44.96) with Microsoft SMTP Server (TLS) id 14.3.195.1; Thu, 12 Feb 2015 18:00:49 +0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.62]) by SHSMSX104.ccr.corp.intel.com ([169.254.5.161]) with mapi id 14.03.0195.001; Thu, 12 Feb 2015 18:00:48 +0800 From: "Liang, Cunming" To: "Zhou, Danny" , "dev@dpdk.org" Thread-Topic: [dpdk-dev] [PATCH v2 3/5] igb: enable rx queue interrupts for PF Thread-Index: AQHQP4orUbN/A9pc9k6m4UpCbURUt5zs1K+g Date: Thu, 12 Feb 2015 10:00:48 +0000 Message-ID: References: <1422951511-28143-1-git-send-email-danny.zhou@intel.com> <1422951511-28143-4-git-send-email-danny.zhou@intel.com> In-Reply-To: <1422951511-28143-4-git-send-email-danny.zhou@intel.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH v2 3/5] igb: enable rx queue interrupts for PF 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: , X-List-Received-Date: Thu, 12 Feb 2015 10:00:55 -0000 > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Zhou Danny > Sent: Tuesday, February 03, 2015 4:18 PM > To: dev@dpdk.org > Subject: [dpdk-dev] [PATCH v2 3/5] igb: enable rx queue interrupts for PF >=20 > v2 changes > - Consolidate review comments related to coding style >=20 > The patch does below for igb PF: > - Setup NIC to generate MSI-X interrupts > - Set the IVAR register to map interrupt causes to vectors > - Implement interrupt enable/disable functions >=20 > Signed-off-by: Danny Zhou > Tested-by: Yong Liu > --- > lib/librte_pmd_e1000/e1000/e1000_hw.h | 3 + > lib/librte_pmd_e1000/e1000_ethdev.h | 6 + > lib/librte_pmd_e1000/igb_ethdev.c | 230 > ++++++++++++++++++++++++++++++---- > 3 files changed, 214 insertions(+), 25 deletions(-) >=20 > diff --git a/lib/librte_pmd_e1000/e1000/e1000_hw.h > b/lib/librte_pmd_e1000/e1000/e1000_hw.h > index 4dd92a3..9b999ec 100644 > --- a/lib/librte_pmd_e1000/e1000/e1000_hw.h > +++ b/lib/librte_pmd_e1000/e1000/e1000_hw.h > @@ -780,6 +780,9 @@ struct e1000_mac_info { > u16 mta_reg_count; > u16 uta_reg_count; >=20 > + u32 max_rx_queues; > + u32 max_tx_queues; > + [LCM] It can be avoid to define new things in share code. The max_rx/tx_queues in mac info only used by eth_igb_configure_msix_intr()= . It the input param won't be limit to 'hw'. If using rte_eth_dev as input, y= ou can get all the info from dev_info. The risk in share code is, on next time code merging, it won't care the cha= nge here do. > /* Maximum size of the MTA register table in all supported adapters */ > #define MAX_MTA_REG 128 > u32 mta_shadow[MAX_MTA_REG]; > diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h > b/lib/librte_pmd_e1000/e1000_ethdev.h > index d155e77..713ca11 100644 > --- a/lib/librte_pmd_e1000/e1000_ethdev.h > +++ b/lib/librte_pmd_e1000/e1000_ethdev.h > @@ -34,6 +34,8 @@ > #ifndef _E1000_ETHDEV_H_ > #define _E1000_ETHDEV_H_ >=20 > +#include > + > /* need update link, bit flag */ > #define E1000_FLAG_NEED_LINK_UPDATE (uint32_t)(1 << 0) > #define E1000_FLAG_MAILBOX (uint32_t)(1 << 1) > @@ -105,10 +107,14 @@ > #define E1000_FTQF_QUEUE_SHIFT 16 > #define E1000_FTQF_QUEUE_ENABLE 0x00000100 >=20 > +/* maximum number of other interrupts besides Rx & Tx interrupts */ > +#define E1000_MAX_OTHER_INTR 1 > + > /* structure for interrupt relative data */ > struct e1000_interrupt { > uint32_t flags; > uint32_t mask; > + rte_spinlock_t lock; > }; >=20 > /* local vfta copy */ > diff --git a/lib/librte_pmd_e1000/igb_ethdev.c > b/lib/librte_pmd_e1000/igb_ethdev.c > index 2a268b8..7d9b103 100644 > --- a/lib/librte_pmd_e1000/igb_ethdev.c > +++ b/lib/librte_pmd_e1000/igb_ethdev.c > @@ -97,6 +97,7 @@ static int eth_igb_flow_ctrl_get(struct rte_eth_dev *d= ev, > static int eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, > struct rte_eth_fc_conf *fc_conf); > static int eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev); > +static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev); > static int eth_igb_interrupt_get_status(struct rte_eth_dev *dev); > static int eth_igb_interrupt_action(struct rte_eth_dev *dev); > static void eth_igb_interrupt_handler(struct rte_intr_handle *handle, > @@ -191,6 +192,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *d= ev, > enum rte_filter_op filter_op, > void *arg); >=20 > +static int eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_= t > queue_id); > +static int eth_igb_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16= _t > queue_id); > +static void eth_igb_assign_msix_vector(struct e1000_hw *hw, int8_t direc= tion, > + uint8_t queue, uint8_t msix_vector); > +static void eth_igb_configure_msix_intr(struct e1000_hw *hw); > +static void eth_igb_write_ivar(struct e1000_hw *hw, uint8_t msix_vector, > + uint8_t index, uint8_t offset); > + > /* > * Define VF Stats MACRO for Non "cleared on read" register > */ > @@ -250,6 +259,8 @@ static struct eth_dev_ops eth_igb_ops =3D { > .vlan_tpid_set =3D eth_igb_vlan_tpid_set, > .vlan_offload_set =3D eth_igb_vlan_offload_set, > .rx_queue_setup =3D eth_igb_rx_queue_setup, > + .rx_queue_intr_enable =3D eth_igb_rx_queue_intr_enable, > + .rx_queue_intr_disable =3D eth_igb_rx_queue_intr_disable, > .rx_queue_release =3D eth_igb_rx_queue_release, > .rx_queue_count =3D eth_igb_rx_queue_count, > .rx_descriptor_done =3D eth_igb_rx_descriptor_done, > @@ -592,6 +603,16 @@ eth_igb_dev_init(__attribute__((unused)) struct > eth_driver *eth_drv, > eth_dev->data->port_id, pci_dev->id.vendor_id, > pci_dev->id.device_id); >=20 > + /* set max interrupt vfio request */ > + struct rte_eth_dev_info dev_info; > + > + memset(&dev_info, 0, sizeof(dev_info)); > + eth_igb_infos_get(eth_dev, &dev_info); > + > + hw->mac.max_rx_queues =3D dev_info.max_rx_queues; > + > + pci_dev->intr_handle.max_intr =3D hw->mac.max_rx_queues + > E1000_MAX_OTHER_INTR; > + > rte_intr_callback_register(&(pci_dev->intr_handle), > eth_igb_interrupt_handler, (void *)eth_dev); >=20 > @@ -754,7 +775,7 @@ eth_igb_start(struct rte_eth_dev *dev) > { > struct e1000_hw *hw =3D > E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); > - int ret, i, mask; > + int ret, mask; > uint32_t ctrl_ext; >=20 > PMD_INIT_FUNC_TRACE(); > @@ -794,6 +815,9 @@ eth_igb_start(struct rte_eth_dev *dev) > /* configure PF module if SRIOV enabled */ > igb_pf_host_configure(dev); >=20 > + /* confiugre msix for rx interrupt */ > + eth_igb_configure_msix_intr(hw); > + > /* Configure for OS presence */ > igb_init_manageability(hw); >=20 > @@ -821,33 +845,9 @@ eth_igb_start(struct rte_eth_dev *dev) > igb_vmdq_vlan_hw_filter_enable(dev); > } >=20 > - /* > - * Configure the Interrupt Moderation register (EITR) with the maximum > - * possible value (0xFFFF) to minimize "System Partial Write" issued by > - * spurious [DMA] memory updates of RX and TX ring descriptors. > - * > - * With a EITR granularity of 2 microseconds in the 82576, only 7/8 > - * spurious memory updates per second should be expected. > - * ((65535 * 2) / 1000.1000 ~=3D 0.131 second). > - * > - * Because interrupts are not used at all, the MSI-X is not activated > - * and interrupt moderation is controlled by EITR[0]. > - * > - * Note that having [almost] disabled memory updates of RX and TX ring > - * descriptors through the Interrupt Moderation mechanism, memory > - * updates of ring descriptors are now moderated by the configurable > - * value of Write-Back Threshold registers. > - */ > if ((hw->mac.type =3D=3D e1000_82576) || (hw->mac.type =3D=3D e1000_825= 80) > || > (hw->mac.type =3D=3D e1000_i350) || (hw->mac.type =3D=3D e1000_i210) > || > (hw->mac.type =3D=3D e1000_i211)) { > - uint32_t ivar; > - > - /* Enable all RX & TX queues in the IVAR registers */ > - ivar =3D (uint32_t) ((E1000_IVAR_VALID << 16) | > E1000_IVAR_VALID); > - for (i =3D 0; i < 8; i++) > - E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, i, ivar); > - > /* Configure EITR with the maximum possible value (0xFFFF) */ > E1000_WRITE_REG(hw, E1000_EITR(0), 0xFFFF); > } > @@ -901,6 +901,10 @@ eth_igb_start(struct rte_eth_dev *dev) > if (dev->data->dev_conf.intr_conf.lsc !=3D 0) > ret =3D eth_igb_lsc_interrupt_setup(dev); >=20 > + /* check if rxq interrupt is enabled */ > + if (dev->data->dev_conf.intr_conf.rxq !=3D 0) > + eth_igb_rxq_interrupt_setup(dev); > + > /* resume enabled intr since hw reset */ > igb_intr_enable(dev); >=20 > @@ -1791,6 +1795,35 @@ eth_igb_lsc_interrupt_setup(struct rte_eth_dev *de= v) > E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private); >=20 > intr->mask |=3D E1000_ICR_LSC; > + rte_spinlock_init(&(intr->lock)); > + > + return 0; > +} > + > +/* > + * It clears the interrupt causes and enables the interrupt. > + * It will be called once only during nic initialized. > + * > + * @param dev > + * Pointer to struct rte_eth_dev. > + * > + * @return > + * - On success, zero. > + * - On failure, a negative value. > + */ > +static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev) > +{ > + uint32_t mask, regval; > + struct e1000_hw *hw =3D > + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); > + struct rte_eth_dev_info dev_info; > + > + memset(&dev_info, 0, sizeof(dev_info)); > + eth_igb_infos_get(dev, &dev_info); > + > + mask =3D 0xFFFFFFFF >> (32 - dev_info.max_rx_queues); > + regval =3D E1000_READ_REG(hw, E1000_EIMS); > + E1000_WRITE_REG(hw, E1000_EIMS, regval | mask); >=20 > return 0; > } > @@ -3256,5 +3289,152 @@ static struct rte_driver pmd_igbvf_drv =3D { > .init =3D rte_igbvf_pmd_init, > }; >=20 > +static int > +eth_igb_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id= ) > +{ > + struct e1000_hw *hw =3D > + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); > + struct e1000_interrupt *intr =3D > + E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private); > + uint32_t mask =3D 1 << queue_id; > + > + rte_spinlock_lock(&(intr->lock)); > + E1000_WRITE_REG(hw, E1000_EIMC, mask); > + E1000_WRITE_FLUSH(hw); > + rte_spinlock_unlock(&(intr->lock)); > + > + return 0; > +} > + > +static int > +eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id) > +{ > + struct e1000_hw *hw =3D > + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); > + struct e1000_interrupt *intr =3D > + E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private); > + uint32_t mask =3D 1 << queue_id; > + uint32_t regval; > + > + rte_spinlock_lock(&(intr->lock)); > + regval =3D E1000_READ_REG(hw, E1000_EIMS); > + E1000_WRITE_REG(hw, E1000_EIMS, regval | mask); > + E1000_WRITE_FLUSH(hw); > + rte_spinlock_unlock(&(intr->lock)); > + > + return 0; > +} > + > +static void > +eth_igb_write_ivar(struct e1000_hw *hw, uint8_t msix_vector, > + uint8_t index, uint8_t offset) > +{ > + uint32_t val =3D E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); > + > + /* clear bits */ > + val &=3D ~((uint32_t)0xFF << offset); > + > + /* write vector and valid bit */ > + val |=3D (msix_vector | E1000_IVAR_VALID) << offset; > + > + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, val); > +} > + > +static void > +eth_igb_assign_msix_vector(struct e1000_hw *hw, int8_t direction, > + uint8_t queue, uint8_t msix_vector) > +{ > + uint32_t tmp =3D 0; > + if (hw->mac.type =3D=3D e1000_82575) { > + if (direction =3D=3D 0) > + tmp =3D E1000_EICR_RX_QUEUE0 << queue; > + else if (direction =3D=3D 1) > + tmp =3D E1000_EICR_TX_QUEUE0 << queue; > + E1000_WRITE_REG(hw, E1000_MSIXBM(msix_vector), tmp); > + } else if (hw->mac.type =3D=3D e1000_82576) { > + if ((direction =3D=3D 0) || (direction =3D=3D 1)) > + eth_igb_write_ivar(hw, msix_vector, queue & 0x7, > + ((queue & 0x8) << 1) + 8 * direction); > + } else if ((hw->mac.type =3D=3D e1000_82580) || > + (hw->mac.type =3D=3D e1000_i350) || > + (hw->mac.type =3D=3D e1000_i354) || > + (hw->mac.type =3D=3D e1000_i210) || > + (hw->mac.type =3D=3D e1000_i211)) { > + if ((direction =3D=3D 0) || (direction =3D=3D 1)) > + eth_igb_write_ivar(hw, msix_vector, > + queue >> 1, > + ((queue & 0x1) << 4) + 8 * direction); > + } > +} > + > +/* > + * Sets up the hardware to generate MSI-X interrupts properly > + * @hw > + * board private structure > + */ > +static void > +eth_igb_configure_msix_intr(struct e1000_hw *hw) > +{ > + int queue_id; > + uint32_t tmpval, regval, intr_mask; > + uint32_t max_rx_queues =3D hw->mac.max_rx_queues; > + > + /* set interrupt vector for other causes */ > + if (hw->mac.type =3D=3D e1000_82575) { > + tmpval =3D E1000_READ_REG(hw, E1000_CTRL_EXT); > + /* enable MSI-X PBA support */ > + tmpval |=3D E1000_CTRL_EXT_PBA_CLR; > + > + /* Auto-Mask interrupts upon ICR read */ > + tmpval |=3D E1000_CTRL_EXT_EIAME; > + tmpval |=3D E1000_CTRL_EXT_IRCA; > + > + E1000_WRITE_REG(hw, E1000_CTRL_EXT, tmpval); > + > + /* enable msix_other interrupt */ > + E1000_WRITE_REG_ARRAY(hw, E1000_MSIXBM(0), 0, > E1000_EIMS_OTHER); > + regval =3D E1000_READ_REG(hw, E1000_EIAC); > + E1000_WRITE_REG(hw, E1000_EIAC, regval | > E1000_EIMS_OTHER); > + regval =3D E1000_READ_REG(hw, E1000_EIAM); > + E1000_WRITE_REG(hw, E1000_EIMS, regval | > E1000_EIMS_OTHER); > + } else if ((hw->mac.type =3D=3D e1000_82576) || > + (hw->mac.type =3D=3D e1000_82580) || > + (hw->mac.type =3D=3D e1000_i350) || > + (hw->mac.type =3D=3D e1000_i354) || > + (hw->mac.type =3D=3D e1000_i210) || > + (hw->mac.type =3D=3D e1000_i211)) { > + /* turn on MSI-X capability first */ > + E1000_WRITE_REG(hw, E1000_GPIE, E1000_GPIE_MSIX_MODE | > + E1000_GPIE_PBA | > E1000_GPIE_EIAME | > + E1000_GPIE_NSICR); > + > + /* enable msix_other interrupt */ > + intr_mask =3D 1 << max_rx_queues; > + regval =3D E1000_READ_REG(hw, E1000_EIAC); > + E1000_WRITE_REG(hw, E1000_EIAC, regval | intr_mask); > + regval =3D E1000_READ_REG(hw, E1000_EIMS); > + E1000_WRITE_REG(hw, E1000_EIMS, regval | intr_mask); > + tmpval =3D (max_rx_queues | E1000_IVAR_VALID) << 8; > + > + E1000_WRITE_REG(hw, E1000_IVAR_MISC, tmpval); > + } > + > + /* > + * use EIAM and EIAC to auto-mask and auto-clear when MSI-X interrupt > is asserted > + * this saves a register write for every interrupt > + */ > + intr_mask =3D 0xFFFFFFFF >> (32 - max_rx_queues); > + regval =3D E1000_READ_REG(hw, E1000_EIAC); > + E1000_WRITE_REG(hw, E1000_EIAC, regval | intr_mask); > + regval =3D E1000_READ_REG(hw, E1000_EIAM); > + E1000_WRITE_REG(hw, E1000_EIAM, regval | intr_mask); > + > + for (queue_id =3D 0; queue_id < VFIO_MAX_QUEUE_ID; queue_id++) > + eth_igb_assign_msix_vector(hw, 0, queue_id, queue_id); > + > + E1000_WRITE_FLUSH(hw); > +} > + > + > PMD_REGISTER_DRIVER(pmd_igb_drv); > PMD_REGISTER_DRIVER(pmd_igbvf_drv); > -- > 1.8.1.4