123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2015-2018, Intel Corporation.
- * Copyright (c) 2021, IBM Corp.
- */
- #include <linux/device.h>
- #include <linux/list.h>
- #include <linux/module.h>
- #include <linux/mutex.h>
- #include "kcs_bmc.h"
- /* Implement both the device and client interfaces here */
- #include "kcs_bmc_device.h"
- #include "kcs_bmc_client.h"
- /* Record registered devices and drivers */
- static DEFINE_MUTEX(kcs_bmc_lock);
- static LIST_HEAD(kcs_bmc_devices);
- static LIST_HEAD(kcs_bmc_drivers);
- /* Consumer data access */
- u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
- {
- return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
- }
- EXPORT_SYMBOL(kcs_bmc_read_data);
- void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data)
- {
- kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
- }
- EXPORT_SYMBOL(kcs_bmc_write_data);
- u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
- {
- return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
- }
- EXPORT_SYMBOL(kcs_bmc_read_status);
- void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data)
- {
- kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
- }
- EXPORT_SYMBOL(kcs_bmc_write_status);
- void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
- {
- kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
- }
- EXPORT_SYMBOL(kcs_bmc_update_status);
- irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
- {
- struct kcs_bmc_client *client;
- irqreturn_t rc = IRQ_NONE;
- spin_lock(&kcs_bmc->lock);
- client = kcs_bmc->client;
- if (client)
- rc = client->ops->event(client);
- spin_unlock(&kcs_bmc->lock);
- return rc;
- }
- EXPORT_SYMBOL(kcs_bmc_handle_event);
- int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
- {
- int rc;
- spin_lock_irq(&kcs_bmc->lock);
- if (kcs_bmc->client) {
- rc = -EBUSY;
- } else {
- u8 mask = KCS_BMC_EVENT_TYPE_IBF;
- kcs_bmc->client = client;
- kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
- rc = 0;
- }
- spin_unlock_irq(&kcs_bmc->lock);
- return rc;
- }
- EXPORT_SYMBOL(kcs_bmc_enable_device);
- void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
- {
- spin_lock_irq(&kcs_bmc->lock);
- if (client == kcs_bmc->client) {
- u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
- kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
- kcs_bmc->client = NULL;
- }
- spin_unlock_irq(&kcs_bmc->lock);
- }
- EXPORT_SYMBOL(kcs_bmc_disable_device);
- int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
- {
- struct kcs_bmc_driver *drv;
- int error = 0;
- int rc;
- spin_lock_init(&kcs_bmc->lock);
- kcs_bmc->client = NULL;
- mutex_lock(&kcs_bmc_lock);
- list_add(&kcs_bmc->entry, &kcs_bmc_devices);
- list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
- rc = drv->ops->add_device(kcs_bmc);
- if (!rc)
- continue;
- dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",
- kcs_bmc->channel, rc);
- error = rc;
- }
- mutex_unlock(&kcs_bmc_lock);
- return error;
- }
- EXPORT_SYMBOL(kcs_bmc_add_device);
- void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
- {
- struct kcs_bmc_driver *drv;
- int rc;
- mutex_lock(&kcs_bmc_lock);
- list_del(&kcs_bmc->entry);
- list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
- rc = drv->ops->remove_device(kcs_bmc);
- if (rc)
- dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",
- kcs_bmc->channel, rc);
- }
- mutex_unlock(&kcs_bmc_lock);
- }
- EXPORT_SYMBOL(kcs_bmc_remove_device);
- void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)
- {
- struct kcs_bmc_device *kcs_bmc;
- int rc;
- mutex_lock(&kcs_bmc_lock);
- list_add(&drv->entry, &kcs_bmc_drivers);
- list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
- rc = drv->ops->add_device(kcs_bmc);
- if (rc)
- dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",
- kcs_bmc->channel, rc);
- }
- mutex_unlock(&kcs_bmc_lock);
- }
- EXPORT_SYMBOL(kcs_bmc_register_driver);
- void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)
- {
- struct kcs_bmc_device *kcs_bmc;
- int rc;
- mutex_lock(&kcs_bmc_lock);
- list_del(&drv->entry);
- list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
- rc = drv->ops->remove_device(kcs_bmc);
- if (rc)
- dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",
- kcs_bmc->channel, rc);
- }
- mutex_unlock(&kcs_bmc_lock);
- }
- EXPORT_SYMBOL(kcs_bmc_unregister_driver);
- void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)
- {
- kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);
- }
- EXPORT_SYMBOL(kcs_bmc_update_event_mask);
- MODULE_LICENSE("GPL v2");
- MODULE_AUTHOR("Haiyue Wang <[email protected]>");
- MODULE_AUTHOR("Andrew Jeffery <[email protected]>");
- MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");
|