ip27-xtalk.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 1999, 2000 Ralf Baechle ([email protected])
  4. * Copyright (C) 1999, 2000 Silcon Graphics, Inc.
  5. * Copyright (C) 2004 Christoph Hellwig.
  6. *
  7. * Generic XTALK initialization code
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/smp.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/platform_data/sgi-w1.h>
  13. #include <linux/platform_data/xtalk-bridge.h>
  14. #include <asm/sn/addrs.h>
  15. #include <asm/sn/types.h>
  16. #include <asm/sn/klconfig.h>
  17. #include <asm/pci/bridge.h>
  18. #include <asm/xtalk/xtalk.h>
  19. #define XBOW_WIDGET_PART_NUM 0x0
  20. #define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */
  21. #define BASE_XBOW_PORT 8 /* Lowest external port */
  22. static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
  23. {
  24. struct xtalk_bridge_platform_data *bd;
  25. struct sgi_w1_platform_data *wd;
  26. struct platform_device *pdev_wd;
  27. struct platform_device *pdev_bd;
  28. struct resource w1_res;
  29. unsigned long offset;
  30. offset = NODE_OFFSET(nasid);
  31. wd = kzalloc(sizeof(*wd), GFP_KERNEL);
  32. if (!wd) {
  33. pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
  34. return;
  35. }
  36. snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
  37. offset + (widget << SWIN_SIZE_BITS));
  38. memset(&w1_res, 0, sizeof(w1_res));
  39. w1_res.start = offset + (widget << SWIN_SIZE_BITS) +
  40. offsetof(struct bridge_regs, b_nic);
  41. w1_res.end = w1_res.start + 3;
  42. w1_res.flags = IORESOURCE_MEM;
  43. pdev_wd = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
  44. if (!pdev_wd) {
  45. pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
  46. goto err_kfree_wd;
  47. }
  48. if (platform_device_add_resources(pdev_wd, &w1_res, 1)) {
  49. pr_warn("xtalk:n%d/%x bridge failed to add platform resources.\n", nasid, widget);
  50. goto err_put_pdev_wd;
  51. }
  52. if (platform_device_add_data(pdev_wd, wd, sizeof(*wd))) {
  53. pr_warn("xtalk:n%d/%x bridge failed to add platform data.\n", nasid, widget);
  54. goto err_put_pdev_wd;
  55. }
  56. if (platform_device_add(pdev_wd)) {
  57. pr_warn("xtalk:n%d/%x bridge failed to add platform device.\n", nasid, widget);
  58. goto err_put_pdev_wd;
  59. }
  60. /* platform_device_add_data() duplicates the data */
  61. kfree(wd);
  62. bd = kzalloc(sizeof(*bd), GFP_KERNEL);
  63. if (!bd) {
  64. pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
  65. goto err_unregister_pdev_wd;
  66. }
  67. pdev_bd = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
  68. if (!pdev_bd) {
  69. pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
  70. goto err_kfree_bd;
  71. }
  72. bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
  73. bd->intr_addr = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
  74. bd->nasid = nasid;
  75. bd->masterwid = masterwid;
  76. bd->mem.name = "Bridge PCI MEM";
  77. bd->mem.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
  78. bd->mem.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
  79. bd->mem.flags = IORESOURCE_MEM;
  80. bd->mem_offset = offset;
  81. bd->io.name = "Bridge PCI IO";
  82. bd->io.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
  83. bd->io.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
  84. bd->io.flags = IORESOURCE_IO;
  85. bd->io_offset = offset;
  86. if (platform_device_add_data(pdev_bd, bd, sizeof(*bd))) {
  87. pr_warn("xtalk:n%d/%x bridge failed to add platform data.\n", nasid, widget);
  88. goto err_put_pdev_bd;
  89. }
  90. if (platform_device_add(pdev_bd)) {
  91. pr_warn("xtalk:n%d/%x bridge failed to add platform device.\n", nasid, widget);
  92. goto err_put_pdev_bd;
  93. }
  94. /* platform_device_add_data() duplicates the data */
  95. kfree(bd);
  96. pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
  97. return;
  98. err_put_pdev_bd:
  99. platform_device_put(pdev_bd);
  100. err_kfree_bd:
  101. kfree(bd);
  102. err_unregister_pdev_wd:
  103. platform_device_unregister(pdev_wd);
  104. return;
  105. err_put_pdev_wd:
  106. platform_device_put(pdev_wd);
  107. err_kfree_wd:
  108. kfree(wd);
  109. return;
  110. }
  111. static int probe_one_port(nasid_t nasid, int widget, int masterwid)
  112. {
  113. widgetreg_t widget_id;
  114. xwidget_part_num_t partnum;
  115. widget_id = *(volatile widgetreg_t *)
  116. (RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
  117. partnum = XWIDGET_PART_NUM(widget_id);
  118. switch (partnum) {
  119. case BRIDGE_WIDGET_PART_NUM:
  120. case XBRIDGE_WIDGET_PART_NUM:
  121. bridge_platform_create(nasid, widget, masterwid);
  122. break;
  123. default:
  124. pr_info("xtalk:n%d/%d unknown widget (0x%x)\n",
  125. nasid, widget, partnum);
  126. break;
  127. }
  128. return 0;
  129. }
  130. static int xbow_probe(nasid_t nasid)
  131. {
  132. lboard_t *brd;
  133. klxbow_t *xbow_p;
  134. unsigned masterwid, i;
  135. /*
  136. * found xbow, so may have multiple bridges
  137. * need to probe xbow
  138. */
  139. brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8);
  140. if (!brd)
  141. return -ENODEV;
  142. xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW);
  143. if (!xbow_p)
  144. return -ENODEV;
  145. /*
  146. * Okay, here's a xbow. Let's arbitrate and find
  147. * out if we should initialize it. Set enabled
  148. * hub connected at highest or lowest widget as
  149. * master.
  150. */
  151. #ifdef WIDGET_A
  152. i = HUB_WIDGET_ID_MAX + 1;
  153. do {
  154. i--;
  155. } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
  156. (!XBOW_PORT_IS_ENABLED(xbow_p, i)));
  157. #else
  158. i = HUB_WIDGET_ID_MIN - 1;
  159. do {
  160. i++;
  161. } while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
  162. (!XBOW_PORT_IS_ENABLED(xbow_p, i)));
  163. #endif
  164. masterwid = i;
  165. if (nasid != XBOW_PORT_NASID(xbow_p, i))
  166. return 1;
  167. for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) {
  168. if (XBOW_PORT_IS_ENABLED(xbow_p, i) &&
  169. XBOW_PORT_TYPE_IO(xbow_p, i))
  170. probe_one_port(nasid, i, masterwid);
  171. }
  172. return 0;
  173. }
  174. static void xtalk_probe_node(nasid_t nasid)
  175. {
  176. volatile u64 hubreg;
  177. xwidget_part_num_t partnum;
  178. widgetreg_t widget_id;
  179. hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
  180. /* check whether the link is up */
  181. if (!(hubreg & IIO_LLP_CSR_IS_UP))
  182. return;
  183. widget_id = *(volatile widgetreg_t *)
  184. (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
  185. partnum = XWIDGET_PART_NUM(widget_id);
  186. switch (partnum) {
  187. case BRIDGE_WIDGET_PART_NUM:
  188. bridge_platform_create(nasid, 0x8, 0xa);
  189. break;
  190. case XBOW_WIDGET_PART_NUM:
  191. case XXBOW_WIDGET_PART_NUM:
  192. pr_info("xtalk:n%d/0 xbow widget\n", nasid);
  193. xbow_probe(nasid);
  194. break;
  195. default:
  196. pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
  197. break;
  198. }
  199. }
  200. static int __init xtalk_init(void)
  201. {
  202. nasid_t nasid;
  203. for_each_online_node(nasid)
  204. xtalk_probe_node(nasid);
  205. return 0;
  206. }
  207. arch_initcall(xtalk_init);