vas.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright 2016-17 IBM Corp.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version
  7. * 2 of the License, or (at your option) any later version.
  8. */
  9. #define pr_fmt(fmt) "vas: " fmt
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/export.h>
  13. #include <linux/types.h>
  14. #include <linux/slab.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/of_platform.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of.h>
  19. #include <asm/prom.h>
  20. #include "vas.h"
  21. DEFINE_MUTEX(vas_mutex);
  22. static LIST_HEAD(vas_instances);
  23. static DEFINE_PER_CPU(int, cpu_vas_id);
  24. static int init_vas_instance(struct platform_device *pdev)
  25. {
  26. int rc, cpu, vasid;
  27. struct resource *res;
  28. struct vas_instance *vinst;
  29. struct device_node *dn = pdev->dev.of_node;
  30. rc = of_property_read_u32(dn, "ibm,vas-id", &vasid);
  31. if (rc) {
  32. pr_err("No ibm,vas-id property for %s?\n", pdev->name);
  33. return -ENODEV;
  34. }
  35. if (pdev->num_resources != 4) {
  36. pr_err("Unexpected DT configuration for [%s, %d]\n",
  37. pdev->name, vasid);
  38. return -ENODEV;
  39. }
  40. vinst = kzalloc(sizeof(*vinst), GFP_KERNEL);
  41. if (!vinst)
  42. return -ENOMEM;
  43. INIT_LIST_HEAD(&vinst->node);
  44. ida_init(&vinst->ida);
  45. mutex_init(&vinst->mutex);
  46. vinst->vas_id = vasid;
  47. vinst->pdev = pdev;
  48. res = &pdev->resource[0];
  49. vinst->hvwc_bar_start = res->start;
  50. res = &pdev->resource[1];
  51. vinst->uwc_bar_start = res->start;
  52. res = &pdev->resource[2];
  53. vinst->paste_base_addr = res->start;
  54. res = &pdev->resource[3];
  55. if (res->end > 62) {
  56. pr_err("Bad 'paste_win_id_shift' in DT, %llx\n", res->end);
  57. goto free_vinst;
  58. }
  59. vinst->paste_win_id_shift = 63 - res->end;
  60. pr_devel("Initialized instance [%s, %d], paste_base 0x%llx, "
  61. "paste_win_id_shift 0x%llx\n", pdev->name, vasid,
  62. vinst->paste_base_addr, vinst->paste_win_id_shift);
  63. for_each_possible_cpu(cpu) {
  64. if (cpu_to_chip_id(cpu) == of_get_ibm_chip_id(dn))
  65. per_cpu(cpu_vas_id, cpu) = vasid;
  66. }
  67. mutex_lock(&vas_mutex);
  68. list_add(&vinst->node, &vas_instances);
  69. mutex_unlock(&vas_mutex);
  70. vas_instance_init_dbgdir(vinst);
  71. dev_set_drvdata(&pdev->dev, vinst);
  72. return 0;
  73. free_vinst:
  74. kfree(vinst);
  75. return -ENODEV;
  76. }
  77. /*
  78. * Although this is read/used multiple times, it is written to only
  79. * during initialization.
  80. */
  81. struct vas_instance *find_vas_instance(int vasid)
  82. {
  83. struct list_head *ent;
  84. struct vas_instance *vinst;
  85. mutex_lock(&vas_mutex);
  86. if (vasid == -1)
  87. vasid = per_cpu(cpu_vas_id, smp_processor_id());
  88. list_for_each(ent, &vas_instances) {
  89. vinst = list_entry(ent, struct vas_instance, node);
  90. if (vinst->vas_id == vasid) {
  91. mutex_unlock(&vas_mutex);
  92. return vinst;
  93. }
  94. }
  95. mutex_unlock(&vas_mutex);
  96. pr_devel("Instance %d not found\n", vasid);
  97. return NULL;
  98. }
  99. int chip_to_vas_id(int chipid)
  100. {
  101. int cpu;
  102. for_each_possible_cpu(cpu) {
  103. if (cpu_to_chip_id(cpu) == chipid)
  104. return per_cpu(cpu_vas_id, cpu);
  105. }
  106. return -1;
  107. }
  108. EXPORT_SYMBOL(chip_to_vas_id);
  109. static int vas_probe(struct platform_device *pdev)
  110. {
  111. return init_vas_instance(pdev);
  112. }
  113. static const struct of_device_id powernv_vas_match[] = {
  114. { .compatible = "ibm,vas",},
  115. {},
  116. };
  117. static struct platform_driver vas_driver = {
  118. .driver = {
  119. .name = "vas",
  120. .of_match_table = powernv_vas_match,
  121. },
  122. .probe = vas_probe,
  123. };
  124. static int __init vas_init(void)
  125. {
  126. int found = 0;
  127. struct device_node *dn;
  128. platform_driver_register(&vas_driver);
  129. for_each_compatible_node(dn, NULL, "ibm,vas") {
  130. of_platform_device_create(dn, NULL, NULL);
  131. found++;
  132. }
  133. if (!found) {
  134. platform_driver_unregister(&vas_driver);
  135. return -ENODEV;
  136. }
  137. pr_devel("Found %d instances\n", found);
  138. return 0;
  139. }
  140. device_initcall(vas_init);