From ae038d93608d8a4106eb3cb261d76d8d3996e63e Mon Sep 17 00:00:00 2001 From: Mohan Thadikamalla Date: Wed, 23 Oct 2019 10:00:03 +0530 Subject: [PATCH] nvethernet: Enable slot function support Issue: Data packets sent via EQOS hardware are not following any packet gaping. The AVB use-cases have different timing requirements for class A data packets. For example, the time difference between two class A data packets are supposed to be 125 microseconds for audio data of frequency 48 kHz. Fix: Enable slot function support to schedule the data fetching from the system memory by the DMA. This feature is useful when the source AV data needs to be transmitted at specific intervals. Bug 200545374 Change-Id: I549014998380cd6c0d161c778bccdaa5ed017129 Signed-off-by: Mohan Thadikamalla Reviewed-on: https://git-master.nvidia.com/r/2223850 Reviewed-by: Bhadram Varka Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Srinivas Ramachandran Reviewed-by: Bitan Biswas Reviewed-by: mobile promotions Tested-by: mobile promotions --- .../ethernet/nvidia/nvethernet/ether_linux.c | 37 +++++++++++++- .../net/ethernet/nvidia/nvethernet/ioctl.c | 12 +++++ drivers/net/ethernet/nvidia/nvethernet/ptp.c | 48 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index 53c60071..87adfd14 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -3052,7 +3052,7 @@ static int ether_parse_dt(struct ether_priv_data *pdata) unsigned int tmp_value[OSI_EQOS_MAX_NUM_QUEUES]; struct device_node *np = dev->of_node; int ret = -EINVAL; - unsigned int i, mtlq; + unsigned int i, mtlq, chan; /* read ptp clock */ ret = of_property_read_u32(np, "nvidia,ptp_ref_clock_speed", @@ -3148,6 +3148,41 @@ static int ether_parse_dt(struct ether_priv_data *pdata) ETHER_QUEUE_PRIO_DEFAULT, ETHER_QUEUE_PRIO_MAX, osi_core->num_mtl_queues); + /* Read TX slot enable check array DT node */ + ret = of_property_read_u32_array(np, "nvidia,slot_num_check", + tmp_value, + osi_dma->num_dma_chans); + if (ret < 0) { + dev_info(dev, + "Failed to read slot_num_check, disabling slot\n"); + for (i = 0; i < osi_dma->num_dma_chans; i++) + osi_dma->slot_enabled[i] = OSI_DISABLE; + } else { + /* Set slot enable flags */ + for (i = 0; i < osi_dma->num_dma_chans; i++) { + chan = osi_dma->dma_chans[i]; + osi_dma->slot_enabled[chan] = tmp_value[i]; + } + + /* Read TX slot intervals DT node */ + ret = of_property_read_u32_array(np, "nvidia,slot_intvl_vals", + tmp_value, + osi_dma->num_dma_chans); + if (ret < 0) { + for (i = 0; i < osi_dma->num_dma_chans; i++) { + chan = osi_dma->dma_chans[i]; + osi_dma->slot_interval[chan] = + OSI_SLOT_INTVL_DEFAULT; + } + } else { + /* Copy slot intervals */ + for (i = 0; i < osi_dma->num_dma_chans; i++) { + chan = osi_dma->dma_chans[i]; + osi_dma->slot_interval[chan] = tmp_value[i]; + } + } + } + /* Read Rx Queue - User priority mapping for tagged packets */ ret = of_property_read_u32_array(np, "nvidia,rx-queue-prio", tmp_value, diff --git a/drivers/net/ethernet/nvidia/nvethernet/ioctl.c b/drivers/net/ethernet/nvidia/nvethernet/ioctl.c index 712533d4..963f528d 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ioctl.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ioctl.c @@ -35,6 +35,8 @@ static int ether_set_avb_algo(struct net_device *ndev, struct ether_priv_data *pdata = netdev_priv(ndev); struct osi_core_priv_data *osi_core = pdata->osi_core; struct osi_core_avb_algorithm l_avb_struct; + struct osi_dma_priv_data *osi_dma = pdata->osi_dma; + struct osi_tx_ring *tx_ring = NULL; int ret = -1; if (ifdata->ptr == NULL) { @@ -51,6 +53,16 @@ static int ether_set_avb_algo(struct net_device *ndev, return ret; } + /* Check AVB mode disable on slot function enable */ + tx_ring = osi_dma->tx_ring[l_avb_struct.qindex]; + if (tx_ring && tx_ring->slot_check == OSI_ENABLE && + l_avb_struct.oper_mode == OSI_MTL_QUEUE_ENABLE) { + dev_err(pdata->dev, + "Can't disable queue:%d AVB mode when slot is enabled", + l_avb_struct.qindex); + return -EINVAL; + } + return osi_set_avb(osi_core, &l_avb_struct); } diff --git a/drivers/net/ethernet/nvidia/nvethernet/ptp.c b/drivers/net/ethernet/nvidia/nvethernet/ptp.c index 4e9f1bab..8a570f99 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ptp.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ptp.c @@ -241,6 +241,52 @@ void ether_ptp_remove(struct ether_priv_data *pdata) } } +/** + * @brief Configure Slot function + * + * Algorithm: This function will set/reset slot funciton + * + * @param[in] pdata: Pointer to private data structure. + * @param[in] set: Flag to set or reset the Slot function. + * + * @note PTP clock driver need to be successfully registered during + * initialization and HW need to support PTP functionality. + * + * @retval none + */ +static void ether_config_slot_function(struct ether_priv_data *pdata, u32 set) +{ + struct osi_dma_priv_data *osi_dma = pdata->osi_dma; + struct osi_core_priv_data *osi_core = pdata->osi_core; + unsigned int ret, i, chan, qinx; + struct osi_core_avb_algorithm avb; + + /* Configure TXQ AVB mode */ + for (i = 0; i < osi_dma->num_dma_chans; i++) { + chan = osi_dma->dma_chans[i]; + if (osi_dma->slot_enabled[chan] == OSI_ENABLE) { + /* Set TXQ AVB info */ + memset(&avb, 0, sizeof(struct osi_core_avb_algorithm)); + qinx = osi_core->mtl_queues[i]; + avb.qindex = qinx; + avb.algo = OSI_MTL_TXQ_AVALG_SP; + avb.oper_mode = (set == OSI_ENABLE) ? + OSI_MTL_QUEUE_AVB : + OSI_MTL_QUEUE_ENABLE; + ret = osi_set_avb(osi_core, &avb); + if (ret != 0) { + dev_err(pdata->dev, + "Failed to set TXQ:%d AVB info\n", + qinx); + return; + } + } + } + + /* Call OSI slot function to configure */ + osi_config_slot_function(osi_dma, set); +} + int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata, struct ifreq *ifr) { @@ -380,6 +426,7 @@ int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata, if (!pdata->hwts_tx_en && !hwts_rx_en) { /* disable the PTP configuration */ osi_ptp_configuration(osi_core, OSI_DISABLE); + ether_config_slot_function(pdata, OSI_DISABLE); } else { /* Store SYS CLOCK */ osi_core->ptp_config.ptp_clock = OSI_ETHER_SYSCLOCK; @@ -396,6 +443,7 @@ int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata, /* Register broadcasting MAC timestamp to clients */ tegra_register_hwtime_source(ether_get_ptptime, pdata); #endif + ether_config_slot_function(pdata, OSI_ENABLE); } return (copy_to_user(ifr->ifr_data, &config,