Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'support-external-snapshots-on-dwmac1000'

Maxime Chevallier says:

====================
Support external snapshots on dwmac1000

The main change since v3 is the move of the fifo flush wait in the
ptp_clock_info enable() function within the mutex that protects the ptp
registers. Thanks Jakub and Paolo for spotting this.

This series also aggregates Daniel's reviews, except for the patch 4
which was modified since then.

This series is another take on the previous work [1] done by
Alexis Lothoré, that fixes the support for external snapshots
timestamping in GMAC3-based devices.

Details on why this is needed are mentionned on the cover [2] from V1.

[1]: https://lore.kernel.org/netdev/20230616100409.164583-1-alexis.lothore@bootlin.com/
[2]: https://lore.kernel.org/netdev/20241029115419.1160201-1-maxime.chevallier@bootlin.com/

Link to V1: https://lore.kernel.org/netdev/20241029115419.1160201-1-maxime.chevallier@bootlin.com/
Link to V2: https://lore.kernel.org/netdev/20241104170251.2202270-1-maxime.chevallier@bootlin.com/
Link to V3: https://lore.kernel.org/netdev/20241106090331.56519-1-maxime.chevallier@bootlin.com/
====================

Link: https://patch.msgid.link/20241112170658.2388529-1-maxime.chevallier@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+196 -11
+4
drivers/net/ethernet/stmicro/stmmac/common.h
··· 549 549 struct mac_device_info; 550 550 551 551 extern const struct stmmac_hwtimestamp stmmac_ptp; 552 + extern const struct stmmac_hwtimestamp dwmac1000_ptp; 552 553 extern const struct stmmac_mode_ops dwmac4_ring_mode_ops; 554 + 555 + extern const struct ptp_clock_info stmmac_ptp_clock_ops; 556 + extern const struct ptp_clock_info dwmac1000_ptp_clock_ops; 553 557 554 558 struct mac_link { 555 559 u32 caps;
+1
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
··· 485 485 plat_dat->pcs_init = socfpga_dwmac_pcs_init; 486 486 plat_dat->pcs_exit = socfpga_dwmac_pcs_exit; 487 487 plat_dat->select_pcs = socfpga_dwmac_select_pcs; 488 + plat_dat->has_gmac = true; 488 489 489 490 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 490 491 if (ret)
+12
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
··· 329 329 #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 330 330 #define GMAC_EXTHASH_BASE 0x500 331 331 332 + /* PTP and timestamping registers */ 333 + 334 + #define GMAC3_X_ATSNS GENMASK(19, 16) 335 + #define GMAC3_X_ATSNS_SHIFT 16 336 + 337 + #define GMAC_PTP_TCR_ATSFC BIT(24) 338 + #define GMAC_PTP_TCR_ATSEN0 BIT(25) 339 + 340 + #define GMAC3_X_TIMESTAMP_STATUS 0x28 341 + #define GMAC_PTP_ATNR 0x30 342 + #define GMAC_PTP_ATSR 0x34 343 + 332 344 extern const struct stmmac_dma_ops dwmac1000_dma_ops; 333 345 #endif /* __DWMAC1000_H__ */
+101
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
··· 18 18 #include <linux/io.h> 19 19 #include "stmmac.h" 20 20 #include "stmmac_pcs.h" 21 + #include "stmmac_ptp.h" 21 22 #include "dwmac1000.h" 22 23 23 24 static void dwmac1000_core_init(struct mac_device_info *hw, ··· 551 550 mac->mii.clk_csr_mask = GENMASK(5, 2); 552 551 553 552 return 0; 553 + } 554 + 555 + /* DWMAC 1000 HW Timestaming ops */ 556 + 557 + void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time) 558 + { 559 + u64 ns; 560 + 561 + ns = readl(ptpaddr + GMAC_PTP_ATNR); 562 + ns += readl(ptpaddr + GMAC_PTP_ATSR) * NSEC_PER_SEC; 563 + 564 + *ptp_time = ns; 565 + } 566 + 567 + void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv) 568 + { 569 + struct ptp_clock_event event; 570 + u32 ts_status, num_snapshot; 571 + unsigned long flags; 572 + u64 ptp_time; 573 + int i; 574 + 575 + /* Clears the timestamp interrupt */ 576 + ts_status = readl(priv->ptpaddr + GMAC3_X_TIMESTAMP_STATUS); 577 + 578 + if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN)) 579 + return; 580 + 581 + num_snapshot = (ts_status & GMAC3_X_ATSNS) >> GMAC3_X_ATSNS_SHIFT; 582 + 583 + for (i = 0; i < num_snapshot; i++) { 584 + read_lock_irqsave(&priv->ptp_lock, flags); 585 + stmmac_get_ptptime(priv, priv->ptpaddr, &ptp_time); 586 + read_unlock_irqrestore(&priv->ptp_lock, flags); 587 + 588 + event.type = PTP_CLOCK_EXTTS; 589 + event.index = 0; 590 + event.timestamp = ptp_time; 591 + ptp_clock_event(priv->ptp_clock, &event); 592 + } 593 + } 594 + 595 + /* DWMAC 1000 ptp_clock_info ops */ 596 + 597 + static void dwmac1000_timestamp_interrupt_cfg(struct stmmac_priv *priv, bool en) 598 + { 599 + void __iomem *ioaddr = priv->ioaddr; 600 + 601 + u32 intr_mask = readl(ioaddr + GMAC_INT_MASK); 602 + 603 + if (en) 604 + intr_mask &= ~GMAC_INT_DISABLE_TIMESTAMP; 605 + else 606 + intr_mask |= GMAC_INT_DISABLE_TIMESTAMP; 607 + 608 + writel(intr_mask, ioaddr + GMAC_INT_MASK); 609 + } 610 + 611 + int dwmac1000_ptp_enable(struct ptp_clock_info *ptp, 612 + struct ptp_clock_request *rq, int on) 613 + { 614 + struct stmmac_priv *priv = 615 + container_of(ptp, struct stmmac_priv, ptp_clock_ops); 616 + void __iomem *ptpaddr = priv->ptpaddr; 617 + int ret = -EOPNOTSUPP; 618 + u32 tcr_val; 619 + 620 + switch (rq->type) { 621 + case PTP_CLK_REQ_EXTTS: 622 + mutex_lock(&priv->aux_ts_lock); 623 + tcr_val = readl(ptpaddr + PTP_TCR); 624 + 625 + if (on) { 626 + tcr_val |= GMAC_PTP_TCR_ATSEN0; 627 + tcr_val |= GMAC_PTP_TCR_ATSFC; 628 + priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN; 629 + } else { 630 + tcr_val &= ~GMAC_PTP_TCR_ATSEN0; 631 + priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN; 632 + } 633 + 634 + netdev_dbg(priv->dev, "Auxiliary Snapshot %s.\n", 635 + on ? "enabled" : "disabled"); 636 + writel(tcr_val, ptpaddr + PTP_TCR); 637 + 638 + /* wait for auxts fifo clear to finish */ 639 + ret = readl_poll_timeout(ptpaddr + PTP_TCR, tcr_val, 640 + !(tcr_val & GMAC_PTP_TCR_ATSFC), 641 + 10, 10000); 642 + 643 + mutex_unlock(&priv->aux_ts_lock); 644 + 645 + dwmac1000_timestamp_interrupt_cfg(priv, on); 646 + break; 647 + 648 + default: 649 + break; 650 + } 651 + 652 + return ret; 554 653 }
+13 -2
drivers/net/ethernet/stmicro/stmmac/hwif.c
··· 113 113 const void *dma; 114 114 const void *mac; 115 115 const void *hwtimestamp; 116 + const void *ptp; 116 117 const void *mode; 117 118 const void *tc; 118 119 const void *mmc; ··· 134 133 .desc = NULL, 135 134 .dma = &dwmac100_dma_ops, 136 135 .mac = &dwmac100_ops, 137 - .hwtimestamp = &stmmac_ptp, 136 + .hwtimestamp = &dwmac1000_ptp, 137 + .ptp = &dwmac1000_ptp_clock_ops, 138 138 .mode = NULL, 139 139 .tc = NULL, 140 140 .mmc = &dwmac_mmc_ops, ··· 153 151 .desc = NULL, 154 152 .dma = &dwmac1000_dma_ops, 155 153 .mac = &dwmac1000_ops, 156 - .hwtimestamp = &stmmac_ptp, 154 + .hwtimestamp = &dwmac1000_ptp, 155 + .ptp = &dwmac1000_ptp_clock_ops, 157 156 .mode = NULL, 158 157 .tc = NULL, 159 158 .mmc = &dwmac_mmc_ops, ··· 174 171 .dma = &dwmac4_dma_ops, 175 172 .mac = &dwmac4_ops, 176 173 .hwtimestamp = &stmmac_ptp, 174 + .ptp = &stmmac_ptp_clock_ops, 177 175 .mode = NULL, 178 176 .tc = &dwmac4_tc_ops, 179 177 .mmc = &dwmac_mmc_ops, ··· 196 192 .dma = &dwmac4_dma_ops, 197 193 .mac = &dwmac410_ops, 198 194 .hwtimestamp = &stmmac_ptp, 195 + .ptp = &stmmac_ptp_clock_ops, 199 196 .mode = &dwmac4_ring_mode_ops, 200 197 .tc = &dwmac510_tc_ops, 201 198 .mmc = &dwmac_mmc_ops, ··· 218 213 .dma = &dwmac410_dma_ops, 219 214 .mac = &dwmac410_ops, 220 215 .hwtimestamp = &stmmac_ptp, 216 + .ptp = &stmmac_ptp_clock_ops, 221 217 .mode = &dwmac4_ring_mode_ops, 222 218 .tc = &dwmac510_tc_ops, 223 219 .mmc = &dwmac_mmc_ops, ··· 240 234 .dma = &dwmac410_dma_ops, 241 235 .mac = &dwmac510_ops, 242 236 .hwtimestamp = &stmmac_ptp, 237 + .ptp = &stmmac_ptp_clock_ops, 243 238 .mode = &dwmac4_ring_mode_ops, 244 239 .tc = &dwmac510_tc_ops, 245 240 .mmc = &dwmac_mmc_ops, ··· 263 256 .dma = &dwxgmac210_dma_ops, 264 257 .mac = &dwxgmac210_ops, 265 258 .hwtimestamp = &stmmac_ptp, 259 + .ptp = &stmmac_ptp_clock_ops, 266 260 .mode = NULL, 267 261 .tc = &dwxgmac_tc_ops, 268 262 .mmc = &dwxgmac_mmc_ops, ··· 286 278 .dma = &dwxgmac210_dma_ops, 287 279 .mac = &dwxlgmac2_ops, 288 280 .hwtimestamp = &stmmac_ptp, 281 + .ptp = &stmmac_ptp_clock_ops, 289 282 .mode = NULL, 290 283 .tc = &dwxgmac_tc_ops, 291 284 .mmc = &dwxgmac_mmc_ops, ··· 371 362 priv->fpe_cfg.reg = entry->regs.fpe_reg; 372 363 priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; 373 364 priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off; 365 + memcpy(&priv->ptp_clock_ops, entry->ptp, 366 + sizeof(struct ptp_clock_info)); 374 367 if (entry->est) 375 368 priv->estaddr = priv->ioaddr + entry->regs.est_off; 376 369
+25 -1
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
··· 18 18 #include "dwmac4.h" 19 19 #include "stmmac.h" 20 20 21 + #define STMMAC_HWTS_CFG_MASK (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \ 22 + PTP_TCR_TSINIT | PTP_TCR_TSUPDT | \ 23 + PTP_TCR_TSCTRLSSR | PTP_TCR_SNAPTYPSEL_1 | \ 24 + PTP_TCR_TSIPV4ENA | PTP_TCR_TSIPV6ENA | \ 25 + PTP_TCR_TSEVNTENA | PTP_TCR_TSMSTRENA | \ 26 + PTP_TCR_TSVER2ENA | PTP_TCR_TSIPENA | \ 27 + PTP_TCR_TSTRIG | PTP_TCR_TSENALL) 28 + 21 29 static void config_hw_tstamping(void __iomem *ioaddr, u32 data) 22 30 { 23 - writel(data, ioaddr + PTP_TCR); 31 + u32 regval = readl(ioaddr + PTP_TCR); 32 + 33 + regval &= ~STMMAC_HWTS_CFG_MASK; 34 + regval |= data; 35 + 36 + writel(regval, ioaddr + PTP_TCR); 24 37 } 25 38 26 39 static void config_sub_second_increment(void __iomem *ioaddr, ··· 281 268 .get_ptptime = get_ptptime, 282 269 .timestamp_interrupt = timestamp_interrupt, 283 270 .hwtstamp_correct_latency = hwtstamp_correct_latency, 271 + }; 272 + 273 + const struct stmmac_hwtimestamp dwmac1000_ptp = { 274 + .config_hw_tstamping = config_hw_tstamping, 275 + .init_systime = init_systime, 276 + .config_sub_second_increment = config_sub_second_increment, 277 + .config_addend = config_addend, 278 + .adjust_systime = adjust_systime, 279 + .get_systime = get_systime, 280 + .get_ptptime = dwmac1000_get_ptptime, 281 + .timestamp_interrupt = dwmac1000_timestamp_interrupt, 284 282 };
+30 -8
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
··· 9 9 *******************************************************************************/ 10 10 #include "stmmac.h" 11 11 #include "stmmac_ptp.h" 12 - #include "dwmac4.h" 13 12 14 13 /** 15 14 * stmmac_adjust_freq ··· 264 265 } 265 266 266 267 /* structure describing a PTP hardware clock */ 267 - static struct ptp_clock_info stmmac_ptp_clock_ops = { 268 + const struct ptp_clock_info stmmac_ptp_clock_ops = { 268 269 .owner = THIS_MODULE, 269 270 .name = "stmmac ptp", 270 271 .max_adj = 62500000, ··· 278 279 .gettime64 = stmmac_get_time, 279 280 .settime64 = stmmac_set_time, 280 281 .enable = stmmac_enable, 282 + .getcrosststamp = stmmac_getcrosststamp, 283 + }; 284 + 285 + /* structure describing a PTP hardware clock */ 286 + const struct ptp_clock_info dwmac1000_ptp_clock_ops = { 287 + .owner = THIS_MODULE, 288 + .name = "stmmac ptp", 289 + .max_adj = 62500000, 290 + .n_alarm = 0, 291 + .n_ext_ts = 1, 292 + .n_per_out = 0, 293 + .n_pins = 0, 294 + .pps = 0, 295 + .adjfine = stmmac_adjust_freq, 296 + .adjtime = stmmac_adjust_time, 297 + .gettime64 = stmmac_get_time, 298 + .settime64 = stmmac_set_time, 299 + .enable = dwmac1000_ptp_enable, 281 300 .getcrosststamp = stmmac_getcrosststamp, 282 301 }; 283 302 ··· 315 298 priv->pps[i].available = true; 316 299 } 317 300 318 - if (priv->plat->ptp_max_adj) 319 - stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; 320 - 321 301 /* Calculate the clock domain crossing (CDC) error if necessary */ 322 302 priv->plat->cdc_error_adj = 0; 323 303 if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) 324 304 priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate; 325 305 326 - stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num; 327 - stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n; 306 + /* Update the ptp clock parameters based on feature discovery, when 307 + * available 308 + */ 309 + if (priv->dma_cap.pps_out_num) 310 + priv->ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num; 311 + 312 + if (priv->dma_cap.aux_snapshot_n) 313 + priv->ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n; 314 + 315 + if (priv->plat->ptp_max_adj) 316 + priv->ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; 328 317 329 318 rwlock_init(&priv->ptp_lock); 330 319 mutex_init(&priv->aux_ts_lock); 331 - priv->ptp_clock_ops = stmmac_ptp_clock_ops; 332 320 333 321 priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops, 334 322 priv->device);
+10
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
··· 94 94 AUX_SNAPSHOT3 = 0x80, 95 95 }; 96 96 97 + struct ptp_clock_info; 98 + struct ptp_clock_request; 99 + struct stmmac_priv; 100 + 101 + int dwmac1000_ptp_enable(struct ptp_clock_info *ptp, 102 + struct ptp_clock_request *rq, int on); 103 + 104 + void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time); 105 + void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv); 106 + 97 107 #endif /* __STMMAC_PTP_H__ */