static struct rte_dpaa2_driver rte_dpaa2_pmd;
static int dpaa2_dev_uninit(struct rte_eth_dev *eth_dev);
+static int dpaa2_dev_link_update(struct rte_eth_dev *dev,
+ int wait_to_complete);
static int dpaa2_dev_set_link_up(struct rte_eth_dev *dev);
static int dpaa2_dev_set_link_down(struct rte_eth_dev *dev);
static int dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
}
}
- /* Check for correct configuration */
- if (eth_conf->rxmode.mq_mode != ETH_MQ_RX_RSS &&
- data->nb_rx_queues > 1) {
- PMD_INIT_LOG(ERR, "Distribution is not enabled, "
- "but Rx queues more than 1\n");
- return -1;
- }
-
if (eth_conf->rxmode.mq_mode == ETH_MQ_RX_RSS) {
- /* Return in case number of Rx queues is 1 */
- if (data->nb_rx_queues == 1)
- return 0;
ret = dpaa2_setup_flow_dist(dev,
eth_conf->rx_adv_conf.rss_conf.rss_hf);
if (ret) {
return ret;
}
}
+
+ /* update the current status */
+ dpaa2_dev_link_update(dev, 0);
+
return 0;
}
return NULL;
}
+/**
+ * Dpaa2 link Interrupt handler
+ *
+ * @param param
+ * The address of parameter (struct rte_eth_dev *) regsitered before.
+ *
+ * @return
+ * void
+ */
+static void
+dpaa2_interrupt_handler(void *param)
+{
+ struct rte_eth_dev *dev = param;
+ struct dpaa2_dev_priv *priv = dev->data->dev_private;
+ struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
+ int ret;
+ int irq_index = DPNI_IRQ_INDEX;
+ unsigned int status = 0, clear = 0;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (dpni == NULL) {
+ RTE_LOG(ERR, PMD, "dpni is NULL");
+ return;
+ }
+
+ ret = dpni_get_irq_status(dpni, CMD_PRI_LOW, priv->token,
+ irq_index, &status);
+ if (unlikely(ret)) {
+ RTE_LOG(ERR, PMD, "Can't get irq status (err %d)", ret);
+ clear = 0xffffffff;
+ goto out;
+ }
+
+ if (status & DPNI_IRQ_EVENT_LINK_CHANGED) {
+ clear = DPNI_IRQ_EVENT_LINK_CHANGED;
+ dpaa2_dev_link_update(dev, 0);
+ /* calling all the apps registered for link status event */
+ _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
+ NULL, NULL);
+ }
+out:
+ ret = dpni_clear_irq_status(dpni, CMD_PRI_LOW, priv->token,
+ irq_index, clear);
+ if (unlikely(ret))
+ RTE_LOG(ERR, PMD, "Can't clear irq status (err %d)", ret);
+}
+
+static int
+dpaa2_eth_setup_irqs(struct rte_eth_dev *dev, int enable)
+{
+ int err = 0;
+ struct dpaa2_dev_priv *priv = dev->data->dev_private;
+ struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
+ int irq_index = DPNI_IRQ_INDEX;
+ unsigned int mask = DPNI_IRQ_EVENT_LINK_CHANGED;
+
+ PMD_INIT_FUNC_TRACE();
+
+ err = dpni_set_irq_mask(dpni, CMD_PRI_LOW, priv->token,
+ irq_index, mask);
+ if (err < 0) {
+ PMD_INIT_LOG(ERR, "Error: dpni_set_irq_mask():%d (%s)", err,
+ strerror(-err));
+ return err;
+ }
+
+ err = dpni_set_irq_enable(dpni, CMD_PRI_LOW, priv->token,
+ irq_index, enable);
+ if (err < 0)
+ PMD_INIT_LOG(ERR, "Error: dpni_set_irq_enable():%d (%s)", err,
+ strerror(-err));
+
+ return err;
+}
+
static int
dpaa2_dev_start(struct rte_eth_dev *dev)
{
+ struct rte_device *rdev = dev->device;
+ struct rte_dpaa2_device *dpaa2_dev;
struct rte_eth_dev_data *data = dev->data;
struct dpaa2_dev_priv *priv = data->dev_private;
struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
struct dpni_queue_id qid;
struct dpaa2_queue *dpaa2_q;
int ret, i;
+ struct rte_intr_handle *intr_handle;
+
+ dpaa2_dev = container_of(rdev, struct rte_dpaa2_device, device);
+ intr_handle = &dpaa2_dev->intr_handle;
PMD_INIT_FUNC_TRACE();
return ret;
}
- /* Power up the phy. Needed to make the link go Up */
+ /* Power up the phy. Needed to make the link go UP */
dpaa2_dev_set_link_up(dev);
ret = dpni_get_qdid(dpni, CMD_PRI_LOW, priv->token,
if (priv->max_vlan_filters)
dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
+ /* if the interrupts were configured on this devices*/
+ if (intr_handle && (intr_handle->fd) &&
+ (dev->data->dev_conf.intr_conf.lsc != 0)) {
+ /* Registering LSC interrupt handler */
+ rte_intr_callback_register(intr_handle,
+ dpaa2_interrupt_handler,
+ (void *)dev);
+
+ /* enable vfio intr/eventfd mapping
+ * Interrupt index 0 is required, so we can not use
+ * rte_intr_enable.
+ */
+ rte_dpaa2_intr_enable(intr_handle, DPNI_IRQ_INDEX);
+
+ /* enable dpni_irqs */
+ dpaa2_eth_setup_irqs(dev, 1);
+ }
+
return 0;
}
struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
int ret;
struct rte_eth_link link;
+ struct rte_intr_handle *intr_handle = dev->intr_handle;
PMD_INIT_FUNC_TRACE();
+ /* reset interrupt callback */
+ if (intr_handle && (intr_handle->fd) &&
+ (dev->data->dev_conf.intr_conf.lsc != 0)) {
+ /*disable dpni irqs */
+ dpaa2_eth_setup_irqs(dev, 0);
+
+ /* disable vfio intr before callback unregister */
+ rte_dpaa2_intr_disable(intr_handle, DPNI_IRQ_INDEX);
+
+ /* Unregistering LSC interrupt handler */
+ rte_intr_callback_unregister(intr_handle,
+ dpaa2_interrupt_handler,
+ (void *)dev);
+ }
+
dpaa2_dev_set_link_down(dev);
ret = dpni_disable(dpni, CMD_PRI_LOW, priv->token);
struct rte_eth_link link, old;
struct dpni_link_state state = {0};
- PMD_INIT_FUNC_TRACE();
-
if (dpni == NULL) {
RTE_LOG(ERR, PMD, "dpni is NULL\n");
return 0;
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);
+ PMD_DRV_LOG(INFO, "Port %d Link is Down", dev->data->port_id);
return 0;
}
struct dpaa2_dev_priv *priv;
struct fsl_mc_io *dpni;
int en = 0;
-
- PMD_INIT_FUNC_TRACE();
+ struct dpni_link_state state = {0};
priv = dev->data->dev_private;
dpni = (struct fsl_mc_io *)priv->hw;
return -EINVAL;
}
}
+ 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\n", ret);
+ return -1;
+ }
+
/* changing tx burst function to start enqueues */
dev->tx_pkt_burst = dpaa2_dev_tx;
- dev->data->dev_link.link_status = 1;
+ dev->data->dev_link.link_status = state.up;
- PMD_DRV_LOG(INFO, "Port %d Link UP successful", dev->data->port_id);
+ if (state.up)
+ PMD_DRV_LOG(INFO, "Port %d Link is set as UP",
+ dev->data->port_id);
+ else
+ PMD_DRV_LOG(INFO, "Port %d Link is DOWN", dev->data->port_id);
return ret;
}
return ret;
}
+static int
+dpaa2_dev_rss_hash_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct rte_eth_dev_data *data = dev->data;
+ struct rte_eth_conf *eth_conf = &data->dev_conf;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (rss_conf->rss_hf) {
+ ret = dpaa2_setup_flow_dist(dev, rss_conf->rss_hf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "unable to set flow dist");
+ return ret;
+ }
+ } else {
+ ret = dpaa2_remove_flow_dist(dev, 0);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "unable to remove flow dist");
+ return ret;
+ }
+ }
+ eth_conf->rx_adv_conf.rss_conf.rss_hf = rss_conf->rss_hf;
+ return 0;
+}
+
+static int
+dpaa2_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct rte_eth_dev_data *data = dev->data;
+ struct rte_eth_conf *eth_conf = &data->dev_conf;
+
+ /* dpaa2 does not support rss_key, so length should be 0*/
+ rss_conf->rss_key_len = 0;
+ rss_conf->rss_hf = eth_conf->rx_adv_conf.rss_conf.rss_hf;
+ return 0;
+}
+
static struct eth_dev_ops dpaa2_ethdev_ops = {
.dev_configure = dpaa2_eth_dev_configure,
.dev_start = dpaa2_dev_start,
.mac_addr_add = dpaa2_dev_add_mac_addr,
.mac_addr_remove = dpaa2_dev_remove_mac_addr,
.mac_addr_set = dpaa2_dev_set_mac_addr,
+ .rss_hash_update = dpaa2_dev_rss_hash_update,
+ .rss_hash_conf_get = dpaa2_dev_rss_hash_conf_get,
};
static int
}
eth_dev->dev_ops = &dpaa2_ethdev_ops;
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
eth_dev->rx_pkt_burst = dpaa2_dev_prefetch_rx;
eth_dev->tx_pkt_burst = dpaa2_dev_tx;