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

Merge branch 'PTP-clock-source-for-SJA1105-tc-taprio-offload'

Vladimir Oltean says:

====================
PTP clock source for SJA1105 tc-taprio offload

This series makes the IEEE 802.1Qbv egress scheduler of the sja1105
switch use a time reference that is synchronized to the network. This
enables quite a few real Time Sensitive Networking use cases, since in
this mode the switch can offer its clients a TDMA sort of access to the
network, and guaranteed latency for frames that are properly scheduled
based on the common PTP time.

The driver needs to do a 2-part activity:
- Program the gate control list into the static config and upload it
over SPI to the switch (already supported)
- Write the activation time of the scheduler (base-time) into the
PTPSCHTM register, and set the PTPSTRTSCH bit.
- Monitor the activation of the scheduler at the planned time and its
health.

Ok, 3 parts.

The time-aware scheduler cannot be programmed to activate at a time in
the past, and there is some logic to avoid that.

PTPCLKCORP is one of those "black magic" registers that just need to be
written to the length of the cycle. There is a 40-line long comment in
the second patch which explains why.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+535 -56
+1
drivers/net/dsa/sja1105/Kconfig
··· 28 28 bool "Support for the Time-Aware Scheduler on NXP SJA1105" 29 29 depends on NET_DSA_SJA1105 && NET_SCH_TAPRIO 30 30 depends on NET_SCH_TAPRIO=y || NET_DSA_SJA1105=m 31 + depends on NET_DSA_SJA1105_PTP 31 32 help 32 33 This enables support for the TTEthernet-based egress scheduling 33 34 engine in the SJA1105 DSA driver, which is controlled using a
+9 -7
drivers/net/dsa/sja1105/sja1105.h
··· 20 20 */ 21 21 #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) 22 22 23 + typedef enum { 24 + SPI_READ = 0, 25 + SPI_WRITE = 1, 26 + } sja1105_spi_rw_mode_t; 27 + 23 28 #include "sja1105_tas.h" 24 29 #include "sja1105_ptp.h" 25 30 ··· 40 35 u64 ptp_control; 41 36 u64 ptpclkval; 42 37 u64 ptpclkrate; 38 + u64 ptpclkcorp; 39 + u64 ptpschtm; 43 40 u64 ptpegr_ts[SJA1105_NUM_PORTS]; 44 41 u64 pad_mii_tx[SJA1105_NUM_PORTS]; 45 42 u64 pad_mii_id[SJA1105_NUM_PORTS]; ··· 78 71 const struct sja1105_dynamic_table_ops *dyn_ops; 79 72 const struct sja1105_table_ops *static_ops; 80 73 const struct sja1105_regs *regs; 81 - int (*ptp_cmd)(const struct dsa_switch *ds, 82 - const struct sja1105_ptp_cmd *cmd); 83 74 int (*reset_cmd)(const void *ctx, const void *data); 84 75 int (*setup_rgmii_delay)(const void *ctx, int port); 85 76 /* Prototypes from include/net/dsa.h */ ··· 85 80 const unsigned char *addr, u16 vid); 86 81 int (*fdb_del_cmd)(struct dsa_switch *ds, int port, 87 82 const unsigned char *addr, u16 vid); 83 + void (*ptp_cmd_packing)(u8 *buf, struct sja1105_ptp_cmd *cmd, 84 + enum packing_op op); 88 85 const char *name; 89 86 }; 90 87 ··· 115 108 u64 read_count; 116 109 u64 address; 117 110 }; 118 - 119 - typedef enum { 120 - SPI_READ = 0, 121 - SPI_WRITE = 1, 122 - } sja1105_spi_rw_mode_t; 123 111 124 112 /* From sja1105_main.c */ 125 113 enum sja1105_reset_reason {
+52 -27
drivers/net/dsa/sja1105/sja1105_ptp.c
··· 193 193 return 0; 194 194 } 195 195 196 - int sja1105et_ptp_cmd(const struct dsa_switch *ds, 197 - const struct sja1105_ptp_cmd *cmd) 196 + void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, 197 + enum packing_op op) 198 198 { 199 - const struct sja1105_private *priv = ds->priv; 200 - const struct sja1105_regs *regs = priv->info->regs; 201 199 const int size = SJA1105_SIZE_PTP_CMD; 202 - u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; 203 200 /* No need to keep this as part of the structure */ 204 201 u64 valid = 1; 205 202 206 - sja1105_pack(buf, &valid, 31, 31, size); 207 - sja1105_pack(buf, &cmd->resptp, 2, 2, size); 208 - sja1105_pack(buf, &cmd->corrclk4ts, 1, 1, size); 209 - sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); 210 - 211 - return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, 212 - SJA1105_SIZE_PTP_CMD); 203 + sja1105_packing(buf, &valid, 31, 31, size, op); 204 + sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op); 205 + sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op); 206 + sja1105_packing(buf, &cmd->resptp, 2, 2, size, op); 207 + sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op); 208 + sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); 213 209 } 214 210 215 - int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, 216 - const struct sja1105_ptp_cmd *cmd) 211 + void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, 212 + enum packing_op op) 217 213 { 218 - const struct sja1105_private *priv = ds->priv; 219 - const struct sja1105_regs *regs = priv->info->regs; 220 214 const int size = SJA1105_SIZE_PTP_CMD; 221 - u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; 222 215 /* No need to keep this as part of the structure */ 223 216 u64 valid = 1; 224 217 225 - sja1105_pack(buf, &valid, 31, 31, size); 226 - sja1105_pack(buf, &cmd->resptp, 3, 3, size); 227 - sja1105_pack(buf, &cmd->corrclk4ts, 2, 2, size); 228 - sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); 218 + sja1105_packing(buf, &valid, 31, 31, size, op); 219 + sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op); 220 + sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op); 221 + sja1105_packing(buf, &cmd->resptp, 3, 3, size, op); 222 + sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op); 223 + sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); 224 + } 229 225 230 - return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, 231 - SJA1105_SIZE_PTP_CMD); 226 + int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd, 227 + sja1105_spi_rw_mode_t rw) 228 + { 229 + const struct sja1105_private *priv = ds->priv; 230 + const struct sja1105_regs *regs = priv->info->regs; 231 + u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; 232 + int rc; 233 + 234 + if (rw == SPI_WRITE) 235 + priv->info->ptp_cmd_packing(buf, cmd, PACK); 236 + 237 + rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, 238 + SJA1105_SIZE_PTP_CMD); 239 + 240 + if (rw == SPI_READ) 241 + priv->info->ptp_cmd_packing(buf, cmd, UNPACK); 242 + 243 + return rc; 232 244 } 233 245 234 246 /* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap ··· 450 438 mutex_lock(&ptp_data->lock); 451 439 452 440 cmd.resptp = 1; 441 + 453 442 dev_dbg(ds->dev, "Resetting PTP clock\n"); 454 - rc = priv->info->ptp_cmd(ds, &cmd); 443 + rc = sja1105_ptp_commit(ds, &cmd, SPI_WRITE); 444 + 445 + sja1105_tas_clockstep(priv->ds); 455 446 456 447 mutex_unlock(&ptp_data->lock); 457 448 ··· 510 495 511 496 ptp_data->cmd.ptpclkadd = mode; 512 497 513 - return priv->info->ptp_cmd(priv->ds, &ptp_data->cmd); 498 + return sja1105_ptp_commit(priv->ds, &ptp_data->cmd, SPI_WRITE); 514 499 } 515 500 516 501 /* Write to PTPCLKVAL while PTPCLKADD is 0 */ ··· 527 512 return rc; 528 513 } 529 514 530 - return sja1105_ptpclkval_write(priv, ticks, ptp_sts); 515 + rc = sja1105_ptpclkval_write(priv, ticks, ptp_sts); 516 + 517 + sja1105_tas_clockstep(priv->ds); 518 + 519 + return rc; 531 520 } 532 521 533 522 static int sja1105_ptp_settime(struct ptp_clock_info *ptp, ··· 573 554 rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32, 574 555 NULL); 575 556 557 + sja1105_tas_adjfreq(priv->ds); 558 + 576 559 mutex_unlock(&ptp_data->lock); 577 560 578 561 return rc; ··· 593 572 return rc; 594 573 } 595 574 596 - return sja1105_ptpclkval_write(priv, ticks, NULL); 575 + rc = sja1105_ptpclkval_write(priv, ticks, NULL); 576 + 577 + sja1105_tas_clockstep(priv->ds); 578 + 579 + return rc; 597 580 } 598 581 599 582 static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+18 -6
drivers/net/dsa/sja1105/sja1105_ptp.h
··· 22 22 } 23 23 24 24 struct sja1105_ptp_cmd { 25 + u64 ptpstrtsch; /* start schedule */ 26 + u64 ptpstopsch; /* stop schedule */ 25 27 u64 resptp; /* reset */ 26 28 u64 corrclk4ts; /* use the corrected clock for timestamps */ 27 29 u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ ··· 41 39 42 40 void sja1105_ptp_clock_unregister(struct dsa_switch *ds); 43 41 44 - int sja1105et_ptp_cmd(const struct dsa_switch *ds, 45 - const struct sja1105_ptp_cmd *cmd); 42 + void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, 43 + enum packing_op op); 46 44 47 - int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, 48 - const struct sja1105_ptp_cmd *cmd); 45 + void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, 46 + enum packing_op op); 49 47 50 48 int sja1105_get_ts_info(struct dsa_switch *ds, int port, 51 49 struct ethtool_ts_info *ts); ··· 70 68 struct ptp_system_timestamp *ptp_sts); 71 69 72 70 int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta); 71 + 72 + int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd, 73 + sja1105_spi_rw_mode_t rw); 73 74 74 75 #else 75 76 ··· 115 110 return 0; 116 111 } 117 112 118 - #define sja1105et_ptp_cmd NULL 113 + static inline int sja1105_ptp_commit(struct dsa_switch *ds, 114 + struct sja1105_ptp_cmd *cmd, 115 + sja1105_spi_rw_mode_t rw) 116 + { 117 + return 0; 118 + } 119 119 120 - #define sja1105pqrs_ptp_cmd NULL 120 + #define sja1105et_ptp_cmd_packing NULL 121 + 122 + #define sja1105pqrs_ptp_cmd_packing NULL 121 123 122 124 #define sja1105_get_ts_info NULL 123 125
+10 -6
drivers/net/dsa/sja1105/sja1105_spi.c
··· 539 539 .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031}, 540 540 .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, 541 541 .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, 542 + .ptpschtm = 0x12, /* Spans 0x12 to 0x13 */ 542 543 .ptp_control = 0x17, 543 544 .ptpclkval = 0x18, /* Spans 0x18 to 0x19 */ 544 545 .ptpclkrate = 0x1A, 546 + .ptpclkcorp = 0x1D, 545 547 }; 546 548 547 549 static struct sja1105_regs sja1105pqrs_regs = { ··· 571 569 .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, 572 570 .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, 573 571 .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, 572 + .ptpschtm = 0x13, /* Spans 0x13 to 0x14 */ 574 573 .ptp_control = 0x18, 575 574 .ptpclkval = 0x19, 576 575 .ptpclkrate = 0x1B, 576 + .ptpclkcorp = 0x1E, 577 577 }; 578 578 579 579 struct sja1105_info sja1105e_info = { ··· 588 584 .reset_cmd = sja1105et_reset_cmd, 589 585 .fdb_add_cmd = sja1105et_fdb_add, 590 586 .fdb_del_cmd = sja1105et_fdb_del, 591 - .ptp_cmd = sja1105et_ptp_cmd, 587 + .ptp_cmd_packing = sja1105et_ptp_cmd_packing, 592 588 .regs = &sja1105et_regs, 593 589 .name = "SJA1105E", 594 590 }; ··· 602 598 .reset_cmd = sja1105et_reset_cmd, 603 599 .fdb_add_cmd = sja1105et_fdb_add, 604 600 .fdb_del_cmd = sja1105et_fdb_del, 605 - .ptp_cmd = sja1105et_ptp_cmd, 601 + .ptp_cmd_packing = sja1105et_ptp_cmd_packing, 606 602 .regs = &sja1105et_regs, 607 603 .name = "SJA1105T", 608 604 }; ··· 617 613 .reset_cmd = sja1105pqrs_reset_cmd, 618 614 .fdb_add_cmd = sja1105pqrs_fdb_add, 619 615 .fdb_del_cmd = sja1105pqrs_fdb_del, 620 - .ptp_cmd = sja1105pqrs_ptp_cmd, 616 + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, 621 617 .regs = &sja1105pqrs_regs, 622 618 .name = "SJA1105P", 623 619 }; ··· 632 628 .reset_cmd = sja1105pqrs_reset_cmd, 633 629 .fdb_add_cmd = sja1105pqrs_fdb_add, 634 630 .fdb_del_cmd = sja1105pqrs_fdb_del, 635 - .ptp_cmd = sja1105pqrs_ptp_cmd, 631 + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, 636 632 .regs = &sja1105pqrs_regs, 637 633 .name = "SJA1105Q", 638 634 }; ··· 647 643 .reset_cmd = sja1105pqrs_reset_cmd, 648 644 .fdb_add_cmd = sja1105pqrs_fdb_add, 649 645 .fdb_del_cmd = sja1105pqrs_fdb_del, 650 - .ptp_cmd = sja1105pqrs_ptp_cmd, 646 + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, 651 647 .regs = &sja1105pqrs_regs, 652 648 .name = "SJA1105R", 653 649 }; ··· 663 659 .reset_cmd = sja1105pqrs_reset_cmd, 664 660 .fdb_add_cmd = sja1105pqrs_fdb_add, 665 661 .fdb_del_cmd = sja1105pqrs_fdb_del, 666 - .ptp_cmd = sja1105pqrs_ptp_cmd, 662 + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, 667 663 .name = "SJA1105S", 668 664 };
+418 -10
drivers/net/dsa/sja1105/sja1105_tas.c
··· 10 10 #define SJA1105_TAS_MAX_DELTA BIT(19) 11 11 #define SJA1105_GATE_MASK GENMASK_ULL(SJA1105_NUM_TC - 1, 0) 12 12 13 + #define work_to_sja1105_tas(d) \ 14 + container_of((d), struct sja1105_tas_data, tas_work) 15 + #define tas_to_sja1105(d) \ 16 + container_of((d), struct sja1105_private, tas_data) 17 + 13 18 /* This is not a preprocessor macro because the "ns" argument may or may not be 14 19 * s64 at caller side. This ensures it is properly type-cast before div_s64. 15 20 */ 16 21 static s64 ns_to_sja1105_delta(s64 ns) 17 22 { 18 23 return div_s64(ns, 200); 24 + } 25 + 26 + static s64 sja1105_delta_to_ns(s64 delta) 27 + { 28 + return delta * 200; 29 + } 30 + 31 + /* Calculate the first base_time in the future that satisfies this 32 + * relationship: 33 + * 34 + * future_base_time = base_time + N x cycle_time >= now, or 35 + * 36 + * now - base_time 37 + * N >= --------------- 38 + * cycle_time 39 + * 40 + * Because N is an integer, the ceiling value of the above "a / b" ratio 41 + * is in fact precisely the floor value of "(a + b - 1) / b", which is 42 + * easier to calculate only having integer division tools. 43 + */ 44 + static s64 future_base_time(s64 base_time, s64 cycle_time, s64 now) 45 + { 46 + s64 a, b, n; 47 + 48 + if (base_time >= now) 49 + return base_time; 50 + 51 + a = now - base_time; 52 + b = cycle_time; 53 + n = div_s64(a + b - 1, b); 54 + 55 + return base_time + n * cycle_time; 56 + } 57 + 58 + static int sja1105_tas_set_runtime_params(struct sja1105_private *priv) 59 + { 60 + struct sja1105_tas_data *tas_data = &priv->tas_data; 61 + struct dsa_switch *ds = priv->ds; 62 + s64 earliest_base_time = S64_MAX; 63 + s64 latest_base_time = 0; 64 + s64 its_cycle_time = 0; 65 + s64 max_cycle_time = 0; 66 + int port; 67 + 68 + tas_data->enabled = false; 69 + 70 + for (port = 0; port < SJA1105_NUM_PORTS; port++) { 71 + const struct tc_taprio_qopt_offload *offload; 72 + 73 + offload = tas_data->offload[port]; 74 + if (!offload) 75 + continue; 76 + 77 + tas_data->enabled = true; 78 + 79 + if (max_cycle_time < offload->cycle_time) 80 + max_cycle_time = offload->cycle_time; 81 + if (latest_base_time < offload->base_time) 82 + latest_base_time = offload->base_time; 83 + if (earliest_base_time > offload->base_time) { 84 + earliest_base_time = offload->base_time; 85 + its_cycle_time = offload->cycle_time; 86 + } 87 + } 88 + 89 + if (!tas_data->enabled) 90 + return 0; 91 + 92 + /* Roll the earliest base time over until it is in a comparable 93 + * time base with the latest, then compare their deltas. 94 + * We want to enforce that all ports' base times are within 95 + * SJA1105_TAS_MAX_DELTA 200ns cycles of one another. 96 + */ 97 + earliest_base_time = future_base_time(earliest_base_time, 98 + its_cycle_time, 99 + latest_base_time); 100 + while (earliest_base_time > latest_base_time) 101 + earliest_base_time -= its_cycle_time; 102 + if (latest_base_time - earliest_base_time > 103 + sja1105_delta_to_ns(SJA1105_TAS_MAX_DELTA)) { 104 + dev_err(ds->dev, 105 + "Base times too far apart: min %llu max %llu\n", 106 + earliest_base_time, latest_base_time); 107 + return -ERANGE; 108 + } 109 + 110 + tas_data->earliest_base_time = earliest_base_time; 111 + tas_data->max_cycle_time = max_cycle_time; 112 + 113 + dev_dbg(ds->dev, "earliest base time %lld ns\n", earliest_base_time); 114 + dev_dbg(ds->dev, "latest base time %lld ns\n", latest_base_time); 115 + dev_dbg(ds->dev, "longest cycle time %lld ns\n", max_cycle_time); 116 + 117 + return 0; 19 118 } 20 119 21 120 /* Lo and behold: the egress scheduler from hell. ··· 198 99 int num_cycles = 0; 199 100 int cycle = 0; 200 101 int i, k = 0; 201 - int port; 102 + int port, rc; 103 + 104 + rc = sja1105_tas_set_runtime_params(priv); 105 + if (rc < 0) 106 + return rc; 202 107 203 108 /* Discard previous Schedule Table */ 204 109 table = &priv->static_config.tables[BLK_IDX_SCHEDULE]; ··· 287 184 schedule_entry_points = table->entries; 288 185 289 186 /* Finally start populating the static config tables */ 290 - schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_STANDALONE; 187 + schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_PTP; 291 188 schedule_entry_points_params->actsubsch = num_cycles - 1; 292 189 293 190 for (port = 0; port < SJA1105_NUM_PORTS; port++) { 294 191 const struct tc_taprio_qopt_offload *offload; 192 + /* Relative base time */ 193 + s64 rbt; 295 194 296 195 offload = tas_data->offload[port]; 297 196 if (!offload) ··· 301 196 302 197 schedule_start_idx = k; 303 198 schedule_end_idx = k + offload->num_entries - 1; 304 - /* TODO this is the base time for the port's subschedule, 305 - * relative to PTPSCHTM. But as we're using the standalone 306 - * clock source and not PTP clock as time reference, there's 307 - * little point in even trying to put more logic into this, 308 - * like preserving the phases between the subschedules of 309 - * different ports. We'll get all of that when switching to the 310 - * PTP clock source. 199 + /* This is the base time expressed as a number of TAS ticks 200 + * relative to PTPSCHTM, which we'll (perhaps improperly) call 201 + * the operational base time. 311 202 */ 312 - entry_point_delta = 1; 203 + rbt = future_base_time(offload->base_time, 204 + offload->cycle_time, 205 + tas_data->earliest_base_time); 206 + rbt -= tas_data->earliest_base_time; 207 + /* UM10944.pdf 4.2.2. Schedule Entry Points table says that 208 + * delta cannot be zero, which is shitty. Advance all relative 209 + * base times by 1 TAS delta, so that even the earliest base 210 + * time becomes 1 in relative terms. Then start the operational 211 + * base time (PTPSCHTM) one TAS delta earlier than planned. 212 + */ 213 + entry_point_delta = ns_to_sja1105_delta(rbt) + 1; 313 214 314 215 schedule_entry_points[cycle].subschindx = cycle; 315 216 schedule_entry_points[cycle].delta = entry_point_delta; ··· 514 403 return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); 515 404 } 516 405 406 + static int sja1105_tas_check_running(struct sja1105_private *priv) 407 + { 408 + struct sja1105_tas_data *tas_data = &priv->tas_data; 409 + struct dsa_switch *ds = priv->ds; 410 + struct sja1105_ptp_cmd cmd = {0}; 411 + int rc; 412 + 413 + rc = sja1105_ptp_commit(ds, &cmd, SPI_READ); 414 + if (rc < 0) 415 + return rc; 416 + 417 + if (cmd.ptpstrtsch == 1) 418 + /* Schedule successfully started */ 419 + tas_data->state = SJA1105_TAS_STATE_RUNNING; 420 + else if (cmd.ptpstopsch == 1) 421 + /* Schedule is stopped */ 422 + tas_data->state = SJA1105_TAS_STATE_DISABLED; 423 + else 424 + /* Schedule is probably not configured with PTP clock source */ 425 + rc = -EINVAL; 426 + 427 + return rc; 428 + } 429 + 430 + /* Write to PTPCLKCORP */ 431 + static int sja1105_tas_adjust_drift(struct sja1105_private *priv, 432 + u64 correction) 433 + { 434 + const struct sja1105_regs *regs = priv->info->regs; 435 + u32 ptpclkcorp = ns_to_sja1105_ticks(correction); 436 + 437 + return sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkcorp, 438 + &ptpclkcorp, NULL); 439 + } 440 + 441 + /* Write to PTPSCHTM */ 442 + static int sja1105_tas_set_base_time(struct sja1105_private *priv, 443 + u64 base_time) 444 + { 445 + const struct sja1105_regs *regs = priv->info->regs; 446 + u64 ptpschtm = ns_to_sja1105_ticks(base_time); 447 + 448 + return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpschtm, 449 + &ptpschtm, NULL); 450 + } 451 + 452 + static int sja1105_tas_start(struct sja1105_private *priv) 453 + { 454 + struct sja1105_tas_data *tas_data = &priv->tas_data; 455 + struct sja1105_ptp_cmd *cmd = &priv->ptp_data.cmd; 456 + struct dsa_switch *ds = priv->ds; 457 + int rc; 458 + 459 + dev_dbg(ds->dev, "Starting the TAS\n"); 460 + 461 + if (tas_data->state == SJA1105_TAS_STATE_ENABLED_NOT_RUNNING || 462 + tas_data->state == SJA1105_TAS_STATE_RUNNING) { 463 + dev_err(ds->dev, "TAS already started\n"); 464 + return -EINVAL; 465 + } 466 + 467 + cmd->ptpstrtsch = 1; 468 + cmd->ptpstopsch = 0; 469 + 470 + rc = sja1105_ptp_commit(ds, cmd, SPI_WRITE); 471 + if (rc < 0) 472 + return rc; 473 + 474 + tas_data->state = SJA1105_TAS_STATE_ENABLED_NOT_RUNNING; 475 + 476 + return 0; 477 + } 478 + 479 + static int sja1105_tas_stop(struct sja1105_private *priv) 480 + { 481 + struct sja1105_tas_data *tas_data = &priv->tas_data; 482 + struct sja1105_ptp_cmd *cmd = &priv->ptp_data.cmd; 483 + struct dsa_switch *ds = priv->ds; 484 + int rc; 485 + 486 + dev_dbg(ds->dev, "Stopping the TAS\n"); 487 + 488 + if (tas_data->state == SJA1105_TAS_STATE_DISABLED) { 489 + dev_err(ds->dev, "TAS already disabled\n"); 490 + return -EINVAL; 491 + } 492 + 493 + cmd->ptpstopsch = 1; 494 + cmd->ptpstrtsch = 0; 495 + 496 + rc = sja1105_ptp_commit(ds, cmd, SPI_WRITE); 497 + if (rc < 0) 498 + return rc; 499 + 500 + tas_data->state = SJA1105_TAS_STATE_DISABLED; 501 + 502 + return 0; 503 + } 504 + 505 + /* The schedule engine and the PTP clock are driven by the same oscillator, and 506 + * they run in parallel. But whilst the PTP clock can keep an absolute 507 + * time-of-day, the schedule engine is only running in 'ticks' (25 ticks make 508 + * up a delta, which is 200ns), and wrapping around at the end of each cycle. 509 + * The schedule engine is started when the PTP clock reaches the PTPSCHTM time 510 + * (in PTP domain). 511 + * Because the PTP clock can be rate-corrected (accelerated or slowed down) by 512 + * a software servo, and the schedule engine clock runs in parallel to the PTP 513 + * clock, there is logic internal to the switch that periodically keeps the 514 + * schedule engine from drifting away. The frequency with which this internal 515 + * syntonization happens is the PTP clock correction period (PTPCLKCORP). It is 516 + * a value also in the PTP clock domain, and is also rate-corrected. 517 + * To be precise, during a correction period, there is logic to determine by 518 + * how many scheduler clock ticks has the PTP clock drifted. At the end of each 519 + * correction period/beginning of new one, the length of a delta is shrunk or 520 + * expanded with an integer number of ticks, compared with the typical 25. 521 + * So a delta lasts for 200ns (or 25 ticks) only on average. 522 + * Sometimes it is longer, sometimes it is shorter. The internal syntonization 523 + * logic can adjust for at most 5 ticks each 20 ticks. 524 + * 525 + * The first implication is that you should choose your schedule correction 526 + * period to be an integer multiple of the schedule length. Preferably one. 527 + * In case there are schedules of multiple ports active, then the correction 528 + * period needs to be a multiple of them all. Given the restriction that the 529 + * cycle times have to be multiples of one another anyway, this means the 530 + * correction period can simply be the largest cycle time, hence the current 531 + * choice. This way, the updates are always synchronous to the transmission 532 + * cycle, and therefore predictable. 533 + * 534 + * The second implication is that at the beginning of a correction period, the 535 + * first few deltas will be modulated in time, until the schedule engine is 536 + * properly phase-aligned with the PTP clock. For this reason, you should place 537 + * your best-effort traffic at the beginning of a cycle, and your 538 + * time-triggered traffic afterwards. 539 + * 540 + * The third implication is that once the schedule engine is started, it can 541 + * only adjust for so much drift within a correction period. In the servo you 542 + * can only change the PTPCLKRATE, but not step the clock (PTPCLKADD). If you 543 + * want to do the latter, you need to stop and restart the schedule engine, 544 + * which is what the state machine handles. 545 + */ 546 + static void sja1105_tas_state_machine(struct work_struct *work) 547 + { 548 + struct sja1105_tas_data *tas_data = work_to_sja1105_tas(work); 549 + struct sja1105_private *priv = tas_to_sja1105(tas_data); 550 + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; 551 + struct timespec64 base_time_ts, now_ts; 552 + struct dsa_switch *ds = priv->ds; 553 + struct timespec64 diff; 554 + s64 base_time, now; 555 + int rc = 0; 556 + 557 + mutex_lock(&ptp_data->lock); 558 + 559 + switch (tas_data->state) { 560 + case SJA1105_TAS_STATE_DISABLED: 561 + /* Can't do anything at all if clock is still being stepped */ 562 + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) 563 + break; 564 + 565 + rc = sja1105_tas_adjust_drift(priv, tas_data->max_cycle_time); 566 + if (rc < 0) 567 + break; 568 + 569 + rc = __sja1105_ptp_gettimex(ds, &now, NULL); 570 + if (rc < 0) 571 + break; 572 + 573 + /* Plan to start the earliest schedule first. The others 574 + * will be started in hardware, by way of their respective 575 + * entry points delta. 576 + * Try our best to avoid fringe cases (race condition between 577 + * ptpschtm and ptpstrtsch) by pushing the oper_base_time at 578 + * least one second in the future from now. This is not ideal, 579 + * but this only needs to buy us time until the 580 + * sja1105_tas_start command below gets executed. 581 + */ 582 + base_time = future_base_time(tas_data->earliest_base_time, 583 + tas_data->max_cycle_time, 584 + now + 1ull * NSEC_PER_SEC); 585 + base_time -= sja1105_delta_to_ns(1); 586 + 587 + rc = sja1105_tas_set_base_time(priv, base_time); 588 + if (rc < 0) 589 + break; 590 + 591 + tas_data->oper_base_time = base_time; 592 + 593 + rc = sja1105_tas_start(priv); 594 + if (rc < 0) 595 + break; 596 + 597 + base_time_ts = ns_to_timespec64(base_time); 598 + now_ts = ns_to_timespec64(now); 599 + 600 + dev_dbg(ds->dev, "OPER base time %lld.%09ld (now %lld.%09ld)\n", 601 + base_time_ts.tv_sec, base_time_ts.tv_nsec, 602 + now_ts.tv_sec, now_ts.tv_nsec); 603 + 604 + break; 605 + 606 + case SJA1105_TAS_STATE_ENABLED_NOT_RUNNING: 607 + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) { 608 + /* Clock was stepped.. bad news for TAS */ 609 + sja1105_tas_stop(priv); 610 + break; 611 + } 612 + 613 + /* Check if TAS has actually started, by comparing the 614 + * scheduled start time with the SJA1105 PTP clock 615 + */ 616 + rc = __sja1105_ptp_gettimex(ds, &now, NULL); 617 + if (rc < 0) 618 + break; 619 + 620 + if (now < tas_data->oper_base_time) { 621 + /* TAS has not started yet */ 622 + diff = ns_to_timespec64(tas_data->oper_base_time - now); 623 + dev_dbg(ds->dev, "time to start: [%lld.%09ld]", 624 + diff.tv_sec, diff.tv_nsec); 625 + break; 626 + } 627 + 628 + /* Time elapsed, what happened? */ 629 + rc = sja1105_tas_check_running(priv); 630 + if (rc < 0) 631 + break; 632 + 633 + if (tas_data->state != SJA1105_TAS_STATE_RUNNING) 634 + /* TAS has started */ 635 + dev_err(ds->dev, 636 + "TAS not started despite time elapsed\n"); 637 + 638 + break; 639 + 640 + case SJA1105_TAS_STATE_RUNNING: 641 + /* Clock was stepped.. bad news for TAS */ 642 + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) { 643 + sja1105_tas_stop(priv); 644 + break; 645 + } 646 + 647 + rc = sja1105_tas_check_running(priv); 648 + if (rc < 0) 649 + break; 650 + 651 + if (tas_data->state != SJA1105_TAS_STATE_RUNNING) 652 + dev_err(ds->dev, "TAS surprisingly stopped\n"); 653 + 654 + break; 655 + 656 + default: 657 + if (net_ratelimit()) 658 + dev_err(ds->dev, "TAS in an invalid state (incorrect use of API)!\n"); 659 + } 660 + 661 + if (rc && net_ratelimit()) 662 + dev_err(ds->dev, "An operation returned %d\n", rc); 663 + 664 + mutex_unlock(&ptp_data->lock); 665 + } 666 + 667 + void sja1105_tas_clockstep(struct dsa_switch *ds) 668 + { 669 + struct sja1105_private *priv = ds->priv; 670 + struct sja1105_tas_data *tas_data = &priv->tas_data; 671 + 672 + if (!tas_data->enabled) 673 + return; 674 + 675 + tas_data->last_op = SJA1105_PTP_CLOCKSTEP; 676 + schedule_work(&tas_data->tas_work); 677 + } 678 + 679 + void sja1105_tas_adjfreq(struct dsa_switch *ds) 680 + { 681 + struct sja1105_private *priv = ds->priv; 682 + struct sja1105_tas_data *tas_data = &priv->tas_data; 683 + 684 + if (!tas_data->enabled) 685 + return; 686 + 687 + /* No reason to schedule the workqueue, nothing changed */ 688 + if (tas_data->state == SJA1105_TAS_STATE_RUNNING) 689 + return; 690 + 691 + tas_data->last_op = SJA1105_PTP_ADJUSTFREQ; 692 + schedule_work(&tas_data->tas_work); 693 + } 694 + 517 695 void sja1105_tas_setup(struct dsa_switch *ds) 518 696 { 697 + struct sja1105_private *priv = ds->priv; 698 + struct sja1105_tas_data *tas_data = &priv->tas_data; 699 + 700 + INIT_WORK(&tas_data->tas_work, sja1105_tas_state_machine); 701 + tas_data->state = SJA1105_TAS_STATE_DISABLED; 702 + tas_data->last_op = SJA1105_PTP_NONE; 519 703 } 520 704 521 705 void sja1105_tas_teardown(struct dsa_switch *ds) ··· 818 412 struct sja1105_private *priv = ds->priv; 819 413 struct tc_taprio_qopt_offload *offload; 820 414 int port; 415 + 416 + cancel_work_sync(&priv->tas_data.tas_work); 821 417 822 418 for (port = 0; port < SJA1105_NUM_PORTS; port++) { 823 419 offload = priv->tas_data.offload[port];
+27
drivers/net/dsa/sja1105/sja1105_tas.h
··· 8 8 9 9 #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) 10 10 11 + enum sja1105_tas_state { 12 + SJA1105_TAS_STATE_DISABLED, 13 + SJA1105_TAS_STATE_ENABLED_NOT_RUNNING, 14 + SJA1105_TAS_STATE_RUNNING, 15 + }; 16 + 17 + enum sja1105_ptp_op { 18 + SJA1105_PTP_NONE, 19 + SJA1105_PTP_CLOCKSTEP, 20 + SJA1105_PTP_ADJUSTFREQ, 21 + }; 22 + 11 23 struct sja1105_tas_data { 12 24 struct tc_taprio_qopt_offload *offload[SJA1105_NUM_PORTS]; 25 + enum sja1105_tas_state state; 26 + enum sja1105_ptp_op last_op; 27 + struct work_struct tas_work; 28 + s64 earliest_base_time; 29 + s64 oper_base_time; 30 + u64 max_cycle_time; 31 + bool enabled; 13 32 }; 14 33 15 34 int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, ··· 37 18 void sja1105_tas_setup(struct dsa_switch *ds); 38 19 39 20 void sja1105_tas_teardown(struct dsa_switch *ds); 21 + 22 + void sja1105_tas_clockstep(struct dsa_switch *ds); 23 + 24 + void sja1105_tas_adjfreq(struct dsa_switch *ds); 40 25 41 26 #else 42 27 ··· 58 35 static inline void sja1105_tas_setup(struct dsa_switch *ds) { } 59 36 60 37 static inline void sja1105_tas_teardown(struct dsa_switch *ds) { } 38 + 39 + static inline void sja1105_tas_clockstep(struct dsa_switch *ds) { } 40 + 41 + static inline void sja1105_tas_adjfreq(struct dsa_switch *ds) { } 61 42 62 43 #endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) */ 63 44