kcs_bmc.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2015-2018, Intel Corporation.
  4. * Copyright (c) 2021, IBM Corp.
  5. */
  6. #include <linux/device.h>
  7. #include <linux/list.h>
  8. #include <linux/module.h>
  9. #include <linux/mutex.h>
  10. #include "kcs_bmc.h"
  11. /* Implement both the device and client interfaces here */
  12. #include "kcs_bmc_device.h"
  13. #include "kcs_bmc_client.h"
  14. /* Record registered devices and drivers */
  15. static DEFINE_MUTEX(kcs_bmc_lock);
  16. static LIST_HEAD(kcs_bmc_devices);
  17. static LIST_HEAD(kcs_bmc_drivers);
  18. /* Consumer data access */
  19. u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
  20. {
  21. return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
  22. }
  23. EXPORT_SYMBOL(kcs_bmc_read_data);
  24. void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data)
  25. {
  26. kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
  27. }
  28. EXPORT_SYMBOL(kcs_bmc_write_data);
  29. u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
  30. {
  31. return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
  32. }
  33. EXPORT_SYMBOL(kcs_bmc_read_status);
  34. void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data)
  35. {
  36. kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
  37. }
  38. EXPORT_SYMBOL(kcs_bmc_write_status);
  39. void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
  40. {
  41. kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
  42. }
  43. EXPORT_SYMBOL(kcs_bmc_update_status);
  44. irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
  45. {
  46. struct kcs_bmc_client *client;
  47. irqreturn_t rc = IRQ_NONE;
  48. spin_lock(&kcs_bmc->lock);
  49. client = kcs_bmc->client;
  50. if (client)
  51. rc = client->ops->event(client);
  52. spin_unlock(&kcs_bmc->lock);
  53. return rc;
  54. }
  55. EXPORT_SYMBOL(kcs_bmc_handle_event);
  56. int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
  57. {
  58. int rc;
  59. spin_lock_irq(&kcs_bmc->lock);
  60. if (kcs_bmc->client) {
  61. rc = -EBUSY;
  62. } else {
  63. u8 mask = KCS_BMC_EVENT_TYPE_IBF;
  64. kcs_bmc->client = client;
  65. kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
  66. rc = 0;
  67. }
  68. spin_unlock_irq(&kcs_bmc->lock);
  69. return rc;
  70. }
  71. EXPORT_SYMBOL(kcs_bmc_enable_device);
  72. void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
  73. {
  74. spin_lock_irq(&kcs_bmc->lock);
  75. if (client == kcs_bmc->client) {
  76. u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
  77. kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
  78. kcs_bmc->client = NULL;
  79. }
  80. spin_unlock_irq(&kcs_bmc->lock);
  81. }
  82. EXPORT_SYMBOL(kcs_bmc_disable_device);
  83. int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
  84. {
  85. struct kcs_bmc_driver *drv;
  86. int error = 0;
  87. int rc;
  88. spin_lock_init(&kcs_bmc->lock);
  89. kcs_bmc->client = NULL;
  90. mutex_lock(&kcs_bmc_lock);
  91. list_add(&kcs_bmc->entry, &kcs_bmc_devices);
  92. list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
  93. rc = drv->ops->add_device(kcs_bmc);
  94. if (!rc)
  95. continue;
  96. dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",
  97. kcs_bmc->channel, rc);
  98. error = rc;
  99. }
  100. mutex_unlock(&kcs_bmc_lock);
  101. return error;
  102. }
  103. EXPORT_SYMBOL(kcs_bmc_add_device);
  104. void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
  105. {
  106. struct kcs_bmc_driver *drv;
  107. int rc;
  108. mutex_lock(&kcs_bmc_lock);
  109. list_del(&kcs_bmc->entry);
  110. list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
  111. rc = drv->ops->remove_device(kcs_bmc);
  112. if (rc)
  113. dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",
  114. kcs_bmc->channel, rc);
  115. }
  116. mutex_unlock(&kcs_bmc_lock);
  117. }
  118. EXPORT_SYMBOL(kcs_bmc_remove_device);
  119. void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)
  120. {
  121. struct kcs_bmc_device *kcs_bmc;
  122. int rc;
  123. mutex_lock(&kcs_bmc_lock);
  124. list_add(&drv->entry, &kcs_bmc_drivers);
  125. list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
  126. rc = drv->ops->add_device(kcs_bmc);
  127. if (rc)
  128. dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",
  129. kcs_bmc->channel, rc);
  130. }
  131. mutex_unlock(&kcs_bmc_lock);
  132. }
  133. EXPORT_SYMBOL(kcs_bmc_register_driver);
  134. void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)
  135. {
  136. struct kcs_bmc_device *kcs_bmc;
  137. int rc;
  138. mutex_lock(&kcs_bmc_lock);
  139. list_del(&drv->entry);
  140. list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
  141. rc = drv->ops->remove_device(kcs_bmc);
  142. if (rc)
  143. dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",
  144. kcs_bmc->channel, rc);
  145. }
  146. mutex_unlock(&kcs_bmc_lock);
  147. }
  148. EXPORT_SYMBOL(kcs_bmc_unregister_driver);
  149. void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)
  150. {
  151. kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);
  152. }
  153. EXPORT_SYMBOL(kcs_bmc_update_event_mask);
  154. MODULE_LICENSE("GPL v2");
  155. MODULE_AUTHOR("Haiyue Wang <[email protected]>");
  156. MODULE_AUTHOR("Andrew Jeffery <[email protected]>");
  157. MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");