net/dpaa2: update link status
[dpdk.git] / drivers / net / dpaa2 / dpaa2_ethdev.c
index f4565b6..03d0e8c 100644 (file)
 
 static struct rte_dpaa2_driver rte_dpaa2_pmd;
 
+/**
+ * Atomically reads the link status information from global
+ * structure rte_eth_dev.
+ *
+ * @param 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
+dpaa2_dev_atomic_read_link_status(struct rte_eth_dev *dev,
+                                 struct rte_eth_link *link)
+{
+       struct rte_eth_link *dst = link;
+       struct rte_eth_link *src = &dev->data->dev_link;
+
+       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+                               *(uint64_t *)src) == 0)
+               return -1;
+
+       return 0;
+}
+
+/**
+ * Atomically writes the link status information into global
+ * structure rte_eth_dev.
+ *
+ * @param 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
+dpaa2_dev_atomic_write_link_status(struct rte_eth_dev *dev,
+                                  struct rte_eth_link *link)
+{
+       struct rte_eth_link *dst = &dev->data->dev_link;
+       struct rte_eth_link *src = link;
+
+       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+                               *(uint64_t *)src) == 0)
+               return -1;
+
+       return 0;
+}
+
 static void
 dpaa2_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
@@ -310,6 +362,28 @@ dpaa2_dev_tx_queue_release(void *q __rte_unused)
        PMD_INIT_FUNC_TRACE();
 }
 
+static const uint32_t *
+dpaa2_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+       static const uint32_t ptypes[] = {
+               /*todo -= add more types */
+               RTE_PTYPE_L2_ETHER,
+               RTE_PTYPE_L3_IPV4,
+               RTE_PTYPE_L3_IPV4_EXT,
+               RTE_PTYPE_L3_IPV6,
+               RTE_PTYPE_L3_IPV6_EXT,
+               RTE_PTYPE_L4_TCP,
+               RTE_PTYPE_L4_UDP,
+               RTE_PTYPE_L4_SCTP,
+               RTE_PTYPE_L4_ICMP,
+               RTE_PTYPE_UNKNOWN
+       };
+
+       if (dev->rx_pkt_burst == dpaa2_dev_rx)
+               return ptypes;
+       return NULL;
+}
+
 static int
 dpaa2_dev_start(struct rte_eth_dev *dev)
 {
@@ -408,6 +482,7 @@ dpaa2_dev_stop(struct rte_eth_dev *dev)
        struct dpaa2_dev_priv *priv = dev->data->dev_private;
        struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
        int ret;
+       struct rte_eth_link link;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -417,6 +492,10 @@ dpaa2_dev_stop(struct rte_eth_dev *dev)
                             ret, priv->hw_id);
                return;
        }
+
+       /* clear the recorded link status */
+       memset(&link, 0, sizeof(link));
+       dpaa2_dev_atomic_write_link_status(dev, &link);
 }
 
 static void
@@ -437,12 +516,138 @@ dpaa2_dev_close(struct rte_eth_dev *dev)
        }
 }
 
+static void
+dpaa2_dev_promiscuous_enable(
+               struct rte_eth_dev *dev)
+{
+       int ret;
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (dpni == NULL) {
+               RTE_LOG(ERR, PMD, "dpni is NULL");
+               return;
+       }
+
+       ret = dpni_set_unicast_promisc(dpni, CMD_PRI_LOW, priv->token, true);
+       if (ret < 0)
+               RTE_LOG(ERR, PMD, "Unable to enable promiscuous mode %d", ret);
+}
+
+static void
+dpaa2_dev_promiscuous_disable(
+               struct rte_eth_dev *dev)
+{
+       int ret;
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (dpni == NULL) {
+               RTE_LOG(ERR, PMD, "dpni is NULL");
+               return;
+       }
+
+       ret = dpni_set_unicast_promisc(dpni, CMD_PRI_LOW, priv->token, false);
+       if (ret < 0)
+               RTE_LOG(ERR, PMD, "Unable to disable promiscuous mode %d", ret);
+}
+
+static int
+dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+       int ret;
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
+       uint32_t frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (dpni == NULL) {
+               RTE_LOG(ERR, PMD, "dpni is NULL");
+               return -EINVAL;
+       }
+
+       /* check that mtu is within the allowed range */
+       if ((mtu < ETHER_MIN_MTU) || (frame_size > DPAA2_MAX_RX_PKT_LEN))
+               return -EINVAL;
+
+       /* Set the Max Rx frame length as 'mtu' +
+        * Maximum Ethernet header length
+        */
+       ret = dpni_set_max_frame_length(dpni, CMD_PRI_LOW, priv->token,
+                                       mtu + ETH_VLAN_HLEN);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "setting the max frame length failed");
+               return -1;
+       }
+       PMD_DRV_LOG(INFO, "MTU is configured %d for the device\n", mtu);
+       return 0;
+}
+
+/* return 0 means link status changed, -1 means not changed */
+static int
+dpaa2_dev_link_update(struct rte_eth_dev *dev,
+                       int wait_to_complete __rte_unused)
+{
+       int ret;
+       struct dpaa2_dev_priv *priv = dev->data->dev_private;
+       struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
+       struct rte_eth_link link, old;
+       struct dpni_link_state state = {0};
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (dpni == NULL) {
+               RTE_LOG(ERR, PMD, "error : dpni is NULL");
+               return 0;
+       }
+       memset(&old, 0, sizeof(old));
+       dpaa2_dev_atomic_read_link_status(dev, &old);
+
+       ret = dpni_get_link_state(dpni, CMD_PRI_LOW, priv->token, &state);
+       if (ret < 0) {
+               RTE_LOG(ERR, PMD, "error: dpni_get_link_state %d", ret);
+               return -1;
+       }
+
+       if ((old.link_status == state.up) && (old.link_speed == state.rate)) {
+               RTE_LOG(DEBUG, PMD, "No change in status\n");
+               return -1;
+       }
+
+       memset(&link, 0, sizeof(struct rte_eth_link));
+       link.link_status = state.up;
+       link.link_speed = state.rate;
+
+       if (state.options & DPNI_LINK_OPT_HALF_DUPLEX)
+               link.link_duplex = ETH_LINK_HALF_DUPLEX;
+       else
+               link.link_duplex = ETH_LINK_FULL_DUPLEX;
+
+       dpaa2_dev_atomic_write_link_status(dev, &link);
+
+       if (link.link_status)
+               PMD_DRV_LOG(INFO, "Port %d Link is Up\n", dev->data->port_id);
+       else
+               PMD_DRV_LOG(INFO, "Port %d Link is Down\n", dev->data->port_id);
+       return 0;
+}
+
 static struct eth_dev_ops dpaa2_ethdev_ops = {
        .dev_configure    = dpaa2_eth_dev_configure,
        .dev_start            = dpaa2_dev_start,
        .dev_stop             = dpaa2_dev_stop,
        .dev_close            = dpaa2_dev_close,
+       .promiscuous_enable   = dpaa2_dev_promiscuous_enable,
+       .promiscuous_disable  = dpaa2_dev_promiscuous_disable,
+       .link_update       = dpaa2_dev_link_update,
        .dev_infos_get     = dpaa2_dev_info_get,
+       .dev_supported_ptypes_get = dpaa2_supported_ptypes_get,
+       .mtu_set           = dpaa2_dev_mtu_set,
        .rx_queue_setup    = dpaa2_dev_rx_queue_setup,
        .rx_queue_release  = dpaa2_dev_rx_queue_release,
        .tx_queue_setup    = dpaa2_dev_tx_queue_setup,
@@ -604,6 +809,8 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev)
        eth_dev->dev_ops = &dpaa2_ethdev_ops;
        eth_dev->data->drv_name = rte_dpaa2_pmd.driver.name;
 
+       eth_dev->rx_pkt_burst = dpaa2_dev_rx;
+       eth_dev->tx_pkt_burst = dpaa2_dev_tx;
        return 0;
 }
 
@@ -657,6 +864,8 @@ dpaa2_dev_uninit(struct rte_eth_dev *eth_dev)
        free(dpni);
 
        eth_dev->dev_ops = NULL;
+       eth_dev->rx_pkt_burst = NULL;
+       eth_dev->tx_pkt_burst = NULL;
 
        return 0;
 }