Discussion:
[dpdk-dev] [PATCH v1 00/11] interrupt mode for i40e
(too old to reply)
Cunming Liang
2015-09-24 05:33:40 UTC
Permalink
This patch series contains four major parts.

1. always reserve vector zero for misc cause in vfio mapping
2. add api to declare the capability of multiple interrupt vector support
3. fix the rx interrupt compatible issue with mbox in ixgbe/igb IOV-PF
4. add rx interrupt support in i40e PF and VF

Cunming Liang (11):
eal/linux: vfio map misc intr to vector zero
ixgbe: reserve intr vector zero for misc cause
igb: reserve intr vector zero for misc cause
eal/linux: not allow to enable zero intr efd
eal/linux: add intr api to report multi-vector capability
ixgbe: fix rx intr compatible issue with PF mbox
ixgbevf: cleanup unnecessary interrupt handler
igb: fix rx intr compatible issue with PF mbox
i40e: add rx interrupt support
i40evf: add rx interrupt support
doc: release note update for intr mode

doc/guides/rel_notes/release_2_2.rst | 2 +
drivers/net/e1000/igb_ethdev.c | 63 ++--
drivers/net/i40e/i40e_ethdev.c | 359 +++++++++++++++++----
drivers/net/i40e/i40e_ethdev.h | 17 +
drivers/net/i40e/i40e_ethdev_vf.c | 141 +++++++-
drivers/net/i40e/i40e_pf.c | 7 +-
drivers/net/ixgbe/ixgbe_ethdev.c | 144 +++------
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 3 +-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 35 +-
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 16 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +
11 files changed, 597 insertions(+), 197 deletions(-)
--
2.4.3
Cunming Liang
2015-09-24 05:33:41 UTC
Permalink
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve the first vector to misc interrupt.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 18 ++++++++++++------
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 3 +++
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 078318c..8e76a7a 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -300,8 +300,10 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
irq_set->start = 0;
fd_ptr = (int *) &irq_set->data;
- memcpy(fd_ptr, intr_handle->efds, sizeof(intr_handle->efds));
- fd_ptr[intr_handle->max_intr - 1] = intr_handle->fd;
+ fd_ptr[MISC_VEC_ID] = intr_handle->fd;
+ /* follow up with misc(0) interrupt */
+ memcpy(&fd_ptr[RX_VEC_START], intr_handle->efds,
+ sizeof(*intr_handle->efds) * intr_handle->nb_efd);

ret = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);

@@ -1068,10 +1070,13 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
struct rte_epoll_event *rev;
struct rte_epoll_data *epdata;
int epfd_op;
+ unsigned int efd_idx;
int rc = 0;

+ efd_idx = (vec >= RX_VEC_START) ? (vec - RX_VEC_START) : vec;
+
if (!intr_handle || intr_handle->nb_efd == 0 ||
- vec >= intr_handle->nb_efd) {
+ efd_idx >= intr_handle->nb_efd) {
RTE_LOG(ERR, EAL, "Wrong intr vector number.\n");
return -EPERM;
}
@@ -1079,7 +1084,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
switch (op) {
case RTE_INTR_EVENT_ADD:
epfd_op = EPOLL_CTL_ADD;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status != RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event already been added.\n");
return -EEXIST;
@@ -1091,7 +1096,8 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
epdata->data = data;
epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
epdata->cb_arg = (void *)intr_handle;
- rc = rte_epoll_ctl(epfd, epfd_op, intr_handle->efds[vec], rev);
+ rc = rte_epoll_ctl(epfd, epfd_op,
+ intr_handle->efds[efd_idx], rev);
if (!rc)
RTE_LOG(DEBUG, EAL,
"efd %d associated with vec %d added on epfd %d"
@@ -1101,7 +1107,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
break;
case RTE_INTR_EVENT_DEL:
epfd_op = EPOLL_CTL_DEL;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status == RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event does not exist.\n");
return -EPERM;
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 45071b7..b8fd318 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -77,6 +77,9 @@ struct rte_epoll_event {
struct rte_epoll_data epdata;
};

+#define MISC_VEC_ID (0)
+#define RX_VEC_START (MISC_VEC_ID + 1)
+
/** Handle for interrupts. */
struct rte_intr_handle {
union {
--
2.4.3
Cunming Liang
2015-09-24 05:33:42 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index ec2918c..dbc0cd4 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -4249,7 +4249,8 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint32_t queue_id, vec = 0;
+ uint32_t queue_id, base = MISC_VEC_ID;
+ uint32_t vec = MISC_VEC_ID;
uint32_t mask;
uint32_t gpie;

@@ -4259,6 +4260,9 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
if (!rte_intr_dp_is_en(intr_handle))
return;

+ if (rte_intr_allow_others(intr_handle))
+ vec = base = RX_VEC_START;
+
/* setup GPIE for MSI-x mode */
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
gpie |= IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_PBA_SUPPORT |
@@ -4282,23 +4286,23 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
/* by default, 1:1 mapping */
ixgbe_set_ivar_map(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++;
}

switch (hw->mac.type) {
case ixgbe_mac_82598EB:
ixgbe_set_ivar_map(hw, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
- intr_handle->max_intr - 1);
+ MISC_VEC_ID);
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- ixgbe_set_ivar_map(hw, -1, 1, intr_handle->max_intr - 1);
+ ixgbe_set_ivar_map(hw, -1, 1, MISC_VEC_ID);
break;
default:
break;
}
- IXGBE_WRITE_REG(hw, IXGBE_EITR(queue_id),
+ IXGBE_WRITE_REG(hw, IXGBE_EITR(MISC_VEC_ID),
IXGBE_MIN_INTER_INTERRUPT_INTERVAL_DEFAULT & 0xFFF);

/* set up to autoclear timer, and the vectors */
--
2.4.3
Cunming Liang
2015-09-24 05:33:43 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/igb_ethdev.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 848ef6e..03400f4 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -4210,7 +4210,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 = MISC_VEC_ID;
+ uint32_t base = 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
@@ -4219,6 +4222,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 = 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);
@@ -4247,8 +4255,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);

@@ -4262,14 +4270,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++;
}
--
2.4.3
Cunming Liang
2015-09-24 05:33:44 UTC
Permalink
The patch adds condition check to avoid enable nothing.
In disable state, both max_intr and nb_efd are zero.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 8 +++++++-
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 88d4ae1..cd8817d 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -82,8 +82,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 8e76a7a..96226d6 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -45,6 +45,7 @@
#include <sys/signalfd.h>
#include <sys/ioctl.h>
#include <sys/eventfd.h>
+#include <assert.h>

#include <rte_common.h>
#include <rte_interrupts.h>
@@ -1132,6 +1133,8 @@ rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
int fd;
uint32_t n = RTE_MIN(nb_efd, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);

+ assert(nb_efd != 0);
+
if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX) {
for (i = 0; i < n; i++) {
fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
@@ -1188,5 +1191,8 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle)
{
- return !!(intr_handle->max_intr - intr_handle->nb_efd);
+ if (!rte_intr_dp_is_en(intr_handle))
+ return 1;
+ else
+ return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index b8fd318..6a2f495 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -176,8 +176,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
--
2.4.3
Cunming Liang
2015-09-24 05:33:45 UTC
Permalink
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 9 +++++++++
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++
3 files changed, 26 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 96226d6..c90bc4d 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -1196,3 +1196,12 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle)
else
return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
+
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
+{
+ if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX)
+ return 1;
+
+ return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 6a2f495..a7b2be4 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -215,4 +215,14 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle);
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle);

+/**
+ * The multiple interrupt vector capability of interrupt handle instance.
+ * It returns zero if no multiple interrupt vector support.
+ *
+ * @param intr_handle
+ * Pointer to the interrupt handle.
+ */
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);
+
#endif /* _RTE_LINUXAPP_INTERRUPTS_H_ */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index dbb8fa1..cb9f4d6 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -128,3 +128,10 @@ DPDK_2.1 {
rte_memzone_free;

} DPDK_2.0;
+
+DPDK_2.2 {
+ global:
+
+ rte_intr_cap_multiple;
+
+} DPDK_2.1;
\ No newline at end of file
--
2.4.3
Cunming Liang
2015-09-24 05:33:46 UTC
Permalink
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 45 +++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index dbc0cd4..f180d75 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1028,6 +1028,13 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&(pci_dev->intr_handle),
+ ixgbe_dev_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&(pci_dev->intr_handle));
+
/* enable support intr */
ixgbe_enable_intr(eth_dev);

@@ -1704,17 +1711,19 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_pf_host_configure(dev);

/* check and configure queue intr-vector mapping */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
- dev->data->nb_rx_queues * sizeof(int),
- 0);
+ dev->data->nb_rx_queues * sizeof(int), 0);
if (intr_handle->intr_vec == NULL) {
PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
" intr_vec\n", dev->data->nb_rx_queues);
@@ -1801,20 +1810,22 @@ ixgbe_dev_start(struct rte_eth_dev *dev)

skip_link_setup:

- /* check if lsc interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- ixgbe_dev_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
ixgbe_dev_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
ixgbe_dev_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -1926,6 +1937,12 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
memset(filter_info->fivetuple_mask, 0,
sizeof(uint32_t) * IXGBE_5TUPLE_ARRAY_SIZE);

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
David Marchand
2015-11-02 16:03:29 UTC
Permalink
Post by Cunming Liang
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during
'dev_init' is required.
Can you describe the cases/situations where you would want a device to
handle interrupts while not started ?


Thanks.
--
David Marchand
Ananyev, Konstantin
2015-11-02 16:09:27 UTC
Permalink
-----Original Message-----
Sent: Monday, November 02, 2015 4:03 PM
To: Liang, Cunming
Subject: Re: [dpdk-dev] [PATCH v1 06/11] ixgbe: fix rx intr compatible issue with PF mbox
Post by Cunming Liang
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during
'dev_init' is required.
Can you describe the cases/situations where you would want a device to
handle interrupts while not started ?
When PF and VF are both controlled by DPDK process(es).
And user doesn't really want to do any RX/TX through PF - uses PF just to control/configure VF
David Marchand
2015-11-02 16:22:24 UTC
Permalink
On Mon, Nov 2, 2015 at 5:09 PM, Ananyev, Konstantin <
Post by Cunming Liang
-----Original Message-----
Sent: Monday, November 02, 2015 4:03 PM
To: Liang, Cunming
Subject: Re: [dpdk-dev] [PATCH v1 06/11] ixgbe: fix rx intr compatible
issue with PF mbox
Post by Cunming Liang
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF
start
Post by Cunming Liang
normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register
during
Post by Cunming Liang
'dev_init' is required.
Can you describe the cases/situations where you would want a device to
handle interrupts while not started ?
When PF and VF are both controlled by DPDK process(es).
And user doesn't really want to do any RX/TX through PF - uses PF just to
control/configure VF(s).
Ok, but the user still needs to whitelist the PF (or ensure the PF is not
blacklisted) in one of these processes.
Then, the application would do a "partial" initialisation ?
If you don't want rx/tx, don't poll the port.

Anyway, this is your code :-)
--
David Marchand
Ananyev, Konstantin
2015-11-02 16:41:32 UTC
Permalink
Sent: Monday, November 02, 2015 4:22 PM
To: Ananyev, Konstantin
Subject: Re: [dpdk-dev] [PATCH v1 06/11] ixgbe: fix rx intr compatible issue with PF mbox
-----Original Message-----
Sent: Monday, November 02, 2015 4:03 PM
To: Liang, Cunming
Subject: Re: [dpdk-dev] [PATCH v1 06/11] ixgbe: fix rx intr compatible issue with PF mbox
Post by Cunming Liang
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during
'dev_init' is required.
Can you describe the cases/situations where you would want a device to
handle interrupts while not started ?
When PF and VF are both controlled by DPDK process(es).
And user doesn't really want to do any RX/TX through PF - uses PF just to control/configure VF(s).
Ok, but the user still needs to whitelist the PF (or ensure the PF is not blacklisted) in one of these processes.
Yes, at least dev_init() need to be called for that device.
Then, the application would do a "partial" initialisation ?
Yep, sort of.
If you don't want rx/tx, don't poll the port.
Well, the question is why to add an extra restriction here?
Probably user deliberately doesn't want to call dev_start() for PF device -
as he doesn't plan to use it for RX/TX.
Or might be dev_stop() was called just to do some re-configuration
(allow to TX scattered packets on the PF queues or so).
Or dev_start() for PF has not yet been called.
Why VF should stop working properly because of that?
Konstantin
Anyway, this is your code :-)
--
David Marchand
2015-11-02 17:06:20 UTC
Permalink
On Mon, Nov 2, 2015 at 5:41 PM, Ananyev, Konstantin <
Post by Ananyev, Konstantin
Post by David Marchand
If you don't want rx/tx, don't poll the port.
Well, the question is why to add an extra restriction here?
Well, until I start a port, I would expect it to do nothing.

Probably user deliberately doesn't want to call dev_start() for PF device -
Post by Ananyev, Konstantin
as he doesn't plan to use it for RX/TX.
Or might be dev_stop() was called just to do some re-configuration
(allow to TX scattered packets on the PF queues or so).
Or dev_start() for PF has not yet been called.
Why VF should stop working properly because of that?
Why not.
--
David Marchand
Ananyev, Konstantin
2015-11-02 17:23:23 UTC
Permalink
Post by David Marchand
Post by Ananyev, Konstantin
Post by David Marchand
If you don't want rx/tx, don't poll the port.
Well, the question is why to add an extra restriction here?
Well, until I start a port, I would expect it to do nothing.
Post by Ananyev, Konstantin
Probably user deliberately doesn't want to call dev_start() for PF device -
as he doesn't plan to use it for RX/TX.
Or might be dev_stop() was called just to do some re-configuration
(allow to TX scattered packets on the PF queues or so).
Or dev_start() for PF has not yet been called.
Why VF should stop working properly because of that?
Why not.
I thought I explained it above.
Basically it means that you can't stop your PF without forcing to stop all VFs first.
And you can't start any of your VFs without starting PF first.
I think that adds an unnecessary restrictions and limits systems availability quite significantly.
Konstantin
David Marchand
2015-11-02 17:45:58 UTC
Permalink
Post by Ananyev, Konstantin
Post by David Marchand
Post by Ananyev, Konstantin
Probably user deliberately doesn't want to call dev_start() for PF device -
as he doesn't plan to use it for RX/TX.
Or might be dev_stop() was called just to do some re-configuration
(allow to TX scattered packets on the PF queues or so).
Or dev_start() for PF has not yet been called.
Why VF should stop working properly because of that?
Why not.
I thought I explained it above.
Sorry wrong choice of words with this "Why not".
I agree with you for this case.
--
David Marchand
Cunming Liang
2015-09-24 05:33:47 UTC
Permalink
As ixgbe vf doesn't support lsc, the patch removes those unused code.
In addition, it does some tiny cleanup.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 85 +++++-----------------------------------
1 file changed, 10 insertions(+), 75 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index f180d75..1d46320 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -206,8 +206,6 @@ static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_conf
/* For Virtual Function support */
static int eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev);
static int eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev);
-static int ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev);
-static int ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev);
static int ixgbevf_dev_configure(struct rte_eth_dev *dev);
static int ixgbevf_dev_start(struct rte_eth_dev *dev);
static void ixgbevf_dev_stop(struct rte_eth_dev *dev);
@@ -223,8 +221,6 @@ 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);
-static void ixgbevf_dev_interrupt_handler(struct rte_intr_handle *handle,
- void *param);
static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
uint16_t queue_id);
static int ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
@@ -2670,30 +2666,6 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev)
-{
- uint32_t eicr;
- struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct ixgbe_interrupt *intr =
- IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-
- /* clear all cause mask */
- ixgbevf_intr_disable(hw);
-
- /* read-on-clear nic registers here */
- eicr = IXGBE_READ_REG(hw, IXGBE_VTEICR);
- PMD_DRV_LOG(INFO, "eicr %x", eicr);
-
- intr->flags = 0;
-
- /* set flag for async link update */
- if (eicr & IXGBE_EICR_LSC)
- intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-
- return 0;
-}
-
/**
* It gets and then prints the link status.
*
@@ -2789,18 +2761,6 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev)
-{
- struct ixgbe_hw *hw =
- IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
- PMD_DRV_LOG(DEBUG, "enable intr immediately");
- ixgbevf_intr_enable(hw);
- rte_intr_enable(&dev->pci_dev->intr_handle);
- return 0;
-}
-
/**
* Interrupt handler which shall be registered for alarm callback for delayed
* handling specific interrupt to wait for the stable nic state. As the
@@ -2863,16 +2823,6 @@ ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
ixgbe_dev_interrupt_action(dev);
}

-static void
-ixgbevf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
- void *param)
-{
- struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-
- ixgbevf_dev_interrupt_get_status(dev);
- ixgbevf_dev_interrupt_action(dev);
-}
-
static int
ixgbe_dev_led_on(struct rte_eth_dev *dev)
{
@@ -3466,11 +3416,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
ixgbevf_dev_rxtx_start(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) {
intr_handle->intr_vec =
@@ -3484,16 +3434,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
}
ixgbevf_configure_msix(dev);

- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle))
- rte_intr_callback_register(intr_handle,
- ixgbevf_dev_interrupt_handler,
- (void *)dev);
- else
- PMD_INIT_LOG(INFO, "lsc won't enable because of"
- " no intr multiplex\n");
- }
-
rte_intr_enable(intr_handle);

/* Re-enable interrupt for VF */
@@ -3539,7 +3479,6 @@ static void
ixgbevf_dev_close(struct rte_eth_dev *dev)
{
struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev;

PMD_INIT_FUNC_TRACE();

@@ -3551,12 +3490,6 @@ ixgbevf_dev_close(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);
-
- pci_dev = dev->pci_dev;
- if (pci_dev->intr_handle.intr_vec) {
- rte_free(pci_dev->intr_handle.intr_vec);
- pci_dev->intr_handle.intr_vec = NULL;
- }
}

static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
@@ -4082,7 +4015,8 @@ ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask |= (1 << queue_id);
+ mask |= (1 << MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

rte_intr_enable(&dev->pci_dev->intr_handle);
@@ -4098,7 +4032,8 @@ ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask &= ~(1 << queue_id);
+ mask &= ~(1 << MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

return 0;
@@ -4234,7 +4169,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
uint32_t q_idx;
- uint32_t vector_idx = 0;
+ uint32_t vector_idx = MISC_VEC_ID;

/* won't configure msix register if no mapping is done
* between intr vector and event fd.
@@ -4251,7 +4186,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
intr_handle->intr_vec[q_idx] = vector_idx;
}

- /* Configure VF Rx queue ivar */
+ /* Configure VF other cause ivar */
ixgbevf_set_ivar_map(hw, -1, 1, vector_idx);
}
--
2.4.3
Cunming Liang
2015-09-24 05:33:48 UTC
Permalink
When igb runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/igb_ethdev.c | 44 +++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 03400f4..967506c 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -651,6 +651,13 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&(pci_dev->intr_handle),
+ eth_igb_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&(pci_dev->intr_handle));
+
/* enable support intr */
igb_intr_enable(eth_dev);

@@ -929,13 +936,16 @@ 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 (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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)) {
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
dev->data->nb_rx_queues * sizeof(int), 0);
@@ -1028,20 +1038,22 @@ eth_igb_start(struct rte_eth_dev *dev)
}
e1000_setup_link(hw);

- /* check if lsc interrupt feature is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- eth_igb_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
eth_igb_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
eth_igb_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -1134,6 +1146,12 @@ eth_igb_stop(struct rte_eth_dev *dev)
}
filter_info->twotuple_mask = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-09-24 05:33:49 UTC
Permalink
The patch enables rx interrupt support on i40e PF non-IOV mode.
Per queue rx interrupt works on vfio, however on uio, all rx queues share one interrupt vector.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 319 +++++++++++++++++++++++++++++++++++------
drivers/net/i40e/i40e_ethdev.h | 2 +
drivers/net/i40e/i40e_pf.c | 2 +
3 files changed, 282 insertions(+), 41 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2dd9fdc..33b5296 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -39,6 +39,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <inttypes.h>
+#include <assert.h>

#include <rte_string_fns.h>
#include <rte_pci.h>
@@ -174,7 +175,7 @@ static void i40e_stat_update_48(struct i40e_hw *hw,
bool offset_loaded,
uint64_t *offset,
uint64_t *stat);
-static void i40e_pf_config_irq0(struct i40e_hw *hw);
+static void i40e_pf_config_irq0(struct i40e_hw *hw, int no_queue);
static void i40e_dev_interrupt_handler(
__rte_unused struct rte_intr_handle *handle, void *param);
static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
@@ -232,6 +233,10 @@ static int i40e_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
uint32_t flags);
static int i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
struct timespec *timestamp);
+static int i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
+ uint16_t queue_id);
+static int i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
+ uint16_t queue_id);

static const struct rte_pci_id pci_id_i40e_map[] = {
#define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -265,6 +270,10 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
.tx_queue_start = i40e_dev_tx_queue_start,
.tx_queue_stop = i40e_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
+#ifdef RTE_NEXT_ABI
+ .rx_queue_intr_enable = i40e_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40e_dev_rx_queue_intr_disable,
+#endif
.rx_queue_release = i40e_dev_rx_queue_release,
.rx_queue_count = i40e_dev_rx_queue_count,
.rx_descriptor_done = i40e_dev_rx_descriptor_done,
@@ -579,7 +588,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
i40e_dev_interrupt_handler, (void *)dev);

/* configure and enable device interrupt */
- i40e_pf_config_irq0(hw);
+ i40e_pf_config_irq0(hw, 1);
i40e_pf_enable_irq0(hw);

/* enable uio intr after callback register */
@@ -718,6 +727,8 @@ err:
void
i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t msix_vect = vsi->msix_intr;
uint16_t i;
@@ -729,15 +740,26 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
}

if (vsi->type != I40E_VSI_SRIOV) {
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1), 0);
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), 0);
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ 0);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1), 0);
+ }
} else {
uint32_t reg;
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), 0);
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
}
I40E_WRITE_FLUSH(hw);
}
@@ -752,29 +774,26 @@ i40e_calc_itr_interval(int16_t interval)
return (interval/2);
}

-void
-i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+static void
+__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
+ int base_queue, int nb_queue)
{
+ int i;
uint32_t val;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
- uint16_t msix_vect = vsi->msix_intr;
- int i;
-
- for (i = 0; i < vsi->nb_qps; i++)
- I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);

/* Bind all RX queues to allocated MSIX interrupt */
- for (i = 0; i < vsi->nb_qps; i++) {
+ for (i = 0; i < nb_queue; i++) {
val = (msix_vect << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
I40E_QINT_RQCTL_ITR_INDX_MASK |
- ((vsi->base_queue + i + 1) <<
- I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+ ((base_queue + i + 1) <<
+ I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
(0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
I40E_QINT_RQCTL_CAUSE_ENA_MASK;

- if (i == vsi->nb_qps - 1)
+ if (i == nb_queue - 1)
val |= I40E_QINT_RQCTL_NEXTQ_INDX_MASK;
- I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), val);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(base_queue + i), val);
}

/* Write first RX queue to Link list register as the head element */
@@ -782,13 +801,26 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
uint16_t interval =
i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);

- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
- (vsi->base_queue <<
- I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
-
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), interval);
+ if (msix_vect == MISC_VEC_ID) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ (base_queue <<
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ interval);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ (base_queue <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1),
+ interval);
+ }

#ifndef I40E_GLINT_CTL
#define I40E_GLINT_CTL 0x0003F800
@@ -796,7 +828,7 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
#endif
/* Disable auto-mask on enabling of all none-zero interrupt */
I40E_WRITE_REG(hw, I40E_GLINT_CTL,
- I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK);
+ I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK);
} else {
uint32_t reg;

@@ -804,34 +836,117 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (vsi->base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
(0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
}

I40E_WRITE_FLUSH(hw);
}

+void
+i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_vect = vsi->msix_intr;
+ uint16_t nb_msix = RTE_MIN(vsi->nb_msix, intr_handle->nb_efd);
+ uint16_t queue_idx = 0;
+ int record = 0;
+ int i;
+
+ for (i = 0; i < vsi->nb_qps; i++) {
+ I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
+ }
+
+ if (rte_intr_dp_is_en(intr_handle)) {
+ if (vsi->type == I40E_VSI_MAIN) {
+ queue_idx = 0;
+ record = 1;
+ } else if (vsi->type == I40E_VSI_VMDQ2) {
+ struct i40e_vsi *main_vsi =
+ I40E_DEV_PRIVATE_TO_MAIN_VSI(vsi->adapter);
+ queue_idx = vsi->base_queue - main_vsi->nb_qps;
+ record = 1;
+ }
+ }
+
+ for (i = 0; i < vsi->nb_used_qps; i++) {
+ if (nb_msix <= 1) {
+ if (!rte_intr_allow_others(intr_handle))
+ /* allow to share MISC_VEC_ID */
+ msix_vect = MISC_VEC_ID;
+
+ /* no enough msix_vect, map all to one */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i,
+ vsi->nb_used_qps - i);
+ for (; !!record && i < vsi->nb_used_qps; i++)
+ intr_handle->intr_vec[queue_idx + i] =
+ msix_vect;
+ break;
+ }
+ /* 1:1 queue/msix_vect mapping */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i, 1);
+ if (!!record)
+ intr_handle->intr_vec[queue_idx + i] = msix_vect;
+
+ msix_vect++;
+ nb_msix--;
+ }
+}
+
static void
i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t interval = i40e_calc_itr_interval(\
- RTE_LIBRTE_I40E_ITR_INTERVAL);
+ RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr, i;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTL0_INTENA_MASK |
+ I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT));
+ return;
+ }

- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1),
- I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
- (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
- (interval << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ }
}

static void
i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_intr, i;

- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1), 0);
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+ return;
+ }
+
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1), 0);
+ }
}

static inline uint8_t
@@ -941,6 +1056,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
int ret, i;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t intr_vector = 0;

hw->adapter_stopped = 0;

@@ -952,6 +1069,29 @@ i40e_dev_start(struct rte_eth_dev *dev)
return -EINVAL;
}

+ rte_intr_disable(intr_handle);
+
+ if (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int),
+ 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
/* Initialize VSI */
ret = i40e_dev_rxtx_init(pf);
if (ret != I40E_SUCCESS) {
@@ -960,11 +1100,14 @@ i40e_dev_start(struct rte_eth_dev *dev)
}

/* Map queues with MSIX interrupt */
+ main_vsi->nb_used_qps = dev->data->nb_rx_queues -
+ pf->nb_cfg_vmdq_vsi * RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(main_vsi);
i40e_vsi_enable_queues_intr(main_vsi);

/* Map VMDQ VSI queues with MSIX interrupt */
for (i = 0; i < pf->nb_cfg_vmdq_vsi; i++) {
+ pf->vmdq[i].vsi->nb_used_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(pf->vmdq[i].vsi);
i40e_vsi_enable_queues_intr(pf->vmdq[i].vsi);
}
@@ -1001,6 +1144,22 @@ i40e_dev_start(struct rte_eth_dev *dev)
goto err_up;
}

+ if (!rte_intr_allow_others(intr_handle)) {
+ rte_intr_callback_unregister(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+ /* configure and enable device interrupt */
+ i40e_pf_config_irq0(hw, 0);
+ i40e_pf_enable_irq0(hw);
+
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
+ PMD_INIT_LOG(INFO, "lsc won't enable because of"
+ " no intr multiplex\n");
+ }
+
+ /* enable uio intr after callback register */
+ rte_intr_enable(intr_handle);
+
return I40E_SUCCESS;

err_up:
@@ -1016,6 +1175,7 @@ i40e_dev_stop(struct rte_eth_dev *dev)
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
struct i40e_mirror_rule *p_mirror;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
int i;

/* Disable all queues */
@@ -1047,6 +1207,18 @@ i40e_dev_stop(struct rte_eth_dev *dev)
}
pf->nb_mirror_rule = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static void
@@ -3073,15 +3245,30 @@ i40e_vsi_setup(struct i40e_pf *pf,
vsi->base_queue = I40E_FDIR_QUEUE_ID;

/* VF has MSIX interrupt in VF range, don't allocate here */
- if (type != I40E_VSI_SRIOV) {
+ if (type == I40E_VSI_MAIN) {
+ ret = i40e_res_pool_alloc(&pf->msix_pool,
+ RTE_MIN(vsi->nb_qps,
+ RTE_MAX_RXTX_INTR_VEC_ID));
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "VSI MAIN %d get heap failed %d",
+ vsi->seid, ret);
+ goto fail_queue_alloc;
+ }
+ vsi->msix_intr = ret;
+ vsi->nb_msix = RTE_MIN(vsi->nb_qps, RTE_MAX_RXTX_INTR_VEC_ID);
+ } else if (type != I40E_VSI_SRIOV) {
ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
if (ret < 0) {
PMD_DRV_LOG(ERR, "VSI %d get heap failed %d", vsi->seid, ret);
goto fail_queue_alloc;
}
vsi->msix_intr = ret;
- } else
+ vsi->nb_msix = 1;
+ } else {
vsi->msix_intr = 0;
+ vsi->nb_msix = 0;
+ }
+
/* Add VSI */
if (type == I40E_VSI_MAIN) {
/* For main VSI, no need to add since it's default one */
@@ -3919,7 +4106,7 @@ i40e_pf_enable_irq0(struct i40e_hw *hw)
}

static void
-i40e_pf_config_irq0(struct i40e_hw *hw)
+i40e_pf_config_irq0(struct i40e_hw *hw, int no_queue)
{
/* read pending request and disable first */
i40e_pf_disable_irq0(hw);
@@ -3927,9 +4114,10 @@ i40e_pf_config_irq0(struct i40e_hw *hw)
I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0,
I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK);

- /* Link no queues with irq0 */
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
- I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ if (no_queue)
+ /* Link no queues with irq0 */
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
}

static void
@@ -6298,3 +6486,52 @@ i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev,

return 0;
}
+
+static int
+i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr - RX_VEC_START),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr - RX_VEC_START),
+ 0);
+
+ return 0;
+}
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 6185657..727ee2d 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -235,6 +235,7 @@ struct i40e_vsi {
uint16_t seid; /* The seid of VSI itself */
uint16_t uplink_seid; /* The uplink seid of this VSI */
uint16_t nb_qps; /* Number of queue pairs VSI can occupy */
+ uint16_t nb_used_qps; /* Number of queue pairs VSI uses */
uint16_t max_macaddrs; /* Maximum number of MAC addresses */
uint16_t base_queue; /* The first queue index of this VSI */
/*
@@ -243,6 +244,7 @@ struct i40e_vsi {
*/
uint16_t vsi_id;
uint16_t msix_intr; /* The MSIX interrupt binds to VSI */
+ uint16_t nb_msix; /* The max number of msix vector */
uint8_t enabled_tc; /* The traffic class enabled */
};

diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 95c960c..c1d58a8 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -554,6 +554,8 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
}
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
+ vf->vsi->nb_msix = irqmap->num_vectors;
+ vf->vsi->nb_used_qps = vf->vsi->nb_qps;

/* Don't care how the TX/RX queue mapping with this vector.
* Link all VF RX queues together. Only did mapping work.
--
2.4.3
Cunming Liang
2015-09-24 05:33:50 UTC
Permalink
The patch enables rx interrupt support on i40e VF and some necessary change on PF IOV mode to support VF.
On PF side, running in IOV mode via uio won't allow rx interrupt which is exclusive with mbox interrupt
in single vector competition.
On VF side, one single vector is shared for all the rx queues.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 46 +++++++------
drivers/net/i40e/i40e_ethdev.h | 15 ++++
drivers/net/i40e/i40e_ethdev_vf.c | 141 ++++++++++++++++++++++++++++++++++----
drivers/net/i40e/i40e_pf.c | 5 --
4 files changed, 169 insertions(+), 38 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 33b5296..7937e37 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -75,11 +75,6 @@
/* Maximun number of VSI */
#define I40E_MAX_NUM_VSIS (384UL)

-/* Default queue interrupt throttling time in microseconds */
-#define I40E_ITR_INDEX_DEFAULT 0
-#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
-#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
-
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */

/* Mask of PF interrupt causes */
@@ -764,16 +759,6 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
I40E_WRITE_FLUSH(hw);
}

-static inline uint16_t
-i40e_calc_itr_interval(int16_t interval)
-{
- if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
- interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
-
- /* Convert to hardware count, as writing each 1 represents 2 us */
- return (interval/2);
-}
-
static void
__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
int base_queue, int nb_queue)
@@ -832,13 +817,24 @@ __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
} else {
uint32_t reg;

- /* num_msix_vectors_vf needs to minus irq0 */
- reg = (hw->func_caps.num_msix_vectors_vf - 1) *
- vsi->user_param + (msix_vect - 1);
+ if (msix_vect == MISC_VEC_ID) {
+ I40E_WRITE_REG(hw,
+ I40E_VPINT_LNKLST0(vsi->user_param),
+ (base_queue <<
+ I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ } else {
+ /* num_msix_vectors_vf needs to minus irq0 */
+ reg = (hw->func_caps.num_msix_vectors_vf - 1) *
+ vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ }
}

I40E_WRITE_FLUSH(hw);
@@ -861,6 +857,14 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
}

+ /* VF bind interrupt */
+ if (vsi->type == I40E_VSI_SRIOV) {
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue, vsi->nb_qps);
+ return;
+ }
+
+ /* PF & VMDq bind interrupt */
if (rte_intr_dp_is_en(intr_handle)) {
if (vsi->type == I40E_VSI_MAIN) {
queue_idx = 0;
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 727ee2d..52fb3f9 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -151,6 +151,11 @@ enum i40e_flxpld_layer_idx {
(1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \
(1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))

+/* Default queue interrupt throttling time in microseconds */
+#define I40E_ITR_INDEX_DEFAULT 0
+#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
+#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
+
struct i40e_adapter;

/**
@@ -573,6 +578,16 @@ i40e_align_floor(int n)
return 1 << (sizeof(n) * CHAR_BIT - 1 - __builtin_clz(n));
}

+static inline uint16_t
+i40e_calc_itr_interval(int16_t interval)
+{
+ if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
+ interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
+
+ /* Convert to hardware count, as writing each 1 represents 2 us */
+ return (interval / 2);
+}
+
#define I40E_VALID_FLOW(flow_type) \
((flow_type) == RTE_ETH_FLOW_FRAG_IPV4 || \
(flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index b694400..074448f 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -144,6 +144,10 @@ static int i40evf_dev_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
static int i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);

/* Default hash key buffer for RSS */
static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
@@ -169,6 +173,9 @@ static const struct eth_dev_ops i40evf_eth_dev_ops = {
.tx_queue_stop = i40evf_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
.rx_queue_release = i40e_dev_rx_queue_release,
+ .rx_queue_intr_enable = i40evf_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40evf_dev_rx_queue_intr_disable,
+ .rx_descriptor_done = i40e_dev_rx_descriptor_done,
.tx_queue_setup = i40e_dev_tx_queue_setup,
.tx_queue_release = i40e_dev_tx_queue_release,
.reta_update = i40evf_dev_rss_reta_update,
@@ -700,19 +707,30 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_irq_map_info) + \
sizeof(struct i40e_virtchnl_vector_map)];
struct i40e_virtchnl_irq_map_info *map_info;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t vector_id;
int i, err;
+
+ if (rte_intr_allow_others(intr_handle))
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ else
+ vector_id = MISC_VEC_ID;
+
map_info = (struct i40e_virtchnl_irq_map_info *)cmd_buffer;
map_info->num_vectors = 1;
map_info->vecmap[0].rxitr_idx = RTE_LIBRTE_I40E_ITR_INTERVAL / 2;
map_info->vecmap[0].txitr_idx = RTE_LIBRTE_I40E_ITR_INTERVAL / 2;
map_info->vecmap[0].vsi_id = vf->vsi_res->vsi_id;
/* Alway use default dynamic MSIX interrupt */
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ map_info->vecmap[0].vector_id = vector_id;
/* Don't map any tx queue */
map_info->vecmap[0].txq_map = 0;
map_info->vecmap[0].rxq_map = 0;
- for (i = 0; i < dev->data->nb_rx_queues; i++)
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
map_info->vecmap[0].rxq_map |= 1 << i;
+ if (rte_intr_dp_is_en(intr_handle))
+ intr_handle->intr_vec[i] = vector_id;
+ }

args.ops = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP;
args.in_args = (u8 *)cmd_buffer;
@@ -1546,18 +1564,88 @@ i40evf_tx_init(struct rte_eth_dev *dev)
}

static inline void
-i40evf_enable_queues_intr(struct i40e_hw *hw)
+i40evf_enable_queues_intr(struct rte_eth_dev *dev)
{
- I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
- I40E_VFINT_DYN_CTLN1_INTENA_MASK |
- I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+ return;
+ }
+
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
+ I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+ I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK);
}

static inline void
-i40evf_disable_queues_intr(struct i40e_hw *hw)
+i40evf_disable_queues_intr(struct rte_eth_dev *dev)
{
- I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
- 0);
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ return;
+ }
+
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
+ 0);
+}
+
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT));
+ else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr - RX_VEC_START),
+ I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+ I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT));
+
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr - RX_VEC_START),
+ 0);
+
+ return 0;
}

static int
@@ -1565,7 +1653,9 @@ i40evf_dev_start(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ether_addr mac_addr;
+ uint32_t intr_vector = 0;

PMD_INIT_FUNC_TRACE();

@@ -1575,6 +1665,24 @@ i40evf_dev_start(struct rte_eth_dev *dev)
vf->num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
dev->data->nb_tx_queues);

+ /* check and configure queue intr-vector mapping */
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int), 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
if (i40evf_rx_init(dev) != 0){
PMD_DRV_LOG(ERR, "failed to do RX init");
return -1;
@@ -1604,7 +1712,9 @@ i40evf_dev_start(struct rte_eth_dev *dev)
goto err_mac;
}

- i40evf_enable_queues_intr(hw);
+ rte_intr_enable(intr_handle);
+
+ i40evf_enable_queues_intr(dev);
return 0;

err_mac:
@@ -1616,13 +1726,20 @@ err_queue:
static void
i40evf_dev_stop(struct rte_eth_dev *dev)
{
- struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;

PMD_INIT_FUNC_TRACE();

- i40evf_disable_queues_intr(hw);
+ i40evf_disable_queues_intr(dev);
i40evf_stop_queues(dev);
i40e_dev_clear_queues(dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static int
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index c1d58a8..cbf4e5b 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -547,11 +547,6 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
goto send_msg;
}

- if (irqmap->vecmap[0].vector_id == 0) {
- PMD_DRV_LOG(ERR, "DPDK host don't support use IRQ0");
- ret = I40E_ERR_PARAM;
- goto send_msg;
- }
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
vf->vsi->nb_msix = irqmap->num_vectors;
--
2.4.3
Cunming Liang
2015-09-24 05:33:51 UTC
Permalink
Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 2 ++
1 file changed, 2 insertions(+)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 682f468..73dba47 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -4,10 +4,12 @@ DPDK Release 2.2
New Features
------------

+* Support interrupt mode on i40e

Resolved Issues
---------------

+* Fix ixgbe/igb rx interrupt compatible issue with mbox

Known Issues
------------
--
2.4.3
Cunming Liang
2015-10-30 05:27:42 UTC
Permalink
v2 change:
- rebase code base
- rework to depend on one previous patch
patch http://dpdk.org/dev/patchwork/patch/7504/
- always set DIS_AUTOMASK_* bit in PF to avoid ENA flag auto-clear

This patch series contains four major parts.

1. always reserve vector zero for misc cause in vfio mapping
2. add api to declare the capability of multiple interrupt vector support
3. fix the rx interrupt compatible issue with mbox in ixgbe/igb IOV-PF
4. add rx interrupt support in i40e PF and VF

Cunming Liang (11):
eal/linux: vfio map misc intr to vector zero
ixgbe: reserve intr vector zero for misc cause
igb: reserve intr vector zero for misc cause
eal/linux: not allow to enable zero intr efd
eal/linux: add intr api to report multi-vector capability
ixgbe: fix rx intr compatible issue with PF mbox
ixgbevf: cleanup unnecessary interrupt handler
igb: fix rx intr compatible issue with PF mbox
i40e: add rx interrupt support
i40evf: add rx interrupt support
doc: release note update for intr mode

doc/guides/rel_notes/release_2_2.rst | 4 +
drivers/net/e1000/igb_ethdev.c | 63 +++-
drivers/net/i40e/i40e_ethdev.c | 374 +++++++++++++++++----
drivers/net/i40e/i40e_ethdev.h | 17 +
drivers/net/i40e/i40e_ethdev_vf.c | 143 +++++++-
drivers/net/i40e/i40e_pf.c | 7 +-
drivers/net/ixgbe/ixgbe_ethdev.c | 144 +++-----
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 3 +-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 35 +-
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 16 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +
11 files changed, 612 insertions(+), 201 deletions(-)
--
2.4.3
Cunming Liang
2015-10-30 05:27:43 UTC
Permalink
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve the first vector to misc interrupt.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 18 ++++++++++++------
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 3 +++
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 078318c..8e76a7a 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -300,8 +300,10 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
irq_set->start = 0;
fd_ptr = (int *) &irq_set->data;
- memcpy(fd_ptr, intr_handle->efds, sizeof(intr_handle->efds));
- fd_ptr[intr_handle->max_intr - 1] = intr_handle->fd;
+ fd_ptr[MISC_VEC_ID] = intr_handle->fd;
+ /* follow up with misc(0) interrupt */
+ memcpy(&fd_ptr[RX_VEC_START], intr_handle->efds,
+ sizeof(*intr_handle->efds) * intr_handle->nb_efd);

ret = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);

@@ -1068,10 +1070,13 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
struct rte_epoll_event *rev;
struct rte_epoll_data *epdata;
int epfd_op;
+ unsigned int efd_idx;
int rc = 0;

+ efd_idx = (vec >= RX_VEC_START) ? (vec - RX_VEC_START) : vec;
+
if (!intr_handle || intr_handle->nb_efd == 0 ||
- vec >= intr_handle->nb_efd) {
+ efd_idx >= intr_handle->nb_efd) {
RTE_LOG(ERR, EAL, "Wrong intr vector number.\n");
return -EPERM;
}
@@ -1079,7 +1084,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
switch (op) {
case RTE_INTR_EVENT_ADD:
epfd_op = EPOLL_CTL_ADD;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status != RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event already been added.\n");
return -EEXIST;
@@ -1091,7 +1096,8 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
epdata->data = data;
epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
epdata->cb_arg = (void *)intr_handle;
- rc = rte_epoll_ctl(epfd, epfd_op, intr_handle->efds[vec], rev);
+ rc = rte_epoll_ctl(epfd, epfd_op,
+ intr_handle->efds[efd_idx], rev);
if (!rc)
RTE_LOG(DEBUG, EAL,
"efd %d associated with vec %d added on epfd %d"
@@ -1101,7 +1107,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
break;
case RTE_INTR_EVENT_DEL:
epfd_op = EPOLL_CTL_DEL;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status == RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event does not exist.\n");
return -EPERM;
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 45071b7..b8fd318 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -77,6 +77,9 @@ struct rte_epoll_event {
struct rte_epoll_data epdata;
};

+#define MISC_VEC_ID (0)
+#define RX_VEC_START (MISC_VEC_ID + 1)
+
/** Handle for interrupts. */
struct rte_intr_handle {
union {
--
2.4.3
He, Shaopeng
2015-10-30 07:11:01 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 01/11] eal/linux: vfio map misc intr to vector zero
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve
the first vector to misc interrupt.
Acked-by : Shaopeng He <***@intel.com>
Zhang, Helin
2015-10-30 07:33:55 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 01/11] eal/linux: vfio map misc intr to vector zero
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve the
first vector to misc interrupt.
Acked-by: Helin Zhang <***@intel.com>
Liang, Cunming
2015-10-30 14:22:31 UTC
Permalink
Hi David,

May I ask your help to review the patch related to eal ?

Thanks,
Steve
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 01/11] eal/linux: vfio map misc intr to vector zero
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve the first
vector to misc interrupt.
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 18
++++++++++++------
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 3 +++
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 078318c..8e76a7a 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -300,8 +300,10 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
irq_set->start = 0;
fd_ptr = (int *) &irq_set->data;
- memcpy(fd_ptr, intr_handle->efds, sizeof(intr_handle->efds));
- fd_ptr[intr_handle->max_intr - 1] = intr_handle->fd;
+ fd_ptr[MISC_VEC_ID] = intr_handle->fd;
+ /* follow up with misc(0) interrupt */
+ memcpy(&fd_ptr[RX_VEC_START], intr_handle->efds,
+ sizeof(*intr_handle->efds) * intr_handle->nb_efd);
ret = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
@@ -1068,10 +1070,13 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
struct rte_epoll_event *rev;
struct rte_epoll_data *epdata;
int epfd_op;
+ unsigned int efd_idx;
int rc = 0;
+ efd_idx = (vec >= RX_VEC_START) ? (vec - RX_VEC_START) : vec;
+
if (!intr_handle || intr_handle->nb_efd == 0 ||
- vec >= intr_handle->nb_efd) {
+ efd_idx >= intr_handle->nb_efd) {
RTE_LOG(ERR, EAL, "Wrong intr vector number.\n");
return -EPERM;
}
@@ -1079,7 +1084,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
switch (op) {
epfd_op = EPOLL_CTL_ADD;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status != RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event already been added.\n");
return -EEXIST;
@@ -1091,7 +1096,8 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
epdata->data = data;
epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
epdata->cb_arg = (void *)intr_handle;
- rc = rte_epoll_ctl(epfd, epfd_op, intr_handle->efds[vec], rev);
+ rc = rte_epoll_ctl(epfd, epfd_op,
+ intr_handle->efds[efd_idx], rev);
if (!rc)
RTE_LOG(DEBUG, EAL,
"efd %d associated with vec %d added on epfd %d"
@@ -1101,7 +1107,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
break;
epfd_op = EPOLL_CTL_DEL;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status == RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event does not exist.\n");
return -EPERM;
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 45071b7..b8fd318 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -77,6 +77,9 @@ struct rte_epoll_event {
struct rte_epoll_data epdata;
};
+#define MISC_VEC_ID (0)
+#define RX_VEC_START (MISC_VEC_ID + 1)
+
/** Handle for interrupts. */
struct rte_intr_handle {
union {
--
2.4.3
David Marchand
2015-11-02 15:53:55 UTC
Permalink
Hello,

On Fri, Oct 30, 2015 at 6:27 AM, Cunming Liang <***@intel.com>
wrote:
[snip]
Post by Cunming Liang
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 45071b7..b8fd318 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -77,6 +77,9 @@ struct rte_epoll_event {
struct rte_epoll_data epdata;
};
+#define MISC_VEC_ID (0)
"misc" is not really descriptive ...
Post by Cunming Liang
+#define RX_VEC_START (MISC_VEC_ID + 1)
+
Please, prefix these macros properly.
Else, when looking at the driver code, this kind of macros seems to be
local to the driver.
--
David Marchand
Liang, Cunming
2015-11-04 01:17:28 UTC
Permalink
Hi David,
Post by David Marchand
Hello,
[snip]
Post by Cunming Liang
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 45071b7..b8fd318 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -77,6 +77,9 @@ struct rte_epoll_event {
struct rte_epoll_data epdata;
};
+#define MISC_VEC_ID (0)
"misc" is not really descriptive ...
Post by Cunming Liang
+#define RX_VEC_START (MISC_VEC_ID + 1)
+
Please, prefix these macros properly.
Else, when looking at the driver code, this kind of macros seems to be
local to the driver.
That makes sense, will fix it in v3. Thanks. /Steve
Cunming Liang
2015-11-04 06:07:30 UTC
Permalink
v3 change:
- rename MISC_VEC_ID and RX_VEC_START
- add bsdapp dummy
- split cleanup and fix patches
- merge doc update along with code change

v2 change:
- rework to depend on one previous patch
patch http://dpdk.org/dev/patchwork/patch/7504/
- always set DIS_AUTOMASK_* bit in PF to avoid ENA flag auto-clear

This patch series contains four major parts.

1. always reserve vector zero for misc cause in vfio mapping
2. add api to declare the capability of multiple interrupt vector support
3. fix the rx interrupt compatible issue with mbox in ixgbe/igb IOV-PF
4. add rx interrupt support in i40e PF and VF


Cunming Liang (13):
eal: vfio map misc intr to vector zero
ixgbe: reserve intr vector zero for misc cause
igb: reserve intr vector zero for misc cause
eal/linux: not allow to enable zero intr efd
ixgbe: fix efd_enable with zero number
igb: fix efd_enable with zero number
eal: add intr api to report multi-vector capability
ixgbe: fix rx intr compatible issue with PF mbox
ixgbe: fix unnecessary intr_vec free in dev_close
ixgbevf: cleanup unnecessary interrupt handler
igb: fix rx intr compatible issue with PF mbox
i40e: add rx interrupt support
i40evf: add rx interrupt support

doc/guides/rel_notes/release_2_2.rst | 5 +
drivers/net/e1000/e1000_ethdev.h | 3 +
drivers/net/e1000/igb_ethdev.c | 63 +++-
drivers/net/i40e/i40e_ethdev.c | 379 +++++++++++++++++----
drivers/net/i40e/i40e_ethdev.h | 20 ++
drivers/net/i40e/i40e_ethdev_vf.c | 144 +++++++-
drivers/net/i40e/i40e_pf.c | 7 +-
drivers/net/ixgbe/ixgbe_ethdev.c | 144 +++-----
drivers/net/ixgbe/ixgbe_ethdev.h | 3 +
lib/librte_eal/bsdapp/eal/eal_interrupts.c | 7 +
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 16 +-
lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 36 +-
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 15 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +
15 files changed, 654 insertions(+), 202 deletions(-)
--
2.4.3
Cunming Liang
2015-11-04 06:07:31 UTC
Permalink
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve the first vector to misc interrupt.

v3 changes:
- rename MISC_VEC_ID to RTE_INTR_VEC_ZERO_OFFSET
- rename RX_VEC_START to RTE_INTR_VEC_RXTX_OFFSET
- add macro definition in bsd header file

Signed-off-by: Cunming Liang <***@intel.com>
---
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 3 +++
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 19 +++++++++++++------
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 2 ++
3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 88d4ae1..05bb484 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -38,6 +38,9 @@
#ifndef _RTE_BSDAPP_INTERRUPTS_H_
#define _RTE_BSDAPP_INTERRUPTS_H_

+#define RTE_INTR_VEC_ZERO_OFFSET 0
+#define RTE_INTR_VEC_RXTX_OFFSET 1
+
enum rte_intr_handle_type {
RTE_INTR_HANDLE_UNKNOWN = 0,
RTE_INTR_HANDLE_UIO, /**< uio device handle */
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index a4b9506..8758239 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -301,8 +301,10 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
irq_set->start = 0;
fd_ptr = (int *) &irq_set->data;
- memcpy(fd_ptr, intr_handle->efds, sizeof(intr_handle->efds));
- fd_ptr[intr_handle->max_intr - 1] = intr_handle->fd;
+ /* INTR vector offset 0 reserve for non-efds mapping */
+ fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = intr_handle->fd;
+ memcpy(&fd_ptr[RTE_INTR_VEC_RXTX_OFFSET], intr_handle->efds,
+ sizeof(*intr_handle->efds) * intr_handle->nb_efd);

ret = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);

@@ -1083,10 +1085,14 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
struct rte_epoll_event *rev;
struct rte_epoll_data *epdata;
int epfd_op;
+ unsigned int efd_idx;
int rc = 0;

+ efd_idx = (vec >= RTE_INTR_VEC_RXTX_OFFSET) ?
+ (vec - RTE_INTR_VEC_RXTX_OFFSET) : vec;
+
if (!intr_handle || intr_handle->nb_efd == 0 ||
- vec >= intr_handle->nb_efd) {
+ efd_idx >= intr_handle->nb_efd) {
RTE_LOG(ERR, EAL, "Wrong intr vector number.\n");
return -EPERM;
}
@@ -1094,7 +1100,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
switch (op) {
case RTE_INTR_EVENT_ADD:
epfd_op = EPOLL_CTL_ADD;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status != RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event already been added.\n");
return -EEXIST;
@@ -1106,7 +1112,8 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
epdata->data = data;
epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
epdata->cb_arg = (void *)intr_handle;
- rc = rte_epoll_ctl(epfd, epfd_op, intr_handle->efds[vec], rev);
+ rc = rte_epoll_ctl(epfd, epfd_op,
+ intr_handle->efds[efd_idx], rev);
if (!rc)
RTE_LOG(DEBUG, EAL,
"efd %d associated with vec %d added on epfd %d"
@@ -1116,7 +1123,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
break;
case RTE_INTR_EVENT_DEL:
epfd_op = EPOLL_CTL_DEL;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status == RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event does not exist.\n");
return -EPERM;
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index b095b86..8da81e7 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -39,6 +39,8 @@
#define _RTE_LINUXAPP_INTERRUPTS_H_

#define RTE_MAX_RXTX_INTR_VEC_ID 32
+#define RTE_INTR_VEC_ZERO_OFFSET 0
+#define RTE_INTR_VEC_RXTX_OFFSET 1

enum rte_intr_handle_type {
RTE_INTR_HANDLE_UNKNOWN = 0,
--
2.4.3
Cunming Liang
2015-11-04 06:07:32 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

v3 changes:
- macro renaming according to the EAL change

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 22 ++++++++++++++--------
drivers/net/ixgbe/ixgbe_ethdev.h | 3 +++
2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 25966ef..153ba98 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -4478,7 +4478,8 @@ ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask |= (1 << queue_id);
+ mask |= (1 << IXGBE_MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

rte_intr_enable(&dev->pci_dev->intr_handle);
@@ -4494,7 +4495,8 @@ ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask &= ~(1 << queue_id);
+ mask &= ~(1 << IXGBE_MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

return 0;
@@ -4630,7 +4632,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
uint32_t q_idx;
- uint32_t vector_idx = 0;
+ uint32_t vector_idx = IXGBE_MISC_VEC_ID;

/* won't configure msix register if no mapping is done
* between intr vector and event fd.
@@ -4662,7 +4664,8 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint32_t queue_id, vec = 0;
+ uint32_t queue_id, base = IXGBE_MISC_VEC_ID;
+ uint32_t vec = IXGBE_MISC_VEC_ID;
uint32_t mask;
uint32_t gpie;

@@ -4672,6 +4675,9 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
if (!rte_intr_dp_is_en(intr_handle))
return;

+ if (rte_intr_allow_others(intr_handle))
+ vec = base = IXGBE_RX_VEC_START;
+
/* setup GPIE for MSI-x mode */
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
gpie |= IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_PBA_SUPPORT |
@@ -4695,23 +4701,23 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
/* by default, 1:1 mapping */
ixgbe_set_ivar_map(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++;
}

switch (hw->mac.type) {
case ixgbe_mac_82598EB:
ixgbe_set_ivar_map(hw, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
- intr_handle->max_intr - 1);
+ IXGBE_MISC_VEC_ID);
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- ixgbe_set_ivar_map(hw, -1, 1, intr_handle->max_intr - 1);
+ ixgbe_set_ivar_map(hw, -1, 1, IXGBE_MISC_VEC_ID);
break;
default:
break;
}
- IXGBE_WRITE_REG(hw, IXGBE_EITR(queue_id),
+ IXGBE_WRITE_REG(hw, IXGBE_EITR(IXGBE_MISC_VEC_ID),
IXGBE_MIN_INTER_INTERRUPT_INTERVAL_DEFAULT & 0xFFF);

/* set up to autoclear timer, and the vectors */
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h b/drivers/net/ixgbe/ixgbe_ethdev.h
index 569d678..1856c42 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.h
+++ b/drivers/net/ixgbe/ixgbe_ethdev.h
@@ -123,6 +123,9 @@
#define IXGBE_VF_IRQ_ENABLE_MASK 3 /* vf irq enable mask */
#define IXGBE_VF_MAXMSIVECTOR 1

+#define IXGBE_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
+#define IXGBE_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
+
/*
* Information about the fdir mode.
*/
--
2.4.3
Cunming Liang
2015-11-04 06:07:33 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

v3 change:
- macro renaming according to the EAL change

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/e1000_ethdev.h | 3 +++
drivers/net/e1000/igb_ethdev.c | 19 ++++++++++++++-----
2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/net/e1000/e1000_ethdev.h b/drivers/net/e1000/e1000_ethdev.h
index 3c6f613..a667a1a 100644
--- a/drivers/net/e1000/e1000_ethdev.h
+++ b/drivers/net/e1000/e1000_ethdev.h
@@ -132,6 +132,9 @@
#define EM_RXD_ALIGN (E1000_ALIGN / sizeof(struct e1000_rx_desc))
#define EM_TXD_ALIGN (E1000_ALIGN / sizeof(struct e1000_data_desc))

+#define E1000_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
+#define E1000_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
+
/* structure for interrupt relative data */
struct e1000_interrupt {
uint32_t flags;
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index cd7f7c1..1332974 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -4495,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
@@ -4504,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);
@@ -4532,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);

@@ -4547,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++;
}
--
2.4.3
Cunming Liang
2015-11-04 06:07:34 UTC
Permalink
The patch adds condition check to avoid enable nothing.
In disable state, both max_intr and nb_efd are zero.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 8 +++++++-
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 05bb484..3d138bf 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -85,8 +85,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 8758239..8938067 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -45,6 +45,7 @@
#include <sys/signalfd.h>
#include <sys/ioctl.h>
#include <sys/eventfd.h>
+#include <assert.h>

#include <rte_common.h>
#include <rte_interrupts.h>
@@ -1148,6 +1149,8 @@ rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
int fd;
uint32_t n = RTE_MIN(nb_efd, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);

+ assert(nb_efd != 0);
+
if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX) {
for (i = 0; i < n; i++) {
fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
@@ -1204,5 +1207,8 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle)
{
- return !!(intr_handle->max_intr - intr_handle->nb_efd);
+ if (!rte_intr_dp_is_en(intr_handle))
+ return 1;
+ else
+ return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 8da81e7..b44e69c 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -176,8 +176,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
--
2.4.3
Cunming Liang
2015-11-04 06:07:36 UTC
Permalink
Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/igb_ethdev.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 1332974..76d2acc 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -1122,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 =
--
2.4.3
Cunming Liang
2015-11-04 06:07:37 UTC
Permalink
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.

v3 change:
- add new api dummy in bsdapp

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/bsdapp/eal/eal_interrupts.c | 7 +++++++
lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 9 +++++++++
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++
6 files changed, 50 insertions(+)

diff --git a/lib/librte_eal/bsdapp/eal/eal_interrupts.c b/lib/librte_eal/bsdapp/eal/eal_interrupts.c
index 51a13fa..836e483 100644
--- a/lib/librte_eal/bsdapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/bsdapp/eal/eal_interrupts.c
@@ -110,3 +110,10 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle)
RTE_SET_USED(intr_handle);
return 1;
}
+
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
+{
+ RTE_SET_USED(intr_handle);
+ return 0;
+}
diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 3d138bf..70a7087 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -122,4 +122,14 @@ int rte_intr_dp_is_en(struct rte_intr_handle *intr_handle);
*/
int rte_intr_allow_others(struct rte_intr_handle *intr_handle);

+/**
+ * The multiple interrupt vector capability of interrupt handle instance.
+ * It returns zero if no multiple interrupt vector support.
+ *
+ * @param intr_handle
+ * Pointer to the interrupt handle.
+ */
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);
+
#endif /* _RTE_BSDAPP_INTERRUPTS_H_ */
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 64fdfb1..8b00761 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -125,3 +125,10 @@ DPDK_2.1 {
rte_memzone_free;

} DPDK_2.0;
+
+DPDK_2.2 {
+ global:
+
+ rte_intr_cap_multiple;
+
+} DPDK_2.1;
\ No newline at end of file
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 8938067..95beb4c 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -1212,3 +1212,12 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle)
else
return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
+
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
+{
+ if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX)
+ return 1;
+
+ return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index b44e69c..3dacbff 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -215,4 +215,14 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle);
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle);

+/**
+ * The multiple interrupt vector capability of interrupt handle instance.
+ * It returns zero if no multiple interrupt vector support.
+ *
+ * @param intr_handle
+ * Pointer to the interrupt handle.
+ */
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);
+
#endif /* _RTE_LINUXAPP_INTERRUPTS_H_ */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index dbb8fa1..cb9f4d6 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -128,3 +128,10 @@ DPDK_2.1 {
rte_memzone_free;

} DPDK_2.0;
+
+DPDK_2.2 {
+ global:
+
+ rte_intr_cap_multiple;
+
+} DPDK_2.1;
\ No newline at end of file
--
2.4.3
Cunming Liang
2015-11-04 06:07:38 UTC
Permalink
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

v3 change:
- add doc update follow on the code change

Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 2 ++
drivers/net/ixgbe/ixgbe_ethdev.c | 39 ++++++++++++++++++++++++++----------
2 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index ca8471b..b082fb6 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -152,6 +152,8 @@ Drivers
hardware transactional memory support, thread scaling did not work,
due to the global ring that is shared by all cores.

+* **ixgbe: Fixed PF rx interrupt compatible issue with mbox.**
+
Libraries
~~~~~~~~~

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index f1a738c..6b075f6 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1126,6 +1126,13 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&pci_dev->intr_handle);
+
/* enable support intr */
ixgbe_enable_intr(eth_dev);

@@ -1975,7 +1982,10 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_pf_host_configure(dev);

/* check and configure queue intr-vector mapping */
- if (dev->data->dev_conf.intr_conf.rxq != 0) {
+ if (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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;
@@ -1984,8 +1994,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
- dev->data->nb_rx_queues * sizeof(int),
- 0);
+ dev->data->nb_rx_queues * sizeof(int), 0);
if (intr_handle->intr_vec == NULL) {
PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
" intr_vec\n", dev->data->nb_rx_queues);
@@ -2072,20 +2081,22 @@ ixgbe_dev_start(struct rte_eth_dev *dev)

skip_link_setup:

- /* check if lsc interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- ixgbe_dev_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
ixgbe_dev_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
ixgbe_dev_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -2197,6 +2208,12 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
memset(filter_info->fivetuple_mask, 0,
sizeof(uint32_t) * IXGBE_5TUPLE_ARRAY_SIZE);

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-11-04 06:07:39 UTC
Permalink
The intr_vec is free in dev_stop. It's not necessary to check in dev_close.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 7 -------
1 file changed, 7 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 6b075f6..d5556cc 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -3952,7 +3952,6 @@ static void
ixgbevf_dev_close(struct rte_eth_dev *dev)
{
struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev;

PMD_INIT_FUNC_TRACE();

@@ -3964,12 +3963,6 @@ ixgbevf_dev_close(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);
-
- pci_dev = dev->pci_dev;
- if (pci_dev->intr_handle.intr_vec) {
- rte_free(pci_dev->intr_handle.intr_vec);
- pci_dev->intr_handle.intr_vec = NULL;
- }
}

static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
--
2.4.3
Cunming Liang
2015-11-04 06:07:40 UTC
Permalink
As ixgbe vf doesn't support lsc, the patch removes those unused code.
In addition, it does some tiny cleanup.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 62 +---------------------------------------
1 file changed, 1 insertion(+), 61 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index d5556cc..96aeee3 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -208,8 +208,6 @@ static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_conf
/* For Virtual Function support */
static int eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev);
static int eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev);
-static int ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev);
-static int ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev);
static int ixgbevf_dev_configure(struct rte_eth_dev *dev);
static int ixgbevf_dev_start(struct rte_eth_dev *dev);
static void ixgbevf_dev_stop(struct rte_eth_dev *dev);
@@ -225,8 +223,6 @@ 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);
-static void ixgbevf_dev_interrupt_handler(struct rte_intr_handle *handle,
- void *param);
static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
uint16_t queue_id);
static int ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
@@ -3068,30 +3064,6 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev)
-{
- uint32_t eicr;
- struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct ixgbe_interrupt *intr =
- IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-
- /* clear all cause mask */
- ixgbevf_intr_disable(hw);
-
- /* read-on-clear nic registers here */
- eicr = IXGBE_READ_REG(hw, IXGBE_VTEICR);
- PMD_DRV_LOG(INFO, "eicr %x", eicr);
-
- intr->flags = 0;
-
- /* set flag for async link update */
- if (eicr & IXGBE_EICR_LSC)
- intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-
- return 0;
-}
-
/**
* It gets and then prints the link status.
*
@@ -3187,18 +3159,6 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev)
-{
- struct ixgbe_hw *hw =
- IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
- PMD_DRV_LOG(DEBUG, "enable intr immediately");
- ixgbevf_intr_enable(hw);
- rte_intr_enable(&dev->pci_dev->intr_handle);
- return 0;
-}
-
/**
* Interrupt handler which shall be registered for alarm callback for delayed
* handling specific interrupt to wait for the stable nic state. As the
@@ -3261,16 +3221,6 @@ ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
ixgbe_dev_interrupt_action(dev);
}

-static void
-ixgbevf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
- void *param)
-{
- struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-
- ixgbevf_dev_interrupt_get_status(dev);
- ixgbevf_dev_interrupt_action(dev);
-}
-
static int
ixgbe_dev_led_on(struct rte_eth_dev *dev)
{
@@ -3897,16 +3847,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
}
ixgbevf_configure_msix(dev);

- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle))
- rte_intr_callback_register(intr_handle,
- ixgbevf_dev_interrupt_handler,
- (void *)dev);
- else
- PMD_INIT_LOG(INFO, "lsc won't enable because of"
- " no intr multiplex\n");
- }
-
rte_intr_enable(intr_handle);

/* Re-enable interrupt for VF */
@@ -4659,7 +4599,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
intr_handle->intr_vec[q_idx] = vector_idx;
}

- /* Configure VF Rx queue ivar */
+ /* Configure VF other cause ivar */
ixgbevf_set_ivar_map(hw, -1, 1, vector_idx);
}
--
2.4.3
Cunming Liang
2015-11-04 06:07:41 UTC
Permalink
When igb runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

v3 change:
- add doc update follow on the code change

Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 2 ++
drivers/net/e1000/igb_ethdev.c | 38 ++++++++++++++++++++++++++----------
2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index b082fb6..38b0612 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -154,6 +154,8 @@ Drivers

* **ixgbe: Fixed PF rx interrupt compatible issue with mbox.**

+* **igb: Fixed PF rx interrupt compatible issue with mbox.**
+
Libraries
~~~~~~~~~

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 76d2acc..fcb4dfb 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -760,6 +760,13 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&pci_dev->intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&pci_dev->intr_handle);
+
/* enable support intr */
igb_intr_enable(eth_dev);

@@ -1122,13 +1129,16 @@ 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 (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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_dp_is_en(intr_handle)) {
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
dev->data->nb_rx_queues * sizeof(int), 0);
@@ -1221,20 +1231,22 @@ eth_igb_start(struct rte_eth_dev *dev)
}
e1000_setup_link(hw);

- /* check if lsc interrupt feature is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- eth_igb_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
eth_igb_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
eth_igb_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -1327,6 +1339,12 @@ eth_igb_stop(struct rte_eth_dev *dev)
}
filter_info->twotuple_mask = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-11-04 06:07:35 UTC
Permalink
Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 153ba98..f1a738c 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1975,11 +1975,11 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_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) {
intr_handle->intr_vec =
@@ -3862,11 +3862,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
ixgbevf_dev_rxtx_start(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) {
intr_handle->intr_vec =
--
2.4.3
Cunming Liang
2015-11-04 06:07:43 UTC
Permalink
The patch enables rx interrupt support on i40e VF and some necessary change on PF IOV mode to support VF.
On PF side, running in IOV mode via uio won't allow rx interrupt which is exclusive with mbox interrupt
in single vector competition.
On VF side, one single vector is shared for all the rx queues.

v3 changes:
- macro change according to EAL
- rebase on patch http://dpdk.org/dev/patchwork/patch/7790

v2 changes:
- turn on intr only when rxq flag is set
- rework base on patch http://dpdk.org/dev/patchwork/patch/7504/

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 38 +++++-----
drivers/net/i40e/i40e_ethdev.h | 15 ++++
drivers/net/i40e/i40e_ethdev_vf.c | 144 +++++++++++++++++++++++++++++++++++---
drivers/net/i40e/i40e_pf.c | 5 --
4 files changed, 167 insertions(+), 35 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index c7a51d4..1a00f2e 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -76,11 +76,6 @@
/* Maximun number of VSI */
#define I40E_MAX_NUM_VSIS (384UL)

-/* Default queue interrupt throttling time in microseconds */
-#define I40E_ITR_INDEX_DEFAULT 0
-#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
-#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
-
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */

/* Flow control default timer */
@@ -1099,16 +1094,6 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
I40E_WRITE_FLUSH(hw);
}

-static inline uint16_t
-i40e_calc_itr_interval(int16_t interval)
-{
- if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
- interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
-
- /* Convert to hardware count, as writing each 1 represents 2 us */
- return (interval/2);
-}
-
static void
__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
int base_queue, int nb_queue)
@@ -1159,13 +1144,24 @@ __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
} else {
uint32_t reg;

- /* num_msix_vectors_vf needs to minus irq0 */
- reg = (hw->func_caps.num_msix_vectors_vf - 1) *
- vsi->user_param + (msix_vect - 1);
+ if (msix_vect == I40E_MISC_VEC_ID) {
+ I40E_WRITE_REG(hw,
+ I40E_VPINT_LNKLST0(vsi->user_param),
+ (base_queue <<
+ I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ } else {
+ /* num_msix_vectors_vf needs to minus irq0 */
+ reg = (hw->func_caps.num_msix_vectors_vf - 1) *
+ vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ }
}

I40E_WRITE_FLUSH(hw);
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index eff3adb..d281935 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -162,6 +162,11 @@ enum i40e_flxpld_layer_idx {
#define I40E_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
#define I40E_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET

+/* Default queue interrupt throttling time in microseconds */
+#define I40E_ITR_INDEX_DEFAULT 0
+#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
+#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
+
struct i40e_adapter;

/**
@@ -638,6 +643,16 @@ i40e_align_floor(int n)
return 1 << (sizeof(n) * CHAR_BIT - 1 - __builtin_clz(n));
}

+static inline uint16_t
+i40e_calc_itr_interval(int16_t interval)
+{
+ if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
+ interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
+
+ /* Convert to hardware count, as writing each 1 represents 2 us */
+ return (interval / 2);
+}
+
#define I40E_VALID_FLOW(flow_type) \
((flow_type) == RTE_ETH_FLOW_FRAG_IPV4 || \
(flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index 18ec46e..d9f1dda 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -150,6 +150,10 @@ static int i40evf_dev_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
static int i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);

/* Default hash key buffer for RSS */
static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
@@ -201,6 +205,9 @@ static const struct eth_dev_ops i40evf_eth_dev_ops = {
.tx_queue_stop = i40evf_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
.rx_queue_release = i40e_dev_rx_queue_release,
+ .rx_queue_intr_enable = i40evf_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40evf_dev_rx_queue_intr_disable,
+ .rx_descriptor_done = i40e_dev_rx_descriptor_done,
.tx_queue_setup = i40e_dev_tx_queue_setup,
.tx_queue_release = i40e_dev_tx_queue_release,
.reta_update = i40evf_dev_rss_reta_update,
@@ -741,22 +748,33 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_irq_map_info) + \
sizeof(struct i40e_virtchnl_vector_map)];
struct i40e_virtchnl_irq_map_info *map_info;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t vector_id;
int i, err;
+
+ if (rte_intr_allow_others(intr_handle)) {
+ if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ else
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
+ } else {
+ vector_id = I40E_MISC_VEC_ID;
+ }
+
map_info = (struct i40e_virtchnl_irq_map_info *)cmd_buffer;
map_info->num_vectors = 1;
map_info->vecmap[0].rxitr_idx = I40E_QINT_RQCTL_MSIX_INDX_NOITR;
map_info->vecmap[0].vsi_id = vf->vsi_res->vsi_id;
/* Alway use default dynamic MSIX interrupt */
- if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
- else
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
-
+ map_info->vecmap[0].vector_id = vector_id;
/* Don't map any tx queue */
map_info->vecmap[0].txq_map = 0;
map_info->vecmap[0].rxq_map = 0;
- for (i = 0; i < dev->data->nb_rx_queues; i++)
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
map_info->vecmap[0].rxq_map |= 1 << i;
+ if (rte_intr_dp_is_en(intr_handle))
+ intr_handle->intr_vec[i] = vector_id;
+ }

args.ops = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP;
args.in_args = (u8 *)cmd_buffer;
@@ -1669,6 +1687,16 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+ I40E_WRITE_FLUSH(hw);
+ return;
+ }

if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
/* To support DPDK PF host */
@@ -1681,6 +1709,8 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
I40E_VFINT_DYN_CTL01_INTENA_MASK |
I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+
+ I40E_WRITE_FLUSH(hw);
}

static inline void
@@ -1688,13 +1718,76 @@ i40evf_disable_queues_intr(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ I40E_WRITE_FLUSH(hw);
+ return;
+ }

if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
I40E_WRITE_REG(hw,
- I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
- 0);
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR
+ - 1),
+ 0);
+ else
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+
+ I40E_WRITE_FLUSH(hw);
+}
+
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT));
else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr - I40E_RX_VEC_START),
+ I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+ I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
+
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr - I40E_RX_VEC_START),
+ 0);
+
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}

static int
@@ -1702,7 +1795,9 @@ i40evf_dev_start(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ether_addr mac_addr;
+ uint32_t intr_vector = 0;

PMD_INIT_FUNC_TRACE();

@@ -1712,6 +1807,24 @@ i40evf_dev_start(struct rte_eth_dev *dev)
vf->num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
dev->data->nb_tx_queues);

+ /* check and configure queue intr-vector mapping */
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int), 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
if (i40evf_rx_init(dev) != 0){
PMD_DRV_LOG(ERR, "failed to do RX init");
return -1;
@@ -1741,6 +1854,10 @@ i40evf_dev_start(struct rte_eth_dev *dev)
goto err_mac;
}

+ /* vf don't allow intr except for rxq intr */
+ if (dev->data->dev_conf.intr_conf.rxq != 0)
+ rte_intr_enable(intr_handle);
+
i40evf_enable_queues_intr(dev);
return 0;

@@ -1753,11 +1870,20 @@ err_queue:
static void
i40evf_dev_stop(struct rte_eth_dev *dev)
{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
PMD_INIT_FUNC_TRACE();

- i40evf_disable_queues_intr(dev);
i40evf_stop_queues(dev);
+ i40evf_disable_queues_intr(dev);
i40e_dev_clear_queues(dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static int
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index c1d58a8..cbf4e5b 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -547,11 +547,6 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
goto send_msg;
}

- if (irqmap->vecmap[0].vector_id == 0) {
- PMD_DRV_LOG(ERR, "DPDK host don't support use IRQ0");
- ret = I40E_ERR_PARAM;
- goto send_msg;
- }
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
vf->vsi->nb_msix = irqmap->num_vectors;
--
2.4.3
Cunming Liang
2015-11-04 06:07:42 UTC
Permalink
The patch enables rx interrupt support on i40e PF non-IOV mode.
Per queue rx interrupt works on vfio, however on uio, all rx queues share one interrupt vector.

v3 change:
- macro change according the EAL
- add doc update follow on the code change

v2 change:
- add write flush
- always set DIS_AUTOMASK_

i40e: pf macro
Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 1 +
drivers/net/i40e/i40e_ethdev.c | 347 ++++++++++++++++++++++++++++++-----
drivers/net/i40e/i40e_ethdev.h | 5 +
drivers/net/i40e/i40e_pf.c | 2 +
4 files changed, 306 insertions(+), 49 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 38b0612..154bf29 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -90,6 +90,7 @@ New Features

* **Added port hotplug support to xenvirt.**

+* **Added interrupt mode support on i40e.**

Resolved Issues
---------------
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 34acc8c..c7a51d4 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -39,6 +39,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <inttypes.h>
+#include <assert.h>

#include <rte_string_fns.h>
#include <rte_pci.h>
@@ -343,7 +344,7 @@ static void i40e_stat_update_48(struct i40e_hw *hw,
bool offset_loaded,
uint64_t *offset,
uint64_t *stat);
-static void i40e_pf_config_irq0(struct i40e_hw *hw);
+static void i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue);
static void i40e_dev_interrupt_handler(
__rte_unused struct rte_intr_handle *handle, void *param);
static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
@@ -404,7 +405,10 @@ static int i40e_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
static int i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
struct timespec *timestamp);
static void i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw);
-
+static int i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
+ uint16_t queue_id);
+static int i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
+ uint16_t queue_id);

static const struct rte_pci_id pci_id_i40e_map[] = {
#define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -440,6 +444,8 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
.tx_queue_start = i40e_dev_tx_queue_start,
.tx_queue_stop = i40e_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
+ .rx_queue_intr_enable = i40e_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40e_dev_rx_queue_intr_disable,
.rx_queue_release = i40e_dev_rx_queue_release,
.rx_queue_count = i40e_dev_rx_queue_count,
.rx_descriptor_done = i40e_dev_rx_descriptor_done,
@@ -875,7 +881,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
i40e_dev_interrupt_handler, (void *)dev);

/* configure and enable device interrupt */
- i40e_pf_config_irq0(hw);
+ i40e_pf_config_irq0(hw, TRUE);
i40e_pf_enable_irq0(hw);

/* enable uio intr after callback register */
@@ -1056,6 +1062,8 @@ err:
void
i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t msix_vect = vsi->msix_intr;
uint16_t i;
@@ -1067,15 +1075,26 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
}

if (vsi->type != I40E_VSI_SRIOV) {
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1), 0);
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), 0);
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ 0);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1), 0);
+ }
} else {
uint32_t reg;
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), 0);
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
}
I40E_WRITE_FLUSH(hw);
}
@@ -1090,29 +1109,26 @@ i40e_calc_itr_interval(int16_t interval)
return (interval/2);
}

-void
-i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+static void
+__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
+ int base_queue, int nb_queue)
{
+ int i;
uint32_t val;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
- uint16_t msix_vect = vsi->msix_intr;
- int i;
-
- for (i = 0; i < vsi->nb_qps; i++)
- I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);

/* Bind all RX queues to allocated MSIX interrupt */
- for (i = 0; i < vsi->nb_qps; i++) {
+ for (i = 0; i < nb_queue; i++) {
val = (msix_vect << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
I40E_QINT_RQCTL_ITR_INDX_MASK |
- ((vsi->base_queue + i + 1) <<
- I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+ ((base_queue + i + 1) <<
+ I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
(0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
I40E_QINT_RQCTL_CAUSE_ENA_MASK;

- if (i == vsi->nb_qps - 1)
+ if (i == nb_queue - 1)
val |= I40E_QINT_RQCTL_NEXTQ_INDX_MASK;
- I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), val);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(base_queue + i), val);
}

/* Write first RX queue to Link list register as the head element */
@@ -1120,21 +1136,26 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
uint16_t interval =
i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);

- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
- (vsi->base_queue <<
- I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
-
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), interval);
-
-#ifndef I40E_GLINT_CTL
-#define I40E_GLINT_CTL 0x0003F800
-#define I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK 0x4
-#endif
- /* Disable auto-mask on enabling of all none-zero interrupt */
- I40E_WRITE_REG(hw, I40E_GLINT_CTL,
- I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK);
+ if (msix_vect == I40E_MISC_VEC_ID) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ (base_queue <<
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ interval);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ (base_queue <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1),
+ interval);
+ }
} else {
uint32_t reg;

@@ -1142,34 +1163,134 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (vsi->base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
(0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
}

I40E_WRITE_FLUSH(hw);
}

+void
+i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_vect = vsi->msix_intr;
+ uint16_t nb_msix = RTE_MIN(vsi->nb_msix, intr_handle->nb_efd);
+ uint16_t queue_idx = 0;
+ int record = 0;
+ uint32_t val;
+ int i;
+
+ for (i = 0; i < vsi->nb_qps; i++) {
+ I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
+ }
+
+ /* INTENA flag is not auto-cleared for interrupt */
+ val = I40E_READ_REG(hw, I40E_GLINT_CTL);
+ val |= I40E_GLINT_CTL_DIS_AUTOMASK_PF0_MASK |
+ I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK |
+ I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK;
+ I40E_WRITE_REG(hw, I40E_GLINT_CTL, val);
+
+ /* VF bind interrupt */
+ if (vsi->type == I40E_VSI_SRIOV) {
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue, vsi->nb_qps);
+ return;
+ }
+
+ /* PF & VMDq bind interrupt */
+ if (rte_intr_dp_is_en(intr_handle)) {
+ if (vsi->type == I40E_VSI_MAIN) {
+ queue_idx = 0;
+ record = 1;
+ } else if (vsi->type == I40E_VSI_VMDQ2) {
+ struct i40e_vsi *main_vsi =
+ I40E_DEV_PRIVATE_TO_MAIN_VSI(vsi->adapter);
+ queue_idx = vsi->base_queue - main_vsi->nb_qps;
+ record = 1;
+ }
+ }
+
+ for (i = 0; i < vsi->nb_used_qps; i++) {
+ if (nb_msix <= 1) {
+ if (!rte_intr_allow_others(intr_handle))
+ /* allow to share MISC_VEC_ID */
+ msix_vect = I40E_MISC_VEC_ID;
+
+ /* no enough msix_vect, map all to one */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i,
+ vsi->nb_used_qps - i);
+ for (; !!record && i < vsi->nb_used_qps; i++)
+ intr_handle->intr_vec[queue_idx + i] =
+ msix_vect;
+ break;
+ }
+ /* 1:1 queue/msix_vect mapping */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i, 1);
+ if (!!record)
+ intr_handle->intr_vec[queue_idx + i] = msix_vect;
+
+ msix_vect++;
+ nb_msix--;
+ }
+}
+
static void
i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t interval = i40e_calc_itr_interval(\
- RTE_LIBRTE_I40E_ITR_INTERVAL);
-
- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1),
- I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr, i;
+
+ if (rte_intr_allow_others(intr_handle))
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
(0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
- (interval << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ }
+ else
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTL0_INTENA_MASK |
+ I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
}

static void
i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_intr, i;

- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1), 0);
+ if (rte_intr_allow_others(intr_handle))
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ 0);
+ }
+ else
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+
+ I40E_WRITE_FLUSH(hw);
}

static inline uint8_t
@@ -1279,6 +1400,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
int ret, i;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t intr_vector = 0;

hw->adapter_stopped = 0;

@@ -1290,6 +1413,29 @@ i40e_dev_start(struct rte_eth_dev *dev)
return -EINVAL;
}

+ rte_intr_disable(intr_handle);
+
+ if (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int),
+ 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
/* Initialize VSI */
ret = i40e_dev_rxtx_init(pf);
if (ret != I40E_SUCCESS) {
@@ -1298,11 +1444,14 @@ i40e_dev_start(struct rte_eth_dev *dev)
}

/* Map queues with MSIX interrupt */
+ main_vsi->nb_used_qps = dev->data->nb_rx_queues -
+ pf->nb_cfg_vmdq_vsi * RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(main_vsi);
i40e_vsi_enable_queues_intr(main_vsi);

/* Map VMDQ VSI queues with MSIX interrupt */
for (i = 0; i < pf->nb_cfg_vmdq_vsi; i++) {
+ pf->vmdq[i].vsi->nb_used_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(pf->vmdq[i].vsi);
i40e_vsi_enable_queues_intr(pf->vmdq[i].vsi);
}
@@ -1339,6 +1488,22 @@ i40e_dev_start(struct rte_eth_dev *dev)
goto err_up;
}

+ if (!rte_intr_allow_others(intr_handle)) {
+ rte_intr_callback_unregister(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+ /* configure and enable device interrupt */
+ i40e_pf_config_irq0(hw, FALSE);
+ i40e_pf_enable_irq0(hw);
+
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
+ PMD_INIT_LOG(INFO, "lsc won't enable because of"
+ " no intr multiplex\n");
+ }
+
+ /* enable uio intr after callback register */
+ rte_intr_enable(intr_handle);
+
return I40E_SUCCESS;

err_up:
@@ -1354,6 +1519,7 @@ i40e_dev_stop(struct rte_eth_dev *dev)
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
struct i40e_mirror_rule *p_mirror;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
int i;

/* Disable all queues */
@@ -1385,6 +1551,18 @@ i40e_dev_stop(struct rte_eth_dev *dev)
}
pf->nb_mirror_rule = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static void
@@ -3701,15 +3879,30 @@ i40e_vsi_setup(struct i40e_pf *pf,
vsi->base_queue = I40E_FDIR_QUEUE_ID;

/* VF has MSIX interrupt in VF range, don't allocate here */
- if (type != I40E_VSI_SRIOV) {
+ if (type == I40E_VSI_MAIN) {
+ ret = i40e_res_pool_alloc(&pf->msix_pool,
+ RTE_MIN(vsi->nb_qps,
+ RTE_MAX_RXTX_INTR_VEC_ID));
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "VSI MAIN %d get heap failed %d",
+ vsi->seid, ret);
+ goto fail_queue_alloc;
+ }
+ vsi->msix_intr = ret;
+ vsi->nb_msix = RTE_MIN(vsi->nb_qps, RTE_MAX_RXTX_INTR_VEC_ID);
+ } else if (type != I40E_VSI_SRIOV) {
ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
if (ret < 0) {
PMD_DRV_LOG(ERR, "VSI %d get heap failed %d", vsi->seid, ret);
goto fail_queue_alloc;
}
vsi->msix_intr = ret;
- } else
+ vsi->nb_msix = 1;
+ } else {
vsi->msix_intr = 0;
+ vsi->nb_msix = 0;
+ }
+
/* Add VSI */
if (type == I40E_VSI_MAIN) {
/* For main VSI, no need to add since it's default one */
@@ -4553,7 +4746,7 @@ i40e_pf_enable_irq0(struct i40e_hw *hw)
}

static void
-i40e_pf_config_irq0(struct i40e_hw *hw)
+i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue)
{
/* read pending request and disable first */
i40e_pf_disable_irq0(hw);
@@ -4561,9 +4754,10 @@ i40e_pf_config_irq0(struct i40e_hw *hw)
I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0,
I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK);

- /* Link no queues with irq0 */
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
- I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ if (no_queue)
+ /* Link no queues with irq0 */
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
}

static void
@@ -8147,6 +8341,7 @@ i40e_dcb_setup(struct rte_eth_dev *dev)
PMD_INIT_LOG(ERR, "dcb sw configure fails");
return -ENOSYS;
}
+
return 0;
}

@@ -8186,5 +8381,59 @@ i40e_dev_get_dcb_info(struct rte_eth_dev *dev,
dcb_info->tc_queue.tc_rxq[0][i].nb_queue;
}
}
+
+ return 0;
+}
+
+static int
+i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr -
+ I40E_RX_VEC_START),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr -
+ I40E_RX_VEC_START),
+ 0);
+ I40E_WRITE_FLUSH(hw);
+
return 0;
}
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index c64f83b..eff3adb 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -159,6 +159,9 @@ enum i40e_flxpld_layer_idx {
(1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \
(1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))

+#define I40E_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
+#define I40E_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
+
struct i40e_adapter;

/**
@@ -256,6 +259,7 @@ struct i40e_vsi {
uint16_t seid; /* The seid of VSI itself */
uint16_t uplink_seid; /* The uplink seid of this VSI */
uint16_t nb_qps; /* Number of queue pairs VSI can occupy */
+ uint16_t nb_used_qps; /* Number of queue pairs VSI uses */
uint16_t max_macaddrs; /* Maximum number of MAC addresses */
uint16_t base_queue; /* The first queue index of this VSI */
/*
@@ -264,6 +268,7 @@ struct i40e_vsi {
*/
uint16_t vsi_id;
uint16_t msix_intr; /* The MSIX interrupt binds to VSI */
+ uint16_t nb_msix; /* The max number of msix vector */
uint8_t enabled_tc; /* The traffic class enabled */
struct i40e_bw_info bw_info; /* VSI bandwidth information */
};
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 95c960c..c1d58a8 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -554,6 +554,8 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
}
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
+ vf->vsi->nb_msix = irqmap->num_vectors;
+ vf->vsi->nb_used_qps = vf->vsi->nb_qps;

/* Don't care how the TX/RX queue mapping with this vector.
* Link all VF RX queues together. Only did mapping work.
--
2.4.3
Cunming Liang
2015-11-04 08:45:27 UTC
Permalink
v4 change:
- remove redundancy condition check on PF

v3 changes:
- rename MISC_VEC_ID and RX_VEC_START
- add bsdapp dummy
- split cleanup and fix patches
- merge doc update along with code change

v2 changes:
- rework to depend on one previous patch
patch http://dpdk.org/dev/patchwork/patch/7504/
- always set DIS_AUTOMASK_* bit in PF to avoid ENA flag auto-clear

This patch series contains four major parts.

1. always reserve vector zero for misc cause in vfio mapping
2. add api to declare the capability of multiple interrupt vector support
3. fix the rx interrupt compatible issue with mbox in ixgbe/igb IOV-PF
4. add rx interrupt support in i40e PF and VF

Cunming Liang (13):
eal: vfio map misc intr to vector zero
ixgbe: reserve intr vector zero for misc cause
igb: reserve intr vector zero for misc cause
eal/linux: not allow to enable zero intr efd
ixgbe: fix efd_enable with zero number
igb: fix efd_enable with zero number
eal: add intr api to report multi-vector capability
ixgbe: fix rx intr compatible issue with PF mbox
ixgbe: fix unnecessary intr_vec free in dev_close
ixgbevf: cleanup unnecessary interrupt handler
igb: fix rx intr compatible issue with PF mbox
i40e: add rx interrupt support
i40evf: add rx interrupt support

doc/guides/rel_notes/release_2_2.rst | 5 +
drivers/net/e1000/e1000_ethdev.h | 3 +
drivers/net/e1000/igb_ethdev.c | 62 +++-
drivers/net/i40e/i40e_ethdev.c | 378 +++++++++++++++++----
drivers/net/i40e/i40e_ethdev.h | 20 ++
drivers/net/i40e/i40e_ethdev_vf.c | 144 +++++++-
drivers/net/i40e/i40e_pf.c | 7 +-
drivers/net/ixgbe/ixgbe_ethdev.c | 143 +++-----
drivers/net/ixgbe/ixgbe_ethdev.h | 3 +
lib/librte_eal/bsdapp/eal/eal_interrupts.c | 7 +
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 16 +-
lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 36 +-
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 15 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +
15 files changed, 651 insertions(+), 202 deletions(-)
--
2.4.3
Cunming Liang
2015-11-04 08:45:28 UTC
Permalink
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve the first vector to misc interrupt.

v3 changes:
- rename MISC_VEC_ID to RTE_INTR_VEC_ZERO_OFFSET
- rename RX_VEC_START to RTE_INTR_VEC_RXTX_OFFSET
- add macro definition in bsd header file

Signed-off-by: Cunming Liang <***@intel.com>
---
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 3 +++
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 19 +++++++++++++------
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 2 ++
3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 88d4ae1..05bb484 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -38,6 +38,9 @@
#ifndef _RTE_BSDAPP_INTERRUPTS_H_
#define _RTE_BSDAPP_INTERRUPTS_H_

+#define RTE_INTR_VEC_ZERO_OFFSET 0
+#define RTE_INTR_VEC_RXTX_OFFSET 1
+
enum rte_intr_handle_type {
RTE_INTR_HANDLE_UNKNOWN = 0,
RTE_INTR_HANDLE_UIO, /**< uio device handle */
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index a4b9506..8758239 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -301,8 +301,10 @@ vfio_enable_msix(struct rte_intr_handle *intr_handle) {
irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
irq_set->start = 0;
fd_ptr = (int *) &irq_set->data;
- memcpy(fd_ptr, intr_handle->efds, sizeof(intr_handle->efds));
- fd_ptr[intr_handle->max_intr - 1] = intr_handle->fd;
+ /* INTR vector offset 0 reserve for non-efds mapping */
+ fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = intr_handle->fd;
+ memcpy(&fd_ptr[RTE_INTR_VEC_RXTX_OFFSET], intr_handle->efds,
+ sizeof(*intr_handle->efds) * intr_handle->nb_efd);

ret = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);

@@ -1083,10 +1085,14 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
struct rte_epoll_event *rev;
struct rte_epoll_data *epdata;
int epfd_op;
+ unsigned int efd_idx;
int rc = 0;

+ efd_idx = (vec >= RTE_INTR_VEC_RXTX_OFFSET) ?
+ (vec - RTE_INTR_VEC_RXTX_OFFSET) : vec;
+
if (!intr_handle || intr_handle->nb_efd == 0 ||
- vec >= intr_handle->nb_efd) {
+ efd_idx >= intr_handle->nb_efd) {
RTE_LOG(ERR, EAL, "Wrong intr vector number.\n");
return -EPERM;
}
@@ -1094,7 +1100,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
switch (op) {
case RTE_INTR_EVENT_ADD:
epfd_op = EPOLL_CTL_ADD;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status != RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event already been added.\n");
return -EEXIST;
@@ -1106,7 +1112,8 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
epdata->data = data;
epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
epdata->cb_arg = (void *)intr_handle;
- rc = rte_epoll_ctl(epfd, epfd_op, intr_handle->efds[vec], rev);
+ rc = rte_epoll_ctl(epfd, epfd_op,
+ intr_handle->efds[efd_idx], rev);
if (!rc)
RTE_LOG(DEBUG, EAL,
"efd %d associated with vec %d added on epfd %d"
@@ -1116,7 +1123,7 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
break;
case RTE_INTR_EVENT_DEL:
epfd_op = EPOLL_CTL_DEL;
- rev = &intr_handle->elist[vec];
+ rev = &intr_handle->elist[efd_idx];
if (rev->status == RTE_EPOLL_INVALID) {
RTE_LOG(INFO, EAL, "Event does not exist.\n");
return -EPERM;
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index b095b86..8da81e7 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -39,6 +39,8 @@
#define _RTE_LINUXAPP_INTERRUPTS_H_

#define RTE_MAX_RXTX_INTR_VEC_ID 32
+#define RTE_INTR_VEC_ZERO_OFFSET 0
+#define RTE_INTR_VEC_RXTX_OFFSET 1

enum rte_intr_handle_type {
RTE_INTR_HANDLE_UNKNOWN = 0,
--
2.4.3
David Marchand
2015-11-04 13:06:14 UTC
Permalink
Post by Cunming Liang
During VFIO_DEVICE_SET_IRQS, the previous order is {Q0_fd, ... Qn_fd, misc_fd}.
The vector number of misc is indeterminable which is ugly to some NIC(e.g. i40e, fm10k).
The patch adjusts the order in {misc_fd, Q0_fd, ... Qn_fd}, always reserve
the first vector to misc interrupt.
- rename MISC_VEC_ID to RTE_INTR_VEC_ZERO_OFFSET
- rename RX_VEC_START to RTE_INTR_VEC_RXTX_OFFSET
- add macro definition in bsd header file
Acked-by: David Marchand <***@6wind.com>
--
David Marchand
Cunming Liang
2015-11-04 08:45:29 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

v3 changes:
- macro renaming according to the EAL change

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 22 ++++++++++++++--------
drivers/net/ixgbe/ixgbe_ethdev.h | 3 +++
2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 25966ef..153ba98 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -4478,7 +4478,8 @@ ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask |= (1 << queue_id);
+ mask |= (1 << IXGBE_MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

rte_intr_enable(&dev->pci_dev->intr_handle);
@@ -4494,7 +4495,8 @@ ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask &= ~(1 << queue_id);
+ mask &= ~(1 << IXGBE_MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

return 0;
@@ -4630,7 +4632,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
uint32_t q_idx;
- uint32_t vector_idx = 0;
+ uint32_t vector_idx = IXGBE_MISC_VEC_ID;

/* won't configure msix register if no mapping is done
* between intr vector and event fd.
@@ -4662,7 +4664,8 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint32_t queue_id, vec = 0;
+ uint32_t queue_id, base = IXGBE_MISC_VEC_ID;
+ uint32_t vec = IXGBE_MISC_VEC_ID;
uint32_t mask;
uint32_t gpie;

@@ -4672,6 +4675,9 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
if (!rte_intr_dp_is_en(intr_handle))
return;

+ if (rte_intr_allow_others(intr_handle))
+ vec = base = IXGBE_RX_VEC_START;
+
/* setup GPIE for MSI-x mode */
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
gpie |= IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_PBA_SUPPORT |
@@ -4695,23 +4701,23 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
/* by default, 1:1 mapping */
ixgbe_set_ivar_map(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++;
}

switch (hw->mac.type) {
case ixgbe_mac_82598EB:
ixgbe_set_ivar_map(hw, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
- intr_handle->max_intr - 1);
+ IXGBE_MISC_VEC_ID);
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- ixgbe_set_ivar_map(hw, -1, 1, intr_handle->max_intr - 1);
+ ixgbe_set_ivar_map(hw, -1, 1, IXGBE_MISC_VEC_ID);
break;
default:
break;
}
- IXGBE_WRITE_REG(hw, IXGBE_EITR(queue_id),
+ IXGBE_WRITE_REG(hw, IXGBE_EITR(IXGBE_MISC_VEC_ID),
IXGBE_MIN_INTER_INTERRUPT_INTERVAL_DEFAULT & 0xFFF);

/* set up to autoclear timer, and the vectors */
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h b/drivers/net/ixgbe/ixgbe_ethdev.h
index 569d678..1856c42 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.h
+++ b/drivers/net/ixgbe/ixgbe_ethdev.h
@@ -123,6 +123,9 @@
#define IXGBE_VF_IRQ_ENABLE_MASK 3 /* vf irq enable mask */
#define IXGBE_VF_MAXMSIVECTOR 1

+#define IXGBE_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
+#define IXGBE_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
+
/*
* Information about the fdir mode.
*/
--
2.4.3
Cunming Liang
2015-11-04 08:45:30 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

v3 change:
- macro renaming according to the EAL change

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/e1000_ethdev.h | 3 +++
drivers/net/e1000/igb_ethdev.c | 19 ++++++++++++++-----
2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/net/e1000/e1000_ethdev.h b/drivers/net/e1000/e1000_ethdev.h
index 3c6f613..a667a1a 100644
--- a/drivers/net/e1000/e1000_ethdev.h
+++ b/drivers/net/e1000/e1000_ethdev.h
@@ -132,6 +132,9 @@
#define EM_RXD_ALIGN (E1000_ALIGN / sizeof(struct e1000_rx_desc))
#define EM_TXD_ALIGN (E1000_ALIGN / sizeof(struct e1000_data_desc))

+#define E1000_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
+#define E1000_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
+
/* structure for interrupt relative data */
struct e1000_interrupt {
uint32_t flags;
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index cd7f7c1..1332974 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -4495,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
@@ -4504,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);
@@ -4532,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);

@@ -4547,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++;
}
--
2.4.3
Cunming Liang
2015-11-04 08:45:31 UTC
Permalink
The patch adds condition check to avoid enable nothing.
In disable state, both max_intr and nb_efd are zero.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 8 +++++++-
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 05bb484..3d138bf 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -85,8 +85,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 8758239..8938067 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -45,6 +45,7 @@
#include <sys/signalfd.h>
#include <sys/ioctl.h>
#include <sys/eventfd.h>
+#include <assert.h>

#include <rte_common.h>
#include <rte_interrupts.h>
@@ -1148,6 +1149,8 @@ rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
int fd;
uint32_t n = RTE_MIN(nb_efd, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);

+ assert(nb_efd != 0);
+
if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX) {
for (i = 0; i < n; i++) {
fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
@@ -1204,5 +1207,8 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle)
{
- return !!(intr_handle->max_intr - intr_handle->nb_efd);
+ if (!rte_intr_dp_is_en(intr_handle))
+ return 1;
+ else
+ return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 8da81e7..b44e69c 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -176,8 +176,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
--
2.4.3
David Marchand
2015-11-04 13:06:38 UTC
Permalink
Post by Cunming Liang
The patch adds condition check to avoid enable nothing.
In disable state, both max_intr and nb_efd are zero.
Acked-by: David Marchand <***@6wind.com>
--
David Marchand
Cunming Liang
2015-11-04 08:45:32 UTC
Permalink
Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 153ba98..f1a738c 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1975,11 +1975,11 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_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) {
intr_handle->intr_vec =
@@ -3862,11 +3862,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
ixgbevf_dev_rxtx_start(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) {
intr_handle->intr_vec =
--
2.4.3
Cunming Liang
2015-11-04 08:45:33 UTC
Permalink
Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/igb_ethdev.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 1332974..76d2acc 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -1122,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 =
--
2.4.3
Cunming Liang
2015-11-04 08:45:34 UTC
Permalink
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.

v3 change:
- add new api dummy in bsdapp

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/bsdapp/eal/eal_interrupts.c | 7 +++++++
lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 9 +++++++++
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++
6 files changed, 50 insertions(+)

diff --git a/lib/librte_eal/bsdapp/eal/eal_interrupts.c b/lib/librte_eal/bsdapp/eal/eal_interrupts.c
index 51a13fa..836e483 100644
--- a/lib/librte_eal/bsdapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/bsdapp/eal/eal_interrupts.c
@@ -110,3 +110,10 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle)
RTE_SET_USED(intr_handle);
return 1;
}
+
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
+{
+ RTE_SET_USED(intr_handle);
+ return 0;
+}
diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 3d138bf..70a7087 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -122,4 +122,14 @@ int rte_intr_dp_is_en(struct rte_intr_handle *intr_handle);
*/
int rte_intr_allow_others(struct rte_intr_handle *intr_handle);

+/**
+ * The multiple interrupt vector capability of interrupt handle instance.
+ * It returns zero if no multiple interrupt vector support.
+ *
+ * @param intr_handle
+ * Pointer to the interrupt handle.
+ */
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);
+
#endif /* _RTE_BSDAPP_INTERRUPTS_H_ */
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 64fdfb1..8b00761 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -125,3 +125,10 @@ DPDK_2.1 {
rte_memzone_free;

} DPDK_2.0;
+
+DPDK_2.2 {
+ global:
+
+ rte_intr_cap_multiple;
+
+} DPDK_2.1;
\ No newline at end of file
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 8938067..95beb4c 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -1212,3 +1212,12 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle)
else
return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
+
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
+{
+ if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX)
+ return 1;
+
+ return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index b44e69c..3dacbff 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -215,4 +215,14 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle);
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle);

+/**
+ * The multiple interrupt vector capability of interrupt handle instance.
+ * It returns zero if no multiple interrupt vector support.
+ *
+ * @param intr_handle
+ * Pointer to the interrupt handle.
+ */
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);
+
#endif /* _RTE_LINUXAPP_INTERRUPTS_H_ */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index dbb8fa1..cb9f4d6 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -128,3 +128,10 @@ DPDK_2.1 {
rte_memzone_free;

} DPDK_2.0;
+
+DPDK_2.2 {
+ global:
+
+ rte_intr_cap_multiple;
+
+} DPDK_2.1;
\ No newline at end of file
--
2.4.3
David Marchand
2015-11-04 13:07:03 UTC
Permalink
Post by Cunming Liang
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.
- add new api dummy in bsdapp
Acked-by: David Marchand <***@6wind.com>
--
David Marchand
Cunming Liang
2015-11-04 08:45:35 UTC
Permalink
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

v4 change:
- remove redundancy condition check

v3 change:
- add doc update follow on the code change

Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 2 ++
drivers/net/ixgbe/ixgbe_ethdev.c | 38 +++++++++++++++++++++++++-----------
2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index ca8471b..b082fb6 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -152,6 +152,8 @@ Drivers
hardware transactional memory support, thread scaling did not work,
due to the global ring that is shared by all cores.

+* **ixgbe: Fixed PF rx interrupt compatible issue with mbox.**
+
Libraries
~~~~~~~~~

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index f1a738c..c322168 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1126,6 +1126,13 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&pci_dev->intr_handle);
+
/* enable support intr */
ixgbe_enable_intr(eth_dev);

@@ -1975,7 +1982,9 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_pf_host_configure(dev);

/* check and configure queue intr-vector mapping */
- if (dev->data->dev_conf.intr_conf.rxq != 0) {
+ if ((rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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;
@@ -1984,8 +1993,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
- dev->data->nb_rx_queues * sizeof(int),
- 0);
+ dev->data->nb_rx_queues * sizeof(int), 0);
if (intr_handle->intr_vec == NULL) {
PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
" intr_vec\n", dev->data->nb_rx_queues);
@@ -2072,20 +2080,22 @@ ixgbe_dev_start(struct rte_eth_dev *dev)

skip_link_setup:

- /* check if lsc interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- ixgbe_dev_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
ixgbe_dev_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
ixgbe_dev_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -2197,6 +2207,12 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
memset(filter_info->fivetuple_mask, 0,
sizeof(uint32_t) * IXGBE_5TUPLE_ARRAY_SIZE);

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-11-04 08:45:36 UTC
Permalink
The intr_vec is free in dev_stop. It's not necessary to check in dev_close.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 7 -------
1 file changed, 7 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index c322168..948a84f 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -3951,7 +3951,6 @@ static void
ixgbevf_dev_close(struct rte_eth_dev *dev)
{
struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev;

PMD_INIT_FUNC_TRACE();

@@ -3963,12 +3962,6 @@ ixgbevf_dev_close(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);
-
- pci_dev = dev->pci_dev;
- if (pci_dev->intr_handle.intr_vec) {
- rte_free(pci_dev->intr_handle.intr_vec);
- pci_dev->intr_handle.intr_vec = NULL;
- }
}

static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
--
2.4.3
Cunming Liang
2015-11-04 08:45:37 UTC
Permalink
As ixgbe vf doesn't support lsc, the patch removes those unused code.
In addition, it does some tiny cleanup.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 62 +---------------------------------------
1 file changed, 1 insertion(+), 61 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 948a84f..c0dbf79 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -208,8 +208,6 @@ static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_conf
/* For Virtual Function support */
static int eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev);
static int eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev);
-static int ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev);
-static int ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev);
static int ixgbevf_dev_configure(struct rte_eth_dev *dev);
static int ixgbevf_dev_start(struct rte_eth_dev *dev);
static void ixgbevf_dev_stop(struct rte_eth_dev *dev);
@@ -225,8 +223,6 @@ 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);
-static void ixgbevf_dev_interrupt_handler(struct rte_intr_handle *handle,
- void *param);
static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
uint16_t queue_id);
static int ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
@@ -3067,30 +3063,6 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev)
-{
- uint32_t eicr;
- struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct ixgbe_interrupt *intr =
- IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-
- /* clear all cause mask */
- ixgbevf_intr_disable(hw);
-
- /* read-on-clear nic registers here */
- eicr = IXGBE_READ_REG(hw, IXGBE_VTEICR);
- PMD_DRV_LOG(INFO, "eicr %x", eicr);
-
- intr->flags = 0;
-
- /* set flag for async link update */
- if (eicr & IXGBE_EICR_LSC)
- intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-
- return 0;
-}
-
/**
* It gets and then prints the link status.
*
@@ -3186,18 +3158,6 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev)
-{
- struct ixgbe_hw *hw =
- IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
- PMD_DRV_LOG(DEBUG, "enable intr immediately");
- ixgbevf_intr_enable(hw);
- rte_intr_enable(&dev->pci_dev->intr_handle);
- return 0;
-}
-
/**
* Interrupt handler which shall be registered for alarm callback for delayed
* handling specific interrupt to wait for the stable nic state. As the
@@ -3260,16 +3220,6 @@ ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
ixgbe_dev_interrupt_action(dev);
}

-static void
-ixgbevf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
- void *param)
-{
- struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-
- ixgbevf_dev_interrupt_get_status(dev);
- ixgbevf_dev_interrupt_action(dev);
-}
-
static int
ixgbe_dev_led_on(struct rte_eth_dev *dev)
{
@@ -3896,16 +3846,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
}
ixgbevf_configure_msix(dev);

- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle))
- rte_intr_callback_register(intr_handle,
- ixgbevf_dev_interrupt_handler,
- (void *)dev);
- else
- PMD_INIT_LOG(INFO, "lsc won't enable because of"
- " no intr multiplex\n");
- }
-
rte_intr_enable(intr_handle);

/* Re-enable interrupt for VF */
@@ -4658,7 +4598,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
intr_handle->intr_vec[q_idx] = vector_idx;
}

- /* Configure VF Rx queue ivar */
+ /* Configure VF other cause ivar */
ixgbevf_set_ivar_map(hw, -1, 1, vector_idx);
}
--
2.4.3
Cunming Liang
2015-11-04 08:45:39 UTC
Permalink
The patch enables rx interrupt support on i40e PF non-IOV mode.
Per queue rx interrupt works on vfio, however on uio, all rx queues share one interrupt vector.

v4 change:
- remove redundancy condition check

v3 change:
- macro change according the EAL
- add doc update follow on the code change

v2 change:
- add write flush
- always set DIS_AUTOMASK_

Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 1 +
drivers/net/i40e/i40e_ethdev.c | 346 ++++++++++++++++++++++++++++++-----
drivers/net/i40e/i40e_ethdev.h | 5 +
drivers/net/i40e/i40e_pf.c | 2 +
4 files changed, 305 insertions(+), 49 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 38b0612..154bf29 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -90,6 +90,7 @@ New Features

* **Added port hotplug support to xenvirt.**

+* **Added interrupt mode support on i40e.**

Resolved Issues
---------------
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 34acc8c..3de1c5c 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -39,6 +39,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <inttypes.h>
+#include <assert.h>

#include <rte_string_fns.h>
#include <rte_pci.h>
@@ -343,7 +344,7 @@ static void i40e_stat_update_48(struct i40e_hw *hw,
bool offset_loaded,
uint64_t *offset,
uint64_t *stat);
-static void i40e_pf_config_irq0(struct i40e_hw *hw);
+static void i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue);
static void i40e_dev_interrupt_handler(
__rte_unused struct rte_intr_handle *handle, void *param);
static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
@@ -404,7 +405,10 @@ static int i40e_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
static int i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
struct timespec *timestamp);
static void i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw);
-
+static int i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
+ uint16_t queue_id);
+static int i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
+ uint16_t queue_id);

static const struct rte_pci_id pci_id_i40e_map[] = {
#define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -440,6 +444,8 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
.tx_queue_start = i40e_dev_tx_queue_start,
.tx_queue_stop = i40e_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
+ .rx_queue_intr_enable = i40e_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40e_dev_rx_queue_intr_disable,
.rx_queue_release = i40e_dev_rx_queue_release,
.rx_queue_count = i40e_dev_rx_queue_count,
.rx_descriptor_done = i40e_dev_rx_descriptor_done,
@@ -875,7 +881,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
i40e_dev_interrupt_handler, (void *)dev);

/* configure and enable device interrupt */
- i40e_pf_config_irq0(hw);
+ i40e_pf_config_irq0(hw, TRUE);
i40e_pf_enable_irq0(hw);

/* enable uio intr after callback register */
@@ -1056,6 +1062,8 @@ err:
void
i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t msix_vect = vsi->msix_intr;
uint16_t i;
@@ -1067,15 +1075,26 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
}

if (vsi->type != I40E_VSI_SRIOV) {
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1), 0);
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), 0);
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ 0);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1), 0);
+ }
} else {
uint32_t reg;
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), 0);
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
}
I40E_WRITE_FLUSH(hw);
}
@@ -1090,29 +1109,26 @@ i40e_calc_itr_interval(int16_t interval)
return (interval/2);
}

-void
-i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+static void
+__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
+ int base_queue, int nb_queue)
{
+ int i;
uint32_t val;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
- uint16_t msix_vect = vsi->msix_intr;
- int i;
-
- for (i = 0; i < vsi->nb_qps; i++)
- I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);

/* Bind all RX queues to allocated MSIX interrupt */
- for (i = 0; i < vsi->nb_qps; i++) {
+ for (i = 0; i < nb_queue; i++) {
val = (msix_vect << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
I40E_QINT_RQCTL_ITR_INDX_MASK |
- ((vsi->base_queue + i + 1) <<
- I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+ ((base_queue + i + 1) <<
+ I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
(0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
I40E_QINT_RQCTL_CAUSE_ENA_MASK;

- if (i == vsi->nb_qps - 1)
+ if (i == nb_queue - 1)
val |= I40E_QINT_RQCTL_NEXTQ_INDX_MASK;
- I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), val);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(base_queue + i), val);
}

/* Write first RX queue to Link list register as the head element */
@@ -1120,21 +1136,26 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
uint16_t interval =
i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);

- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
- (vsi->base_queue <<
- I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
-
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), interval);
-
-#ifndef I40E_GLINT_CTL
-#define I40E_GLINT_CTL 0x0003F800
-#define I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK 0x4
-#endif
- /* Disable auto-mask on enabling of all none-zero interrupt */
- I40E_WRITE_REG(hw, I40E_GLINT_CTL,
- I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK);
+ if (msix_vect == I40E_MISC_VEC_ID) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ (base_queue <<
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ interval);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ (base_queue <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1),
+ interval);
+ }
} else {
uint32_t reg;

@@ -1142,34 +1163,134 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (vsi->base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
(0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
}

I40E_WRITE_FLUSH(hw);
}

+void
+i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_vect = vsi->msix_intr;
+ uint16_t nb_msix = RTE_MIN(vsi->nb_msix, intr_handle->nb_efd);
+ uint16_t queue_idx = 0;
+ int record = 0;
+ uint32_t val;
+ int i;
+
+ for (i = 0; i < vsi->nb_qps; i++) {
+ I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
+ }
+
+ /* INTENA flag is not auto-cleared for interrupt */
+ val = I40E_READ_REG(hw, I40E_GLINT_CTL);
+ val |= I40E_GLINT_CTL_DIS_AUTOMASK_PF0_MASK |
+ I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK |
+ I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK;
+ I40E_WRITE_REG(hw, I40E_GLINT_CTL, val);
+
+ /* VF bind interrupt */
+ if (vsi->type == I40E_VSI_SRIOV) {
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue, vsi->nb_qps);
+ return;
+ }
+
+ /* PF & VMDq bind interrupt */
+ if (rte_intr_dp_is_en(intr_handle)) {
+ if (vsi->type == I40E_VSI_MAIN) {
+ queue_idx = 0;
+ record = 1;
+ } else if (vsi->type == I40E_VSI_VMDQ2) {
+ struct i40e_vsi *main_vsi =
+ I40E_DEV_PRIVATE_TO_MAIN_VSI(vsi->adapter);
+ queue_idx = vsi->base_queue - main_vsi->nb_qps;
+ record = 1;
+ }
+ }
+
+ for (i = 0; i < vsi->nb_used_qps; i++) {
+ if (nb_msix <= 1) {
+ if (!rte_intr_allow_others(intr_handle))
+ /* allow to share MISC_VEC_ID */
+ msix_vect = I40E_MISC_VEC_ID;
+
+ /* no enough msix_vect, map all to one */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i,
+ vsi->nb_used_qps - i);
+ for (; !!record && i < vsi->nb_used_qps; i++)
+ intr_handle->intr_vec[queue_idx + i] =
+ msix_vect;
+ break;
+ }
+ /* 1:1 queue/msix_vect mapping */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i, 1);
+ if (!!record)
+ intr_handle->intr_vec[queue_idx + i] = msix_vect;
+
+ msix_vect++;
+ nb_msix--;
+ }
+}
+
static void
i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t interval = i40e_calc_itr_interval(\
- RTE_LIBRTE_I40E_ITR_INTERVAL);
-
- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1),
- I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr, i;
+
+ if (rte_intr_allow_others(intr_handle))
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
(0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
- (interval << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ }
+ else
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTL0_INTENA_MASK |
+ I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
}

static void
i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_intr, i;

- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1), 0);
+ if (rte_intr_allow_others(intr_handle))
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ 0);
+ }
+ else
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+
+ I40E_WRITE_FLUSH(hw);
}

static inline uint8_t
@@ -1279,6 +1400,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
int ret, i;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t intr_vector = 0;

hw->adapter_stopped = 0;

@@ -1290,6 +1413,28 @@ i40e_dev_start(struct rte_eth_dev *dev)
return -EINVAL;
}

+ rte_intr_disable(intr_handle);
+
+ if ((rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int),
+ 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
/* Initialize VSI */
ret = i40e_dev_rxtx_init(pf);
if (ret != I40E_SUCCESS) {
@@ -1298,11 +1443,14 @@ i40e_dev_start(struct rte_eth_dev *dev)
}

/* Map queues with MSIX interrupt */
+ main_vsi->nb_used_qps = dev->data->nb_rx_queues -
+ pf->nb_cfg_vmdq_vsi * RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(main_vsi);
i40e_vsi_enable_queues_intr(main_vsi);

/* Map VMDQ VSI queues with MSIX interrupt */
for (i = 0; i < pf->nb_cfg_vmdq_vsi; i++) {
+ pf->vmdq[i].vsi->nb_used_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(pf->vmdq[i].vsi);
i40e_vsi_enable_queues_intr(pf->vmdq[i].vsi);
}
@@ -1339,6 +1487,22 @@ i40e_dev_start(struct rte_eth_dev *dev)
goto err_up;
}

+ if (!rte_intr_allow_others(intr_handle)) {
+ rte_intr_callback_unregister(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+ /* configure and enable device interrupt */
+ i40e_pf_config_irq0(hw, FALSE);
+ i40e_pf_enable_irq0(hw);
+
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
+ PMD_INIT_LOG(INFO, "lsc won't enable because of"
+ " no intr multiplex\n");
+ }
+
+ /* enable uio intr after callback register */
+ rte_intr_enable(intr_handle);
+
return I40E_SUCCESS;

err_up:
@@ -1354,6 +1518,7 @@ i40e_dev_stop(struct rte_eth_dev *dev)
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
struct i40e_mirror_rule *p_mirror;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
int i;

/* Disable all queues */
@@ -1385,6 +1550,18 @@ i40e_dev_stop(struct rte_eth_dev *dev)
}
pf->nb_mirror_rule = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static void
@@ -3701,15 +3878,30 @@ i40e_vsi_setup(struct i40e_pf *pf,
vsi->base_queue = I40E_FDIR_QUEUE_ID;

/* VF has MSIX interrupt in VF range, don't allocate here */
- if (type != I40E_VSI_SRIOV) {
+ if (type == I40E_VSI_MAIN) {
+ ret = i40e_res_pool_alloc(&pf->msix_pool,
+ RTE_MIN(vsi->nb_qps,
+ RTE_MAX_RXTX_INTR_VEC_ID));
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "VSI MAIN %d get heap failed %d",
+ vsi->seid, ret);
+ goto fail_queue_alloc;
+ }
+ vsi->msix_intr = ret;
+ vsi->nb_msix = RTE_MIN(vsi->nb_qps, RTE_MAX_RXTX_INTR_VEC_ID);
+ } else if (type != I40E_VSI_SRIOV) {
ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
if (ret < 0) {
PMD_DRV_LOG(ERR, "VSI %d get heap failed %d", vsi->seid, ret);
goto fail_queue_alloc;
}
vsi->msix_intr = ret;
- } else
+ vsi->nb_msix = 1;
+ } else {
vsi->msix_intr = 0;
+ vsi->nb_msix = 0;
+ }
+
/* Add VSI */
if (type == I40E_VSI_MAIN) {
/* For main VSI, no need to add since it's default one */
@@ -4553,7 +4745,7 @@ i40e_pf_enable_irq0(struct i40e_hw *hw)
}

static void
-i40e_pf_config_irq0(struct i40e_hw *hw)
+i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue)
{
/* read pending request and disable first */
i40e_pf_disable_irq0(hw);
@@ -4561,9 +4753,10 @@ i40e_pf_config_irq0(struct i40e_hw *hw)
I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0,
I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK);

- /* Link no queues with irq0 */
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
- I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ if (no_queue)
+ /* Link no queues with irq0 */
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
}

static void
@@ -8147,6 +8340,7 @@ i40e_dcb_setup(struct rte_eth_dev *dev)
PMD_INIT_LOG(ERR, "dcb sw configure fails");
return -ENOSYS;
}
+
return 0;
}

@@ -8186,5 +8380,59 @@ i40e_dev_get_dcb_info(struct rte_eth_dev *dev,
dcb_info->tc_queue.tc_rxq[0][i].nb_queue;
}
}
+
+ return 0;
+}
+
+static int
+i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr -
+ I40E_RX_VEC_START),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr -
+ I40E_RX_VEC_START),
+ 0);
+ I40E_WRITE_FLUSH(hw);
+
return 0;
}
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index c64f83b..eff3adb 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -159,6 +159,9 @@ enum i40e_flxpld_layer_idx {
(1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \
(1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))

+#define I40E_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
+#define I40E_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
+
struct i40e_adapter;

/**
@@ -256,6 +259,7 @@ struct i40e_vsi {
uint16_t seid; /* The seid of VSI itself */
uint16_t uplink_seid; /* The uplink seid of this VSI */
uint16_t nb_qps; /* Number of queue pairs VSI can occupy */
+ uint16_t nb_used_qps; /* Number of queue pairs VSI uses */
uint16_t max_macaddrs; /* Maximum number of MAC addresses */
uint16_t base_queue; /* The first queue index of this VSI */
/*
@@ -264,6 +268,7 @@ struct i40e_vsi {
*/
uint16_t vsi_id;
uint16_t msix_intr; /* The MSIX interrupt binds to VSI */
+ uint16_t nb_msix; /* The max number of msix vector */
uint8_t enabled_tc; /* The traffic class enabled */
struct i40e_bw_info bw_info; /* VSI bandwidth information */
};
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 95c960c..c1d58a8 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -554,6 +554,8 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
}
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
+ vf->vsi->nb_msix = irqmap->num_vectors;
+ vf->vsi->nb_used_qps = vf->vsi->nb_qps;

/* Don't care how the TX/RX queue mapping with this vector.
* Link all VF RX queues together. Only did mapping work.
--
2.4.3
Cunming Liang
2015-11-04 08:45:38 UTC
Permalink
When igb runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

v4 change:
- remove redundancy condition check

v3 change:
- add doc update follow on the code change

Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 2 ++
drivers/net/e1000/igb_ethdev.c | 37 ++++++++++++++++++++++++++----------
2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index b082fb6..38b0612 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -154,6 +154,8 @@ Drivers

* **ixgbe: Fixed PF rx interrupt compatible issue with mbox.**

+* **igb: Fixed PF rx interrupt compatible issue with mbox.**
+
Libraries
~~~~~~~~~

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 76d2acc..2cb115c 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -760,6 +760,13 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&pci_dev->intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&pci_dev->intr_handle);
+
/* enable support intr */
igb_intr_enable(eth_dev);

@@ -1122,13 +1129,15 @@ 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 ((rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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_dp_is_en(intr_handle)) {
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
dev->data->nb_rx_queues * sizeof(int), 0);
@@ -1221,20 +1230,22 @@ eth_igb_start(struct rte_eth_dev *dev)
}
e1000_setup_link(hw);

- /* check if lsc interrupt feature is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- eth_igb_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
eth_igb_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
eth_igb_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -1327,6 +1338,12 @@ eth_igb_stop(struct rte_eth_dev *dev)
}
filter_info->twotuple_mask = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-11-04 08:45:40 UTC
Permalink
The patch enables rx interrupt support on i40e VF and some necessary change on PF IOV mode to support VF.
On PF side, running in IOV mode via uio won't allow rx interrupt which is exclusive with mbox interrupt
in single vector competition.
On VF side, one single vector is shared for all the rx queues.

v3 changes:
- macro change according to EAL
- rebase on patch http://dpdk.org/dev/patchwork/patch/7790

v2 changes:
- turn on intr only when rxq flag is set
- rework base on patch http://dpdk.org/dev/patchwork/patch/7504/

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 38 +++++-----
drivers/net/i40e/i40e_ethdev.h | 15 ++++
drivers/net/i40e/i40e_ethdev_vf.c | 146 +++++++++++++++++++++++++++++++++++---
drivers/net/i40e/i40e_pf.c | 5 --
4 files changed, 169 insertions(+), 35 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 3de1c5c..2d1c445 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -76,11 +76,6 @@
/* Maximun number of VSI */
#define I40E_MAX_NUM_VSIS (384UL)

-/* Default queue interrupt throttling time in microseconds */
-#define I40E_ITR_INDEX_DEFAULT 0
-#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
-#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
-
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */

/* Flow control default timer */
@@ -1099,16 +1094,6 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
I40E_WRITE_FLUSH(hw);
}

-static inline uint16_t
-i40e_calc_itr_interval(int16_t interval)
-{
- if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
- interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
-
- /* Convert to hardware count, as writing each 1 represents 2 us */
- return (interval/2);
-}
-
static void
__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
int base_queue, int nb_queue)
@@ -1159,13 +1144,24 @@ __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
} else {
uint32_t reg;

- /* num_msix_vectors_vf needs to minus irq0 */
- reg = (hw->func_caps.num_msix_vectors_vf - 1) *
- vsi->user_param + (msix_vect - 1);
+ if (msix_vect == I40E_MISC_VEC_ID) {
+ I40E_WRITE_REG(hw,
+ I40E_VPINT_LNKLST0(vsi->user_param),
+ (base_queue <<
+ I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ } else {
+ /* num_msix_vectors_vf needs to minus irq0 */
+ reg = (hw->func_caps.num_msix_vectors_vf - 1) *
+ vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ }
}

I40E_WRITE_FLUSH(hw);
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index eff3adb..d281935 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -162,6 +162,11 @@ enum i40e_flxpld_layer_idx {
#define I40E_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
#define I40E_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET

+/* Default queue interrupt throttling time in microseconds */
+#define I40E_ITR_INDEX_DEFAULT 0
+#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
+#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
+
struct i40e_adapter;

/**
@@ -638,6 +643,16 @@ i40e_align_floor(int n)
return 1 << (sizeof(n) * CHAR_BIT - 1 - __builtin_clz(n));
}

+static inline uint16_t
+i40e_calc_itr_interval(int16_t interval)
+{
+ if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
+ interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
+
+ /* Convert to hardware count, as writing each 1 represents 2 us */
+ return (interval / 2);
+}
+
#define I40E_VALID_FLOW(flow_type) \
((flow_type) == RTE_ETH_FLOW_FRAG_IPV4 || \
(flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index 18ec46e..615da8d 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -150,6 +150,10 @@ static int i40evf_dev_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
static int i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);

/* Default hash key buffer for RSS */
static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
@@ -201,6 +205,9 @@ static const struct eth_dev_ops i40evf_eth_dev_ops = {
.tx_queue_stop = i40evf_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
.rx_queue_release = i40e_dev_rx_queue_release,
+ .rx_queue_intr_enable = i40evf_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40evf_dev_rx_queue_intr_disable,
+ .rx_descriptor_done = i40e_dev_rx_descriptor_done,
.tx_queue_setup = i40e_dev_tx_queue_setup,
.tx_queue_release = i40e_dev_tx_queue_release,
.reta_update = i40evf_dev_rss_reta_update,
@@ -741,22 +748,33 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_irq_map_info) + \
sizeof(struct i40e_virtchnl_vector_map)];
struct i40e_virtchnl_irq_map_info *map_info;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t vector_id;
int i, err;
+
+ if (rte_intr_allow_others(intr_handle)) {
+ if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ else
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
+ } else {
+ vector_id = I40E_MISC_VEC_ID;
+ }
+
map_info = (struct i40e_virtchnl_irq_map_info *)cmd_buffer;
map_info->num_vectors = 1;
map_info->vecmap[0].rxitr_idx = I40E_QINT_RQCTL_MSIX_INDX_NOITR;
map_info->vecmap[0].vsi_id = vf->vsi_res->vsi_id;
/* Alway use default dynamic MSIX interrupt */
- if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
- else
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
-
+ map_info->vecmap[0].vector_id = vector_id;
/* Don't map any tx queue */
map_info->vecmap[0].txq_map = 0;
map_info->vecmap[0].rxq_map = 0;
- for (i = 0; i < dev->data->nb_rx_queues; i++)
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
map_info->vecmap[0].rxq_map |= 1 << i;
+ if (rte_intr_dp_is_en(intr_handle))
+ intr_handle->intr_vec[i] = vector_id;
+ }

args.ops = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP;
args.in_args = (u8 *)cmd_buffer;
@@ -1669,6 +1687,16 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+ I40E_WRITE_FLUSH(hw);
+ return;
+ }

if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
/* To support DPDK PF host */
@@ -1681,6 +1709,8 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
I40E_VFINT_DYN_CTL01_INTENA_MASK |
I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+
+ I40E_WRITE_FLUSH(hw);
}

static inline void
@@ -1688,13 +1718,78 @@ i40evf_disable_queues_intr(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ I40E_WRITE_FLUSH(hw);
+ return;
+ }

if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
I40E_WRITE_REG(hw,
- I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
- 0);
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR
+ - 1),
+ 0);
+ else
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+
+ I40E_WRITE_FLUSH(hw);
+}
+
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT));
else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr -
+ I40E_RX_VEC_START),
+ I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+ I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
+
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == I40E_MISC_VEC_ID)
I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr -
+ I40E_RX_VEC_START),
+ 0);
+
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}

static int
@@ -1702,7 +1797,9 @@ i40evf_dev_start(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ether_addr mac_addr;
+ uint32_t intr_vector = 0;

PMD_INIT_FUNC_TRACE();

@@ -1712,6 +1809,24 @@ i40evf_dev_start(struct rte_eth_dev *dev)
vf->num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
dev->data->nb_tx_queues);

+ /* check and configure queue intr-vector mapping */
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int), 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
if (i40evf_rx_init(dev) != 0){
PMD_DRV_LOG(ERR, "failed to do RX init");
return -1;
@@ -1741,6 +1856,10 @@ i40evf_dev_start(struct rte_eth_dev *dev)
goto err_mac;
}

+ /* vf don't allow intr except for rxq intr */
+ if (dev->data->dev_conf.intr_conf.rxq != 0)
+ rte_intr_enable(intr_handle);
+
i40evf_enable_queues_intr(dev);
return 0;

@@ -1753,11 +1872,20 @@ err_queue:
static void
i40evf_dev_stop(struct rte_eth_dev *dev)
{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
PMD_INIT_FUNC_TRACE();

- i40evf_disable_queues_intr(dev);
i40evf_stop_queues(dev);
+ i40evf_disable_queues_intr(dev);
i40e_dev_clear_queues(dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static int
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index c1d58a8..cbf4e5b 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -547,11 +547,6 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
goto send_msg;
}

- if (irqmap->vecmap[0].vector_id == 0) {
- PMD_DRV_LOG(ERR, "DPDK host don't support use IRQ0");
- ret = I40E_ERR_PARAM;
- goto send_msg;
- }
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
vf->vsi->nb_msix = irqmap->num_vectors;
--
2.4.3
Thomas Monjalon
2015-11-04 14:29:10 UTC
Permalink
Post by Cunming Liang
- remove redundancy condition check on PF
- rename MISC_VEC_ID and RX_VEC_START
- add bsdapp dummy
- split cleanup and fix patches
- merge doc update along with code change
- rework to depend on one previous patch
patch http://dpdk.org/dev/patchwork/patch/7504/
- always set DIS_AUTOMASK_* bit in PF to avoid ENA flag auto-clear
This patch series contains four major parts.
1. always reserve vector zero for misc cause in vfio mapping
2. add api to declare the capability of multiple interrupt vector support
3. fix the rx interrupt compatible issue with mbox in ixgbe/igb IOV-PF
4. add rx interrupt support in i40e PF and VF
Applied, thanks

Cunming Liang
2015-10-30 05:27:46 UTC
Permalink
The patch adds condition check to avoid enable nothing.
In disable state, both max_intr and nb_efd are zero.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 8 +++++++-
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 3 ++-
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
index 88d4ae1..cd8817d 100644
--- a/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/bsdapp/eal/include/exec-env/rte_interrupts.h
@@ -82,8 +82,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 8e76a7a..96226d6 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -45,6 +45,7 @@
#include <sys/signalfd.h>
#include <sys/ioctl.h>
#include <sys/eventfd.h>
+#include <assert.h>

#include <rte_common.h>
#include <rte_interrupts.h>
@@ -1132,6 +1133,8 @@ rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
int fd;
uint32_t n = RTE_MIN(nb_efd, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);

+ assert(nb_efd != 0);
+
if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX) {
for (i = 0; i < n; i++) {
fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
@@ -1188,5 +1191,8 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle)
{
- return !!(intr_handle->max_intr - intr_handle->nb_efd);
+ if (!rte_intr_dp_is_en(intr_handle))
+ return 1;
+ else
+ return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index b8fd318..6a2f495 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -176,8 +176,9 @@ rte_intr_rx_ctl(struct rte_intr_handle *intr_handle,
*
* @param intr_handle
* Pointer to the interrupt handle.
- * @param nb_vec
+ * @param nb_efd
* Number of interrupt vector trying to enable.
+ * The value 0 is not allowed.
* @return
* - On success, zero.
* - On failure, a negative value.
--
2.4.3
He, Shaopeng
2015-10-30 07:11:50 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 04/11] eal/linux: not allow to enable zero intr efd
The patch adds condition check to avoid enable nothing.
In disable state, both max_intr and nb_efd are zero.
Acked-by : Shaopeng He <***@intel.com>
Cunming Liang
2015-10-30 05:27:44 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 4373661..4e1467c 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -4275,7 +4275,8 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- uint32_t queue_id, vec = 0;
+ uint32_t queue_id, base = MISC_VEC_ID;
+ uint32_t vec = MISC_VEC_ID;
uint32_t mask;
uint32_t gpie;

@@ -4285,6 +4286,9 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
if (!rte_intr_dp_is_en(intr_handle))
return;

+ if (rte_intr_allow_others(intr_handle))
+ vec = base = RX_VEC_START;
+
/* setup GPIE for MSI-x mode */
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
gpie |= IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_PBA_SUPPORT |
@@ -4308,23 +4312,23 @@ ixgbe_configure_msix(struct rte_eth_dev *dev)
/* by default, 1:1 mapping */
ixgbe_set_ivar_map(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++;
}

switch (hw->mac.type) {
case ixgbe_mac_82598EB:
ixgbe_set_ivar_map(hw, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
- intr_handle->max_intr - 1);
+ MISC_VEC_ID);
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- ixgbe_set_ivar_map(hw, -1, 1, intr_handle->max_intr - 1);
+ ixgbe_set_ivar_map(hw, -1, 1, MISC_VEC_ID);
break;
default:
break;
}
- IXGBE_WRITE_REG(hw, IXGBE_EITR(queue_id),
+ IXGBE_WRITE_REG(hw, IXGBE_EITR(MISC_VEC_ID),
IXGBE_MIN_INTER_INTERRUPT_INTERVAL_DEFAULT & 0xFFF);

/* set up to autoclear timer, and the vectors */
--
2.4.3
Cunming Liang
2015-10-30 05:27:45 UTC
Permalink
According to the VFIO interrupt mapping, the interrupt vector id for rxq starts from RX_VEC_START.
It doesn't impact the UIO cases.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/igb_ethdev.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 3ab082e..b3a802f 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -4213,7 +4213,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 = MISC_VEC_ID;
+ uint32_t base = 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
@@ -4222,6 +4225,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 = 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);
@@ -4250,8 +4258,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);

@@ -4265,14 +4273,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++;
}
--
2.4.3
Cunming Liang
2015-10-30 05:27:47 UTC
Permalink
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.

Signed-off-by: Cunming Liang <***@intel.com>
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 9 +++++++++
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++
3 files changed, 26 insertions(+)

diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 96226d6..c90bc4d 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -1196,3 +1196,12 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle)
else
return !!(intr_handle->max_intr - intr_handle->nb_efd);
}
+
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
+{
+ if (intr_handle->type == RTE_INTR_HANDLE_VFIO_MSIX)
+ return 1;
+
+ return 0;
+}
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
index 6a2f495..a7b2be4 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -215,4 +215,14 @@ rte_intr_dp_is_en(struct rte_intr_handle *intr_handle);
int
rte_intr_allow_others(struct rte_intr_handle *intr_handle);

+/**
+ * The multiple interrupt vector capability of interrupt handle instance.
+ * It returns zero if no multiple interrupt vector support.
+ *
+ * @param intr_handle
+ * Pointer to the interrupt handle.
+ */
+int
+rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);
+
#endif /* _RTE_LINUXAPP_INTERRUPTS_H_ */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index dbb8fa1..cb9f4d6 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -128,3 +128,10 @@ DPDK_2.1 {
rte_memzone_free;

} DPDK_2.0;
+
+DPDK_2.2 {
+ global:
+
+ rte_intr_cap_multiple;
+
+} DPDK_2.1;
\ No newline at end of file
--
2.4.3
He, Shaopeng
2015-10-30 07:13:24 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 05/11] eal/linux: add intr api to report multi-vector
capability
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.
Acked-by: Shaopeng He <***@intel.com>
David Marchand
2015-11-02 15:59:07 UTC
Permalink
Post by Cunming Liang
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 9 +++++++++
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++
3 files changed, 26 insertions(+)
BSD has wrappers for the rest of this api, please add one for this too.
--
David Marchand
Liang, Cunming
2015-11-04 01:21:27 UTC
Permalink
Hi David,
Post by David Marchand
Post by Cunming Liang
VFIO allows multiple MSI-X vector, others doesn't, but maybe will allow it in the future.
Device drivers need to be aware of the capability.
It's better to avoid condition check on interrupt type(VFIO) everywhere, instead
a capability api is more flexible for the condition change.
---
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 9 +++++++++
lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h | 10 ++++++++++
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++
3 files changed, 26 insertions(+)
BSD has wrappers for the rest of this api, please add one for this too.
Yes, you're right. Thanks.
Cunming Liang
2015-10-30 05:27:48 UTC
Permalink
When ixgbe runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 45 +++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 4e1467c..366923f 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1032,6 +1032,13 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&pci_dev->intr_handle);
+
/* enable support intr */
ixgbe_enable_intr(eth_dev);

@@ -1708,17 +1715,19 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_pf_host_configure(dev);

/* check and configure queue intr-vector mapping */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
- dev->data->nb_rx_queues * sizeof(int),
- 0);
+ dev->data->nb_rx_queues * sizeof(int), 0);
if (intr_handle->intr_vec == NULL) {
PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
" intr_vec\n", dev->data->nb_rx_queues);
@@ -1805,20 +1814,22 @@ ixgbe_dev_start(struct rte_eth_dev *dev)

skip_link_setup:

- /* check if lsc interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- ixgbe_dev_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
ixgbe_dev_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
ixgbe_dev_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -1930,6 +1941,12 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
memset(filter_info->fivetuple_mask, 0,
sizeof(uint32_t) * IXGBE_5TUPLE_ARRAY_SIZE);

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ ixgbe_dev_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-10-30 05:27:49 UTC
Permalink
As ixgbe vf doesn't support lsc, the patch removes those unused code.
In addition, it does some tiny cleanup.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 85 +++++-----------------------------------
1 file changed, 10 insertions(+), 75 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 366923f..794171c 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -206,8 +206,6 @@ static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_conf
/* For Virtual Function support */
static int eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev);
static int eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev);
-static int ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev);
-static int ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev);
static int ixgbevf_dev_configure(struct rte_eth_dev *dev);
static int ixgbevf_dev_start(struct rte_eth_dev *dev);
static void ixgbevf_dev_stop(struct rte_eth_dev *dev);
@@ -223,8 +221,6 @@ 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);
-static void ixgbevf_dev_interrupt_handler(struct rte_intr_handle *handle,
- void *param);
static int ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
uint16_t queue_id);
static int ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
@@ -2681,30 +2677,6 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev)
-{
- uint32_t eicr;
- struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct ixgbe_interrupt *intr =
- IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-
- /* clear all cause mask */
- ixgbevf_intr_disable(hw);
-
- /* read-on-clear nic registers here */
- eicr = IXGBE_READ_REG(hw, IXGBE_VTEICR);
- PMD_DRV_LOG(INFO, "eicr %x", eicr);
-
- intr->flags = 0;
-
- /* set flag for async link update */
- if (eicr & IXGBE_EICR_LSC)
- intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-
- return 0;
-}
-
/**
* It gets and then prints the link status.
*
@@ -2800,18 +2772,6 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
return 0;
}

-static int
-ixgbevf_dev_interrupt_action(struct rte_eth_dev *dev)
-{
- struct ixgbe_hw *hw =
- IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
- PMD_DRV_LOG(DEBUG, "enable intr immediately");
- ixgbevf_intr_enable(hw);
- rte_intr_enable(&dev->pci_dev->intr_handle);
- return 0;
-}
-
/**
* Interrupt handler which shall be registered for alarm callback for delayed
* handling specific interrupt to wait for the stable nic state. As the
@@ -2874,16 +2834,6 @@ ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
ixgbe_dev_interrupt_action(dev);
}

-static void
-ixgbevf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
- void *param)
-{
- struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-
- ixgbevf_dev_interrupt_get_status(dev);
- ixgbevf_dev_interrupt_action(dev);
-}
-
static int
ixgbe_dev_led_on(struct rte_eth_dev *dev)
{
@@ -3492,11 +3442,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
ixgbevf_dev_rxtx_start(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) {
intr_handle->intr_vec =
@@ -3510,16 +3460,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
}
ixgbevf_configure_msix(dev);

- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle))
- rte_intr_callback_register(intr_handle,
- ixgbevf_dev_interrupt_handler,
- (void *)dev);
- else
- PMD_INIT_LOG(INFO, "lsc won't enable because of"
- " no intr multiplex\n");
- }
-
rte_intr_enable(intr_handle);

/* Re-enable interrupt for VF */
@@ -3565,7 +3505,6 @@ static void
ixgbevf_dev_close(struct rte_eth_dev *dev)
{
struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct rte_pci_device *pci_dev;

PMD_INIT_FUNC_TRACE();

@@ -3577,12 +3516,6 @@ ixgbevf_dev_close(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);
-
- pci_dev = dev->pci_dev;
- if (pci_dev->intr_handle.intr_vec) {
- rte_free(pci_dev->intr_handle.intr_vec);
- pci_dev->intr_handle.intr_vec = NULL;
- }
}

static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
@@ -4108,7 +4041,8 @@ ixgbevf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask |= (1 << queue_id);
+ mask |= (1 << MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

rte_intr_enable(&dev->pci_dev->intr_handle);
@@ -4124,7 +4058,8 @@ ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);

mask = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
- mask &= ~(1 << queue_id);
+ mask &= ~(1 << MISC_VEC_ID);
+ RTE_SET_USED(queue_id);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);

return 0;
@@ -4260,7 +4195,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
uint32_t q_idx;
- uint32_t vector_idx = 0;
+ uint32_t vector_idx = MISC_VEC_ID;

/* won't configure msix register if no mapping is done
* between intr vector and event fd.
@@ -4277,7 +4212,7 @@ ixgbevf_configure_msix(struct rte_eth_dev *dev)
intr_handle->intr_vec[q_idx] = vector_idx;
}

- /* Configure VF Rx queue ivar */
+ /* Configure VF other cause ivar */
ixgbevf_set_ivar_map(hw, -1, 1, vector_idx);
}
--
2.4.3
David Marchand
2015-11-02 16:06:14 UTC
Permalink
Post by Cunming Liang
As ixgbe vf doesn't support lsc, the patch removes those unused code.
In addition, it does some tiny cleanup.
Please, can you describe this tiny cleanup ?
Did it trigger some bug ?
Post by Cunming Liang
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c
b/drivers/net/ixgbe/ixgbe_ethdev.c
index 366923f..794171c 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
[snip]
@@ -3492,11 +3442,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
ixgbevf_dev_rxtx_start(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;
+ }
--
David Marchand
Liang, Cunming
2015-11-04 01:37:34 UTC
Permalink
Hi David,
Post by David Marchand
Post by Cunming Liang
As ixgbe vf doesn't support lsc, the patch removes those unused code.
In addition, it does some tiny cleanup.
Please, can you describe this tiny cleanup ?
Did it trigger some bug ?
It causes confusing to enable/allocate efd with a zero number of vector.
But this piece of code shall be merged in a different patch. Thanks.
Post by David Marchand
Post by Cunming Liang
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c
b/drivers/net/ixgbe/ixgbe_ethdev.c
index 366923f..794171c 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
[snip]
@@ -3492,11 +3442,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
ixgbevf_dev_rxtx_start(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;
+ }
Cunming Liang
2015-10-30 05:27:50 UTC
Permalink
When igb runs as a PF, mbox interrupt is prerequisite to make VF start normally.
And PF sometimes won't 'dev_start', so the mbox interrupt register during 'dev_init' is required.
The patch rolls back the interrupt register for mbox,lsc to the 'dev_init'.
As UIO doesn't support multiple vector, mbox has to occupy the only one.
It adds condition check on 'dev_start', rxq interrupt is not allowed when PF running in IOV mode via UIO.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/e1000/igb_ethdev.c | 44 +++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index b3a802f..2494fc8 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -650,6 +650,13 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);

+ rte_intr_callback_register(&pci_dev->intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)eth_dev);
+
+ /* enable uio/vfio intr/eventfd mapping */
+ rte_intr_enable(&pci_dev->intr_handle);
+
/* enable support intr */
igb_intr_enable(eth_dev);

@@ -928,13 +935,16 @@ 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 (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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)) {
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
dev->data->nb_rx_queues * sizeof(int), 0);
@@ -1027,20 +1037,22 @@ eth_igb_start(struct rte_eth_dev *dev)
}
e1000_setup_link(hw);

- /* check if lsc interrupt feature is enabled */
- if (dev->data->dev_conf.intr_conf.lsc != 0) {
- if (rte_intr_allow_others(intr_handle)) {
- rte_intr_callback_register(intr_handle,
- eth_igb_interrupt_handler,
- (void *)dev);
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
eth_igb_lsc_interrupt_setup(dev);
- } else
+ } else {
+ rte_intr_callback_unregister(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO, "lsc won't enable because of"
" no intr multiplex\n");
}

/* check if rxq interrupt is enabled */
- if (dev->data->dev_conf.intr_conf.rxq != 0)
+ if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+ rte_intr_dp_is_en(intr_handle))
eth_igb_rxq_interrupt_setup(dev);

/* enable uio/vfio intr/eventfd mapping */
@@ -1133,6 +1145,12 @@ eth_igb_stop(struct rte_eth_dev *dev)
}
filter_info->twotuple_mask = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ eth_igb_interrupt_handler,
+ (void *)dev);
+
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
--
2.4.3
Cunming Liang
2015-10-30 05:27:51 UTC
Permalink
v2 changes:
- add write flush
- always set DIS_AUTOMASK_* bit

The patch enables rx interrupt support on i40e PF non-IOV mode.
Per queue rx interrupt works on vfio, however on uio, all rx queues share one interrupt vector.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 342 +++++++++++++++++++++++++++++++++++------
drivers/net/i40e/i40e_ethdev.h | 2 +
drivers/net/i40e/i40e_pf.c | 2 +
3 files changed, 298 insertions(+), 48 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2dd9fdc..d4a663c 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -39,6 +39,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <inttypes.h>
+#include <assert.h>

#include <rte_string_fns.h>
#include <rte_pci.h>
@@ -174,7 +175,7 @@ static void i40e_stat_update_48(struct i40e_hw *hw,
bool offset_loaded,
uint64_t *offset,
uint64_t *stat);
-static void i40e_pf_config_irq0(struct i40e_hw *hw);
+static void i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue);
static void i40e_dev_interrupt_handler(
__rte_unused struct rte_intr_handle *handle, void *param);
static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
@@ -232,6 +233,10 @@ static int i40e_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
uint32_t flags);
static int i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
struct timespec *timestamp);
+static int i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev,
+ uint16_t queue_id);
+static int i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
+ uint16_t queue_id);

static const struct rte_pci_id pci_id_i40e_map[] = {
#define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -265,6 +270,8 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
.tx_queue_start = i40e_dev_tx_queue_start,
.tx_queue_stop = i40e_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
+ .rx_queue_intr_enable = i40e_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40e_dev_rx_queue_intr_disable,
.rx_queue_release = i40e_dev_rx_queue_release,
.rx_queue_count = i40e_dev_rx_queue_count,
.rx_descriptor_done = i40e_dev_rx_descriptor_done,
@@ -579,7 +586,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
i40e_dev_interrupt_handler, (void *)dev);

/* configure and enable device interrupt */
- i40e_pf_config_irq0(hw);
+ i40e_pf_config_irq0(hw, TRUE);
i40e_pf_enable_irq0(hw);

/* enable uio intr after callback register */
@@ -718,6 +725,8 @@ err:
void
i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t msix_vect = vsi->msix_intr;
uint16_t i;
@@ -729,15 +738,26 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
}

if (vsi->type != I40E_VSI_SRIOV) {
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1), 0);
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), 0);
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ 0);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK);
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1), 0);
+ }
} else {
uint32_t reg;
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), 0);
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
}
I40E_WRITE_FLUSH(hw);
}
@@ -752,29 +772,26 @@ i40e_calc_itr_interval(int16_t interval)
return (interval/2);
}

-void
-i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+static void
+__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
+ int base_queue, int nb_queue)
{
+ int i;
uint32_t val;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
- uint16_t msix_vect = vsi->msix_intr;
- int i;
-
- for (i = 0; i < vsi->nb_qps; i++)
- I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);

/* Bind all RX queues to allocated MSIX interrupt */
- for (i = 0; i < vsi->nb_qps; i++) {
+ for (i = 0; i < nb_queue; i++) {
val = (msix_vect << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
I40E_QINT_RQCTL_ITR_INDX_MASK |
- ((vsi->base_queue + i + 1) <<
- I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+ ((base_queue + i + 1) <<
+ I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
(0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
I40E_QINT_RQCTL_CAUSE_ENA_MASK;

- if (i == vsi->nb_qps - 1)
+ if (i == nb_queue - 1)
val |= I40E_QINT_RQCTL_NEXTQ_INDX_MASK;
- I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), val);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(base_queue + i), val);
}

/* Write first RX queue to Link list register as the head element */
@@ -782,21 +799,26 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
uint16_t interval =
i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);

- I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
- (vsi->base_queue <<
- I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
-
- I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
- msix_vect - 1), interval);
-
-#ifndef I40E_GLINT_CTL
-#define I40E_GLINT_CTL 0x0003F800
-#define I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK 0x4
-#endif
- /* Disable auto-mask on enabling of all none-zero interrupt */
- I40E_WRITE_REG(hw, I40E_GLINT_CTL,
- I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK);
+ if (msix_vect == MISC_VEC_ID) {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ (base_queue <<
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITR0(I40E_ITR_INDEX_DEFAULT),
+ interval);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+ (base_queue <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+ msix_vect - 1),
+ interval);
+ }
} else {
uint32_t reg;

@@ -804,34 +826,134 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
reg = (hw->func_caps.num_msix_vectors_vf - 1) *
vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (vsi->base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
(0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
}

I40E_WRITE_FLUSH(hw);
}

+void
+i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_vect = vsi->msix_intr;
+ uint16_t nb_msix = RTE_MIN(vsi->nb_msix, intr_handle->nb_efd);
+ uint16_t queue_idx = 0;
+ int record = 0;
+ uint32_t val;
+ int i;
+
+ for (i = 0; i < vsi->nb_qps; i++) {
+ I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);
+ I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
+ }
+
+ /* INTENA flag is not auto-cleared for interrupt */
+ val = I40E_READ_REG(hw, I40E_GLINT_CTL);
+ val |= I40E_GLINT_CTL_DIS_AUTOMASK_PF0_MASK |
+ I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK |
+ I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK;
+ I40E_WRITE_REG(hw, I40E_GLINT_CTL, val);
+
+ /* VF bind interrupt */
+ if (vsi->type == I40E_VSI_SRIOV) {
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue, vsi->nb_qps);
+ return;
+ }
+
+ /* PF & VMDq bind interrupt */
+ if (rte_intr_dp_is_en(intr_handle)) {
+ if (vsi->type == I40E_VSI_MAIN) {
+ queue_idx = 0;
+ record = 1;
+ } else if (vsi->type == I40E_VSI_VMDQ2) {
+ struct i40e_vsi *main_vsi =
+ I40E_DEV_PRIVATE_TO_MAIN_VSI(vsi->adapter);
+ queue_idx = vsi->base_queue - main_vsi->nb_qps;
+ record = 1;
+ }
+ }
+
+ for (i = 0; i < vsi->nb_used_qps; i++) {
+ if (nb_msix <= 1) {
+ if (!rte_intr_allow_others(intr_handle))
+ /* allow to share MISC_VEC_ID */
+ msix_vect = MISC_VEC_ID;
+
+ /* no enough msix_vect, map all to one */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i,
+ vsi->nb_used_qps - i);
+ for (; !!record && i < vsi->nb_used_qps; i++)
+ intr_handle->intr_vec[queue_idx + i] =
+ msix_vect;
+ break;
+ }
+ /* 1:1 queue/msix_vect mapping */
+ __vsi_queues_bind_intr(vsi, msix_vect,
+ vsi->base_queue + i, 1);
+ if (!!record)
+ intr_handle->intr_vec[queue_idx + i] = msix_vect;
+
+ msix_vect++;
+ nb_msix--;
+ }
+}
+
static void
i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
uint16_t interval = i40e_calc_itr_interval(\
- RTE_LIBRTE_I40E_ITR_INTERVAL);
-
- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1),
- I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr, i;
+
+ if (rte_intr_allow_others(intr_handle))
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
(0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
- (interval << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ }
+ else
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTL0_INTENA_MASK |
+ I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
}

static void
i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
{
+ struct rte_eth_dev *dev = vsi->adapter->eth_dev;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+ uint16_t msix_intr, i;

- I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1), 0);
+ if (rte_intr_allow_others(intr_handle))
+ for (i = 0; i < vsi->nb_msix; i++) {
+ msix_intr = vsi->msix_intr + i;
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
+ 0);
+ }
+ else
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+
+ I40E_WRITE_FLUSH(hw);
}

static inline uint8_t
@@ -941,6 +1063,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
int ret, i;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t intr_vector = 0;

hw->adapter_stopped = 0;

@@ -952,6 +1076,29 @@ i40e_dev_start(struct rte_eth_dev *dev)
return -EINVAL;
}

+ rte_intr_disable(intr_handle);
+
+ if (((RTE_ETH_DEV_SRIOV(dev).active &&
+ rte_intr_cap_multiple(intr_handle)) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) &&
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int),
+ 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
/* Initialize VSI */
ret = i40e_dev_rxtx_init(pf);
if (ret != I40E_SUCCESS) {
@@ -960,11 +1107,14 @@ i40e_dev_start(struct rte_eth_dev *dev)
}

/* Map queues with MSIX interrupt */
+ main_vsi->nb_used_qps = dev->data->nb_rx_queues -
+ pf->nb_cfg_vmdq_vsi * RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(main_vsi);
i40e_vsi_enable_queues_intr(main_vsi);

/* Map VMDQ VSI queues with MSIX interrupt */
for (i = 0; i < pf->nb_cfg_vmdq_vsi; i++) {
+ pf->vmdq[i].vsi->nb_used_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
i40e_vsi_queues_bind_intr(pf->vmdq[i].vsi);
i40e_vsi_enable_queues_intr(pf->vmdq[i].vsi);
}
@@ -1001,6 +1151,22 @@ i40e_dev_start(struct rte_eth_dev *dev)
goto err_up;
}

+ if (!rte_intr_allow_others(intr_handle)) {
+ rte_intr_callback_unregister(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+ /* configure and enable device interrupt */
+ i40e_pf_config_irq0(hw, FALSE);
+ i40e_pf_enable_irq0(hw);
+
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
+ PMD_INIT_LOG(INFO, "lsc won't enable because of"
+ " no intr multiplex\n");
+ }
+
+ /* enable uio intr after callback register */
+ rte_intr_enable(intr_handle);
+
return I40E_SUCCESS;

err_up:
@@ -1016,6 +1182,7 @@ i40e_dev_stop(struct rte_eth_dev *dev)
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
struct i40e_vsi *main_vsi = pf->main_vsi;
struct i40e_mirror_rule *p_mirror;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
int i;

/* Disable all queues */
@@ -1047,6 +1214,18 @@ i40e_dev_stop(struct rte_eth_dev *dev)
}
pf->nb_mirror_rule = 0;

+ if (!rte_intr_allow_others(intr_handle))
+ /* resume to the default handler */
+ rte_intr_callback_register(intr_handle,
+ i40e_dev_interrupt_handler,
+ (void *)dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static void
@@ -3073,15 +3252,30 @@ i40e_vsi_setup(struct i40e_pf *pf,
vsi->base_queue = I40E_FDIR_QUEUE_ID;

/* VF has MSIX interrupt in VF range, don't allocate here */
- if (type != I40E_VSI_SRIOV) {
+ if (type == I40E_VSI_MAIN) {
+ ret = i40e_res_pool_alloc(&pf->msix_pool,
+ RTE_MIN(vsi->nb_qps,
+ RTE_MAX_RXTX_INTR_VEC_ID));
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "VSI MAIN %d get heap failed %d",
+ vsi->seid, ret);
+ goto fail_queue_alloc;
+ }
+ vsi->msix_intr = ret;
+ vsi->nb_msix = RTE_MIN(vsi->nb_qps, RTE_MAX_RXTX_INTR_VEC_ID);
+ } else if (type != I40E_VSI_SRIOV) {
ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
if (ret < 0) {
PMD_DRV_LOG(ERR, "VSI %d get heap failed %d", vsi->seid, ret);
goto fail_queue_alloc;
}
vsi->msix_intr = ret;
- } else
+ vsi->nb_msix = 1;
+ } else {
vsi->msix_intr = 0;
+ vsi->nb_msix = 0;
+ }
+
/* Add VSI */
if (type == I40E_VSI_MAIN) {
/* For main VSI, no need to add since it's default one */
@@ -3919,7 +4113,7 @@ i40e_pf_enable_irq0(struct i40e_hw *hw)
}

static void
-i40e_pf_config_irq0(struct i40e_hw *hw)
+i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue)
{
/* read pending request and disable first */
i40e_pf_disable_irq0(hw);
@@ -3927,9 +4121,10 @@ i40e_pf_config_irq0(struct i40e_hw *hw)
I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0,
I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK);

- /* Link no queues with irq0 */
- I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
- I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+ if (no_queue)
+ /* Link no queues with irq0 */
+ I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+ I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
}

static void
@@ -6298,3 +6493,54 @@ i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev,

return 0;
}
+
+static int
+i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr - RX_VEC_START),
+ I40E_PFINT_DYN_CTLN_INTENA_MASK |
+ I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+ (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_PFINT_DYN_CTLN(msix_intr - RX_VEC_START),
+ 0);
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
+}
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index d42487d..20d52f8 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -240,6 +240,7 @@ struct i40e_vsi {
uint16_t seid; /* The seid of VSI itself */
uint16_t uplink_seid; /* The uplink seid of this VSI */
uint16_t nb_qps; /* Number of queue pairs VSI can occupy */
+ uint16_t nb_used_qps; /* Number of queue pairs VSI uses */
uint16_t max_macaddrs; /* Maximum number of MAC addresses */
uint16_t base_queue; /* The first queue index of this VSI */
/*
@@ -248,6 +249,7 @@ struct i40e_vsi {
*/
uint16_t vsi_id;
uint16_t msix_intr; /* The MSIX interrupt binds to VSI */
+ uint16_t nb_msix; /* The max number of msix vector */
uint8_t enabled_tc; /* The traffic class enabled */
};

diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 95c960c..c1d58a8 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -554,6 +554,8 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
}
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
+ vf->vsi->nb_msix = irqmap->num_vectors;
+ vf->vsi->nb_used_qps = vf->vsi->nb_qps;

/* Don't care how the TX/RX queue mapping with this vector.
* Link all VF RX queues together. Only did mapping work.
--
2.4.3
Zhang, Helin
2015-10-30 07:33:13 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 09/11] i40e: add rx interrupt support
- add write flush
- always set DIS_AUTOMASK_* bit
The patch enables rx interrupt support on i40e PF non-IOV mode.
Per queue rx interrupt works on vfio, however on uio, all rx queues share one
interrupt vector.
Acked-by: Helin Zhang <***@intel.com>
Wu, Jingjing
2015-10-30 07:35:00 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 09/11] i40e: add rx interrupt support
- add write flush
- always set DIS_AUTOMASK_* bit
The patch enables rx interrupt support on i40e PF non-IOV mode.
Per queue rx interrupt works on vfio, however on uio, all rx queues share
one interrupt vector.
---
drivers/net/i40e/i40e_ethdev.c | 342
+++++++++++++++++++++++++++++++++++------
drivers/net/i40e/i40e_ethdev.h | 2 +
drivers/net/i40e/i40e_pf.c | 2 +
3 files changed, 298 insertions(+), 48 deletions(-)
Cunming Liang
2015-10-30 05:27:52 UTC
Permalink
v2 changes:
- turn on intr only when rxq flag is set
- rework base on patch http://dpdk.org/dev/patchwork/patch/7504/

The patch enables rx interrupt support on i40e VF and some necessary change on PF IOV mode to support VF.
On PF side, running in IOV mode via uio won't allow rx interrupt which is exclusive with mbox interrupt
in single vector competition.
On VF side, one single vector is shared for all the rx queues.

Signed-off-by: Cunming Liang <***@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 38 +++++-----
drivers/net/i40e/i40e_ethdev.h | 15 ++++
drivers/net/i40e/i40e_ethdev_vf.c | 143 +++++++++++++++++++++++++++++++++++---
drivers/net/i40e/i40e_pf.c | 5 --
4 files changed, 166 insertions(+), 35 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index d4a663c..40ed852 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -75,11 +75,6 @@
/* Maximun number of VSI */
#define I40E_MAX_NUM_VSIS (384UL)

-/* Default queue interrupt throttling time in microseconds */
-#define I40E_ITR_INDEX_DEFAULT 0
-#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
-#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
-
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */

/* Mask of PF interrupt causes */
@@ -762,16 +757,6 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
I40E_WRITE_FLUSH(hw);
}

-static inline uint16_t
-i40e_calc_itr_interval(int16_t interval)
-{
- if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
- interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
-
- /* Convert to hardware count, as writing each 1 represents 2 us */
- return (interval/2);
-}
-
static void
__vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
int base_queue, int nb_queue)
@@ -822,13 +807,24 @@ __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
} else {
uint32_t reg;

- /* num_msix_vectors_vf needs to minus irq0 */
- reg = (hw->func_caps.num_msix_vectors_vf - 1) *
- vsi->user_param + (msix_vect - 1);
+ if (msix_vect == MISC_VEC_ID) {
+ I40E_WRITE_REG(hw,
+ I40E_VPINT_LNKLST0(vsi->user_param),
+ (base_queue <<
+ I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
+ } else {
+ /* num_msix_vectors_vf needs to minus irq0 */
+ reg = (hw->func_caps.num_msix_vectors_vf - 1) *
+ vsi->user_param + (msix_vect - 1);

- I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), (base_queue <<
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
- (0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+ (base_queue <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+ (0x0 <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+ }
}

I40E_WRITE_FLUSH(hw);
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 20d52f8..eeff6d7 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -156,6 +156,11 @@ enum i40e_flxpld_layer_idx {
(1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \
(1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))

+/* Default queue interrupt throttling time in microseconds */
+#define I40E_ITR_INDEX_DEFAULT 0
+#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
+#define I40E_QUEUE_ITR_INTERVAL_MAX 8160 /* 8160 us */
+
struct i40e_adapter;

/**
@@ -578,6 +583,16 @@ i40e_align_floor(int n)
return 1 << (sizeof(n) * CHAR_BIT - 1 - __builtin_clz(n));
}

+static inline uint16_t
+i40e_calc_itr_interval(int16_t interval)
+{
+ if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
+ interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
+
+ /* Convert to hardware count, as writing each 1 represents 2 us */
+ return (interval / 2);
+}
+
#define I40E_VALID_FLOW(flow_type) \
((flow_type) == RTE_ETH_FLOW_FRAG_IPV4 || \
(flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index 176a2f6..4fdb401 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -145,6 +145,10 @@ static int i40evf_dev_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
static int i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);

/* Default hash key buffer for RSS */
static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
@@ -170,6 +174,9 @@ static const struct eth_dev_ops i40evf_eth_dev_ops = {
.tx_queue_stop = i40evf_dev_tx_queue_stop,
.rx_queue_setup = i40e_dev_rx_queue_setup,
.rx_queue_release = i40e_dev_rx_queue_release,
+ .rx_queue_intr_enable = i40evf_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = i40evf_dev_rx_queue_intr_disable,
+ .rx_descriptor_done = i40e_dev_rx_descriptor_done,
.tx_queue_setup = i40e_dev_tx_queue_setup,
.tx_queue_release = i40e_dev_tx_queue_release,
.reta_update = i40evf_dev_rss_reta_update,
@@ -712,22 +719,33 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_irq_map_info) + \
sizeof(struct i40e_virtchnl_vector_map)];
struct i40e_virtchnl_irq_map_info *map_info;
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ uint32_t vector_id;
int i, err;
+
+ if (rte_intr_allow_others(intr_handle)) {
+ if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ else
+ vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
+ } else {
+ vector_id = MISC_VEC_ID;
+ }
+
map_info = (struct i40e_virtchnl_irq_map_info *)cmd_buffer;
map_info->num_vectors = 1;
map_info->vecmap[0].rxitr_idx = I40E_QINT_RQCTL_MSIX_INDX_NOITR;
map_info->vecmap[0].vsi_id = vf->vsi_res->vsi_id;
/* Alway use default dynamic MSIX interrupt */
- if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
- else
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
-
+ map_info->vecmap[0].vector_id = vector_id;
/* Don't map any tx queue */
map_info->vecmap[0].txq_map = 0;
map_info->vecmap[0].rxq_map = 0;
- for (i = 0; i < dev->data->nb_rx_queues; i++)
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
map_info->vecmap[0].rxq_map |= 1 << i;
+ if (rte_intr_dp_is_en(intr_handle))
+ intr_handle->intr_vec[i] = vector_id;
+ }

args.ops = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP;
args.in_args = (u8 *)cmd_buffer;
@@ -1565,6 +1583,16 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+ I40E_WRITE_FLUSH(hw);
+ return;
+ }

if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
/* To support DPDK PF host */
@@ -1577,6 +1605,8 @@ i40evf_enable_queues_intr(struct rte_eth_dev *dev)
I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
I40E_VFINT_DYN_CTL01_INTENA_MASK |
I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
+
+ I40E_WRITE_FLUSH(hw);
}

static inline void
@@ -1584,14 +1614,76 @@ i40evf_disable_queues_intr(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
+ if (!rte_intr_allow_others(intr_handle)) {
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ I40E_WRITE_FLUSH(hw);
+ return;
+ }

if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
I40E_WRITE_REG(hw,
- I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
- 0);
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR
+ - 1),
+ 0);
else
I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);

+ I40E_WRITE_FLUSH(hw);
+}
+
+static int
+i40evf_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t interval =
+ i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT));
+ else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr - RX_VEC_START),
+ I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+ I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
+ (0 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
+ (interval <<
+ I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT));
+
+ I40E_WRITE_FLUSH(hw);
+
+ rte_intr_enable(&dev->pci_dev->intr_handle);
+
+ return 0;
+}
+
+static int
+i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t msix_intr;
+
+ msix_intr = intr_handle->intr_vec[queue_id];
+ if (msix_intr == MISC_VEC_ID)
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
+ else
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(msix_intr - RX_VEC_START),
+ 0);
+
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}

static int
@@ -1599,7 +1691,9 @@ i40evf_dev_start(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
struct ether_addr mac_addr;
+ uint32_t intr_vector = 0;

PMD_INIT_FUNC_TRACE();

@@ -1609,6 +1703,24 @@ i40evf_dev_start(struct rte_eth_dev *dev)
vf->num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
dev->data->nb_tx_queues);

+ /* check and configure queue intr-vector mapping */
+ 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_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ dev->data->nb_rx_queues * sizeof(int), 0);
+ if (!intr_handle->intr_vec) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+ " intr_vec\n", dev->data->nb_rx_queues);
+ return -ENOMEM;
+ }
+ }
+
if (i40evf_rx_init(dev) != 0){
PMD_DRV_LOG(ERR, "failed to do RX init");
return -1;
@@ -1638,6 +1750,10 @@ i40evf_dev_start(struct rte_eth_dev *dev)
goto err_mac;
}

+ /* vf don't allow intr except for rxq intr */
+ if (dev->data->dev_conf.intr_conf.rxq != 0)
+ rte_intr_enable(intr_handle);
+
i40evf_enable_queues_intr(dev);
return 0;

@@ -1650,11 +1766,20 @@ err_queue:
static void
i40evf_dev_stop(struct rte_eth_dev *dev)
{
+ struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+
PMD_INIT_FUNC_TRACE();

- i40evf_disable_queues_intr(dev);
i40evf_stop_queues(dev);
+ i40evf_disable_queues_intr(dev);
i40e_dev_clear_queues(dev);
+
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
}

static int
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index c1d58a8..cbf4e5b 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -547,11 +547,6 @@ i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
goto send_msg;
}

- if (irqmap->vecmap[0].vector_id == 0) {
- PMD_DRV_LOG(ERR, "DPDK host don't support use IRQ0");
- ret = I40E_ERR_PARAM;
- goto send_msg;
- }
/* This MSIX intr store the intr in VF range */
vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
vf->vsi->nb_msix = irqmap->num_vectors;
--
2.4.3
Wu, Jingjing
2015-10-30 07:36:36 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 10/11] i40evf: add rx interrupt support
- turn on intr only when rxq flag is set
- rework base on patch http://dpdk.org/dev/patchwork/patch/7504/
The patch enables rx interrupt support on i40e VF and some necessary
change on PF IOV mode to support VF.
On PF side, running in IOV mode via uio won't allow rx interrupt which is
exclusive with mbox interrupt in single vector competition.
On VF side, one single vector is shared for all the rx queues.
---
Acked-by: Jingjing Wu <***@intel.com>

Just note that http://dpdk.org/dev/patchwork/patch/7504/ is already replace
by http://dpdk.org/dev/patchwork/patch/7790/ for few code style fix.
drivers/net/i40e/i40e_ethdev.c | 38 +++++-----
drivers/net/i40e/i40e_ethdev.h | 15 ++++
drivers/net/i40e/i40e_ethdev_vf.c | 143
+++++++++++++++++++++++++++++++++++---
drivers/net/i40e/i40e_pf.c | 5 --
4 files changed, 166 insertions(+), 35 deletions(-)
Zhang, Helin
2015-10-30 07:38:49 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 10/11] i40evf: add rx interrupt support
- turn on intr only when rxq flag is set
- rework base on patch http://dpdk.org/dev/patchwork/patch/7504/
The patch enables rx interrupt support on i40e VF and some necessary change on
PF IOV mode to support VF.
On PF side, running in IOV mode via uio won't allow rx interrupt which is exclusive
with mbox interrupt in single vector competition.
On VF side, one single vector is shared for all the rx queues.
Acked-by: Helin Zhang <***@intel.com>
Cunming Liang
2015-10-30 05:27:53 UTC
Permalink
Signed-off-by: Cunming Liang <***@intel.com>
---
doc/guides/rel_notes/release_2_2.rst | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index be6f827..01bd4bb 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -23,6 +23,7 @@ New Features

* **Added vhost-user multiple queue support.**

+* **Added interrupt mode support on i40e.**

Resolved Issues
---------------
@@ -72,6 +73,9 @@ Drivers

Fixed issue when releasing null control queue.

+* **ixgbe: Fixed PF rx interrupt compatible issue with mbox.**
+
+* **igb: Fixed PF rx interrupt compatible issue with mbox.**

Libraries
~~~~~~~~~
--
2.4.3
Zhang, Helin
2015-10-30 08:21:56 UTC
Permalink
-----Original Message-----
From: Liang, Cunming
Sent: Friday, October 30, 2015 1:28 PM
Cc: Zhang, Helin; He, Shaopeng; Wu, Jingjing; Liang, Cunming
Subject: [PATCH v2 00/11] interrupt mode for i40e
- rebase code base
- rework to depend on one previous patch
patch http://dpdk.org/dev/patchwork/patch/7504/
- always set DIS_AUTOMASK_* bit in PF to avoid ENA flag auto-clear
This patch series contains four major parts.
1. always reserve vector zero for misc cause in vfio mapping 2. add api to declare
the capability of multiple interrupt vector support 3. fix the rx interrupt
compatible issue with mbox in ixgbe/igb IOV-PF 4. add rx interrupt support in
i40e PF and VF
eal/linux: vfio map misc intr to vector zero
ixgbe: reserve intr vector zero for misc cause
igb: reserve intr vector zero for misc cause
eal/linux: not allow to enable zero intr efd
eal/linux: add intr api to report multi-vector capability
ixgbe: fix rx intr compatible issue with PF mbox
ixgbevf: cleanup unnecessary interrupt handler
igb: fix rx intr compatible issue with PF mbox
i40e: add rx interrupt support
i40evf: add rx interrupt support
doc: release note update for intr mode
doc/guides/rel_notes/release_2_2.rst | 4 +
drivers/net/e1000/igb_ethdev.c | 63 +++-
drivers/net/i40e/i40e_ethdev.c | 374
+++++++++++++++++----
drivers/net/i40e/i40e_ethdev.h | 17 +
drivers/net/i40e/i40e_ethdev_vf.c | 143 +++++++-
drivers/net/i40e/i40e_pf.c | 7 +-
drivers/net/ixgbe/ixgbe_ethdev.c | 144 +++-----
.../bsdapp/eal/include/exec-env/rte_interrupts.h | 3 +-
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 35 +-
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 16 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +
11 files changed, 612 insertions(+), 201 deletions(-)
--
2.4.3
Acked-by: Helin Zhang <***@intel.com>
Continue reading on narkive:
Loading...