Skip to content

Commit

Permalink
octeontx2-pf: Add support for PTP clock
Browse files Browse the repository at this point in the history
This patch adds PTP clock and uses it in Octeontx2
network device. PTP clock uses mailbox calls to
access the hardware counter on the RVU side.

Co-developed-by: Subbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: Aleksey Makarov <amakarov@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Aleksey Makarov authored and David S. Miller committed Aug 25, 2020
1 parent 4086f2a commit c9c12d3
Show file tree
Hide file tree
Showing 9 changed files with 532 additions and 6 deletions.
3 changes: 2 additions & 1 deletion drivers/net/ethernet/marvell/octeontx2/nic/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
obj-$(CONFIG_OCTEONTX2_PF) += octeontx2_nicpf.o
obj-$(CONFIG_OCTEONTX2_VF) += octeontx2_nicvf.o

octeontx2_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o
octeontx2_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \
otx2_ptp.o
octeontx2_nicvf-y := otx2_vf.o

ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
7 changes: 7 additions & 0 deletions drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,13 @@ static int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
if (!sq->sg)
return -ENOMEM;

if (pfvf->ptp) {
err = qmem_alloc(pfvf->dev, &sq->timestamps, qset->sqe_cnt,
sizeof(*sq->timestamps));
if (err)
return err;
}

sq->head = 0;
sq->sqe_per_sqb = (pfvf->hw.sqb_size / sq->sqe_size) - 1;
sq->num_sqbs = (qset->sqe_cnt + sq->sqe_per_sqb) / sq->sqe_per_sqb;
Expand Down
19 changes: 19 additions & 0 deletions drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

#include <linux/pci.h>
#include <linux/iommu.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>

#include <mbox.h>
#include "otx2_reg.h"
Expand Down Expand Up @@ -209,13 +212,26 @@ struct refill_work {
struct otx2_nic *pf;
};

struct otx2_ptp {
struct ptp_clock_info ptp_info;
struct ptp_clock *ptp_clock;
struct otx2_nic *nic;

struct cyclecounter cycle_counter;
struct timecounter time_counter;
};

#define OTX2_HW_TIMESTAMP_LEN 8

struct otx2_nic {
void __iomem *reg_base;
struct net_device *netdev;
void *iommu_domain;
u16 max_frs;
u16 rbsize; /* Receive buffer size */

#define OTX2_FLAG_RX_TSTAMP_ENABLED BIT_ULL(0)
#define OTX2_FLAG_TX_TSTAMP_ENABLED BIT_ULL(1)
#define OTX2_FLAG_INTF_DOWN BIT_ULL(2)
#define OTX2_FLAG_RX_PAUSE_ENABLED BIT_ULL(9)
#define OTX2_FLAG_TX_PAUSE_ENABLED BIT_ULL(10)
Expand Down Expand Up @@ -251,6 +267,9 @@ struct otx2_nic {

/* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */
int nix_blkaddr;

struct otx2_ptp *ptp;
struct hwtstamp_config tstamp;
};

static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
Expand Down
28 changes: 28 additions & 0 deletions drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
#include <linux/stddef.h>
#include <linux/etherdevice.h>
#include <linux/log2.h>
#include <linux/net_tstamp.h>

#include "otx2_common.h"
#include "otx2_ptp.h"

#define DRV_NAME "octeontx2-nicpf"
#define DRV_VF_NAME "octeontx2-nicvf"
Expand Down Expand Up @@ -663,6 +665,31 @@ static u32 otx2_get_link(struct net_device *netdev)
return pfvf->linfo.link_up;
}

static int otx2_get_ts_info(struct net_device *netdev,
struct ethtool_ts_info *info)
{
struct otx2_nic *pfvf = netdev_priv(netdev);

if (!pfvf->ptp)
return ethtool_op_get_ts_info(netdev, info);

info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;

info->phc_index = otx2_ptp_clock_index(pfvf);

info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);

info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_ALL);

return 0;
}

static const struct ethtool_ops otx2_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES,
Expand All @@ -687,6 +714,7 @@ static const struct ethtool_ops otx2_ethtool_ops = {
.set_msglevel = otx2_set_msglevel,
.get_pauseparam = otx2_get_pauseparam,
.set_pauseparam = otx2_set_pauseparam,
.get_ts_info = otx2_get_ts_info,
};

void otx2_set_ethtool_ops(struct net_device *netdev)
Expand Down
168 changes: 166 additions & 2 deletions drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "otx2_common.h"
#include "otx2_txrx.h"
#include "otx2_struct.h"
#include "otx2_ptp.h"

#define DRV_NAME "octeontx2-nicpf"
#define DRV_STRING "Marvell OcteonTX2 NIC Physical Function Driver"
Expand All @@ -41,6 +42,9 @@ enum {
TYPE_PFVF,
};

static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable);
static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable);

static int otx2_change_mtu(struct net_device *netdev, int new_mtu)
{
bool if_up = netif_running(netdev);
Expand Down Expand Up @@ -1281,7 +1285,8 @@ static int otx2_init_hw_resources(struct otx2_nic *pf)
hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt;

/* Get the size of receive buffers to allocate */
pf->rbsize = RCV_FRAG_LEN(pf->netdev->mtu + OTX2_ETH_HLEN);
pf->rbsize = RCV_FRAG_LEN(OTX2_HW_TIMESTAMP_LEN + pf->netdev->mtu +
OTX2_ETH_HLEN);

mutex_lock(&mbox->lock);
/* NPA init */
Expand Down Expand Up @@ -1547,6 +1552,16 @@ int otx2_open(struct net_device *netdev)

otx2_set_cints_affinity(pf);

/* When reinitializing enable time stamping if it is enabled before */
if (pf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED) {
pf->flags &= ~OTX2_FLAG_TX_TSTAMP_ENABLED;
otx2_config_hw_tx_tstamp(pf, true);
}
if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED) {
pf->flags &= ~OTX2_FLAG_RX_TSTAMP_ENABLED;
otx2_config_hw_rx_tstamp(pf, true);
}

pf->flags &= ~OTX2_FLAG_INTF_DOWN;
/* 'intf_down' may be checked on any cpu */
smp_wmb();
Expand Down Expand Up @@ -1738,6 +1753,143 @@ static void otx2_reset_task(struct work_struct *work)
rtnl_unlock();
}

static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable)
{
struct msg_req *req;
int err;

if (pfvf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED && enable)
return 0;

mutex_lock(&pfvf->mbox.lock);
if (enable)
req = otx2_mbox_alloc_msg_cgx_ptp_rx_enable(&pfvf->mbox);
else
req = otx2_mbox_alloc_msg_cgx_ptp_rx_disable(&pfvf->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}

err = otx2_sync_mbox_msg(&pfvf->mbox);
if (err) {
mutex_unlock(&pfvf->mbox.lock);
return err;
}

mutex_unlock(&pfvf->mbox.lock);
if (enable)
pfvf->flags |= OTX2_FLAG_RX_TSTAMP_ENABLED;
else
pfvf->flags &= ~OTX2_FLAG_RX_TSTAMP_ENABLED;
return 0;
}

static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable)
{
struct msg_req *req;
int err;

if (pfvf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED && enable)
return 0;

mutex_lock(&pfvf->mbox.lock);
if (enable)
req = otx2_mbox_alloc_msg_nix_lf_ptp_tx_enable(&pfvf->mbox);
else
req = otx2_mbox_alloc_msg_nix_lf_ptp_tx_disable(&pfvf->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}

err = otx2_sync_mbox_msg(&pfvf->mbox);
if (err) {
mutex_unlock(&pfvf->mbox.lock);
return err;
}

mutex_unlock(&pfvf->mbox.lock);
if (enable)
pfvf->flags |= OTX2_FLAG_TX_TSTAMP_ENABLED;
else
pfvf->flags &= ~OTX2_FLAG_TX_TSTAMP_ENABLED;
return 0;
}

static int otx2_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
struct hwtstamp_config config;

if (!pfvf->ptp)
return -ENODEV;

if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;

/* reserved for future extensions */
if (config.flags)
return -EINVAL;

switch (config.tx_type) {
case HWTSTAMP_TX_OFF:
otx2_config_hw_tx_tstamp(pfvf, false);
break;
case HWTSTAMP_TX_ON:
otx2_config_hw_tx_tstamp(pfvf, true);
break;
default:
return -ERANGE;
}

switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE:
otx2_config_hw_rx_tstamp(pfvf, false);
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
otx2_config_hw_rx_tstamp(pfvf, true);
config.rx_filter = HWTSTAMP_FILTER_ALL;
break;
default:
return -ERANGE;
}

memcpy(&pfvf->tstamp, &config, sizeof(config));

return copy_to_user(ifr->ifr_data, &config,
sizeof(config)) ? -EFAULT : 0;
}

static int otx2_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
struct hwtstamp_config *cfg = &pfvf->tstamp;

switch (cmd) {
case SIOCSHWTSTAMP:
return otx2_config_hwtstamp(netdev, req);
case SIOCGHWTSTAMP:
return copy_to_user(req->ifr_data, cfg,
sizeof(*cfg)) ? -EFAULT : 0;
default:
return -EOPNOTSUPP;
}
}

static const struct net_device_ops otx2_netdev_ops = {
.ndo_open = otx2_open,
.ndo_stop = otx2_stop,
Expand All @@ -1748,6 +1900,7 @@ static const struct net_device_ops otx2_netdev_ops = {
.ndo_set_features = otx2_set_features,
.ndo_tx_timeout = otx2_tx_timeout,
.ndo_get_stats64 = otx2_get_stats64,
.ndo_do_ioctl = otx2_ioctl,
};

static int otx2_wq_init(struct otx2_nic *pf)
Expand Down Expand Up @@ -1920,6 +2073,9 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* Assign default mac address */
otx2_get_mac_from_af(netdev);

/* Don't check for error. Proceed without ptp */
otx2_ptp_init(pf);

/* NPA's pool is a stack to which SW frees buffer pointers via Aura.
* HW allocates buffer pointer from stack and uses it for DMA'ing
* ingress packet. In some scenarios HW can free back allocated buffer
Expand Down Expand Up @@ -1952,7 +2108,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
goto err_detach_rsrc;
goto err_ptp_destroy;
}

err = otx2_wq_init(pf);
Expand All @@ -1972,6 +2128,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)

err_unreg_netdev:
unregister_netdev(netdev);
err_ptp_destroy:
otx2_ptp_destroy(pf);
err_detach_rsrc:
otx2_detach_resources(&pf->mbox);
err_disable_mbox_intr:
Expand Down Expand Up @@ -2113,6 +2271,11 @@ static void otx2_remove(struct pci_dev *pdev)

pf = netdev_priv(netdev);

if (pf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED)
otx2_config_hw_tx_tstamp(pf, false);
if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED)
otx2_config_hw_rx_tstamp(pf, false);

cancel_work_sync(&pf->reset_task);
/* Disable link notifications */
otx2_cgx_config_linkevents(pf, false);
Expand All @@ -2122,6 +2285,7 @@ static void otx2_remove(struct pci_dev *pdev)
if (pf->otx2_wq)
destroy_workqueue(pf->otx2_wq);

otx2_ptp_destroy(pf);
otx2_detach_resources(&pf->mbox);
otx2_disable_mbox_intr(pf);
otx2_pfaf_mbox_destroy(pf);
Expand Down
Loading

0 comments on commit c9c12d3

Please sign in to comment.