+ dev->data->dev_link.link_duplex = edata.duplex ? ETH_LINK_FULL_DUPLEX :
+ ETH_LINK_HALF_DUPLEX;
+ dev->data->dev_link.link_autoneg = edata.autoneg ? ETH_LINK_AUTONEG :
+ ETH_LINK_FIXED;
+ pp2_ppio_get_link_state(priv->ppio, &link_up);
+ dev->data->dev_link.link_status = link_up ? ETH_LINK_UP : ETH_LINK_DOWN;
+
+ return 0;
+}
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_enable(struct rte_eth_dev *dev)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ int ret;
+
+ if (!priv->ppio)
+ return;
+
+ ret = pp2_ppio_set_promisc(priv->ppio, 1);
+ if (ret)
+ RTE_LOG(ERR, PMD, "Failed to enable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to enable allmulti mode.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_enable(struct rte_eth_dev *dev)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ int ret;
+
+ if (!priv->ppio)
+ return;
+
+ ret = pp2_ppio_set_mc_promisc(priv->ppio, 1);
+ if (ret)
+ RTE_LOG(ERR, PMD, "Failed enable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_disable(struct rte_eth_dev *dev)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ int ret;
+
+ if (!priv->ppio)
+ return;
+
+ ret = pp2_ppio_set_promisc(priv->ppio, 0);
+ if (ret)
+ RTE_LOG(ERR, PMD, "Failed to disable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_disable(struct rte_eth_dev *dev)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ int ret;
+
+ if (!priv->ppio)
+ return;
+
+ ret = pp2_ppio_set_mc_promisc(priv->ppio, 0);
+ if (ret)
+ RTE_LOG(ERR, PMD, "Failed to disable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param index
+ * MAC address index.
+ */
+static void
+mrvl_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ char buf[ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ if (!priv->ppio)
+ return;
+
+ ret = pp2_ppio_remove_mac_addr(priv->ppio,
+ dev->data->mac_addrs[index].addr_bytes);
+ if (ret) {
+ ether_format_addr(buf, sizeof(buf),
+ &dev->data->mac_addrs[index]);
+ RTE_LOG(ERR, PMD, "Failed to remove mac %s\n", buf);
+ }
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param mac_addr
+ * MAC address to register.
+ * @param index
+ * MAC address index.
+ * @param vmdq
+ * VMDq pool index to associate address with (unused).
+ *
+ * @return
+ * 0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
+ uint32_t index, uint32_t vmdq __rte_unused)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ char buf[ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ if (index == 0)
+ /* For setting index 0, mrvl_mac_addr_set() should be used.*/
+ return -1;
+
+ if (!priv->ppio)
+ return 0;
+
+ /*
+ * Maximum number of uc addresses can be tuned via kernel module mvpp2x
+ * parameter uc_filter_max. Maximum number of mc addresses is then
+ * MRVL_MAC_ADDRS_MAX - uc_filter_max. Currently it defaults to 4 and
+ * 21 respectively.
+ *
+ * If more than uc_filter_max uc addresses were added to filter list
+ * then NIC will switch to promiscuous mode automatically.
+ *
+ * If more than MRVL_MAC_ADDRS_MAX - uc_filter_max number mc addresses
+ * were added to filter list then NIC will switch to all-multicast mode
+ * automatically.
+ */
+ ret = pp2_ppio_add_mac_addr(priv->ppio, mac_addr->addr_bytes);
+ if (ret) {
+ ether_format_addr(buf, sizeof(buf), mac_addr);
+ RTE_LOG(ERR, PMD, "Failed to add mac %s\n", buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * DPDK callback to set the primary MAC address.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param mac_addr
+ * MAC address to register.
+ */
+static void
+mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ int ret;
+
+ if (!priv->ppio)
+ return;
+
+ ret = pp2_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes);
+ if (ret) {
+ char buf[ETHER_ADDR_FMT_SIZE];
+ ether_format_addr(buf, sizeof(buf), mac_addr);
+ RTE_LOG(ERR, PMD, "Failed to set mac to %s\n", buf);
+ }
+}
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param stats
+ * Stats structure output buffer.
+ *
+ * @return
+ * 0 on success, negative error value otherwise.
+ */
+static int
+mrvl_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+ struct mrvl_priv *priv = dev->data->dev_private;
+ struct pp2_ppio_statistics ppio_stats;
+ uint64_t drop_mac = 0;
+ unsigned int i, idx, ret;
+
+ if (!priv->ppio)
+ return -EPERM;
+
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
+ struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+ struct pp2_ppio_inq_statistics rx_stats;
+
+ if (!rxq)
+ continue;
+
+ idx = rxq->queue_id;
+ if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+ RTE_LOG(ERR, PMD,
+ "rx queue %d stats out of range (0 - %d)\n",
+ idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+ continue;
+ }
+
+ ret = pp2_ppio_inq_get_statistics(priv->ppio,
+ priv->rxq_map[idx].tc,
+ priv->rxq_map[idx].inq,
+ &rx_stats, 0);
+ if (unlikely(ret)) {
+ RTE_LOG(ERR, PMD,
+ "Failed to update rx queue %d stats\n", idx);
+ break;
+ }
+
+ stats->q_ibytes[idx] = rxq->bytes_recv;
+ stats->q_ipackets[idx] = rx_stats.enq_desc - rxq->drop_mac;
+ stats->q_errors[idx] = rx_stats.drop_early +
+ rx_stats.drop_fullq +
+ rx_stats.drop_bm +
+ rxq->drop_mac;
+ stats->ibytes += rxq->bytes_recv;
+ drop_mac += rxq->drop_mac;
+ }
+
+ for (i = 0; i < dev->data->nb_tx_queues; i++) {
+ struct mrvl_txq *txq = dev->data->tx_queues[i];
+ struct pp2_ppio_outq_statistics tx_stats;
+
+ if (!txq)
+ continue;
+
+ idx = txq->queue_id;
+ if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+ RTE_LOG(ERR, PMD,
+ "tx queue %d stats out of range (0 - %d)\n",
+ idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+ }
+
+ ret = pp2_ppio_outq_get_statistics(priv->ppio, idx,
+ &tx_stats, 0);
+ if (unlikely(ret)) {
+ RTE_LOG(ERR, PMD,
+ "Failed to update tx queue %d stats\n", idx);
+ break;
+ }
+
+ stats->q_opackets[idx] = tx_stats.deq_desc;
+ stats->q_obytes[idx] = txq->bytes_sent;
+ stats->obytes += txq->bytes_sent;
+ }
+
+ ret = pp2_ppio_get_statistics(priv->ppio, &ppio_stats, 0);
+ if (unlikely(ret)) {
+ RTE_LOG(ERR, PMD, "Failed to update port statistics\n");
+ return ret;
+ }
+
+ stats->ipackets += ppio_stats.rx_packets - drop_mac;
+ stats->opackets += ppio_stats.tx_packets;
+ stats->imissed += ppio_stats.rx_fullq_dropped +
+ ppio_stats.rx_bm_dropped +
+ ppio_stats.rx_early_dropped +
+ ppio_stats.rx_fifo_dropped +
+ ppio_stats.rx_cls_dropped;
+ stats->ierrors = drop_mac;