/* CNXK platform independent eth dev ops */
struct eth_dev_ops cnxk_eth_dev_ops = {
.dev_infos_get = cnxk_nix_info_get,
+ .link_update = cnxk_nix_link_update,
};
static int
goto error;
}
+ /* Register up msg callbacks */
+ roc_nix_mac_link_cb_register(nix, cnxk_eth_dev_link_status_cb);
+
dev->eth_dev = eth_dev;
dev->configured = 0;
roc_nix_npc_rx_ena_dis(nix, false);
+ /* Disable link status events */
+ roc_nix_mac_link_event_start_stop(nix, false);
+
/* Free up SQs */
for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
dev_ops->tx_queue_release(eth_dev->data->tx_queues[i]);
#define CNXK_ETH_DEV_PMD_VERSION "1.0"
+/* Used for struct cnxk_eth_dev::flags */
+#define CNXK_LINK_CFG_IN_PROGRESS_F BIT_ULL(0)
+
/* VLAN tag inserted by NIX_TX_VTAG_ACTION.
* In Tx space is always reserved for this in FRS.
*/
uint32_t cnxk_rss_ethdev_to_nix(struct cnxk_eth_dev *dev, uint64_t ethdev_rss,
uint8_t rss_level);
+/* Link */
+void cnxk_eth_dev_link_status_cb(struct roc_nix *nix,
+ struct roc_nix_link_info *link);
+int cnxk_nix_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete);
+
/* Devargs */
int cnxk_ethdev_parse_devargs(struct rte_devargs *devargs,
struct cnxk_eth_dev *dev);
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include "cnxk_ethdev.h"
+
+static inline int
+nix_wait_for_link_cfg(struct cnxk_eth_dev *dev)
+{
+ uint16_t wait = 1000;
+
+ do {
+ rte_atomic_thread_fence(__ATOMIC_ACQUIRE);
+ if (!(dev->flags & CNXK_LINK_CFG_IN_PROGRESS_F))
+ break;
+ wait--;
+ rte_delay_ms(1);
+ } while (wait);
+
+ return wait ? 0 : -1;
+}
+
+static void
+nix_link_status_print(struct rte_eth_dev *eth_dev, struct rte_eth_link *link)
+{
+ if (link && link->link_status)
+ plt_info("Port %d: Link Up - speed %u Mbps - %s",
+ (int)(eth_dev->data->port_id),
+ (uint32_t)link->link_speed,
+ link->link_duplex == ETH_LINK_FULL_DUPLEX
+ ? "full-duplex"
+ : "half-duplex");
+ else
+ plt_info("Port %d: Link Down", (int)(eth_dev->data->port_id));
+}
+
+void
+cnxk_eth_dev_link_status_cb(struct roc_nix *nix, struct roc_nix_link_info *link)
+{
+ struct cnxk_eth_dev *dev = (struct cnxk_eth_dev *)nix;
+ struct rte_eth_link eth_link;
+ struct rte_eth_dev *eth_dev;
+
+ if (!link || !nix)
+ return;
+
+ eth_dev = dev->eth_dev;
+ if (!eth_dev || !eth_dev->data->dev_conf.intr_conf.lsc)
+ return;
+
+ if (nix_wait_for_link_cfg(dev)) {
+ plt_err("Timeout waiting for link_cfg to complete");
+ return;
+ }
+
+ eth_link.link_status = link->status;
+ eth_link.link_speed = link->speed;
+ eth_link.link_autoneg = ETH_LINK_AUTONEG;
+ eth_link.link_duplex = link->full_duplex;
+
+ /* Print link info */
+ nix_link_status_print(eth_dev, ð_link);
+
+ /* Update link info */
+ rte_eth_linkstatus_set(eth_dev, ð_link);
+
+ /* Set the flag and execute application callbacks */
+ rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+}
+
+int
+cnxk_nix_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete)
+{
+ struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+ struct roc_nix_link_info info;
+ struct rte_eth_link link;
+ int rc;
+
+ RTE_SET_USED(wait_to_complete);
+ memset(&link, 0, sizeof(struct rte_eth_link));
+
+ if (roc_nix_is_sdp(&dev->nix))
+ return 0;
+
+ if (roc_nix_is_lbk(&dev->nix)) {
+ link.link_status = ETH_LINK_UP;
+ link.link_speed = ETH_SPEED_NUM_100G;
+ link.link_autoneg = ETH_LINK_FIXED;
+ link.link_duplex = ETH_LINK_FULL_DUPLEX;
+ } else {
+ rc = roc_nix_mac_link_info_get(&dev->nix, &info);
+ if (rc)
+ return rc;
+ link.link_status = info.status;
+ link.link_speed = info.speed;
+ link.link_autoneg = ETH_LINK_AUTONEG;
+ if (info.full_duplex)
+ link.link_duplex = info.full_duplex;
+ }
+
+ return rte_eth_linkstatus_set(eth_dev, &link);
+}