stmmac_est.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2023, Intel Corporation
  4. * stmmac EST(802.3 Qbv) handling
  5. */
  6. #include <linux/iopoll.h>
  7. #include <linux/types.h>
  8. #include "stmmac.h"
  9. #include "stmmac_est.h"
  10. static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
  11. {
  12. u32 ctrl;
  13. writel(val, est_addr + EST_GCL_DATA);
  14. ctrl = (reg << EST_ADDR_SHIFT);
  15. ctrl |= gcl ? 0 : EST_GCRR;
  16. writel(ctrl, est_addr + EST_GCL_CONTROL);
  17. ctrl |= EST_SRWO;
  18. writel(ctrl, est_addr + EST_GCL_CONTROL);
  19. return readl_poll_timeout(est_addr + EST_GCL_CONTROL, ctrl,
  20. !(ctrl & EST_SRWO), 100, 5000);
  21. }
  22. static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
  23. unsigned int ptp_rate)
  24. {
  25. void __iomem *est_addr = priv->estaddr;
  26. int i, ret = 0;
  27. u32 ctrl;
  28. if (!ptp_rate) {
  29. netdev_warn(priv->dev, "Invalid PTP rate");
  30. return -EINVAL;
  31. }
  32. ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false);
  33. ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false);
  34. ret |= est_write(est_addr, EST_TER, cfg->ter, false);
  35. ret |= est_write(est_addr, EST_LLR, cfg->gcl_size, false);
  36. ret |= est_write(est_addr, EST_CTR_LOW, cfg->ctr[0], false);
  37. ret |= est_write(est_addr, EST_CTR_HIGH, cfg->ctr[1], false);
  38. if (ret)
  39. return ret;
  40. for (i = 0; i < cfg->gcl_size; i++) {
  41. ret = est_write(est_addr, i, cfg->gcl[i], true);
  42. if (ret)
  43. return ret;
  44. }
  45. ctrl = readl(est_addr + EST_CONTROL);
  46. if (priv->plat->has_xgmac) {
  47. ctrl &= ~EST_XGMAC_PTOV;
  48. ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) <<
  49. EST_XGMAC_PTOV_SHIFT;
  50. } else {
  51. ctrl &= ~EST_GMAC5_PTOV;
  52. ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
  53. EST_GMAC5_PTOV_SHIFT;
  54. }
  55. if (cfg->enable)
  56. ctrl |= EST_EEST | EST_SSWL;
  57. else
  58. ctrl &= ~EST_EEST;
  59. writel(ctrl, est_addr + EST_CONTROL);
  60. /* Configure EST interrupt */
  61. if (cfg->enable)
  62. ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
  63. else
  64. ctrl = 0;
  65. writel(ctrl, est_addr + EST_INT_EN);
  66. return 0;
  67. }
  68. static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
  69. struct stmmac_extra_stats *x, u32 txqcnt)
  70. {
  71. u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max;
  72. void __iomem *est_addr = priv->estaddr;
  73. u32 txqcnt_mask = BIT(txqcnt) - 1;
  74. int i;
  75. status = readl(est_addr + EST_STATUS);
  76. value = EST_CGCE | EST_HLBS | EST_HLBF | EST_BTRE | EST_SWLC;
  77. /* Return if there is no error */
  78. if (!(status & value))
  79. return;
  80. if (status & EST_CGCE) {
  81. /* Clear Interrupt */
  82. writel(EST_CGCE, est_addr + EST_STATUS);
  83. x->mtl_est_cgce++;
  84. }
  85. if (status & EST_HLBS) {
  86. value = readl(est_addr + EST_SCH_ERR);
  87. value &= txqcnt_mask;
  88. x->mtl_est_hlbs++;
  89. /* Clear Interrupt */
  90. writel(value, est_addr + EST_SCH_ERR);
  91. /* Collecting info to shows all the queues that has HLBS
  92. * issue. The only way to clear this is to clear the
  93. * statistic
  94. */
  95. if (net_ratelimit())
  96. netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
  97. }
  98. if (status & EST_HLBF) {
  99. value = readl(est_addr + EST_FRM_SZ_ERR);
  100. feqn = value & txqcnt_mask;
  101. value = readl(est_addr + EST_FRM_SZ_CAP);
  102. hbfq = (value & EST_SZ_CAP_HBFQ_MASK(txqcnt)) >>
  103. EST_SZ_CAP_HBFQ_SHIFT;
  104. hbfs = value & EST_SZ_CAP_HBFS_MASK;
  105. x->mtl_est_hlbf++;
  106. for (i = 0; i < txqcnt; i++) {
  107. if (feqn & BIT(i))
  108. x->mtl_est_txq_hlbf[i]++;
  109. }
  110. /* Clear Interrupt */
  111. writel(feqn, est_addr + EST_FRM_SZ_ERR);
  112. if (net_ratelimit())
  113. netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
  114. hbfq, hbfs);
  115. }
  116. if (status & EST_BTRE) {
  117. if (priv->plat->has_xgmac) {
  118. btrl = FIELD_GET(EST_XGMAC_BTRL, status);
  119. btrl_max = FIELD_MAX(EST_XGMAC_BTRL);
  120. } else {
  121. btrl = FIELD_GET(EST_GMAC5_BTRL, status);
  122. btrl_max = FIELD_MAX(EST_GMAC5_BTRL);
  123. }
  124. if (btrl == btrl_max)
  125. x->mtl_est_btrlm++;
  126. else
  127. x->mtl_est_btre++;
  128. if (net_ratelimit())
  129. netdev_info(dev, "EST: BTR Error Loop Count %u\n",
  130. btrl);
  131. writel(EST_BTRE, est_addr + EST_STATUS);
  132. }
  133. if (status & EST_SWLC) {
  134. writel(EST_SWLC, est_addr + EST_STATUS);
  135. netdev_info(dev, "EST: SWOL has been switched\n");
  136. }
  137. }
  138. const struct stmmac_est_ops dwmac510_est_ops = {
  139. .configure = est_configure,
  140. .irq_status = est_irq_status,
  141. };