diff options
author | Andrew Jeffery <andrew@aj.id.au> | 2021-06-08 20:17:48 +0930 |
---|---|---|
committer | Corey Minyard <cminyard@mvista.com> | 2021-06-21 19:50:22 -0500 |
commit | d4e7ac68f771addc19352121706d8584eb0166cd (patch) | |
tree | cb9cc19a3648713f755bdd47f83c42e166899bca /drivers/char/ipmi/kcs_bmc.c | |
parent | faae6e391eda73a5b9870c78349064282a625bfa (diff) | |
download | linux-stable-d4e7ac68f771addc19352121706d8584eb0166cd.tar.gz linux-stable-d4e7ac68f771addc19352121706d8584eb0166cd.tar.bz2 linux-stable-d4e7ac68f771addc19352121706d8584eb0166cd.zip |
ipmi: kcs_bmc: Strip private client data from struct kcs_bmc
Move all client-private data out of `struct kcs_bmc` into the KCS client
implementation.
With this change the KCS BMC core code now only concerns itself with
abstract `struct kcs_bmc` and `struct kcs_bmc_client` types, achieving
expected separation of concerns. Further, the change clears the path for
implementation of alternative userspace interfaces.
The chardev data-structures are rearranged in the same manner applied to
the KCS device driver data-structures in an earlier patch - `struct
kcs_bmc_client` is embedded in the client's private data and we exploit
container_of() to translate as required.
Finally, now that it is free of client data, `struct kcs_bmc` is renamed
to `struct kcs_bmc_device` to contrast `struct kcs_bmc_client`.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Zev Weiss <zweiss@equinix.com>
Message-Id: <20210608104757.582199-8-andrew@aj.id.au>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Diffstat (limited to 'drivers/char/ipmi/kcs_bmc.c')
-rw-r--r-- | drivers/char/ipmi/kcs_bmc.c | 70 |
1 files changed, 59 insertions, 11 deletions
diff --git a/drivers/char/ipmi/kcs_bmc.c b/drivers/char/ipmi/kcs_bmc.c index c347cf6f9337..2ec934f0dba3 100644 --- a/drivers/char/ipmi/kcs_bmc.c +++ b/drivers/char/ipmi/kcs_bmc.c @@ -4,6 +4,7 @@ * Copyright (c) 2021, IBM Corp. */ +#include <linux/device.h> #include <linux/module.h> #include "kcs_bmc.h" @@ -14,51 +15,98 @@ /* Consumer data access */ -u8 kcs_bmc_read_data(struct kcs_bmc *kcs_bmc) +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 *kcs_bmc, u8 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 *kcs_bmc) +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 *kcs_bmc, u8 data) +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 *kcs_bmc, u8 mask, u8 val) +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 *kcs_bmc) +irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc) { - return kcs_bmc->client.ops->event(&kcs_bmc->client); + struct kcs_bmc_client *client; + irqreturn_t rc; + + spin_lock(&kcs_bmc->lock); + client = kcs_bmc->client; + if (client) { + rc = client->ops->event(client); + } else { + u8 status; + + status = kcs_bmc_read_status(kcs_bmc); + if (status & KCS_BMC_STR_IBF) { + /* Ack the event by reading the data */ + kcs_bmc_read_data(kcs_bmc); + rc = IRQ_HANDLED; + } else { + rc = IRQ_NONE; + } + } + spin_unlock(&kcs_bmc->lock); + + return rc; } EXPORT_SYMBOL(kcs_bmc_handle_event); -int kcs_bmc_ipmi_add_device(struct kcs_bmc *kcs_bmc); -int kcs_bmc_add_device(struct kcs_bmc *kcs_bmc) +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 { + kcs_bmc->client = client; + 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) + kcs_bmc->client = NULL; + spin_unlock_irq(&kcs_bmc->lock); +} +EXPORT_SYMBOL(kcs_bmc_disable_device); + +int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc); +int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc) { return kcs_bmc_ipmi_add_device(kcs_bmc); } EXPORT_SYMBOL(kcs_bmc_add_device); -int kcs_bmc_ipmi_remove_device(struct kcs_bmc *kcs_bmc); -void kcs_bmc_remove_device(struct kcs_bmc *kcs_bmc) +int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc); +void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc) { if (kcs_bmc_ipmi_remove_device(kcs_bmc)) pr_warn("Failed to remove device for KCS channel %d\n", |