hisi_soc_hha.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Driver for HiSilicon Hydra Home Agent (HHA).
  4. *
  5. * Copyright (c) 2025 HiSilicon Technologies Co., Ltd.
  6. * Author: Yicong Yang <yangyicong@hisilicon.com>
  7. * Yushan Wang <wangyushan12@huawei.com>
  8. *
  9. * A system typically contains multiple HHAs. Each is responsible for a subset
  10. * of the physical addresses in the system, but interleave can make the mapping
  11. * from a particular cache line to a responsible HHA complex. As such no
  12. * filtering is done in the driver, with the hardware being responsible for
  13. * responding with success for even if it was not responsible for any addresses
  14. * in the range on which the operation was requested.
  15. */
  16. #include <linux/bitfield.h>
  17. #include <linux/cache_coherency.h>
  18. #include <linux/dev_printk.h>
  19. #include <linux/init.h>
  20. #include <linux/io.h>
  21. #include <linux/iopoll.h>
  22. #include <linux/kernel.h>
  23. #include <linux/memregion.h>
  24. #include <linux/module.h>
  25. #include <linux/mod_devicetable.h>
  26. #include <linux/mutex.h>
  27. #include <linux/platform_device.h>
  28. #define HISI_HHA_CTRL 0x5004
  29. #define HISI_HHA_CTRL_EN BIT(0)
  30. #define HISI_HHA_CTRL_RANGE BIT(1)
  31. #define HISI_HHA_CTRL_TYPE GENMASK(3, 2)
  32. #define HISI_HHA_START_L 0x5008
  33. #define HISI_HHA_START_H 0x500c
  34. #define HISI_HHA_LEN_L 0x5010
  35. #define HISI_HHA_LEN_H 0x5014
  36. /* The maintain operation performs in a 128 Byte granularity */
  37. #define HISI_HHA_MAINT_ALIGN 128
  38. #define HISI_HHA_POLL_GAP_US 10
  39. #define HISI_HHA_POLL_TIMEOUT_US 50000
  40. struct hisi_soc_hha {
  41. /* Must be first element */
  42. struct cache_coherency_ops_inst cci;
  43. /* Locks HHA instance to forbid overlapping access. */
  44. struct mutex lock;
  45. void __iomem *base;
  46. };
  47. static bool hisi_hha_cache_maintain_wait_finished(struct hisi_soc_hha *soc_hha)
  48. {
  49. u32 val;
  50. return !readl_poll_timeout_atomic(soc_hha->base + HISI_HHA_CTRL, val,
  51. !(val & HISI_HHA_CTRL_EN),
  52. HISI_HHA_POLL_GAP_US,
  53. HISI_HHA_POLL_TIMEOUT_US);
  54. }
  55. static int hisi_soc_hha_wbinv(struct cache_coherency_ops_inst *cci,
  56. struct cc_inval_params *invp)
  57. {
  58. struct hisi_soc_hha *soc_hha =
  59. container_of(cci, struct hisi_soc_hha, cci);
  60. phys_addr_t top, addr = invp->addr;
  61. size_t size = invp->size;
  62. u32 reg;
  63. if (!size)
  64. return -EINVAL;
  65. addr = ALIGN_DOWN(addr, HISI_HHA_MAINT_ALIGN);
  66. top = ALIGN(addr + size, HISI_HHA_MAINT_ALIGN);
  67. size = top - addr;
  68. guard(mutex)(&soc_hha->lock);
  69. if (!hisi_hha_cache_maintain_wait_finished(soc_hha))
  70. return -EBUSY;
  71. /*
  72. * Hardware will search for addresses ranging [addr, addr + size - 1],
  73. * last byte included, and perform maintenance in 128 byte granules
  74. * on those cachelines which contain the addresses. If a given instance
  75. * is either not responsible for a cacheline or that cacheline is not
  76. * currently present then the search will fail, no operation will be
  77. * necessary and the device will report success.
  78. */
  79. size -= 1;
  80. writel(lower_32_bits(addr), soc_hha->base + HISI_HHA_START_L);
  81. writel(upper_32_bits(addr), soc_hha->base + HISI_HHA_START_H);
  82. writel(lower_32_bits(size), soc_hha->base + HISI_HHA_LEN_L);
  83. writel(upper_32_bits(size), soc_hha->base + HISI_HHA_LEN_H);
  84. reg = FIELD_PREP(HISI_HHA_CTRL_TYPE, 1); /* Clean Invalid */
  85. reg |= HISI_HHA_CTRL_RANGE | HISI_HHA_CTRL_EN;
  86. writel(reg, soc_hha->base + HISI_HHA_CTRL);
  87. return 0;
  88. }
  89. static int hisi_soc_hha_done(struct cache_coherency_ops_inst *cci)
  90. {
  91. struct hisi_soc_hha *soc_hha =
  92. container_of(cci, struct hisi_soc_hha, cci);
  93. guard(mutex)(&soc_hha->lock);
  94. if (!hisi_hha_cache_maintain_wait_finished(soc_hha))
  95. return -ETIMEDOUT;
  96. return 0;
  97. }
  98. static const struct cache_coherency_ops hha_ops = {
  99. .wbinv = hisi_soc_hha_wbinv,
  100. .done = hisi_soc_hha_done,
  101. };
  102. static int hisi_soc_hha_probe(struct platform_device *pdev)
  103. {
  104. struct hisi_soc_hha *soc_hha;
  105. struct resource *mem;
  106. int ret;
  107. soc_hha = cache_coherency_ops_instance_alloc(&hha_ops,
  108. struct hisi_soc_hha, cci);
  109. if (!soc_hha)
  110. return -ENOMEM;
  111. platform_set_drvdata(pdev, soc_hha);
  112. mutex_init(&soc_hha->lock);
  113. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  114. if (!mem) {
  115. ret = -ENOMEM;
  116. goto err_free_cci;
  117. }
  118. soc_hha->base = ioremap(mem->start, resource_size(mem));
  119. if (!soc_hha->base) {
  120. ret = dev_err_probe(&pdev->dev, -ENOMEM,
  121. "failed to remap io memory");
  122. goto err_free_cci;
  123. }
  124. ret = cache_coherency_ops_instance_register(&soc_hha->cci);
  125. if (ret)
  126. goto err_iounmap;
  127. return 0;
  128. err_iounmap:
  129. iounmap(soc_hha->base);
  130. err_free_cci:
  131. cache_coherency_ops_instance_put(&soc_hha->cci);
  132. return ret;
  133. }
  134. static void hisi_soc_hha_remove(struct platform_device *pdev)
  135. {
  136. struct hisi_soc_hha *soc_hha = platform_get_drvdata(pdev);
  137. cache_coherency_ops_instance_unregister(&soc_hha->cci);
  138. iounmap(soc_hha->base);
  139. cache_coherency_ops_instance_put(&soc_hha->cci);
  140. }
  141. static const struct acpi_device_id hisi_soc_hha_ids[] = {
  142. { "HISI0511", },
  143. { }
  144. };
  145. MODULE_DEVICE_TABLE(acpi, hisi_soc_hha_ids);
  146. static struct platform_driver hisi_soc_hha_driver = {
  147. .driver = {
  148. .name = "hisi_soc_hha",
  149. .acpi_match_table = hisi_soc_hha_ids,
  150. },
  151. .probe = hisi_soc_hha_probe,
  152. .remove = hisi_soc_hha_remove,
  153. };
  154. module_platform_driver(hisi_soc_hha_driver);
  155. MODULE_IMPORT_NS("CACHE_COHERENCY");
  156. MODULE_DESCRIPTION("HiSilicon Hydra Home Agent driver supporting cache maintenance");
  157. MODULE_AUTHOR("Yicong Yang <yangyicong@hisilicon.com>");
  158. MODULE_AUTHOR("Yushan Wang <wangyushan12@huawei.com>");
  159. MODULE_LICENSE("GPL");