kcs_bmc.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. unsigned long flags;
  49. spin_lock_irqsave(&kcs_bmc->lock, flags);
  50. client = kcs_bmc->client;
  51. if (client)
  52. rc = client->ops->event(client);
  53. spin_unlock_irqrestore(&kcs_bmc->lock, flags);
  54. return rc;
  55. }
  56. EXPORT_SYMBOL(kcs_bmc_handle_event);
  57. int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
  58. {
  59. int rc;
  60. spin_lock_irq(&kcs_bmc->lock);
  61. if (kcs_bmc->client) {
  62. rc = -EBUSY;
  63. } else {
  64. u8 mask = KCS_BMC_EVENT_TYPE_IBF;
  65. kcs_bmc->client = client;
  66. kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
  67. rc = 0;
  68. }
  69. spin_unlock_irq(&kcs_bmc->lock);
  70. return rc;
  71. }
  72. EXPORT_SYMBOL(kcs_bmc_enable_device);
  73. void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
  74. {
  75. spin_lock_irq(&kcs_bmc->lock);
  76. if (client == kcs_bmc->client) {
  77. u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
  78. kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
  79. kcs_bmc->client = NULL;
  80. }
  81. spin_unlock_irq(&kcs_bmc->lock);
  82. }
  83. EXPORT_SYMBOL(kcs_bmc_disable_device);
  84. int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
  85. {
  86. struct kcs_bmc_driver *drv;
  87. int error = 0;
  88. int rc;
  89. spin_lock_init(&kcs_bmc->lock);
  90. kcs_bmc->client = NULL;
  91. mutex_lock(&kcs_bmc_lock);
  92. list_add(&kcs_bmc->entry, &kcs_bmc_devices);
  93. list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
  94. rc = drv->ops->add_device(kcs_bmc);
  95. if (!rc)
  96. continue;
  97. dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",
  98. kcs_bmc->channel, rc);
  99. error = rc;
  100. }
  101. mutex_unlock(&kcs_bmc_lock);
  102. return error;
  103. }
  104. EXPORT_SYMBOL(kcs_bmc_add_device);
  105. void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
  106. {
  107. struct kcs_bmc_driver *drv;
  108. int rc;
  109. mutex_lock(&kcs_bmc_lock);
  110. list_del(&kcs_bmc->entry);
  111. list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
  112. rc = drv->ops->remove_device(kcs_bmc);
  113. if (rc)
  114. dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",
  115. kcs_bmc->channel, rc);
  116. }
  117. mutex_unlock(&kcs_bmc_lock);
  118. }
  119. EXPORT_SYMBOL(kcs_bmc_remove_device);
  120. void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)
  121. {
  122. struct kcs_bmc_device *kcs_bmc;
  123. int rc;
  124. mutex_lock(&kcs_bmc_lock);
  125. list_add(&drv->entry, &kcs_bmc_drivers);
  126. list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
  127. rc = drv->ops->add_device(kcs_bmc);
  128. if (rc)
  129. dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",
  130. kcs_bmc->channel, rc);
  131. }
  132. mutex_unlock(&kcs_bmc_lock);
  133. }
  134. EXPORT_SYMBOL(kcs_bmc_register_driver);
  135. void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)
  136. {
  137. struct kcs_bmc_device *kcs_bmc;
  138. int rc;
  139. mutex_lock(&kcs_bmc_lock);
  140. list_del(&drv->entry);
  141. list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
  142. rc = drv->ops->remove_device(kcs_bmc);
  143. if (rc)
  144. dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",
  145. kcs_bmc->channel, rc);
  146. }
  147. mutex_unlock(&kcs_bmc_lock);
  148. }
  149. EXPORT_SYMBOL(kcs_bmc_unregister_driver);
  150. void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)
  151. {
  152. kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);
  153. }
  154. EXPORT_SYMBOL(kcs_bmc_update_event_mask);
  155. MODULE_LICENSE("GPL v2");
  156. MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
  157. MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
  158. MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");