-/*
- * BSD LICENSE
- *
- * Copyright(c) 2017 Cavium, Inc.. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Cavium, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
*/
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
#include <rte_cycles.h>
#include <rte_malloc.h>
#include <rte_alarm.h>
+#include <rte_ether.h>
#include "lio_logs.h"
#include "lio_23xx_vf.h"
#include "lio_ethdev.h"
#include "lio_rxtx.h"
+int lio_logtype_init;
+int lio_logtype_driver;
+
/* Default RSS key in use */
static uint8_t lio_rss_key[40] = {
0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
return 0;
}
+/* store statistics names and its offset in stats structure */
+struct rte_lio_xstats_name_off {
+ char name[RTE_ETH_XSTATS_NAME_SIZE];
+ unsigned int offset;
+};
+
+static const struct rte_lio_xstats_name_off rte_lio_stats_strings[] = {
+ {"rx_pkts", offsetof(struct octeon_rx_stats, total_rcvd)},
+ {"rx_bytes", offsetof(struct octeon_rx_stats, bytes_rcvd)},
+ {"rx_broadcast_pkts", offsetof(struct octeon_rx_stats, total_bcst)},
+ {"rx_multicast_pkts", offsetof(struct octeon_rx_stats, total_mcst)},
+ {"rx_flow_ctrl_pkts", offsetof(struct octeon_rx_stats, ctl_rcvd)},
+ {"rx_fifo_err", offsetof(struct octeon_rx_stats, fifo_err)},
+ {"rx_dmac_drop", offsetof(struct octeon_rx_stats, dmac_drop)},
+ {"rx_fcs_err", offsetof(struct octeon_rx_stats, fcs_err)},
+ {"rx_jabber_err", offsetof(struct octeon_rx_stats, jabber_err)},
+ {"rx_l2_err", offsetof(struct octeon_rx_stats, l2_err)},
+ {"rx_vxlan_pkts", offsetof(struct octeon_rx_stats, fw_rx_vxlan)},
+ {"rx_vxlan_err", offsetof(struct octeon_rx_stats, fw_rx_vxlan_err)},
+ {"rx_lro_pkts", offsetof(struct octeon_rx_stats, fw_lro_pkts)},
+ {"tx_pkts", (offsetof(struct octeon_tx_stats, total_pkts_sent)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_bytes", (offsetof(struct octeon_tx_stats, total_bytes_sent)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_broadcast_pkts",
+ (offsetof(struct octeon_tx_stats, bcast_pkts_sent)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_multicast_pkts",
+ (offsetof(struct octeon_tx_stats, mcast_pkts_sent)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_flow_ctrl_pkts", (offsetof(struct octeon_tx_stats, ctl_sent)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_fifo_err", (offsetof(struct octeon_tx_stats, fifo_err)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_total_collisions", (offsetof(struct octeon_tx_stats,
+ total_collisions)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_tso", (offsetof(struct octeon_tx_stats, fw_tso)) +
+ sizeof(struct octeon_rx_stats)},
+ {"tx_vxlan_pkts", (offsetof(struct octeon_tx_stats, fw_tx_vxlan)) +
+ sizeof(struct octeon_rx_stats)},
+};
+
+#define LIO_NB_XSTATS RTE_DIM(rte_lio_stats_strings)
+
+/* Get hw stats of the port */
+static int
+lio_dev_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
+ unsigned int n)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ uint16_t timeout = LIO_MAX_CMD_TIMEOUT;
+ struct octeon_link_stats *hw_stats;
+ struct lio_link_stats_resp *resp;
+ struct lio_soft_command *sc;
+ uint32_t resp_size;
+ unsigned int i;
+ int retval;
+
+ if (!lio_dev->intf_open) {
+ lio_dev_err(lio_dev, "Port %d down\n",
+ lio_dev->port_id);
+ return -EINVAL;
+ }
+
+ if (n < LIO_NB_XSTATS)
+ return LIO_NB_XSTATS;
+
+ resp_size = sizeof(struct lio_link_stats_resp);
+ sc = lio_alloc_soft_command(lio_dev, 0, resp_size, 0);
+ if (sc == NULL)
+ return -ENOMEM;
+
+ resp = (struct lio_link_stats_resp *)sc->virtrptr;
+ lio_prepare_soft_command(lio_dev, sc, LIO_OPCODE,
+ LIO_OPCODE_PORT_STATS, 0, 0, 0);
+
+ /* Setting wait time in seconds */
+ sc->wait_time = LIO_MAX_CMD_TIMEOUT / 1000;
+
+ retval = lio_send_soft_command(lio_dev, sc);
+ if (retval == LIO_IQ_SEND_FAILED) {
+ lio_dev_err(lio_dev, "failed to get port stats from firmware. status: %x\n",
+ retval);
+ goto get_stats_fail;
+ }
+
+ while ((*sc->status_word == LIO_COMPLETION_WORD_INIT) && --timeout) {
+ lio_flush_iq(lio_dev, lio_dev->instr_queue[sc->iq_no]);
+ lio_process_ordered_list(lio_dev);
+ rte_delay_ms(1);
+ }
+
+ retval = resp->status;
+ if (retval) {
+ lio_dev_err(lio_dev, "failed to get port stats from firmware\n");
+ goto get_stats_fail;
+ }
+
+ lio_swap_8B_data((uint64_t *)(&resp->link_stats),
+ sizeof(struct octeon_link_stats) >> 3);
+
+ hw_stats = &resp->link_stats;
+
+ for (i = 0; i < LIO_NB_XSTATS; i++) {
+ xstats[i].id = i;
+ xstats[i].value =
+ *(uint64_t *)(((char *)hw_stats) +
+ rte_lio_stats_strings[i].offset);
+ }
+
+ lio_free_soft_command(sc);
+
+ return LIO_NB_XSTATS;
+
+get_stats_fail:
+ lio_free_soft_command(sc);
+
+ return -1;
+}
+
+static int
+lio_dev_xstats_get_names(struct rte_eth_dev *eth_dev,
+ struct rte_eth_xstat_name *xstats_names,
+ unsigned limit __rte_unused)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ unsigned int i;
+
+ if (!lio_dev->intf_open) {
+ lio_dev_err(lio_dev, "Port %d down\n",
+ lio_dev->port_id);
+ return -EINVAL;
+ }
+
+ if (xstats_names == NULL)
+ return LIO_NB_XSTATS;
+
+ /* Note: limit checked in rte_eth_xstats_names() */
+
+ for (i = 0; i < LIO_NB_XSTATS; i++) {
+ snprintf(xstats_names[i].name, sizeof(xstats_names[i].name),
+ "%s", rte_lio_stats_strings[i].name);
+ }
+
+ return LIO_NB_XSTATS;
+}
+
+/* Reset hw stats for the port */
+static void
+lio_dev_xstats_reset(struct rte_eth_dev *eth_dev)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ struct lio_dev_ctrl_cmd ctrl_cmd;
+ struct lio_ctrl_pkt ctrl_pkt;
+
+ if (!lio_dev->intf_open) {
+ lio_dev_err(lio_dev, "Port %d down\n",
+ lio_dev->port_id);
+ return;
+ }
+
+ /* flush added to prevent cmd failure
+ * incase the queue is full
+ */
+ lio_flush_iq(lio_dev, lio_dev->instr_queue[0]);
+
+ memset(&ctrl_pkt, 0, sizeof(struct lio_ctrl_pkt));
+ memset(&ctrl_cmd, 0, sizeof(struct lio_dev_ctrl_cmd));
+
+ ctrl_cmd.eth_dev = eth_dev;
+ ctrl_cmd.cond = 0;
+
+ ctrl_pkt.ncmd.s.cmd = LIO_CMD_CLEAR_STATS;
+ ctrl_pkt.ctrl_cmd = &ctrl_cmd;
+
+ if (lio_send_ctrl_pkt(lio_dev, &ctrl_pkt)) {
+ lio_dev_err(lio_dev, "Failed to send clear stats command\n");
+ return;
+ }
+
+ if (lio_wait_for_ctrl_cmd(lio_dev, &ctrl_cmd)) {
+ lio_dev_err(lio_dev, "Clear stats command timed out\n");
+ return;
+ }
+
+ /* clear stored per queue stats */
+ RTE_FUNC_PTR_OR_RET(*eth_dev->dev_ops->stats_reset);
+ (*eth_dev->dev_ops->stats_reset)(eth_dev);
+}
+
+/* Retrieve the device statistics (# packets in/out, # bytes in/out, etc */
+static int
+lio_dev_stats_get(struct rte_eth_dev *eth_dev,
+ struct rte_eth_stats *stats)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ struct lio_droq_stats *oq_stats;
+ struct lio_iq_stats *iq_stats;
+ struct lio_instr_queue *txq;
+ struct lio_droq *droq;
+ int i, iq_no, oq_no;
+ uint64_t bytes = 0;
+ uint64_t pkts = 0;
+ uint64_t drop = 0;
+
+ for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
+ iq_no = lio_dev->linfo.txpciq[i].s.q_no;
+ txq = lio_dev->instr_queue[iq_no];
+ if (txq != NULL) {
+ iq_stats = &txq->stats;
+ pkts += iq_stats->tx_done;
+ drop += iq_stats->tx_dropped;
+ bytes += iq_stats->tx_tot_bytes;
+ }
+ }
+
+ stats->opackets = pkts;
+ stats->obytes = bytes;
+ stats->oerrors = drop;
+
+ pkts = 0;
+ drop = 0;
+ bytes = 0;
+
+ for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
+ oq_no = lio_dev->linfo.rxpciq[i].s.q_no;
+ droq = lio_dev->droq[oq_no];
+ if (droq != NULL) {
+ oq_stats = &droq->stats;
+ pkts += oq_stats->rx_pkts_received;
+ drop += (oq_stats->rx_dropped +
+ oq_stats->dropped_toomany +
+ oq_stats->dropped_nomem);
+ bytes += oq_stats->rx_bytes_received;
+ }
+ }
+ stats->ibytes = bytes;
+ stats->ipackets = pkts;
+ stats->ierrors = drop;
+
+ return 0;
+}
+
+static void
+lio_dev_stats_reset(struct rte_eth_dev *eth_dev)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ struct lio_droq_stats *oq_stats;
+ struct lio_iq_stats *iq_stats;
+ struct lio_instr_queue *txq;
+ struct lio_droq *droq;
+ int i, iq_no, oq_no;
+
+ for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
+ iq_no = lio_dev->linfo.txpciq[i].s.q_no;
+ txq = lio_dev->instr_queue[iq_no];
+ if (txq != NULL) {
+ iq_stats = &txq->stats;
+ memset(iq_stats, 0, sizeof(struct lio_iq_stats));
+ }
+ }
+
+ for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
+ oq_no = lio_dev->linfo.rxpciq[i].s.q_no;
+ droq = lio_dev->droq[oq_no];
+ if (droq != NULL) {
+ oq_stats = &droq->stats;
+ memset(oq_stats, 0, sizeof(struct lio_droq_stats));
+ }
+ }
+}
+
static void
lio_dev_info_get(struct rte_eth_dev *eth_dev,
struct rte_eth_dev_info *devinfo)
{
struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+
+ switch (pci_dev->id.subsystem_device_id) {
+ /* CN23xx 10G cards */
+ case PCI_SUBSYS_DEV_ID_CN2350_210:
+ case PCI_SUBSYS_DEV_ID_CN2360_210:
+ case PCI_SUBSYS_DEV_ID_CN2350_210SVPN3:
+ case PCI_SUBSYS_DEV_ID_CN2360_210SVPN3:
+ case PCI_SUBSYS_DEV_ID_CN2350_210SVPT:
+ case PCI_SUBSYS_DEV_ID_CN2360_210SVPT:
+ devinfo->speed_capa = ETH_LINK_SPEED_10G;
+ break;
+ /* CN23xx 25G cards */
+ case PCI_SUBSYS_DEV_ID_CN2350_225:
+ case PCI_SUBSYS_DEV_ID_CN2360_225:
+ devinfo->speed_capa = ETH_LINK_SPEED_25G;
+ break;
+ default:
+ devinfo->speed_capa = ETH_LINK_SPEED_10G;
+ lio_dev_err(lio_dev,
+ "Unknown CN23XX subsystem device id. Setting 10G as default link speed.\n");
+ }
devinfo->max_rx_queues = lio_dev->max_rx_queues;
devinfo->max_tx_queues = lio_dev->max_tx_queues;
devinfo->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM |
DEV_RX_OFFLOAD_UDP_CKSUM |
- DEV_RX_OFFLOAD_TCP_CKSUM);
+ DEV_RX_OFFLOAD_TCP_CKSUM |
+ DEV_RX_OFFLOAD_VLAN_STRIP);
devinfo->tx_offload_capa = (DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_UDP_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM |
}
static int
-lio_dev_validate_vf_mtu(struct rte_eth_dev *eth_dev, uint16_t new_mtu)
+lio_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
{
struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ uint16_t pf_mtu = lio_dev->linfo.link.s.mtu;
+ uint32_t frame_len = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+ struct lio_dev_ctrl_cmd ctrl_cmd;
+ struct lio_ctrl_pkt ctrl_pkt;
PMD_INIT_FUNC_TRACE();
if (!lio_dev->intf_open) {
- lio_dev_err(lio_dev, "Port %d down, can't check MTU\n",
+ lio_dev_err(lio_dev, "Port %d down, can't set MTU\n",
lio_dev->port_id);
return -EINVAL;
}
- /* Limit the MTU to make sure the ethernet packets are between
- * ETHER_MIN_MTU bytes and PF's MTU
+ /* check if VF MTU is within allowed range.
+ * New value should not exceed PF MTU.
*/
- if ((new_mtu < ETHER_MIN_MTU) ||
- (new_mtu > lio_dev->linfo.link.s.mtu)) {
- lio_dev_err(lio_dev, "Invalid MTU: %d\n", new_mtu);
- lio_dev_err(lio_dev, "Valid range %d and %d\n",
- ETHER_MIN_MTU, lio_dev->linfo.link.s.mtu);
+ if ((mtu < ETHER_MIN_MTU) || (mtu > pf_mtu)) {
+ lio_dev_err(lio_dev, "VF MTU should be >= %d and <= %d\n",
+ ETHER_MIN_MTU, pf_mtu);
return -EINVAL;
}
+ /* flush added to prevent cmd failure
+ * incase the queue is full
+ */
+ lio_flush_iq(lio_dev, lio_dev->instr_queue[0]);
+
+ memset(&ctrl_pkt, 0, sizeof(struct lio_ctrl_pkt));
+ memset(&ctrl_cmd, 0, sizeof(struct lio_dev_ctrl_cmd));
+
+ ctrl_cmd.eth_dev = eth_dev;
+ ctrl_cmd.cond = 0;
+
+ ctrl_pkt.ncmd.s.cmd = LIO_CMD_CHANGE_MTU;
+ ctrl_pkt.ncmd.s.param1 = mtu;
+ ctrl_pkt.ctrl_cmd = &ctrl_cmd;
+
+ if (lio_send_ctrl_pkt(lio_dev, &ctrl_pkt)) {
+ lio_dev_err(lio_dev, "Failed to send command to change MTU\n");
+ return -1;
+ }
+
+ if (lio_wait_for_ctrl_cmd(lio_dev, &ctrl_cmd)) {
+ lio_dev_err(lio_dev, "Command to change MTU timed out\n");
+ return -1;
+ }
+
+ if (frame_len > ETHER_MAX_LEN)
+ eth_dev->data->dev_conf.rxmode.offloads |=
+ DEV_RX_OFFLOAD_JUMBO_FRAME;
+ else
+ eth_dev->data->dev_conf.rxmode.offloads &=
+ ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+
+ eth_dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_len;
+ eth_dev->data->mtu = mtu;
+
return 0;
}
return 0;
}
-/**
- * Atomically writes the link status information into global
- * structure rte_eth_dev.
- *
- * @param eth_dev
- * - Pointer to the structure rte_eth_dev to read from.
- * - Pointer to the buffer to be saved with the link status.
- *
- * @return
- * - On success, zero.
- * - On failure, negative value.
- */
-static inline int
-lio_dev_atomic_write_link_status(struct rte_eth_dev *eth_dev,
- struct rte_eth_link *link)
+static int
+lio_dev_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id, int on)
{
- struct rte_eth_link *dst = ð_dev->data->dev_link;
- struct rte_eth_link *src = link;
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ struct lio_dev_ctrl_cmd ctrl_cmd;
+ struct lio_ctrl_pkt ctrl_pkt;
+
+ if (lio_dev->linfo.vlan_is_admin_assigned)
+ return -EPERM;
- if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
- *(uint64_t *)src) == 0)
+ /* flush added to prevent cmd failure
+ * incase the queue is full
+ */
+ lio_flush_iq(lio_dev, lio_dev->instr_queue[0]);
+
+ memset(&ctrl_pkt, 0, sizeof(struct lio_ctrl_pkt));
+ memset(&ctrl_cmd, 0, sizeof(struct lio_dev_ctrl_cmd));
+
+ ctrl_cmd.eth_dev = eth_dev;
+ ctrl_cmd.cond = 0;
+
+ ctrl_pkt.ncmd.s.cmd = on ?
+ LIO_CMD_ADD_VLAN_FILTER : LIO_CMD_DEL_VLAN_FILTER;
+ ctrl_pkt.ncmd.s.param1 = vlan_id;
+ ctrl_pkt.ctrl_cmd = &ctrl_cmd;
+
+ if (lio_send_ctrl_pkt(lio_dev, &ctrl_pkt)) {
+ lio_dev_err(lio_dev, "Failed to %s VLAN port\n",
+ on ? "add" : "remove");
+ return -1;
+ }
+
+ if (lio_wait_for_ctrl_cmd(lio_dev, &ctrl_cmd)) {
+ lio_dev_err(lio_dev, "Command to %s VLAN port timed out\n",
+ on ? "add" : "remove");
return -1;
+ }
return 0;
}
int wait_to_complete __rte_unused)
{
struct lio_device *lio_dev = LIO_DEV(eth_dev);
- struct rte_eth_link link, old;
+ struct rte_eth_link link;
/* Initialize */
+ memset(&link, 0, sizeof(link));
link.link_status = ETH_LINK_DOWN;
link.link_speed = ETH_SPEED_NUM_NONE;
link.link_duplex = ETH_LINK_HALF_DUPLEX;
- memset(&old, 0, sizeof(old));
+ link.link_autoneg = ETH_LINK_AUTONEG;
/* Return what we found */
if (lio_dev->linfo.link.s.link_up == 0) {
/* Interface is down */
- if (lio_dev_atomic_write_link_status(eth_dev, &link))
- return -1;
- if (link.link_status == old.link_status)
- return -1;
- return 0;
+ return rte_eth_linkstatus_set(eth_dev, &link);
}
link.link_status = ETH_LINK_UP; /* Interface is up */
case LIO_LINK_SPEED_10000:
link.link_speed = ETH_SPEED_NUM_10G;
break;
+ case LIO_LINK_SPEED_25000:
+ link.link_speed = ETH_SPEED_NUM_25G;
+ break;
default:
link.link_speed = ETH_SPEED_NUM_NONE;
link.link_duplex = ETH_LINK_HALF_DUPLEX;
}
- if (lio_dev_atomic_write_link_status(eth_dev, &link))
- return -1;
-
- if (link.link_status == old.link_status)
- return -1;
-
- return 0;
+ return rte_eth_linkstatus_set(eth_dev, &link);
}
/**
lio_dev_err(lio_dev, "Change dev flag command timed out\n");
}
+static void
+lio_dev_promiscuous_enable(struct rte_eth_dev *eth_dev)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+
+ if (strcmp(lio_dev->firmware_version, LIO_VF_TRUST_MIN_VERSION) < 0) {
+ lio_dev_err(lio_dev, "Require firmware version >= %s\n",
+ LIO_VF_TRUST_MIN_VERSION);
+ return;
+ }
+
+ if (!lio_dev->intf_open) {
+ lio_dev_err(lio_dev, "Port %d down, can't enable promiscuous\n",
+ lio_dev->port_id);
+ return;
+ }
+
+ lio_dev->ifflags |= LIO_IFFLAG_PROMISC;
+ lio_change_dev_flag(eth_dev);
+}
+
+static void
+lio_dev_promiscuous_disable(struct rte_eth_dev *eth_dev)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+
+ if (strcmp(lio_dev->firmware_version, LIO_VF_TRUST_MIN_VERSION) < 0) {
+ lio_dev_err(lio_dev, "Require firmware version >= %s\n",
+ LIO_VF_TRUST_MIN_VERSION);
+ return;
+ }
+
+ if (!lio_dev->intf_open) {
+ lio_dev_err(lio_dev, "Port %d down, can't disable promiscuous\n",
+ lio_dev->port_id);
+ return;
+ }
+
+ lio_dev->ifflags &= ~LIO_IFFLAG_PROMISC;
+ lio_change_dev_flag(eth_dev);
+}
+
static void
lio_dev_allmulticast_enable(struct rte_eth_dev *eth_dev)
{
fw_mapped_oq = lio_dev->linfo.rxpciq[q_no].s.q_no;
- if ((lio_dev->droq[fw_mapped_oq]) &&
- (num_rx_descs != lio_dev->droq[fw_mapped_oq]->max_count)) {
- lio_dev_err(lio_dev,
- "Reconfiguring Rx descs not supported. Configure descs to same value %u or restart application\n",
- lio_dev->droq[fw_mapped_oq]->max_count);
- return -ENOTSUP;
+ /* Free previous allocation if any */
+ if (eth_dev->data->rx_queues[q_no] != NULL) {
+ lio_dev_rx_queue_release(eth_dev->data->rx_queues[q_no]);
+ eth_dev->data->rx_queues[q_no] = NULL;
}
mbp_priv = rte_mempool_get_priv(mp);
* @return
* - nothing
*/
-static void
+void
lio_dev_rx_queue_release(void *rxq)
{
struct lio_droq *droq = rxq;
- struct lio_device *lio_dev = droq->lio_dev;
int oq_no;
- /* Run time queue deletion not supported */
- if (lio_dev->port_configured)
- return;
-
- if (droq != NULL) {
+ if (droq) {
oq_no = droq->q_no;
lio_delete_droq_queue(droq->lio_dev, oq_no);
}
lio_dev_dbg(lio_dev, "setting up tx queue %u\n", q_no);
- if ((lio_dev->instr_queue[fw_mapped_iq] != NULL) &&
- (num_tx_descs != lio_dev->instr_queue[fw_mapped_iq]->max_count)) {
- lio_dev_err(lio_dev,
- "Reconfiguring Tx descs not supported. Configure descs to same value %u or restart application\n",
- lio_dev->instr_queue[fw_mapped_iq]->max_count);
- return -ENOTSUP;
+ /* Free previous allocation if any */
+ if (eth_dev->data->tx_queues[q_no] != NULL) {
+ lio_dev_tx_queue_release(eth_dev->data->tx_queues[q_no]);
+ eth_dev->data->tx_queues[q_no] = NULL;
}
retval = lio_setup_iq(lio_dev, q_no, lio_dev->linfo.txpciq[q_no],
}
retval = lio_setup_sglists(lio_dev, q_no, fw_mapped_iq,
- lio_dev->instr_queue[fw_mapped_iq]->max_count,
+ lio_dev->instr_queue[fw_mapped_iq]->nb_desc,
socket_id);
if (retval) {
* @return
* - nothing
*/
-static void
+void
lio_dev_tx_queue_release(void *txq)
{
struct lio_instr_queue *tq = txq;
- struct lio_device *lio_dev = tq->lio_dev;
uint32_t fw_mapped_iq_no;
- /* Run time queue deletion not supported */
- if (lio_dev->port_configured)
- return;
- if (tq != NULL) {
+ if (tq) {
/* Free sg_list */
lio_delete_sglist(tq);
lio_swap_8B_data((uint64_t *)ls, sizeof(union octeon_link_status) >> 3);
if (lio_dev->linfo.link.link_status64 != ls->link_status64) {
+ if (ls->s.mtu < eth_dev->data->mtu) {
+ lio_dev_info(lio_dev, "Lowered VF MTU to %d as PF MTU dropped\n",
+ ls->s.mtu);
+ eth_dev->data->mtu = ls->s.mtu;
+ }
lio_dev->linfo.link.link_status64 = ls->link_status64;
lio_dev_link_update(eth_dev, 0);
}
static int
lio_dev_start(struct rte_eth_dev *eth_dev)
{
- uint16_t mtu = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+ uint16_t mtu;
+ uint32_t frame_len = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
struct lio_device *lio_dev = LIO_DEV(eth_dev);
uint16_t timeout = LIO_MAX_CMD_TIMEOUT;
int ret = 0;
/* Configure RSS if device configured with multiple RX queues. */
lio_dev_mq_rx_configure(eth_dev);
+ /* Before update the link info,
+ * must set linfo.link.link_status64 to 0.
+ */
+ lio_dev->linfo.link.link_status64 = 0;
+
/* start polling for lsc */
ret = rte_eal_alarm_set(LIO_LSC_TIMEOUT,
lio_sync_link_state_check,
if (lio_dev->linfo.link.link_status64 == 0) {
ret = -1;
- goto dev_mtu_check_error;
+ goto dev_mtu_set_error;
}
- if (lio_dev->linfo.link.s.mtu != mtu) {
- ret = lio_dev_validate_vf_mtu(eth_dev, mtu);
+ mtu = (uint16_t)(frame_len - ETHER_HDR_LEN - ETHER_CRC_LEN);
+ if (mtu < ETHER_MIN_MTU)
+ mtu = ETHER_MIN_MTU;
+
+ if (eth_dev->data->mtu != mtu) {
+ ret = lio_dev_mtu_set(eth_dev, mtu);
if (ret)
- goto dev_mtu_check_error;
+ goto dev_mtu_set_error;
}
return 0;
-dev_mtu_check_error:
+dev_mtu_set_error:
rte_eal_alarm_cancel(lio_sync_link_state_check, eth_dev);
dev_lsc_handle_error:
return ret;
}
+/* Stop device and disable input/output functions */
+static void
+lio_dev_stop(struct rte_eth_dev *eth_dev)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+
+ lio_dev_info(lio_dev, "Stopping port %d\n", eth_dev->data->port_id);
+ lio_dev->intf_open = 0;
+ rte_mb();
+
+ /* Cancel callback if still running. */
+ rte_eal_alarm_cancel(lio_sync_link_state_check, eth_dev);
+
+ lio_send_rx_ctrl_cmd(eth_dev, 0);
+
+ lio_wait_for_instr_fetch(lio_dev);
+
+ /* Clear recorded link status */
+ lio_dev->linfo.link.link_status64 = 0;
+}
+
static int
lio_dev_set_link_up(struct rte_eth_dev *eth_dev)
{
return 0;
}
+/**
+ * Reset and stop the device. This occurs on the first
+ * call to this routine. Subsequent calls will simply
+ * return. NB: This will require the NIC to be rebooted.
+ *
+ * @param eth_dev
+ * Pointer to the structure rte_eth_dev
+ *
+ * @return
+ * - nothing
+ */
+static void
+lio_dev_close(struct rte_eth_dev *eth_dev)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+
+ lio_dev_info(lio_dev, "closing port %d\n", eth_dev->data->port_id);
+
+ if (lio_dev->intf_open)
+ lio_dev_stop(eth_dev);
+
+ /* Reset ioq regs */
+ lio_dev->fn_list.setup_device_regs(lio_dev);
+
+ if (lio_dev->pci_dev->kdrv == RTE_KDRV_IGB_UIO) {
+ cn23xx_vf_ask_pf_to_do_flr(lio_dev);
+ rte_delay_ms(LIO_PCI_FLR_WAIT);
+ }
+
+ /* lio_free_mbox */
+ lio_dev->fn_list.free_mbox(lio_dev);
+
+ /* Free glist resources */
+ rte_free(lio_dev->glist_head);
+ rte_free(lio_dev->glist_lock);
+ lio_dev->glist_head = NULL;
+ lio_dev->glist_lock = NULL;
+
+ lio_dev->port_configured = 0;
+
+ /* Delete all queues */
+ lio_dev_clear_queues(eth_dev);
+}
+
/**
* Enable tunnel rx checksum verification from firmware.
*/
lio_dev_err(lio_dev, "TNL_TX_CSUM command timed out\n");
}
-static int lio_dev_configure(struct rte_eth_dev *eth_dev)
+static int
+lio_send_queue_count_update(struct rte_eth_dev *eth_dev, int num_txq,
+ int num_rxq)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+ struct lio_dev_ctrl_cmd ctrl_cmd;
+ struct lio_ctrl_pkt ctrl_pkt;
+
+ if (strcmp(lio_dev->firmware_version, LIO_Q_RECONF_MIN_VERSION) < 0) {
+ lio_dev_err(lio_dev, "Require firmware version >= %s\n",
+ LIO_Q_RECONF_MIN_VERSION);
+ return -ENOTSUP;
+ }
+
+ /* flush added to prevent cmd failure
+ * incase the queue is full
+ */
+ lio_flush_iq(lio_dev, lio_dev->instr_queue[0]);
+
+ memset(&ctrl_pkt, 0, sizeof(struct lio_ctrl_pkt));
+ memset(&ctrl_cmd, 0, sizeof(struct lio_dev_ctrl_cmd));
+
+ ctrl_cmd.eth_dev = eth_dev;
+ ctrl_cmd.cond = 0;
+
+ ctrl_pkt.ncmd.s.cmd = LIO_CMD_QUEUE_COUNT_CTL;
+ ctrl_pkt.ncmd.s.param1 = num_txq;
+ ctrl_pkt.ncmd.s.param2 = num_rxq;
+ ctrl_pkt.ctrl_cmd = &ctrl_cmd;
+
+ if (lio_send_ctrl_pkt(lio_dev, &ctrl_pkt)) {
+ lio_dev_err(lio_dev, "Failed to send queue count control command\n");
+ return -1;
+ }
+
+ if (lio_wait_for_ctrl_cmd(lio_dev, &ctrl_cmd)) {
+ lio_dev_err(lio_dev, "Queue count control command timed out\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+lio_reconf_queues(struct rte_eth_dev *eth_dev, int num_txq, int num_rxq)
+{
+ struct lio_device *lio_dev = LIO_DEV(eth_dev);
+
+ if (lio_dev->nb_rx_queues != num_rxq ||
+ lio_dev->nb_tx_queues != num_txq) {
+ if (lio_send_queue_count_update(eth_dev, num_txq, num_rxq))
+ return -1;
+ lio_dev->nb_rx_queues = num_rxq;
+ lio_dev->nb_tx_queues = num_txq;
+ }
+
+ if (lio_dev->intf_open)
+ lio_dev_stop(eth_dev);
+
+ /* Reset ioq registers */
+ if (lio_dev->fn_list.setup_device_regs(lio_dev)) {
+ lio_dev_err(lio_dev, "Failed to configure device registers\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+lio_dev_configure(struct rte_eth_dev *eth_dev)
{
struct lio_device *lio_dev = LIO_DEV(eth_dev);
uint16_t timeout = LIO_MAX_CMD_TIMEOUT;
PMD_INIT_FUNC_TRACE();
- /* Re-configuring firmware not supported.
- * Can't change tx/rx queues per port from initial value.
+ /* Inform firmware about change in number of queues to use.
+ * Disable IO queues and reset registers for re-configuration.
*/
- if (lio_dev->port_configured) {
- if ((lio_dev->nb_rx_queues != eth_dev->data->nb_rx_queues) ||
- (lio_dev->nb_tx_queues != eth_dev->data->nb_tx_queues)) {
- lio_dev_err(lio_dev,
- "rxq/txq re-conf not supported. Restart application with new value.\n");
- return -ENOTSUP;
- }
- return 0;
- }
+ if (lio_dev->port_configured)
+ return lio_reconf_queues(eth_dev,
+ eth_dev->data->nb_tx_queues,
+ eth_dev->data->nb_rx_queues);
lio_dev->nb_rx_queues = eth_dev->data->nb_rx_queues;
lio_dev->nb_tx_queues = eth_dev->data->nb_tx_queues;
+ /* Set max number of queues which can be re-configured. */
+ lio_dev->max_rx_queues = eth_dev->data->nb_rx_queues;
+ lio_dev->max_tx_queues = eth_dev->data->nb_tx_queues;
+
resp_size = sizeof(struct lio_if_cfg_resp);
sc = lio_alloc_soft_command(lio_dev, 0, resp_size, 0);
if (sc == NULL)
goto nic_config_fail;
}
+ snprintf(lio_dev->firmware_version, LIO_FW_VERSION_LENGTH, "%s",
+ resp->cfg_info.lio_firmware_version);
+
lio_swap_8B_data((uint64_t *)(&resp->cfg_info),
sizeof(struct octeon_if_cfg_info) >> 3);
lio_free_soft_command(sc);
- /* Disable iq_0 for reconf */
- lio_dev->fn_list.disable_io_queues(lio_dev);
-
/* Reset ioq regs */
lio_dev->fn_list.setup_device_regs(lio_dev);
static const struct eth_dev_ops liovf_eth_dev_ops = {
.dev_configure = lio_dev_configure,
.dev_start = lio_dev_start,
+ .dev_stop = lio_dev_stop,
.dev_set_link_up = lio_dev_set_link_up,
.dev_set_link_down = lio_dev_set_link_down,
+ .dev_close = lio_dev_close,
+ .promiscuous_enable = lio_dev_promiscuous_enable,
+ .promiscuous_disable = lio_dev_promiscuous_disable,
.allmulticast_enable = lio_dev_allmulticast_enable,
.allmulticast_disable = lio_dev_allmulticast_disable,
.link_update = lio_dev_link_update,
+ .stats_get = lio_dev_stats_get,
+ .xstats_get = lio_dev_xstats_get,
+ .xstats_get_names = lio_dev_xstats_get_names,
+ .stats_reset = lio_dev_stats_reset,
+ .xstats_reset = lio_dev_xstats_reset,
.dev_infos_get = lio_dev_info_get,
+ .vlan_filter_set = lio_dev_vlan_filter_set,
.rx_queue_setup = lio_dev_rx_queue_setup,
.rx_queue_release = lio_dev_rx_queue_release,
.tx_queue_setup = lio_dev_tx_queue_setup,
.rss_hash_update = lio_dev_rss_hash_update,
.udp_tunnel_port_add = lio_dev_udp_tunnel_add,
.udp_tunnel_port_del = lio_dev_udp_tunnel_del,
+ .mtu_set = lio_dev_mtu_set,
};
static void
if (cn23xx_pfvf_handshake(lio_dev))
goto error;
- /* Initial reset */
- cn23xx_vf_ask_pf_to_do_flr(lio_dev);
- /* Wait for FLR for 100ms per SRIOV specification */
- rte_delay_ms(100);
-
- if (cn23xx_vf_set_io_queues_off(lio_dev)) {
- lio_dev_err(lio_dev, "Setting io queues off failed\n");
- goto error;
+ /* Request and wait for device reset. */
+ if (pdev->kdrv == RTE_KDRV_IGB_UIO) {
+ cn23xx_vf_ask_pf_to_do_flr(lio_dev);
+ /* FLR wait time doubled as a precaution. */
+ rte_delay_ms(LIO_PCI_FLR_WAIT * 2);
}
if (lio_dev->fn_list.setup_device_regs(lio_dev)) {
PMD_INIT_FUNC_TRACE();
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
- return -EPERM;
+ return 0;
/* lio_free_sc_buffer_pool */
lio_free_sc_buffer_pool(lio_dev);
rte_free(eth_dev->data->mac_addrs);
eth_dev->data->mac_addrs = NULL;
+ eth_dev->dev_ops = NULL;
eth_dev->rx_pkt_burst = NULL;
eth_dev->tx_pkt_burst = NULL;
static int
lio_eth_dev_init(struct rte_eth_dev *eth_dev)
{
- struct rte_pci_device *pdev = RTE_DEV_TO_PCI(eth_dev->device);
+ struct rte_pci_device *pdev = RTE_ETH_DEV_TO_PCI(eth_dev);
struct lio_device *lio_dev = LIO_DEV(eth_dev);
PMD_INIT_FUNC_TRACE();
return 0;
rte_eth_copy_pci_info(eth_dev, pdev);
- eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
if (pdev->mem_resource[0].addr) {
lio_dev->hw_addr = pdev->mem_resource[0].addr;
return 0;
}
+static int
+lio_eth_dev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+ struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct lio_device),
+ lio_eth_dev_init);
+}
+
+static int
+lio_eth_dev_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev,
+ lio_eth_dev_uninit);
+}
+
/* Set of PCI devices this driver supports */
static const struct rte_pci_id pci_id_liovf_map[] = {
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_VF_VID) },
{ .vendor_id = 0, /* sentinel */ }
};
-static struct eth_driver rte_liovf_pmd = {
- .pci_drv = {
- .id_table = pci_id_liovf_map,
- .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
- .probe = rte_eth_dev_pci_probe,
- .remove = rte_eth_dev_pci_remove,
- },
- .eth_dev_init = lio_eth_dev_init,
- .eth_dev_uninit = lio_eth_dev_uninit,
- .dev_private_size = sizeof(struct lio_device),
+static struct rte_pci_driver rte_liovf_pmd = {
+ .id_table = pci_id_liovf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = lio_eth_dev_pci_probe,
+ .remove = lio_eth_dev_pci_remove,
};
-RTE_PMD_REGISTER_PCI(net_liovf, rte_liovf_pmd.pci_drv);
+RTE_PMD_REGISTER_PCI(net_liovf, rte_liovf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_liovf, pci_id_liovf_map);
-RTE_PMD_REGISTER_KMOD_DEP(net_liovf, "* igb_uio | vfio");
+RTE_PMD_REGISTER_KMOD_DEP(net_liovf, "* igb_uio | vfio-pci");
+
+RTE_INIT(lio_init_log)
+{
+ lio_logtype_init = rte_log_register("pmd.net.liquidio.init");
+ if (lio_logtype_init >= 0)
+ rte_log_set_level(lio_logtype_init, RTE_LOG_NOTICE);
+ lio_logtype_driver = rte_log_register("pmd.net.liquidio.driver");
+ if (lio_logtype_driver >= 0)
+ rte_log_set_level(lio_logtype_driver, RTE_LOG_NOTICE);
+}