hellcreek_hwtstamp.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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 <[email protected]>
  9. * Kurt Kanzenbach <[email protected]>
  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 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 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 ifreq *ifr)
  93. {
  94. struct hellcreek *hellcreek = ds->priv;
  95. struct hellcreek_port_hwtstamp *ps;
  96. struct hwtstamp_config config;
  97. int err;
  98. ps = &hellcreek->ports[port].port_hwtstamp;
  99. if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
  100. return -EFAULT;
  101. err = hellcreek_set_hwtstamp_config(hellcreek, port, &config);
  102. if (err)
  103. return err;
  104. /* Save the chosen configuration to be returned later */
  105. memcpy(&ps->tstamp_config, &config, sizeof(config));
  106. return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
  107. -EFAULT : 0;
  108. }
  109. int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port,
  110. struct ifreq *ifr)
  111. {
  112. struct hellcreek *hellcreek = ds->priv;
  113. struct hellcreek_port_hwtstamp *ps;
  114. struct hwtstamp_config *config;
  115. ps = &hellcreek->ports[port].port_hwtstamp;
  116. config = &ps->tstamp_config;
  117. return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
  118. -EFAULT : 0;
  119. }
  120. /* Returns a pointer to the PTP header if the caller should time stamp, or NULL
  121. * if the caller should not.
  122. */
  123. static struct ptp_header *hellcreek_should_tstamp(struct hellcreek *hellcreek,
  124. int port, struct sk_buff *skb,
  125. unsigned int type)
  126. {
  127. struct hellcreek_port_hwtstamp *ps =
  128. &hellcreek->ports[port].port_hwtstamp;
  129. struct ptp_header *hdr;
  130. hdr = ptp_parse_header(skb, type);
  131. if (!hdr)
  132. return NULL;
  133. if (!test_bit(HELLCREEK_HWTSTAMP_ENABLED, &ps->state))
  134. return NULL;
  135. return hdr;
  136. }
  137. static u64 hellcreek_get_reserved_field(const struct ptp_header *hdr)
  138. {
  139. return be32_to_cpu(hdr->reserved2);
  140. }
  141. static void hellcreek_clear_reserved_field(struct ptp_header *hdr)
  142. {
  143. hdr->reserved2 = 0;
  144. }
  145. static int hellcreek_ptp_hwtstamp_available(struct hellcreek *hellcreek,
  146. unsigned int ts_reg)
  147. {
  148. u16 status;
  149. status = hellcreek_ptp_read(hellcreek, ts_reg);
  150. if (status & PR_TS_STATUS_TS_LOST)
  151. dev_err(hellcreek->dev,
  152. "Tx time stamp lost! This should never happen!\n");
  153. /* If hwtstamp is not available, this means the previous hwtstamp was
  154. * successfully read, and the one we need is not yet available
  155. */
  156. return (status & PR_TS_STATUS_TS_AVAIL) ? 1 : 0;
  157. }
  158. /* Get nanoseconds timestamp from timestamping unit */
  159. static u64 hellcreek_ptp_hwtstamp_read(struct hellcreek *hellcreek,
  160. unsigned int ts_reg)
  161. {
  162. u16 nsl, nsh;
  163. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  164. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  165. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  166. nsh = hellcreek_ptp_read(hellcreek, ts_reg);
  167. nsl = hellcreek_ptp_read(hellcreek, ts_reg);
  168. return (u64)nsl | ((u64)nsh << 16);
  169. }
  170. static int hellcreek_txtstamp_work(struct hellcreek *hellcreek,
  171. struct hellcreek_port_hwtstamp *ps, int port)
  172. {
  173. struct skb_shared_hwtstamps shhwtstamps;
  174. unsigned int status_reg, data_reg;
  175. struct sk_buff *tmp_skb;
  176. int ts_status;
  177. u64 ns = 0;
  178. if (!ps->tx_skb)
  179. return 0;
  180. switch (port) {
  181. case 2:
  182. status_reg = PR_TS_TX_P1_STATUS_C;
  183. data_reg = PR_TS_TX_P1_DATA_C;
  184. break;
  185. case 3:
  186. status_reg = PR_TS_TX_P2_STATUS_C;
  187. data_reg = PR_TS_TX_P2_DATA_C;
  188. break;
  189. default:
  190. dev_err(hellcreek->dev, "Wrong port for timestamping!\n");
  191. return 0;
  192. }
  193. ts_status = hellcreek_ptp_hwtstamp_available(hellcreek, status_reg);
  194. /* Not available yet? */
  195. if (ts_status == 0) {
  196. /* Check whether the operation of reading the tx timestamp has
  197. * exceeded its allowed period
  198. */
  199. if (time_is_before_jiffies(ps->tx_tstamp_start +
  200. TX_TSTAMP_TIMEOUT)) {
  201. dev_err(hellcreek->dev,
  202. "Timeout while waiting for Tx timestamp!\n");
  203. goto free_and_clear_skb;
  204. }
  205. /* The timestamp should be available quickly, while getting it
  206. * in high priority. Restart the work
  207. */
  208. return 1;
  209. }
  210. mutex_lock(&hellcreek->ptp_lock);
  211. ns = hellcreek_ptp_hwtstamp_read(hellcreek, data_reg);
  212. ns += hellcreek_ptp_gettime_seconds(hellcreek, ns);
  213. mutex_unlock(&hellcreek->ptp_lock);
  214. /* Now we have the timestamp in nanoseconds, store it in the correct
  215. * structure in order to send it to the user
  216. */
  217. memset(&shhwtstamps, 0, sizeof(shhwtstamps));
  218. shhwtstamps.hwtstamp = ns_to_ktime(ns);
  219. tmp_skb = ps->tx_skb;
  220. ps->tx_skb = NULL;
  221. /* skb_complete_tx_timestamp() frees up the client to make another
  222. * timestampable transmit. We have to be ready for it by clearing the
  223. * ps->tx_skb "flag" beforehand
  224. */
  225. clear_bit_unlock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
  226. /* Deliver a clone of the original outgoing tx_skb with tx hwtstamp */
  227. skb_complete_tx_timestamp(tmp_skb, &shhwtstamps);
  228. return 0;
  229. free_and_clear_skb:
  230. dev_kfree_skb_any(ps->tx_skb);
  231. ps->tx_skb = NULL;
  232. clear_bit_unlock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
  233. return 0;
  234. }
  235. static void hellcreek_get_rxts(struct hellcreek *hellcreek,
  236. struct hellcreek_port_hwtstamp *ps,
  237. struct sk_buff *skb, struct sk_buff_head *rxq,
  238. int port)
  239. {
  240. struct skb_shared_hwtstamps *shwt;
  241. struct sk_buff_head received;
  242. unsigned long flags;
  243. /* The latched timestamp belongs to one of the received frames. */
  244. __skb_queue_head_init(&received);
  245. /* Lock & disable interrupts */
  246. spin_lock_irqsave(&rxq->lock, flags);
  247. /* Add the reception queue "rxq" to the "received" queue an reintialize
  248. * "rxq". From now on, we deal with "received" not with "rxq"
  249. */
  250. skb_queue_splice_tail_init(rxq, &received);
  251. spin_unlock_irqrestore(&rxq->lock, flags);
  252. for (; skb; skb = __skb_dequeue(&received)) {
  253. struct ptp_header *hdr;
  254. unsigned int type;
  255. u64 ns;
  256. /* Get nanoseconds from ptp packet */
  257. type = SKB_PTP_TYPE(skb);
  258. hdr = ptp_parse_header(skb, type);
  259. ns = hellcreek_get_reserved_field(hdr);
  260. hellcreek_clear_reserved_field(hdr);
  261. /* Add seconds part */
  262. mutex_lock(&hellcreek->ptp_lock);
  263. ns += hellcreek_ptp_gettime_seconds(hellcreek, ns);
  264. mutex_unlock(&hellcreek->ptp_lock);
  265. /* Save time stamp */
  266. shwt = skb_hwtstamps(skb);
  267. memset(shwt, 0, sizeof(*shwt));
  268. shwt->hwtstamp = ns_to_ktime(ns);
  269. netif_rx(skb);
  270. }
  271. }
  272. static void hellcreek_rxtstamp_work(struct hellcreek *hellcreek,
  273. struct hellcreek_port_hwtstamp *ps,
  274. int port)
  275. {
  276. struct sk_buff *skb;
  277. skb = skb_dequeue(&ps->rx_queue);
  278. if (skb)
  279. hellcreek_get_rxts(hellcreek, ps, skb, &ps->rx_queue, port);
  280. }
  281. long hellcreek_hwtstamp_work(struct ptp_clock_info *ptp)
  282. {
  283. struct hellcreek *hellcreek = ptp_to_hellcreek(ptp);
  284. struct dsa_switch *ds = hellcreek->ds;
  285. int i, restart = 0;
  286. for (i = 0; i < ds->num_ports; i++) {
  287. struct hellcreek_port_hwtstamp *ps;
  288. if (!dsa_is_user_port(ds, i))
  289. continue;
  290. ps = &hellcreek->ports[i].port_hwtstamp;
  291. if (test_bit(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state))
  292. restart |= hellcreek_txtstamp_work(hellcreek, ps, i);
  293. hellcreek_rxtstamp_work(hellcreek, ps, i);
  294. }
  295. return restart ? 1 : -1;
  296. }
  297. void hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
  298. struct sk_buff *skb)
  299. {
  300. struct hellcreek *hellcreek = ds->priv;
  301. struct hellcreek_port_hwtstamp *ps;
  302. struct ptp_header *hdr;
  303. struct sk_buff *clone;
  304. unsigned int type;
  305. ps = &hellcreek->ports[port].port_hwtstamp;
  306. type = ptp_classify_raw(skb);
  307. if (type == PTP_CLASS_NONE)
  308. return;
  309. /* Make sure the message is a PTP message that needs to be timestamped
  310. * and the interaction with the HW timestamping is enabled. If not, stop
  311. * here
  312. */
  313. hdr = hellcreek_should_tstamp(hellcreek, port, skb, type);
  314. if (!hdr)
  315. return;
  316. clone = skb_clone_sk(skb);
  317. if (!clone)
  318. return;
  319. if (test_and_set_bit_lock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS,
  320. &ps->state)) {
  321. kfree_skb(clone);
  322. return;
  323. }
  324. ps->tx_skb = clone;
  325. /* store the number of ticks occurred since system start-up till this
  326. * moment
  327. */
  328. ps->tx_tstamp_start = jiffies;
  329. ptp_schedule_worker(hellcreek->ptp_clock, 0);
  330. }
  331. bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
  332. struct sk_buff *skb, unsigned int type)
  333. {
  334. struct hellcreek *hellcreek = ds->priv;
  335. struct hellcreek_port_hwtstamp *ps;
  336. struct ptp_header *hdr;
  337. ps = &hellcreek->ports[port].port_hwtstamp;
  338. /* This check only fails if the user did not initialize hardware
  339. * timestamping beforehand.
  340. */
  341. if (ps->tstamp_config.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT)
  342. return false;
  343. /* Make sure the message is a PTP message that needs to be timestamped
  344. * and the interaction with the HW timestamping is enabled. If not, stop
  345. * here
  346. */
  347. hdr = hellcreek_should_tstamp(hellcreek, port, skb, type);
  348. if (!hdr)
  349. return false;
  350. SKB_PTP_TYPE(skb) = type;
  351. skb_queue_tail(&ps->rx_queue, skb);
  352. ptp_schedule_worker(hellcreek->ptp_clock, 0);
  353. return true;
  354. }
  355. static void hellcreek_hwtstamp_port_setup(struct hellcreek *hellcreek, int port)
  356. {
  357. struct hellcreek_port_hwtstamp *ps =
  358. &hellcreek->ports[port].port_hwtstamp;
  359. skb_queue_head_init(&ps->rx_queue);
  360. }
  361. int hellcreek_hwtstamp_setup(struct hellcreek *hellcreek)
  362. {
  363. struct dsa_switch *ds = hellcreek->ds;
  364. int i;
  365. /* Initialize timestamping ports. */
  366. for (i = 0; i < ds->num_ports; ++i) {
  367. if (!dsa_is_user_port(ds, i))
  368. continue;
  369. hellcreek_hwtstamp_port_setup(hellcreek, i);
  370. }
  371. /* Select the synchronized clock as the source timekeeper for the
  372. * timestamps and enable inline timestamping.
  373. */
  374. hellcreek_ptp_write(hellcreek, PR_SETTINGS_C_TS_SRC_TK_MASK |
  375. PR_SETTINGS_C_RES3TS,
  376. PR_SETTINGS_C);
  377. return 0;
  378. }
  379. void hellcreek_hwtstamp_free(struct hellcreek *hellcreek)
  380. {
  381. /* Nothing todo */
  382. }