diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 5ae805e62..3444bb141 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -422,6 +422,70 @@ dpdk_watchdog(void *dummy OVS_UNUSED) return NULL; } +static int +dpdk_eth_dev_queue_setup(struct netdev_dpdk *dev, int n_rxq, int n_txq) +{ + int diag = 0; + int i; + + /* A device may report more queues than it makes available (this has + * been observed for Intel xl710, which reserves some of them for + * SRIOV): rte_eth_*_queue_setup will fail if a queue is not + * available. When this happens we can retry the configuration + * and request less queues */ + while (n_rxq && n_txq) { + if (diag) { + VLOG_INFO("Retrying setup with (rxq:%d txq:%d)", n_rxq, n_txq); + } + + diag = rte_eth_dev_configure(dev->port_id, n_rxq, n_txq, &port_conf); + if (diag) { + break; + } + + for (i = 0; i < n_txq; i++) { + diag = rte_eth_tx_queue_setup(dev->port_id, i, NIC_PORT_TX_Q_SIZE, + dev->socket_id, NULL); + if (diag) { + VLOG_INFO("Interface %s txq(%d) setup error: %s", + dev->up.name, i, rte_strerror(-diag)); + break; + } + } + + if (i != n_txq) { + /* Retry with less tx queues */ + n_txq = i; + continue; + } + + for (i = 0; i < n_rxq; i++) { + diag = rte_eth_rx_queue_setup(dev->port_id, i, NIC_PORT_RX_Q_SIZE, + dev->socket_id, NULL, + dev->dpdk_mp->mp); + if (diag) { + VLOG_INFO("Interface %s rxq(%d) setup error: %s", + dev->up.name, i, rte_strerror(-diag)); + break; + } + } + + if (i != n_rxq) { + /* Retry with less rx queues */ + n_rxq = i; + continue; + } + + dev->up.n_rxq = n_rxq; + dev->real_n_txq = n_txq; + + return 0; + } + + return diag; +} + + static int dpdk_eth_dev_init(struct netdev_dpdk *dev) OVS_REQUIRES(dpdk_mutex) { @@ -429,46 +493,28 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev) OVS_REQUIRES(dpdk_mutex) struct rte_eth_dev_info info; struct ether_addr eth_addr; int diag; - int i; + int n_rxq, n_txq; if (dev->port_id < 0 || dev->port_id >= rte_eth_dev_count()) { return ENODEV; } rte_eth_dev_info_get(dev->port_id, &info); - dev->up.n_rxq = MIN(info.max_rx_queues, dev->up.n_rxq); - dev->real_n_txq = MIN(info.max_tx_queues, dev->up.n_txq); - diag = rte_eth_dev_configure(dev->port_id, dev->up.n_rxq, dev->real_n_txq, - &port_conf); + n_rxq = MIN(info.max_rx_queues, dev->up.n_rxq); + n_txq = MIN(info.max_tx_queues, dev->up.n_txq); + + diag = dpdk_eth_dev_queue_setup(dev, n_rxq, n_txq); if (diag) { - VLOG_ERR("eth dev config error %d. rxq:%d txq:%d", diag, dev->up.n_rxq, - dev->real_n_txq); + VLOG_ERR("Interface %s(rxq:%d txq:%d) configure error: %s", + dev->up.name, n_rxq, n_txq, rte_strerror(-diag)); return -diag; } - for (i = 0; i < dev->real_n_txq; i++) { - diag = rte_eth_tx_queue_setup(dev->port_id, i, NIC_PORT_TX_Q_SIZE, - dev->socket_id, NULL); - if (diag) { - VLOG_ERR("eth dev tx queue setup error %d",diag); - return -diag; - } - } - - for (i = 0; i < dev->up.n_rxq; i++) { - diag = rte_eth_rx_queue_setup(dev->port_id, i, NIC_PORT_RX_Q_SIZE, - dev->socket_id, - NULL, dev->dpdk_mp->mp); - if (diag) { - VLOG_ERR("eth dev rx queue setup error %d",diag); - return -diag; - } - } - diag = rte_eth_dev_start(dev->port_id); if (diag) { - VLOG_ERR("eth dev start error %d",diag); + VLOG_ERR("Interface %s start error: %s", dev->up.name, + rte_strerror(-diag)); return -diag; }