From 59e2c4272520d5887b2a6bdf07b78c40a664e5fb Mon Sep 17 00:00:00 2001 From: Rakesh Goyal Date: Mon, 16 Dec 2019 15:59:48 +0530 Subject: [PATCH] nvethernet: Extend PTP support Adding support for one step sync Adding support for user input from sysfs node Bug 200562043 Change-Id: I686f035d54c8fb998db968178aca772258830ec7 Signed-off-by: rakesh goyal Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2314229 Reviewed-by: Bhadram Varka --- .../net/ethernet/nvidia/nvethernet/Makefile | 1 + .../ethernet/nvidia/nvethernet/ether_linux.c | 25 ++- .../net/ethernet/nvidia/nvethernet/ethtool.c | 4 +- drivers/net/ethernet/nvidia/nvethernet/ptp.c | 20 ++- .../net/ethernet/nvidia/nvethernet/sysfs.c | 150 +++++++++++++++++- 5 files changed, 188 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/nvidia/nvethernet/Makefile b/drivers/net/ethernet/nvidia/nvethernet/Makefile index 6272f0a5..82c9608c 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/Makefile +++ b/drivers/net/ethernet/nvidia/nvethernet/Makefile @@ -30,6 +30,7 @@ nvethernet-objs:= ether_linux.o \ $(OSI_CORE)/osi_core.o \ $(OSI_COMMON)/osi_common.o \ $(OSI_COMMON)/eqos_common.o \ + $(OSI_COMMON)/mgbe_common.o \ $(OSI_DMA)/osi_dma.o \ $(OSI_DMA)/osi_dma_txrx.o \ $(OSI_CORE)/eqos_core.o \ diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index 374671c3..e74acd8e 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -1701,6 +1701,8 @@ static int ether_open(struct net_device *dev) * structure variable as well */ pdata->vlan_hash_filtering = OSI_PERFECT_FILTER_MODE; pdata->l2_filtering_mode = OSI_PERFECT_FILTER_MODE; + /* Set default PTP mode as Two step */ + pdata->osi_dma->ptp_flag = OSI_PTP_SYNC_TWOSTEP; /* Initialize PTP */ ret = ether_ptp_init(pdata); @@ -1955,13 +1957,14 @@ static int ether_handle_tso(struct osi_tx_pkt_cx *tx_pkt_cx, * @retval "number of descriptors" on success * @retval "negative value" on failure. */ -static int ether_tx_swcx_alloc(struct device *dev, +static int ether_tx_swcx_alloc(struct ether_priv_data *pdata, struct osi_tx_ring *tx_ring, struct sk_buff *skb) { struct osi_tx_pkt_cx *tx_pkt_cx = &tx_ring->tx_pkt_cx; unsigned int cur_tx_idx = tx_ring->cur_tx_idx; struct osi_tx_swcx *tx_swcx = NULL; + struct device *dev = pdata->dev; unsigned int len = 0, offset = 0, size = 0; int cnt = 0, ret = 0, i, num_frags; #if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE) @@ -2003,7 +2006,12 @@ static int ether_tx_swcx_alloc(struct device *dev, } if (((tx_pkt_cx->flags & OSI_PKT_CX_VLAN) == OSI_PKT_CX_VLAN) || - ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO)) { + ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO) || + (((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) && + /* Check only MGBE as we need ctx fro both sync mode */ + ((pdata->osi_core->mac == OSI_MAC_HW_MGBE) || + ((pdata->osi_dma->ptp_flag & OSI_PTP_SYNC_ONESTEP) == + OSI_PTP_SYNC_ONESTEP)))) { tx_swcx = tx_ring->tx_swcx + cur_tx_idx; if (tx_swcx->len) { return 0; @@ -2042,7 +2050,7 @@ static int ether_tx_swcx_alloc(struct device *dev, ret = -ENOMEM; goto dma_map_failed; } - tx_swcx->is_paged_buf = 0; + tx_swcx->flags &= ~OSI_PKT_CX_PAGED_BUF; tx_swcx->len = size; len -= size; @@ -2075,7 +2083,7 @@ static int ether_tx_swcx_alloc(struct device *dev, goto dma_map_failed; } - tx_swcx->is_paged_buf = 0; + tx_swcx->flags &= ~OSI_PKT_CX_PAGED_BUF; tx_swcx->len = size; len -= size; offset += size; @@ -2118,7 +2126,7 @@ static int ether_tx_swcx_alloc(struct device *dev, ret = -ENOMEM; goto dma_map_failed; } - tx_swcx->is_paged_buf = 1; + tx_swcx->flags |= OSI_PKT_CX_PAGED_BUF; tx_swcx->len = size; len -= size; @@ -2142,7 +2150,8 @@ dma_map_failed: DECR_TX_DESC_INDEX(cur_tx_idx, 1U); tx_swcx = tx_ring->tx_swcx + cur_tx_idx; if (tx_swcx->buf_phy_addr) { - if (tx_swcx->is_paged_buf) { + if ((tx_swcx->flags & OSI_PKT_CX_PAGED_BUF) == + OSI_PKT_CX_PAGED_BUF) { dma_unmap_page(dev, tx_swcx->buf_phy_addr, tx_swcx->len, DMA_TO_DEVICE); } else { @@ -2153,7 +2162,7 @@ dma_map_failed: } tx_swcx->len = 0; - tx_swcx->is_paged_buf = 0; + tx_swcx->flags &= ~OSI_PKT_CX_PAGED_BUF; cnt--; } return ret; @@ -2229,7 +2238,7 @@ static int ether_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct osi_tx_ring *tx_ring = osi_dma->tx_ring[chan]; int count = 0; - count = ether_tx_swcx_alloc(pdata->dev, tx_ring, skb); + count = ether_tx_swcx_alloc(pdata, tx_ring, skb); if (count <= 0) { if (count == 0) { netif_stop_subqueue(ndev, qinx); diff --git a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c index dcb1fef0..705420ad 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c @@ -686,7 +686,9 @@ static int ether_get_ts_info(struct net_device *ndev, info->phc_index = ptp_clock_index(pdata->ptp_clock); } - info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + info->tx_types = ((1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON) | + (1 << HWTSTAMP_TX_ONESTEP_SYNC)); info->rx_filters |= ((1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | diff --git a/drivers/net/ethernet/nvidia/nvethernet/ptp.c b/drivers/net/ethernet/nvidia/nvethernet/ptp.c index fdbe7f3f..cb649254 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ptp.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ptp.c @@ -302,6 +302,7 @@ int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata, struct ifreq *ifr) { struct osi_core_priv_data *osi_core = pdata->osi_core; + struct osi_dma_priv_data *osi_dma = pdata->osi_dma; struct hwtstamp_config config; unsigned int hwts_rx_en = 1; #if KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE @@ -335,6 +336,7 @@ int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata, break; case HWTSTAMP_TX_ON: + case HWTSTAMP_TX_ONESTEP_SYNC: pdata->hwts_tx_en = OSI_ENABLE; break; @@ -400,11 +402,25 @@ int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata, /* PTP v2/802.AS1, any layer, any kind of event packet */ case HWTSTAMP_FILTER_PTP_V2_EVENT: - osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_SNAPTYPSEL_1 | - OSI_MAC_TCR_TSIPV4ENA | + osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSIPV4ENA | OSI_MAC_TCR_TSIPV6ENA | OSI_MAC_TCR_TSVER2ENA | OSI_MAC_TCR_TSIPENA; + + if ((osi_dma->ptp_flag & OSI_PTP_SYNC_ONESTEP) == + OSI_PTP_SYNC_ONESTEP) { + osi_core->ptp_config.ptp_filter |= + (OSI_MAC_TCR_TSEVENTENA | + OSI_MAC_TCR_CSC); + if ((osi_dma->ptp_flag & OSI_PTP_SYNC_MASTER) == + OSI_PTP_SYNC_MASTER) { + osi_core->ptp_config.ptp_filter |= + OSI_MAC_TCR_TSMASTERENA; + } + } else { + osi_core->ptp_config.ptp_filter |= + OSI_MAC_TCR_SNAPTYPSEL_1; + } break; /* PTP v2/802.AS1, any layer, Sync packet */ diff --git a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c index 8ceca1e0..9d3b562d 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/sysfs.c +++ b/drivers/net/ethernet/nvidia/nvethernet/sysfs.c @@ -37,7 +37,6 @@ static ssize_t ether_mac_loopback_show(struct device *dev, { struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); struct ether_priv_data *pdata = netdev_priv(ndev); - return scnprintf(buf, PAGE_SIZE, "%s\n", (pdata->mac_loopback_mode == 1U) ? "enabled" : "disabled"); @@ -122,11 +121,160 @@ static DEVICE_ATTR(mac_loopback, (S_IRUGO | S_IWUSR), ether_mac_loopback_show, ether_mac_loopback_store); +/** + * @brief Shows the current setting of PTP mode + * + * Algorithm: Display the current PTP mode setting. + * + * @param[in] dev: Device data. + * @param[in] attr: Device attribute + * @param[in] buf: Buffer to store the current PTP mode + * + * @note MAC and PHY need to be initialized. + */ +static ssize_t ether_ptp_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); + struct ether_priv_data *pdata = netdev_priv(ndev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + ((pdata->osi_dma->ptp_flag & OSI_PTP_SYNC_MASTER) == + OSI_PTP_SYNC_MASTER) ? "master" : + ((pdata->osi_dma->ptp_flag & OSI_PTP_SYNC_SLAVE) == + OSI_PTP_SYNC_SLAVE) ? "slave" : " "); +} + +/** + * @brief Set the user setting of PTP mode + * + * Algorithm: This is used to set the user mode settings of PTP mode + * @param[in] dev: Device data. + * @param[in] attr: Device attribute + * @param[in] buf: Buffer which contains the user settings of PTP mode + * @param[in] size: size of buffer + * + * @note MAC and PHY need to be initialized. + * + * @return size of buffer. + */ +static ssize_t ether_ptp_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); + struct ether_priv_data *pdata = netdev_priv(ndev); + + if (!netif_running(ndev)) { + dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n"); + return size; + } + + if (strncmp(buf, "master", 6) == 0U) { + pdata->osi_dma->ptp_flag &= ~(OSI_PTP_SYNC_MASTER | + OSI_PTP_SYNC_SLAVE); + pdata->osi_dma->ptp_flag |= OSI_PTP_SYNC_MASTER; + } else if (strncmp(buf, "slave", 5) == 0U) { + pdata->osi_dma->ptp_flag &= ~(OSI_PTP_SYNC_MASTER | + OSI_PTP_SYNC_SLAVE); + pdata->osi_dma->ptp_flag |= OSI_PTP_SYNC_SLAVE; + } else { + dev_err(pdata->dev, + "Invalid entry. Valid Entries are master or slave\n"); + } + + return size; +} + +/** + * @brief Sysfs attribute for PTP MODE + * + */ +static DEVICE_ATTR(ptp_mode, (S_IRUGO | S_IWUSR), + ether_ptp_mode_show, + ether_ptp_mode_store); + +/** + * @brief Shows the current setting of PTP sync method + * + * Algorithm: Display the current PTP sync method. + * + * @param[in] dev: Device data. + * @param[in] attr: Device attribute + * @param[in] buf: Buffer to store the current ptp sync method + * + * @note MAC and PHY need to be initialized. + */ +static ssize_t ether_ptp_sync_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); + struct ether_priv_data *pdata = netdev_priv(ndev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + ((pdata->osi_dma->ptp_flag & OSI_PTP_SYNC_TWOSTEP) == + OSI_PTP_SYNC_TWOSTEP) ? "twostep" : + ((pdata->osi_dma->ptp_flag & OSI_PTP_SYNC_ONESTEP) == + OSI_PTP_SYNC_ONESTEP) ? "onestep" : " "); +} + +/** + * @brief Set the user setting of PTP sync method + * + * Algorithm: This is used to set the user mode settings of PTP sync method + * @param[in] dev: Device data. + * @param[in] attr: Device attribute + * @param[in] buf: Buffer which contains the user settings of PTP sync method + * @param[in] size: size of buffer + * + * @note MAC and PHY need to be initialized. + * + * @return size of buffer. + */ +static ssize_t ether_ptp_sync_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev); + struct ether_priv_data *pdata = netdev_priv(ndev); + + if (!netif_running(ndev)) { + dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n"); + return size; + } + + if (strncmp(buf, "onestep", 7) == 0U) { + pdata->osi_dma->ptp_flag &= ~(OSI_PTP_SYNC_ONESTEP | + OSI_PTP_SYNC_TWOSTEP); + pdata->osi_dma->ptp_flag |= OSI_PTP_SYNC_ONESTEP; + + } else if (strncmp(buf, "twostep", 7) == 0U) { + pdata->osi_dma->ptp_flag &= ~(OSI_PTP_SYNC_ONESTEP | + OSI_PTP_SYNC_TWOSTEP); + pdata->osi_dma->ptp_flag |= OSI_PTP_SYNC_TWOSTEP; + } else { + dev_err(pdata->dev, + "Invalid entry. Valid Entries are onestep or twostep\n"); + } + + return size; +} + +/** + * @brief Sysfs attribute for PTP sync method + * + */ +static DEVICE_ATTR(ptp_sync, (S_IRUGO | S_IWUSR), + ether_ptp_sync_show, + ether_ptp_sync_store); + /** * @brief Attributes for nvethernet sysfs */ static struct attribute *ether_sysfs_attrs[] = { &dev_attr_mac_loopback.attr, + &dev_attr_ptp_mode.attr, + &dev_attr_ptp_sync.attr, NULL };