0001
0002
0003
0004
0005
0006
0007 #include <linux/device.h>
0008 #include <linux/list.h>
0009 #include <linux/module.h>
0010 #include <linux/mutex.h>
0011
0012 #include "kcs_bmc.h"
0013
0014
0015 #include "kcs_bmc_device.h"
0016 #include "kcs_bmc_client.h"
0017
0018
0019 static DEFINE_MUTEX(kcs_bmc_lock);
0020 static LIST_HEAD(kcs_bmc_devices);
0021 static LIST_HEAD(kcs_bmc_drivers);
0022
0023
0024
0025 u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
0026 {
0027 return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
0028 }
0029 EXPORT_SYMBOL(kcs_bmc_read_data);
0030
0031 void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data)
0032 {
0033 kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
0034 }
0035 EXPORT_SYMBOL(kcs_bmc_write_data);
0036
0037 u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
0038 {
0039 return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
0040 }
0041 EXPORT_SYMBOL(kcs_bmc_read_status);
0042
0043 void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data)
0044 {
0045 kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
0046 }
0047 EXPORT_SYMBOL(kcs_bmc_write_status);
0048
0049 void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
0050 {
0051 kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
0052 }
0053 EXPORT_SYMBOL(kcs_bmc_update_status);
0054
0055 irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
0056 {
0057 struct kcs_bmc_client *client;
0058 irqreturn_t rc = IRQ_NONE;
0059
0060 spin_lock(&kcs_bmc->lock);
0061 client = kcs_bmc->client;
0062 if (client)
0063 rc = client->ops->event(client);
0064 spin_unlock(&kcs_bmc->lock);
0065
0066 return rc;
0067 }
0068 EXPORT_SYMBOL(kcs_bmc_handle_event);
0069
0070 int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
0071 {
0072 int rc;
0073
0074 spin_lock_irq(&kcs_bmc->lock);
0075 if (kcs_bmc->client) {
0076 rc = -EBUSY;
0077 } else {
0078 u8 mask = KCS_BMC_EVENT_TYPE_IBF;
0079
0080 kcs_bmc->client = client;
0081 kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
0082 rc = 0;
0083 }
0084 spin_unlock_irq(&kcs_bmc->lock);
0085
0086 return rc;
0087 }
0088 EXPORT_SYMBOL(kcs_bmc_enable_device);
0089
0090 void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
0091 {
0092 spin_lock_irq(&kcs_bmc->lock);
0093 if (client == kcs_bmc->client) {
0094 u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
0095
0096 kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
0097 kcs_bmc->client = NULL;
0098 }
0099 spin_unlock_irq(&kcs_bmc->lock);
0100 }
0101 EXPORT_SYMBOL(kcs_bmc_disable_device);
0102
0103 int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
0104 {
0105 struct kcs_bmc_driver *drv;
0106 int error = 0;
0107 int rc;
0108
0109 spin_lock_init(&kcs_bmc->lock);
0110 kcs_bmc->client = NULL;
0111
0112 mutex_lock(&kcs_bmc_lock);
0113 list_add(&kcs_bmc->entry, &kcs_bmc_devices);
0114 list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
0115 rc = drv->ops->add_device(kcs_bmc);
0116 if (!rc)
0117 continue;
0118
0119 dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",
0120 kcs_bmc->channel, rc);
0121 error = rc;
0122 }
0123 mutex_unlock(&kcs_bmc_lock);
0124
0125 return error;
0126 }
0127 EXPORT_SYMBOL(kcs_bmc_add_device);
0128
0129 void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
0130 {
0131 struct kcs_bmc_driver *drv;
0132 int rc;
0133
0134 mutex_lock(&kcs_bmc_lock);
0135 list_del(&kcs_bmc->entry);
0136 list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
0137 rc = drv->ops->remove_device(kcs_bmc);
0138 if (rc)
0139 dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",
0140 kcs_bmc->channel, rc);
0141 }
0142 mutex_unlock(&kcs_bmc_lock);
0143 }
0144 EXPORT_SYMBOL(kcs_bmc_remove_device);
0145
0146 void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)
0147 {
0148 struct kcs_bmc_device *kcs_bmc;
0149 int rc;
0150
0151 mutex_lock(&kcs_bmc_lock);
0152 list_add(&drv->entry, &kcs_bmc_drivers);
0153 list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
0154 rc = drv->ops->add_device(kcs_bmc);
0155 if (rc)
0156 dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",
0157 kcs_bmc->channel, rc);
0158 }
0159 mutex_unlock(&kcs_bmc_lock);
0160 }
0161 EXPORT_SYMBOL(kcs_bmc_register_driver);
0162
0163 void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)
0164 {
0165 struct kcs_bmc_device *kcs_bmc;
0166 int rc;
0167
0168 mutex_lock(&kcs_bmc_lock);
0169 list_del(&drv->entry);
0170 list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
0171 rc = drv->ops->remove_device(kcs_bmc);
0172 if (rc)
0173 dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",
0174 kcs_bmc->channel, rc);
0175 }
0176 mutex_unlock(&kcs_bmc_lock);
0177 }
0178 EXPORT_SYMBOL(kcs_bmc_unregister_driver);
0179
0180 void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)
0181 {
0182 kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);
0183 }
0184 EXPORT_SYMBOL(kcs_bmc_update_event_mask);
0185
0186 MODULE_LICENSE("GPL v2");
0187 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
0188 MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
0189 MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");