Adds complete support for hardware-based PTP (IEEE 1588) timestamping to the AMD XGBE driver. - Initialize and configure the MAC PTP registers based on link speed and reference clock. - Support both 50MHz and 125MHz PTP reference clocks. - Update the driver interface and version data to support PTP clock frequency selection. Signed-off-by: Raju Rangoju --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 10 ++ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 9 +- drivers/net/ethernet/amd/xgbe/xgbe-hwtstamp.c | 148 ++++++++++++++---- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 2 + drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 73 ++++----- drivers/net/ethernet/amd/xgbe/xgbe.h | 23 ++- 6 files changed, 179 insertions(+), 86 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index e54e3e36d3f9..009fbc9b11ce 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -223,6 +223,10 @@ #define MAC_TSSR 0x0d20 #define MAC_TXSNR 0x0d30 #define MAC_TXSSR 0x0d34 +#define MAC_TICNR 0x0d58 +#define MAC_TICSNR 0x0d5C +#define MAC_TECNR 0x0d60 +#define MAC_TECSNR 0x0d64 #define MAC_QTFCR_INC 4 #define MAC_MACA_INC 4 @@ -428,6 +432,8 @@ #define MAC_TSCR_SNAPTYPSEL_WIDTH 2 #define MAC_TSCR_TSADDREG_INDEX 5 #define MAC_TSCR_TSADDREG_WIDTH 1 +#define MAC_TSCR_TSUPDT_INDEX 3 +#define MAC_TSCR_TSUPDT_WIDTH 1 #define MAC_TSCR_TSCFUPDT_INDEX 1 #define MAC_TSCR_TSCFUPDT_WIDTH 1 #define MAC_TSCR_TSCTRLSSR_INDEX 9 @@ -456,6 +462,10 @@ #define MAC_TSSR_TXTSC_WIDTH 1 #define MAC_TXSNR_TXTSSTSMIS_INDEX 31 #define MAC_TXSNR_TXTSSTSMIS_WIDTH 1 +#define MAC_TICSNR_TSICSNS_INDEX 8 +#define MAC_TICSNR_TSICSNS_WIDTH 8 +#define MAC_TECSNR_TSECSNS_INDEX 8 +#define MAC_TECSNR_TSECSNS_WIDTH 8 #define MAC_VLANHTR_VLHT_INDEX 0 #define MAC_VLANHTR_VLHT_WIDTH 16 #define MAC_VLANIR_VLTI_INDEX 20 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 20d688a1962c..2e9b95a94f89 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1583,6 +1583,9 @@ static int xgbe_open(struct net_device *netdev) INIT_WORK(&pdata->stopdev_work, xgbe_stopdev); INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); + /* Initialize PTP timestamping and clock. */ + xgbe_init_ptp(pdata); + ret = xgbe_alloc_memory(pdata); if (ret) goto err_ptpclk; @@ -2353,12 +2356,8 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) if (XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, RX_TSTAMP)) { - u64 nsec; - - nsec = timecounter_cyc2time(&pdata->tstamp_tc, - packet->rx_tstamp); hwtstamps = skb_hwtstamps(skb); - hwtstamps->hwtstamp = ns_to_ktime(nsec); + hwtstamps->hwtstamp = ns_to_ktime(packet->rx_tstamp); } if (XGMAC_GET_BITS(packet->attributes, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-hwtstamp.c b/drivers/net/ethernet/amd/xgbe/xgbe-hwtstamp.c index 3ee641a7ebaf..bc52e5ec6420 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-hwtstamp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-hwtstamp.c @@ -10,6 +10,30 @@ #include "xgbe.h" #include "xgbe-common.h" +void xgbe_update_tstamp_time(struct xgbe_prv_data *pdata, + unsigned int sec, unsigned int nsec) +{ + int count; + + /* Set the time values and tell the device */ + XGMAC_IOWRITE(pdata, MAC_STSUR, sec); + XGMAC_IOWRITE(pdata, MAC_STNUR, nsec); + + /* issue command to update the system time value */ + XGMAC_IOWRITE(pdata, MAC_TSCR, + XGMAC_IOREAD(pdata, MAC_TSCR) | + (1 << MAC_TSCR_TSUPDT_INDEX)); + + /* Wait for the time adjust/update to complete */ + count = 10000; + while (--count && XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSUPDT)) + udelay(5); + + if (count < 0) + netdev_err(pdata->netdev, + "timed out updating system timestamp\n"); +} + void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata, unsigned int addend) { @@ -88,8 +112,8 @@ void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSA) && !XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSD)) { nsec = le32_to_cpu(rdesc->desc1); - nsec <<= 32; - nsec |= le32_to_cpu(rdesc->desc0); + nsec *= NSEC_PER_SEC; + nsec += le32_to_cpu(rdesc->desc0); if (nsec != 0xffffffffffffffffULL) { packet->rx_tstamp = nsec; XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, @@ -98,34 +122,13 @@ void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, } } -int xgbe_config_tstamp(struct xgbe_prv_data *pdata, unsigned int mac_tscr) +void xgbe_config_tstamp(struct xgbe_prv_data *pdata, unsigned int mac_tscr) { - /* Set one nano-second accuracy */ - XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1); - - /* Set fine timestamp update */ - XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1); - - /* Overwrite earlier timestamps */ - XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1); - - XGMAC_IOWRITE(pdata, MAC_TSCR, mac_tscr); - - /* Exit if timestamping is not enabled */ - if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA)) - return 0; - - /* Initialize time registers */ - XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC); - XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC); - xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend); - xgbe_set_tstamp_time(pdata, 0, 0); - - /* Initialize the timecounter */ - timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, - ktime_to_ns(ktime_get_real())); + unsigned int value = 0; - return 0; + value = XGMAC_IOREAD(pdata, MAC_TSCR); + value |= mac_tscr; + XGMAC_IOWRITE(pdata, MAC_TSCR, value); } void xgbe_tx_tstamp(struct work_struct *work) @@ -135,18 +138,14 @@ void xgbe_tx_tstamp(struct work_struct *work) tx_tstamp_work); struct skb_shared_hwtstamps hwtstamps; unsigned long flags; - u64 nsec; spin_lock_irqsave(&pdata->tstamp_lock, flags); if (!pdata->tx_tstamp_skb) goto unlock; if (pdata->tx_tstamp) { - nsec = timecounter_cyc2time(&pdata->tstamp_tc, - pdata->tx_tstamp); - memset(&hwtstamps, 0, sizeof(hwtstamps)); - hwtstamps.hwtstamp = ns_to_ktime(nsec); + hwtstamps.hwtstamp = ns_to_ktime(pdata->tx_tstamp); skb_tstamp_tx(pdata->tx_tstamp_skb, &hwtstamps); } @@ -317,3 +316,86 @@ void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, skb_tx_timestamp(skb); } + +int xgbe_init_ptp(struct xgbe_prv_data *pdata) +{ + unsigned int mac_tscr = 0; + struct timespec64 now; + u64 dividend; + + /* Register Settings to be done based on the link speed. */ + switch (pdata->phy.speed) { + case SPEED_1000: + XGMAC_IOWRITE(pdata, MAC_TICNR, MAC_TICNR_1G_INITVAL); + XGMAC_IOWRITE(pdata, MAC_TECNR, MAC_TECNR_1G_INITVAL); + break; + case SPEED_2500: + case SPEED_10000: + XGMAC_IOWRITE_BITS(pdata, MAC_TICSNR, TSICSNS, + MAC_TICSNR_10G_INITVAL); + XGMAC_IOWRITE(pdata, MAC_TECNR, MAC_TECNR_10G_INITVAL); + XGMAC_IOWRITE_BITS(pdata, MAC_TECSNR, TSECSNS, + MAC_TECSNR_10G_INITVAL); + break; + case SPEED_UNKNOWN: + default: + break; + } + + /* Enable IEEE1588 PTP clock. */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + + /* Overwrite earlier timestamps */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1); + + /* Set one nano-second accuracy */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1); + + /* Set fine timestamp update */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1); + + xgbe_config_tstamp(pdata, mac_tscr); + + /* Exit if timestamping is not enabled */ + if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA)) + return -EOPNOTSUPP; + + if (pdata->vdata->tstamp_ptp_clock_freq) { + /* Initialize time registers based on + * 125MHz PTP Clock Frequency + */ + XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, + XGBE_V2_TSTAMP_SSINC); + XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, + XGBE_V2_TSTAMP_SNSINC); + } else { + /* Initialize time registers based on + * 50MHz PTP Clock Frequency + */ + XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC); + XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC); + } + + /* Calculate the addend: + * addend = 2^32 / (PTP ref clock / (PTP clock based on SSINC)) + * = (2^32 * (PTP clock based on SSINC)) / PTP ref clock + */ + if (pdata->vdata->tstamp_ptp_clock_freq) + dividend = XGBE_V2_PTP_ACT_CLK_FREQ; + else + dividend = XGBE_PTP_ACT_CLK_FREQ; + + dividend = (u64)(dividend << 32); + pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); + + xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend); + + dma_wmb(); + /* initialize system time */ + ktime_get_real_ts64(&now); + + /* lower 32 bits of tv_sec are safe until y2106 */ + xgbe_set_tstamp_time(pdata, (u32)now.tv_sec, now.tv_nsec); + + return 0; +} diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 097ec5e4f261..e3e1dca9856a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -414,6 +414,7 @@ static struct xgbe_version_data xgbe_v2a = { .tx_max_fifo_size = 229376, .rx_max_fifo_size = 229376, .tx_tstamp_workaround = 1, + .tstamp_ptp_clock_freq = 1, .ecc_support = 1, .i2c_support = 1, .irq_reissue_support = 1, @@ -430,6 +431,7 @@ static struct xgbe_version_data xgbe_v2b = { .tx_max_fifo_size = 65536, .rx_max_fifo_size = 65536, .tx_tstamp_workaround = 1, + .tstamp_ptp_clock_freq = 1, .ecc_support = 1, .i2c_support = 1, .irq_reissue_support = 1, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index 3b8b4de8f91f..3658afc7801d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -13,18 +13,6 @@ #include "xgbe.h" #include "xgbe-common.h" -static u64 xgbe_cc_read(const struct cyclecounter *cc) -{ - struct xgbe_prv_data *pdata = container_of(cc, - struct xgbe_prv_data, - tstamp_cc); - u64 nsec; - - nsec = xgbe_get_tstamp_time(pdata); - - return nsec; -} - static int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm) { struct xgbe_prv_data *pdata = container_of(info, @@ -49,16 +37,39 @@ static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) struct xgbe_prv_data *pdata = container_of(info, struct xgbe_prv_data, ptp_clock_info); + unsigned int neg_adjust = 0; + unsigned int sec, nsec; + u32 quotient, reminder; unsigned long flags; + if (delta < 0) { + neg_adjust = 1; + delta = -delta; + } + + quotient = div_u64_rem(delta, 1000000000ULL, &reminder); + sec = quotient; + nsec = reminder; + + /* Negative adjustment for Hw timer register. */ + if (neg_adjust) { + sec = -sec; + if (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSCTRLSSR)) + nsec = (1000000000UL - nsec); + else + nsec = (0x80000000UL - nsec); + } + nsec = (neg_adjust << 31) | nsec; + spin_lock_irqsave(&pdata->tstamp_lock, flags); - timecounter_adjtime(&pdata->tstamp_tc, delta); + xgbe_update_tstamp_time(pdata, sec, nsec); spin_unlock_irqrestore(&pdata->tstamp_lock, flags); return 0; } -static int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts) +static int xgbe_gettimex(struct ptp_clock_info *info, struct timespec64 *ts, + struct ptp_system_timestamp *sts) { struct xgbe_prv_data *pdata = container_of(info, struct xgbe_prv_data, @@ -67,9 +78,9 @@ static int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts) u64 nsec; spin_lock_irqsave(&pdata->tstamp_lock, flags); - - nsec = timecounter_read(&pdata->tstamp_tc); - + ptp_read_system_prets(sts); + nsec = xgbe_get_tstamp_time(pdata); + ptp_read_system_postts(sts); spin_unlock_irqrestore(&pdata->tstamp_lock, flags); *ts = ns_to_timespec64(nsec); @@ -84,14 +95,9 @@ static int xgbe_settime(struct ptp_clock_info *info, struct xgbe_prv_data, ptp_clock_info); unsigned long flags; - u64 nsec; - - nsec = timespec64_to_ns(ts); spin_lock_irqsave(&pdata->tstamp_lock, flags); - - timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); - + xgbe_set_tstamp_time(pdata, ts->tv_sec, ts->tv_nsec); spin_unlock_irqrestore(&pdata->tstamp_lock, flags); return 0; @@ -107,8 +113,6 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) { struct ptp_clock_info *info = &pdata->ptp_clock_info; struct ptp_clock *clock; - struct cyclecounter *cc = &pdata->tstamp_cc; - u64 dividend; snprintf(info->name, sizeof(info->name), "%s", netdev_name(pdata->netdev)); @@ -116,7 +120,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) info->max_adj = pdata->ptpclk_rate; info->adjfine = xgbe_adjfine; info->adjtime = xgbe_adjtime; - info->gettime64 = xgbe_gettime; + info->gettimex64 = xgbe_gettimex; info->settime64 = xgbe_settime; info->enable = xgbe_enable; @@ -128,23 +132,6 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) pdata->ptp_clock = clock; - /* Calculate the addend: - * addend = 2^32 / (PTP ref clock / 50Mhz) - * = (2^32 * 50Mhz) / PTP ref clock - */ - dividend = 50000000; - dividend <<= 32; - pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); - - /* Setup the timecounter */ - cc->read = xgbe_cc_read; - cc->mask = CLOCKSOURCE_MASK(64); - cc->mult = 1; - cc->shift = 0; - - timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, - ktime_to_ns(ktime_get_real())); - /* Disable all timestamping to start */ XGMAC_IOWRITE(pdata, MAC_TSCR, 0); pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 2341c7d213a7..d7e03e292ec4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -119,6 +119,14 @@ #define XGBE_MSI_BASE_COUNT 4 #define XGBE_MSI_MIN_COUNT (XGBE_MSI_BASE_COUNT + 1) +/* Initial PTP register values based on Link Speed. */ +#define MAC_TICNR_1G_INITVAL 0x10 +#define MAC_TECNR_1G_INITVAL 0x28 + +#define MAC_TICSNR_10G_INITVAL 0x33 +#define MAC_TECNR_10G_INITVAL 0x14 +#define MAC_TECSNR_10G_INITVAL 0xCC + /* PCI clock frequencies */ #define XGBE_V2_DMA_CLOCK_FREQ 500000000 /* 500 MHz */ #define XGBE_V2_PTP_CLOCK_FREQ 125000000 /* 125 MHz */ @@ -128,6 +136,11 @@ */ #define XGBE_TSTAMP_SSINC 20 #define XGBE_TSTAMP_SNSINC 0 +#define XGBE_PTP_ACT_CLK_FREQ 500000000 + +#define XGBE_V2_TSTAMP_SSINC 0xA +#define XGBE_V2_TSTAMP_SNSINC 0 +#define XGBE_V2_PTP_ACT_CLK_FREQ 1000000000 /* Driver PMT macros */ #define XGMAC_DRIVER_CONTEXT 1 @@ -938,6 +951,7 @@ struct xgbe_version_data { unsigned int tx_max_fifo_size; unsigned int rx_max_fifo_size; unsigned int tx_tstamp_workaround; + unsigned int tstamp_ptp_clock_freq; unsigned int ecc_support; unsigned int i2c_support; unsigned int irq_reissue_support; @@ -1123,8 +1137,6 @@ struct xgbe_prv_data { struct ptp_clock_info ptp_clock_info; struct ptp_clock *ptp_clock; struct hwtstamp_config tstamp_config; - struct cyclecounter tstamp_cc; - struct timecounter tstamp_tc; unsigned int tstamp_addend; struct work_struct tx_tstamp_work; struct sk_buff *tx_tstamp_skb; @@ -1270,7 +1282,7 @@ void xgbe_restart_dev(struct xgbe_prv_data *pdata); void xgbe_full_restart_dev(struct xgbe_prv_data *pdata); /* For Timestamp config */ -int xgbe_config_tstamp(struct xgbe_prv_data *pdata, unsigned int mac_tscr); +void xgbe_config_tstamp(struct xgbe_prv_data *pdata, unsigned int mac_tscr); u64 xgbe_get_tstamp_time(struct xgbe_prv_data *pdata); u64 xgbe_get_tx_tstamp(struct xgbe_prv_data *pdata); void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, @@ -1281,7 +1293,6 @@ void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata, unsigned int addend); void xgbe_set_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec, unsigned int nsec); -int xgbe_config_tstamp(struct xgbe_prv_data *pdata, unsigned int mac_tscr); void xgbe_tx_tstamp(struct work_struct *work); int xgbe_get_hwtstamp_settings(struct xgbe_prv_data *pdata, struct ifreq *ifreq); @@ -1290,7 +1301,9 @@ int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata, void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, struct sk_buff *skb, struct xgbe_packet_data *packet); - +int xgbe_init_ptp(struct xgbe_prv_data *pdata); +void xgbe_update_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec, + unsigned int nsec); #ifdef CONFIG_DEBUG_FS void xgbe_debugfs_init(struct xgbe_prv_data *); void xgbe_debugfs_exit(struct xgbe_prv_data *); -- 2.34.1