qed_ptp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /* QLogic qed NIC Driver
  2. * Copyright (c) 2015-2017 QLogic Corporation
  3. *
  4. * This software is available to you under a choice of one of two
  5. * licenses. You may choose to be licensed under the terms of the GNU
  6. * General Public License (GPL) Version 2, available from the file
  7. * COPYING in the main directory of this source tree, or the
  8. * OpenIB.org BSD license below:
  9. *
  10. * Redistribution and use in source and binary forms, with or
  11. * without modification, are permitted provided that the following
  12. * conditions are met:
  13. *
  14. * - Redistributions of source code must retain the above
  15. * copyright notice, this list of conditions and the following
  16. * disclaimer.
  17. *
  18. * - Redistributions in binary form must reproduce the above
  19. * copyright notice, this list of conditions and the following
  20. * disclaimer in the documentation and /or other materials
  21. * provided with the distribution.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30. * SOFTWARE.
  31. */
  32. #include <linux/types.h>
  33. #include "qed.h"
  34. #include "qed_dev_api.h"
  35. #include "qed_hw.h"
  36. #include "qed_l2.h"
  37. #include "qed_mcp.h"
  38. #include "qed_reg_addr.h"
  39. /* 16 nano second time quantas to wait before making a Drift adjustment */
  40. #define QED_DRIFT_CNTR_TIME_QUANTA_SHIFT 0
  41. /* Nano seconds to add/subtract when making a Drift adjustment */
  42. #define QED_DRIFT_CNTR_ADJUSTMENT_SHIFT 28
  43. /* Add/subtract the Adjustment_Value when making a Drift adjustment */
  44. #define QED_DRIFT_CNTR_DIRECTION_SHIFT 31
  45. #define QED_TIMESTAMP_MASK BIT(16)
  46. static enum qed_resc_lock qed_ptcdev_to_resc(struct qed_hwfn *p_hwfn)
  47. {
  48. switch (qed_device_get_port_id(p_hwfn->cdev)) {
  49. case 0:
  50. return QED_RESC_LOCK_PTP_PORT0;
  51. case 1:
  52. return QED_RESC_LOCK_PTP_PORT1;
  53. case 2:
  54. return QED_RESC_LOCK_PTP_PORT2;
  55. case 3:
  56. return QED_RESC_LOCK_PTP_PORT3;
  57. default:
  58. return QED_RESC_LOCK_RESC_INVALID;
  59. }
  60. }
  61. static int qed_ptp_res_lock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
  62. {
  63. struct qed_resc_lock_params params;
  64. enum qed_resc_lock resource;
  65. int rc;
  66. resource = qed_ptcdev_to_resc(p_hwfn);
  67. if (resource == QED_RESC_LOCK_RESC_INVALID)
  68. return -EINVAL;
  69. qed_mcp_resc_lock_default_init(&params, NULL, resource, true);
  70. rc = qed_mcp_resc_lock(p_hwfn, p_ptt, &params);
  71. if (rc && rc != -EINVAL) {
  72. return rc;
  73. } else if (rc == -EINVAL) {
  74. /* MFW doesn't support resource locking, first PF on the port
  75. * has lock ownership.
  76. */
  77. if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engine)
  78. return 0;
  79. DP_INFO(p_hwfn, "PF doesn't have lock ownership\n");
  80. return -EBUSY;
  81. } else if (!rc && !params.b_granted) {
  82. DP_INFO(p_hwfn, "Failed to acquire ptp resource lock\n");
  83. return -EBUSY;
  84. }
  85. return rc;
  86. }
  87. static int qed_ptp_res_unlock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
  88. {
  89. struct qed_resc_unlock_params params;
  90. enum qed_resc_lock resource;
  91. int rc;
  92. resource = qed_ptcdev_to_resc(p_hwfn);
  93. if (resource == QED_RESC_LOCK_RESC_INVALID)
  94. return -EINVAL;
  95. qed_mcp_resc_lock_default_init(NULL, &params, resource, true);
  96. rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, &params);
  97. if (rc == -EINVAL) {
  98. /* MFW doesn't support locking, first PF has lock ownership */
  99. if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engine) {
  100. rc = 0;
  101. } else {
  102. DP_INFO(p_hwfn, "PF doesn't have lock ownership\n");
  103. return -EINVAL;
  104. }
  105. } else if (rc) {
  106. DP_INFO(p_hwfn, "Failed to release the ptp resource lock\n");
  107. }
  108. return rc;
  109. }
  110. /* Read Rx timestamp */
  111. static int qed_ptp_hw_read_rx_ts(struct qed_dev *cdev, u64 *timestamp)
  112. {
  113. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  114. struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
  115. u32 val;
  116. *timestamp = 0;
  117. val = qed_rd(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_SEQID);
  118. if (!(val & QED_TIMESTAMP_MASK)) {
  119. DP_INFO(p_hwfn, "Invalid Rx timestamp, buf_seqid = %d\n", val);
  120. return -EINVAL;
  121. }
  122. val = qed_rd(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_TS_LSB);
  123. *timestamp = qed_rd(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_TS_MSB);
  124. *timestamp <<= 32;
  125. *timestamp |= val;
  126. /* Reset timestamp register to allow new timestamp */
  127. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_SEQID,
  128. QED_TIMESTAMP_MASK);
  129. return 0;
  130. }
  131. /* Read Tx timestamp */
  132. static int qed_ptp_hw_read_tx_ts(struct qed_dev *cdev, u64 *timestamp)
  133. {
  134. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  135. struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
  136. u32 val;
  137. *timestamp = 0;
  138. val = qed_rd(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_BUF_SEQID);
  139. if (!(val & QED_TIMESTAMP_MASK)) {
  140. DP_INFO(p_hwfn, "Invalid Tx timestamp, buf_seqid = %d\n", val);
  141. return -EINVAL;
  142. }
  143. val = qed_rd(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_BUF_TS_LSB);
  144. *timestamp = qed_rd(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_BUF_TS_MSB);
  145. *timestamp <<= 32;
  146. *timestamp |= val;
  147. /* Reset timestamp register to allow new timestamp */
  148. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_BUF_SEQID, QED_TIMESTAMP_MASK);
  149. return 0;
  150. }
  151. /* Read Phy Hardware Clock */
  152. static int qed_ptp_hw_read_cc(struct qed_dev *cdev, u64 *phc_cycles)
  153. {
  154. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  155. struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
  156. u32 temp = 0;
  157. temp = qed_rd(p_hwfn, p_ptt, NIG_REG_TSGEN_SYNC_TIME_LSB);
  158. *phc_cycles = qed_rd(p_hwfn, p_ptt, NIG_REG_TSGEN_SYNC_TIME_MSB);
  159. *phc_cycles <<= 32;
  160. *phc_cycles |= temp;
  161. return 0;
  162. }
  163. /* Filter PTP protocol packets that need to be timestamped */
  164. static int qed_ptp_hw_cfg_filters(struct qed_dev *cdev,
  165. enum qed_ptp_filter_type rx_type,
  166. enum qed_ptp_hwtstamp_tx_type tx_type)
  167. {
  168. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  169. struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
  170. u32 rule_mask, enable_cfg = 0x0;
  171. switch (rx_type) {
  172. case QED_PTP_FILTER_NONE:
  173. enable_cfg = 0x0;
  174. rule_mask = 0x3FFF;
  175. break;
  176. case QED_PTP_FILTER_ALL:
  177. enable_cfg = 0x7;
  178. rule_mask = 0x3CAA;
  179. break;
  180. case QED_PTP_FILTER_V1_L4_EVENT:
  181. enable_cfg = 0x3;
  182. rule_mask = 0x3FFA;
  183. break;
  184. case QED_PTP_FILTER_V1_L4_GEN:
  185. enable_cfg = 0x3;
  186. rule_mask = 0x3FFE;
  187. break;
  188. case QED_PTP_FILTER_V2_L4_EVENT:
  189. enable_cfg = 0x5;
  190. rule_mask = 0x3FAA;
  191. break;
  192. case QED_PTP_FILTER_V2_L4_GEN:
  193. enable_cfg = 0x5;
  194. rule_mask = 0x3FEE;
  195. break;
  196. case QED_PTP_FILTER_V2_L2_EVENT:
  197. enable_cfg = 0x5;
  198. rule_mask = 0x3CFF;
  199. break;
  200. case QED_PTP_FILTER_V2_L2_GEN:
  201. enable_cfg = 0x5;
  202. rule_mask = 0x3EFF;
  203. break;
  204. case QED_PTP_FILTER_V2_EVENT:
  205. enable_cfg = 0x5;
  206. rule_mask = 0x3CAA;
  207. break;
  208. case QED_PTP_FILTER_V2_GEN:
  209. enable_cfg = 0x5;
  210. rule_mask = 0x3EEE;
  211. break;
  212. default:
  213. DP_INFO(p_hwfn, "Invalid PTP filter type %d\n", rx_type);
  214. return -EINVAL;
  215. }
  216. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK, 0);
  217. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_RULE_MASK, rule_mask);
  218. qed_wr(p_hwfn, p_ptt, NIG_REG_RX_PTP_EN, enable_cfg);
  219. if (tx_type == QED_PTP_HWTSTAMP_TX_OFF) {
  220. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_PTP_EN, 0x0);
  221. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_PARAM_MASK, 0x7FF);
  222. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_RULE_MASK, 0x3FFF);
  223. } else {
  224. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_PTP_EN, enable_cfg);
  225. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_PARAM_MASK, 0);
  226. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_RULE_MASK, rule_mask);
  227. }
  228. /* Reset possibly old timestamps */
  229. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_SEQID,
  230. QED_TIMESTAMP_MASK);
  231. return 0;
  232. }
  233. /* Adjust the HW clock by a rate given in parts-per-billion (ppb) units.
  234. * FW/HW accepts the adjustment value in terms of 3 parameters:
  235. * Drift period - adjustment happens once in certain number of nano seconds.
  236. * Drift value - time is adjusted by a certain value, for example by 5 ns.
  237. * Drift direction - add or subtract the adjustment value.
  238. * The routine translates ppb into the adjustment triplet in an optimal manner.
  239. */
  240. static int qed_ptp_hw_adjfreq(struct qed_dev *cdev, s32 ppb)
  241. {
  242. s64 best_val = 0, val, best_period = 0, period, approx_dev, dif, dif2;
  243. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  244. struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
  245. u32 drift_ctr_cfg = 0, drift_state;
  246. int drift_dir = 1;
  247. if (ppb < 0) {
  248. ppb = -ppb;
  249. drift_dir = 0;
  250. }
  251. if (ppb > 1) {
  252. s64 best_dif = ppb, best_approx_dev = 1;
  253. /* Adjustment value is up to +/-7ns, find an optimal value in
  254. * this range.
  255. */
  256. for (val = 7; val > 0; val--) {
  257. period = div_s64(val * 1000000000, ppb);
  258. period -= 8;
  259. period >>= 4;
  260. if (period < 1)
  261. period = 1;
  262. if (period > 0xFFFFFFE)
  263. period = 0xFFFFFFE;
  264. /* Check both rounding ends for approximate error */
  265. approx_dev = period * 16 + 8;
  266. dif = ppb * approx_dev - val * 1000000000;
  267. dif2 = dif + 16 * ppb;
  268. if (dif < 0)
  269. dif = -dif;
  270. if (dif2 < 0)
  271. dif2 = -dif2;
  272. /* Determine which end gives better approximation */
  273. if (dif * (approx_dev + 16) > dif2 * approx_dev) {
  274. period++;
  275. approx_dev += 16;
  276. dif = dif2;
  277. }
  278. /* Track best approximation found so far */
  279. if (best_dif * approx_dev > dif * best_approx_dev) {
  280. best_dif = dif;
  281. best_val = val;
  282. best_period = period;
  283. best_approx_dev = approx_dev;
  284. }
  285. }
  286. } else if (ppb == 1) {
  287. /* This is a special case as its the only value which wouldn't
  288. * fit in a s64 variable. In order to prevent castings simple
  289. * handle it seperately.
  290. */
  291. best_val = 4;
  292. best_period = 0xee6b27f;
  293. } else {
  294. best_val = 0;
  295. best_period = 0xFFFFFFF;
  296. }
  297. drift_ctr_cfg = (best_period << QED_DRIFT_CNTR_TIME_QUANTA_SHIFT) |
  298. (((int)best_val) << QED_DRIFT_CNTR_ADJUSTMENT_SHIFT) |
  299. (((int)drift_dir) << QED_DRIFT_CNTR_DIRECTION_SHIFT);
  300. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_RST_DRIFT_CNTR, 0x1);
  301. drift_state = qed_rd(p_hwfn, p_ptt, NIG_REG_TSGEN_RST_DRIFT_CNTR);
  302. if (drift_state & 1) {
  303. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_DRIFT_CNTR_CONF,
  304. drift_ctr_cfg);
  305. } else {
  306. DP_INFO(p_hwfn, "Drift counter is not reset\n");
  307. return -EINVAL;
  308. }
  309. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_RST_DRIFT_CNTR, 0x0);
  310. return 0;
  311. }
  312. static int qed_ptp_hw_enable(struct qed_dev *cdev)
  313. {
  314. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  315. struct qed_ptt *p_ptt;
  316. int rc;
  317. p_ptt = qed_ptt_acquire(p_hwfn);
  318. if (!p_ptt) {
  319. DP_NOTICE(p_hwfn, "Failed to acquire PTT for PTP\n");
  320. return -EBUSY;
  321. }
  322. p_hwfn->p_ptp_ptt = p_ptt;
  323. rc = qed_ptp_res_lock(p_hwfn, p_ptt);
  324. if (rc) {
  325. DP_INFO(p_hwfn,
  326. "Couldn't acquire the resource lock, skip ptp enable for this PF\n");
  327. qed_ptt_release(p_hwfn, p_ptt);
  328. p_hwfn->p_ptp_ptt = NULL;
  329. return rc;
  330. }
  331. /* Reset PTP event detection rules - will be configured in the IOCTL */
  332. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK, 0x7FF);
  333. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_RULE_MASK, 0x3FFF);
  334. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_PARAM_MASK, 0x7FF);
  335. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_RULE_MASK, 0x3FFF);
  336. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_PTP_EN, 7);
  337. qed_wr(p_hwfn, p_ptt, NIG_REG_RX_PTP_EN, 7);
  338. qed_wr(p_hwfn, p_ptt, NIG_REG_TS_OUTPUT_ENABLE_PDA, 0x1);
  339. /* Pause free running counter */
  340. if (QED_IS_BB_B0(p_hwfn->cdev))
  341. qed_wr(p_hwfn, p_ptt, NIG_REG_TIMESYNC_GEN_REG_BB, 2);
  342. if (QED_IS_AH(p_hwfn->cdev))
  343. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_FREECNT_UPDATE_K2, 2);
  344. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_FREE_CNT_VALUE_LSB, 0);
  345. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_FREE_CNT_VALUE_MSB, 0);
  346. /* Resume free running counter */
  347. if (QED_IS_BB_B0(p_hwfn->cdev))
  348. qed_wr(p_hwfn, p_ptt, NIG_REG_TIMESYNC_GEN_REG_BB, 4);
  349. if (QED_IS_AH(p_hwfn->cdev)) {
  350. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_FREECNT_UPDATE_K2, 4);
  351. qed_wr(p_hwfn, p_ptt, NIG_REG_PTP_LATCH_OSTS_PKT_TIME, 1);
  352. }
  353. /* Disable drift register */
  354. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_DRIFT_CNTR_CONF, 0x0);
  355. qed_wr(p_hwfn, p_ptt, NIG_REG_TSGEN_RST_DRIFT_CNTR, 0x0);
  356. /* Reset possibly old timestamps */
  357. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_SEQID,
  358. QED_TIMESTAMP_MASK);
  359. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_BUF_SEQID, QED_TIMESTAMP_MASK);
  360. return 0;
  361. }
  362. static int qed_ptp_hw_disable(struct qed_dev *cdev)
  363. {
  364. struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
  365. struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
  366. qed_ptp_res_unlock(p_hwfn, p_ptt);
  367. /* Reset PTP event detection rules */
  368. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK, 0x7FF);
  369. qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_RULE_MASK, 0x3FFF);
  370. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_PARAM_MASK, 0x7FF);
  371. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_RULE_MASK, 0x3FFF);
  372. /* Disable the PTP feature */
  373. qed_wr(p_hwfn, p_ptt, NIG_REG_RX_PTP_EN, 0x0);
  374. qed_wr(p_hwfn, p_ptt, NIG_REG_TX_PTP_EN, 0x0);
  375. qed_ptt_release(p_hwfn, p_ptt);
  376. p_hwfn->p_ptp_ptt = NULL;
  377. return 0;
  378. }
  379. const struct qed_eth_ptp_ops qed_ptp_ops_pass = {
  380. .cfg_filters = qed_ptp_hw_cfg_filters,
  381. .read_rx_ts = qed_ptp_hw_read_rx_ts,
  382. .read_tx_ts = qed_ptp_hw_read_tx_ts,
  383. .read_cc = qed_ptp_hw_read_cc,
  384. .adjfreq = qed_ptp_hw_adjfreq,
  385. .disable = qed_ptp_hw_disable,
  386. .enable = qed_ptp_hw_enable,
  387. };