hellcreek_hwtstamp.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /*
  3. * DSA driver for:
  4. * Hirschmann Hellcreek TSN switch.
  5. *
  6. * Copyright (C) 2019,2020 Hochschule Offenburg
  7. * Copyright (C) 2019,2020 Linutronix GmbH
  8. * Authors: Kamil Alkhouri <kamil.alkhouri@hs-offenburg.de>
  9. * Kurt Kanzenbach <kurt@linutronix.de>
  10. */
  11. #include <linux/ptp_classify.h>
  12. #include "hellcreek.h"
  13. #include "hellcreek_hwtstamp.h"
  14. #include "hellcreek_ptp.h"
  15. int hellcreek_get_ts_info(struct dsa_switch *ds, int port,
  16. struct kernel_ethtool_ts_info *info)
  17. {
  18. struct hellcreek *hellcreek = ds->priv;
  19. info->phc_index = hellcreek->ptp_clock ?
  20. ptp_clock_index(hellcreek->ptp_clock) : -1;
  21. info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
  22. SOF_TIMESTAMPING_RX_HARDWARE |
  23. SOF_TIMESTAMPING_RAW_HARDWARE;
  24. /* enabled tx timestamping */
  25. info->tx_types = BIT(HWTSTAMP_TX_ON);
  26. /* L2 & L4 PTPv2 event rx messages are timestamped */
  27. info->rx_filters = BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
  28. return 0;
  29. }
  30. /* Enabling/disabling TX and RX HW timestamping for different PTP messages is
  31. * not available in the switch. Thus, this function only serves as a check if
  32. * the user requested what is actually available or not
  33. */
  34. static int hellcreek_set_hwtstamp_config(struct hellcreek *hellcreek, int port,
  35. struct kernel_hwtstamp_config *config)
  36. {
  37. struct hellcreek_port_hwtstamp *ps =
  38. &hellcreek->ports[port].port_hwtstamp;
  39. bool tx_tstamp_enable = false;
  40. bool rx_tstamp_enable = false;
  41. /* Interaction with the timestamp hardware is prevented here. It is
  42. * enabled when this config function ends successfully
  43. */
  44. clear_bit_unlock(HELLCREEK_HWTSTAMP_ENABLED, &ps->state);
  45. switch (config->tx_type) {
  46. case HWTSTAMP_TX_ON:
  47. tx_tstamp_enable = true;
  48. break;
  49. /* TX HW timestamping can't be disabled on the switch */
  50. case HWTSTAMP_TX_OFF:
  51. config->tx_type = HWTSTAMP_TX_ON;
  52. break;
  53. default:
  54. return -ERANGE;
  55. }
  56. switch (config->rx_filter) {
  57. /* RX HW timestamping can't be disabled on the switch */
  58. case HWTSTAMP_FILTER_NONE:
  59. config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
  60. break;
  61. case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
  62. case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
  63. case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
  64. case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
  65. case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
  66. case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
  67. case HWTSTAMP_FILTER_PTP_V2_EVENT:
  68. case HWTSTAMP_FILTER_PTP_V2_SYNC:
  69. case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
  70. config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
  71. rx_tstamp_enable = true;
  72. break;
  73. /* RX HW timestamping can't be enabled for all messages on the switch */
  74. case HWTSTAMP_FILTER_ALL:
  75. config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
  76. break;
  77. default:
  78. return -ERANGE;
  79. }
  80. if (!tx_tstamp_enable)
  81. return -ERANGE;
  82. if (!rx_tstamp_enable)
  83. return -ERANGE;
  84. /* If this point is reached, then the requested hwtstamp config is
  85. * compatible with the hwtstamp offered by the switch. Therefore,
  86. * enable the interaction with the HW timestamping
  87. */
  88. set_bit(HELLCREEK_HWTSTAMP_ENABLED, &ps->state);
  89. return 0;
  90. }
  91. int hellcreek_port_hwtstamp_set(struct dsa_switch *ds, int port,
  92. struct kernel_hwtstamp_config *config,
  93. struct netlink_ext_ack *extack)
  94. {
  95. struct hellcreek *hellcreek = ds->priv;
  96. struct hellcreek_port_hwtstamp *ps;
  97. int err;
  98. ps = &hellcreek->ports[port].port_hwtstamp;
  99. err = hellcreek_set_hwtstamp_config(hellcreek, port, config);
  100. if (err)
  101. return err;
  102. /* Save the chosen configuration to be returned later */
  103. ps->tstamp_config = *config;
  104. return 0;
  105. }
  106. int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port,
  107. struct kernel_hwtstamp_config *config)
  108. {
  109. struct hellcreek *hellcreek = ds->priv;
  110. struct hellcreek_port_hwtstamp *ps;
  111. ps = &hellcreek->ports[port].port_hwtstamp;
  112. *config = ps->tstamp_config;
  113. return 0;
  114. }
  115. /* Returns a pointer to the PTP header if the caller should time stamp, or NULL
  116. * if the caller should not.
  117. */
  118. static struct ptp_header *hellcreek_should_tstamp(struct hellcreek *hellcreek,
  119. int port, struct sk_buff *skb,
  120. unsigned int type)
  121. {
  122. struct hellcreek_port_hwtstamp *ps =
  123. &hellcreek->ports[port].port_hwtstamp;
  124. struct ptp_header *hdr;
  125. hdr = ptp_parse_header(skb, type);
  126. if (!hdr)
  127. return NULL;
  128. if (!test_bit(HELLCREEK_HWTSTAMP_ENABLED, &ps->state))
  129. return NULL;
  130. return hdr;
  131. }
  132. static u64 hellcreek_get_reserved_field(const struct ptp_header *hdr)
  133. {
  134. return be32_to_cpu(hdr->reserved2);
  135. }
  136. static void hellcreek_clear_reserved_field(struct ptp_header *hdr)
  137. {
  138. hdr->reserved2 = 0;
  139. }
  140. static int hellcreek_ptp_hwtstamp_available(struct hellcreek *hellcreek,
  141. unsigned int ts_reg)
  142. {
  143. u16 status;
  144. status = hellcreek_ptp_read(hellcreek, ts_reg);
  145. if (status & PR_TS_STATUS_TS_LOST)
  146. dev_err(hellcreek->dev,
  147. "Tx time stamp lost! This should never happen!\n");
  148. /* If hwtstamp is not available, this means the previous hwtstamp was
  149. * successfully read, and the one we need is not yet available
  150. */
  151. return (status & PR_TS_STATUS_TS_AVAIL) ? 1 : 0;
  152. }
  153. /* Get nanoseconds timestamp from timestamping unit */
  154. static u64 hellcreek_ptp_hwtstamp_read(struct hellcreek *hellcreek,
  155. unsigned int ts_reg)
  156. {
  157. u16 nsl, nsh;
  158. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  159. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  160. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  161. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  162. nsl = hellcreek_ptp_read(hellcreek, ts_reg);
  163. return (u64)nsl | ((u64)nsh << 16);
  164. }
  165. static int hellcreek_txtstamp_work(struct hellcreek *hellcreek,
  166. struct hellcreek_port_hwtstamp *ps, int port)
  167. {
  168. struct skb_shared_hwtstamps shhwtstamps;
  169. unsigned int status_reg, data_reg;
  170. struct sk_buff *tmp_skb;
  171. int ts_status;
  172. u64 ns = 0;
  173. if (!ps->tx_skb)
  174. return 0;
  175. switch (port) {
  176. case 2:
  177. status_reg = PR_TS_TX_P1_STATUS_C;
  178. data_reg = PR_TS_TX_P1_DATA_C;
  179. break;
  180. case 3:
  181. status_reg = PR_TS_TX_P2_STATUS_C;
  182. data_reg = PR_TS_TX_P2_DATA_C;
  183. break;
  184. default:
  185. dev_err(hellcreek->dev, "Wrong port for timestamping!\n");
  186. return 0;
  187. }
  188. ts_status = hellcreek_ptp_hwtstamp_available(hellcreek, status_reg);
  189. /* Not available yet? */
  190. if (ts_status == 0) {
  191. /* Check whether the operation of reading the tx timestamp has
  192. * exceeded its allowed period
  193. */
  194. if (time_is_before_jiffies(ps->tx_tstamp_start +
  195. TX_TSTAMP_TIMEOUT)) {
  196. dev_err(hellcreek->dev,
  197. "Timeout while waiting for Tx timestamp!\n");
  198. goto free_and_clear_skb;
  199. }
  200. /* The timestamp should be available quickly, while getting it
  201. * in high priority. Restart the work
  202. */
  203. return 1;
  204. }
  205. mutex_lock(&hellcreek->ptp_lock);
  206. ns = hellcreek_ptp_hwtstamp_read(hellcreek, data_reg);
  207. ns += hellcreek_ptp_gettime_seconds(hellcreek, ns);
  208. mutex_unlock(&hellcreek->ptp_lock);
  209. /* Now we have the timestamp in nanoseconds, store it in the correct
  210. * structure in order to send it to the user
  211. */
  212. memset(&shhwtstamps, 0, sizeof(shhwtstamps));
  213. shhwtstamps.hwtstamp = ns_to_ktime(ns);
  214. tmp_skb = ps->tx_skb;
  215. ps->tx_skb = NULL;
  216. /* skb_complete_tx_timestamp() frees up the client to make another
  217. * timestampable transmit. We have to be ready for it by clearing the
  218. * ps->tx_skb "flag" beforehand
  219. */
  220. clear_bit_unlock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
  221. /* Deliver a clone of the original outgoing tx_skb with tx hwtstamp */
  222. skb_complete_tx_timestamp(tmp_skb, &shhwtstamps);
  223. return 0;
  224. free_and_clear_skb:
  225. dev_kfree_skb_any(ps->tx_skb);
  226. ps->tx_skb = NULL;
  227. clear_bit_unlock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
  228. return 0;
  229. }
  230. static void hellcreek_get_rxts(struct hellcreek *hellcreek,
  231. struct hellcreek_port_hwtstamp *ps,
  232. struct sk_buff *skb, struct sk_buff_head *rxq,
  233. int port)
  234. {
  235. struct skb_shared_hwtstamps *shwt;
  236. struct sk_buff_head received;
  237. unsigned long flags;
  238. /* Construct Rx timestamps for all received PTP packets. */
  239. __skb_queue_head_init(&received);
  240. spin_lock_irqsave(&rxq->lock, flags);
  241. skb_queue_splice_tail_init(rxq, &received);
  242. spin_unlock_irqrestore(&rxq->lock, flags);
  243. for (; skb; skb = __skb_dequeue(&received)) {
  244. struct ptp_header *hdr;
  245. unsigned int type;
  246. u64 ns;
  247. /* Get nanoseconds from ptp packet */
  248. type = SKB_PTP_TYPE(skb);
  249. hdr = ptp_parse_header(skb, type);
  250. ns = hellcreek_get_reserved_field(hdr);
  251. hellcreek_clear_reserved_field(hdr);
  252. /* Add seconds part */
  253. mutex_lock(&hellcreek->ptp_lock);
  254. ns += hellcreek_ptp_gettime_seconds(hellcreek, ns);
  255. mutex_unlock(&hellcreek->ptp_lock);
  256. /* Save time stamp */
  257. shwt = skb_hwtstamps(skb);
  258. memset(shwt, 0, sizeof(*shwt));
  259. shwt->hwtstamp = ns_to_ktime(ns);
  260. netif_rx(skb);
  261. }
  262. }
  263. static void hellcreek_rxtstamp_work(struct hellcreek *hellcreek,
  264. struct hellcreek_port_hwtstamp *ps,
  265. int port)
  266. {
  267. struct sk_buff *skb;
  268. skb = skb_dequeue(&ps->rx_queue);
  269. if (skb)
  270. hellcreek_get_rxts(hellcreek, ps, skb, &ps->rx_queue, port);
  271. }
  272. long hellcreek_hwtstamp_work(struct ptp_clock_info *ptp)
  273. {
  274. struct hellcreek *hellcreek = ptp_to_hellcreek(ptp);
  275. struct dsa_switch *ds = hellcreek->ds;
  276. int i, restart = 0;
  277. for (i = 0; i < ds->num_ports; i++) {
  278. struct hellcreek_port_hwtstamp *ps;
  279. if (!dsa_is_user_port(ds, i))
  280. continue;
  281. ps = &hellcreek->ports[i].port_hwtstamp;
  282. if (test_bit(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state))
  283. restart |= hellcreek_txtstamp_work(hellcreek, ps, i);
  284. hellcreek_rxtstamp_work(hellcreek, ps, i);
  285. }
  286. return restart ? 1 : -1;
  287. }
  288. void hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
  289. struct sk_buff *skb)
  290. {
  291. struct hellcreek *hellcreek = ds->priv;
  292. struct hellcreek_port_hwtstamp *ps;
  293. struct ptp_header *hdr;
  294. struct sk_buff *clone;
  295. unsigned int type;
  296. ps = &hellcreek->ports[port].port_hwtstamp;
  297. type = ptp_classify_raw(skb);
  298. if (type == PTP_CLASS_NONE)
  299. return;
  300. /* Make sure the message is a PTP message that needs to be timestamped
  301. * and the interaction with the HW timestamping is enabled. If not, stop
  302. * here
  303. */
  304. hdr = hellcreek_should_tstamp(hellcreek, port, skb, type);
  305. if (!hdr)
  306. return;
  307. clone = skb_clone_sk(skb);
  308. if (!clone)
  309. return;
  310. if (test_and_set_bit_lock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS,
  311. &ps->state)) {
  312. kfree_skb(clone);
  313. return;
  314. }
  315. ps->tx_skb = clone;
  316. /* store the number of ticks occurred since system start-up till this
  317. * moment
  318. */
  319. ps->tx_tstamp_start = jiffies;
  320. ptp_schedule_worker(hellcreek->ptp_clock, 0);
  321. }
  322. bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
  323. struct sk_buff *skb, unsigned int type)
  324. {
  325. struct hellcreek *hellcreek = ds->priv;
  326. struct hellcreek_port_hwtstamp *ps;
  327. struct ptp_header *hdr;
  328. ps = &hellcreek->ports[port].port_hwtstamp;
  329. /* This check only fails if the user did not initialize hardware
  330. * timestamping beforehand.
  331. */
  332. if (ps->tstamp_config.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT)
  333. return false;
  334. /* Make sure the message is a PTP message that needs to be timestamped
  335. * and the interaction with the HW timestamping is enabled. If not, stop
  336. * here
  337. */
  338. hdr = hellcreek_should_tstamp(hellcreek, port, skb, type);
  339. if (!hdr)
  340. return false;
  341. SKB_PTP_TYPE(skb) = type;
  342. skb_queue_tail(&ps->rx_queue, skb);
  343. ptp_schedule_worker(hellcreek->ptp_clock, 0);
  344. return true;
  345. }
  346. static void hellcreek_hwtstamp_port_setup(struct hellcreek *hellcreek, int port)
  347. {
  348. struct hellcreek_port_hwtstamp *ps =
  349. &hellcreek->ports[port].port_hwtstamp;
  350. skb_queue_head_init(&ps->rx_queue);
  351. }
  352. int hellcreek_hwtstamp_setup(struct hellcreek *hellcreek)
  353. {
  354. struct dsa_switch *ds = hellcreek->ds;
  355. int i;
  356. /* Initialize timestamping ports. */
  357. for (i = 0; i < ds->num_ports; ++i) {
  358. if (!dsa_is_user_port(ds, i))
  359. continue;
  360. hellcreek_hwtstamp_port_setup(hellcreek, i);
  361. }
  362. /* Select the synchronized clock as the source timekeeper for the
  363. * timestamps and enable inline timestamping.
  364. */
  365. hellcreek_ptp_write(hellcreek, PR_SETTINGS_C_TS_SRC_TK_MASK |
  366. PR_SETTINGS_C_RES3TS,
  367. PR_SETTINGS_C);
  368. return 0;
  369. }
  370. void hellcreek_hwtstamp_free(struct hellcreek *hellcreek)
  371. {
  372. /* Nothing todo */
  373. }