Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipmi: kcs_bmc: Decouple the IPMI chardev from the core

Now that we have untangled the data-structures, split the userspace
interface out into its own module. Userspace interfaces and drivers are
registered to the KCS BMC core to support arbitrary binding of either.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Message-Id: <20210608104757.582199-9-andrew@aj.id.au>
Reviewed-by: Zev Weiss <zweiss@equinix.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>

authored by

Andrew Jeffery and committed by
Corey Minyard
7cafff99 d4e7ac68

+128 -13
+13
drivers/char/ipmi/Kconfig
··· 124 124 This support is also available as a module. If so, the module 125 125 will be called kcs_bmc_npcm7xx. 126 126 127 + config IPMI_KCS_BMC_CDEV_IPMI 128 + depends on IPMI_KCS_BMC 129 + tristate "IPMI character device interface for BMC KCS devices" 130 + help 131 + Provides a BMC-side character device implementing IPMI 132 + semantics for KCS IPMI devices. 133 + 134 + Say YES if you wish to expose KCS devices on the BMC for IPMI 135 + purposes. 136 + 137 + This support is also available as a module. The module will be 138 + called kcs_bmc_cdev_ipmi. 139 + 127 140 config ASPEED_BT_IPMI_BMC 128 141 depends on ARCH_ASPEED || COMPILE_TEST 129 142 depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
+2 -1
drivers/char/ipmi/Makefile
··· 22 22 obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o 23 23 obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o 24 24 obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o 25 - obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o kcs_bmc_cdev_ipmi.o 25 + obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o 26 + obj-$(CONFIG_IPMI_KCS_BMC_CDEV_IPMI) += kcs_bmc_cdev_ipmi.o 26 27 obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o 27 28 obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o 28 29 obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o
+74 -6
drivers/char/ipmi/kcs_bmc.c
··· 5 5 */ 6 6 7 7 #include <linux/device.h> 8 + #include <linux/list.h> 8 9 #include <linux/module.h> 10 + #include <linux/mutex.h> 9 11 10 12 #include "kcs_bmc.h" 11 13 12 14 /* Implement both the device and client interfaces here */ 13 15 #include "kcs_bmc_device.h" 14 16 #include "kcs_bmc_client.h" 17 + 18 + /* Record registered devices and drivers */ 19 + static DEFINE_MUTEX(kcs_bmc_lock); 20 + static LIST_HEAD(kcs_bmc_devices); 21 + static LIST_HEAD(kcs_bmc_drivers); 15 22 16 23 /* Consumer data access */ 17 24 ··· 105 98 } 106 99 EXPORT_SYMBOL(kcs_bmc_disable_device); 107 100 108 - int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc); 109 101 int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc) 110 102 { 111 - return kcs_bmc_ipmi_add_device(kcs_bmc); 103 + struct kcs_bmc_driver *drv; 104 + int error = 0; 105 + int rc; 106 + 107 + spin_lock_init(&kcs_bmc->lock); 108 + kcs_bmc->client = NULL; 109 + 110 + mutex_lock(&kcs_bmc_lock); 111 + list_add(&kcs_bmc->entry, &kcs_bmc_devices); 112 + list_for_each_entry(drv, &kcs_bmc_drivers, entry) { 113 + rc = drv->ops->add_device(kcs_bmc); 114 + if (!rc) 115 + continue; 116 + 117 + dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d", 118 + kcs_bmc->channel, rc); 119 + error = rc; 120 + } 121 + mutex_unlock(&kcs_bmc_lock); 122 + 123 + return error; 112 124 } 113 125 EXPORT_SYMBOL(kcs_bmc_add_device); 114 126 115 - int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc); 116 127 void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc) 117 128 { 118 - if (kcs_bmc_ipmi_remove_device(kcs_bmc)) 119 - pr_warn("Failed to remove device for KCS channel %d\n", 120 - kcs_bmc->channel); 129 + struct kcs_bmc_driver *drv; 130 + int rc; 131 + 132 + mutex_lock(&kcs_bmc_lock); 133 + list_del(&kcs_bmc->entry); 134 + list_for_each_entry(drv, &kcs_bmc_drivers, entry) { 135 + rc = drv->ops->remove_device(kcs_bmc); 136 + if (rc) 137 + dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d", 138 + kcs_bmc->channel, rc); 139 + } 140 + mutex_unlock(&kcs_bmc_lock); 121 141 } 122 142 EXPORT_SYMBOL(kcs_bmc_remove_device); 143 + 144 + void kcs_bmc_register_driver(struct kcs_bmc_driver *drv) 145 + { 146 + struct kcs_bmc_device *kcs_bmc; 147 + int rc; 148 + 149 + mutex_lock(&kcs_bmc_lock); 150 + list_add(&drv->entry, &kcs_bmc_drivers); 151 + list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) { 152 + rc = drv->ops->add_device(kcs_bmc); 153 + if (rc) 154 + dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d", 155 + kcs_bmc->channel, rc); 156 + } 157 + mutex_unlock(&kcs_bmc_lock); 158 + } 159 + EXPORT_SYMBOL(kcs_bmc_register_driver); 160 + 161 + void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv) 162 + { 163 + struct kcs_bmc_device *kcs_bmc; 164 + int rc; 165 + 166 + mutex_lock(&kcs_bmc_lock); 167 + list_del(&drv->entry); 168 + list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) { 169 + rc = drv->ops->remove_device(kcs_bmc); 170 + if (rc) 171 + dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d", 172 + kcs_bmc->channel, rc); 173 + } 174 + mutex_unlock(&kcs_bmc_lock); 175 + } 176 + EXPORT_SYMBOL(kcs_bmc_unregister_driver); 123 177 124 178 MODULE_LICENSE("GPL v2"); 125 179 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+25 -6
drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
··· 469 469 static DEFINE_SPINLOCK(kcs_bmc_ipmi_instances_lock); 470 470 static LIST_HEAD(kcs_bmc_ipmi_instances); 471 471 472 - int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc); 473 - int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc) 472 + static int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc) 474 473 { 475 474 struct kcs_bmc_ipmi *priv; 476 475 int rc; ··· 511 512 512 513 return 0; 513 514 } 514 - EXPORT_SYMBOL(kcs_bmc_ipmi_add_device); 515 515 516 - int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc); 517 - int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc) 516 + static int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc) 518 517 { 519 518 struct kcs_bmc_ipmi *priv = NULL, *pos; 520 519 ··· 538 541 539 542 return 0; 540 543 } 541 - EXPORT_SYMBOL(kcs_bmc_ipmi_remove_device); 544 + 545 + static const struct kcs_bmc_driver_ops kcs_bmc_ipmi_driver_ops = { 546 + .add_device = kcs_bmc_ipmi_add_device, 547 + .remove_device = kcs_bmc_ipmi_remove_device, 548 + }; 549 + 550 + static struct kcs_bmc_driver kcs_bmc_ipmi_driver = { 551 + .ops = &kcs_bmc_ipmi_driver_ops, 552 + }; 553 + 554 + static int kcs_bmc_ipmi_init(void) 555 + { 556 + kcs_bmc_register_driver(&kcs_bmc_ipmi_driver); 557 + 558 + return 0; 559 + } 560 + module_init(kcs_bmc_ipmi_init); 561 + 562 + static void kcs_bmc_ipmi_exit(void) 563 + { 564 + kcs_bmc_unregister_driver(&kcs_bmc_ipmi_driver); 565 + } 566 + module_exit(kcs_bmc_ipmi_exit); 542 567 543 568 MODULE_LICENSE("GPL v2"); 544 569 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+14
drivers/char/ipmi/kcs_bmc_client.h
··· 8 8 9 9 #include "kcs_bmc.h" 10 10 11 + struct kcs_bmc_driver_ops { 12 + int (*add_device)(struct kcs_bmc_device *kcs_bmc); 13 + int (*remove_device)(struct kcs_bmc_device *kcs_bmc); 14 + }; 15 + 16 + struct kcs_bmc_driver { 17 + struct list_head entry; 18 + 19 + const struct kcs_bmc_driver_ops *ops; 20 + }; 21 + 11 22 struct kcs_bmc_client_ops { 12 23 irqreturn_t (*event)(struct kcs_bmc_client *client); 13 24 }; ··· 28 17 29 18 struct kcs_bmc_device *dev; 30 19 }; 20 + 21 + void kcs_bmc_register_driver(struct kcs_bmc_driver *drv); 22 + void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv); 31 23 32 24 int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client); 33 25 void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client);