summaryrefslogtreecommitdiff
path: root/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2021-06-08 20:17:46 +0930
committerCorey Minyard <cminyard@mvista.com>2021-06-21 19:50:13 -0500
commitd7096970075ef47c9906fd241cc4939cc11ddd01 (patch)
tree7a9481c20718d953e8c4a77a76a3ea401155ad9a /drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
parent55ab48b4e356212fbe084ca110db73bb9a6e7058 (diff)
ipmi: kcs_bmc: Turn the driver data-structures inside-out
Make the KCS device drivers responsible for allocating their own memory. Until now the private data for the device driver was allocated internal to the private data for the chardev interface. This coupling required the slightly awkward API of passing through the struct size for the driver private data to the chardev constructor, and then retrieving a pointer to the driver private data from the allocated chardev memory. In addition to being awkward, the arrangement prevents the implementation of alternative userspace interfaces as the device driver private data is not independent. Peel a layer off the onion and turn the data-structures inside out by exploiting container_of() and embedding `struct kcs_device` in the driver private data. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Reviewed-by: Zev Weiss <zweiss@equinix.com> Message-Id: <20210608104757.582199-6-andrew@aj.id.au> Signed-off-by: Corey Minyard <cminyard@mvista.com>
Diffstat (limited to 'drivers/char/ipmi/kcs_bmc_cdev_ipmi.c')
-rw-r--r--drivers/char/ipmi/kcs_bmc_cdev_ipmi.c60
1 files changed, 41 insertions, 19 deletions
diff --git a/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c b/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
index 82c77994e481..5060643bf530 100644
--- a/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
+++ b/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
@@ -382,7 +382,7 @@ static int kcs_bmc_ipmi_release(struct inode *inode, struct file *filp)
return 0;
}
-static const struct file_operations kcs_bmc_fops = {
+static const struct file_operations kcs_bmc_ipmi_fops = {
.owner = THIS_MODULE,
.open = kcs_bmc_ipmi_open,
.read = kcs_bmc_ipmi_read,
@@ -392,36 +392,58 @@ static const struct file_operations kcs_bmc_fops = {
.unlocked_ioctl = kcs_bmc_ipmi_ioctl,
};
-struct kcs_bmc *kcs_bmc_ipmi_alloc(struct device *dev, int sizeof_priv, u32 channel);
-struct kcs_bmc *kcs_bmc_ipmi_alloc(struct device *dev, int sizeof_priv, u32 channel)
+int kcs_bmc_ipmi_add_device(struct kcs_bmc *kcs_bmc);
+int kcs_bmc_ipmi_add_device(struct kcs_bmc *kcs_bmc)
{
- struct kcs_bmc *kcs_bmc;
-
- kcs_bmc = devm_kzalloc(dev, sizeof(*kcs_bmc) + sizeof_priv, GFP_KERNEL);
- if (!kcs_bmc)
- return NULL;
+ int rc;
spin_lock_init(&kcs_bmc->lock);
- kcs_bmc->channel = channel;
-
mutex_init(&kcs_bmc->mutex);
init_waitqueue_head(&kcs_bmc->queue);
- kcs_bmc->data_in = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
- kcs_bmc->data_out = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
- kcs_bmc->kbuffer = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+ kcs_bmc->data_in = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+ kcs_bmc->data_out = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+ kcs_bmc->kbuffer = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
kcs_bmc->miscdev.minor = MISC_DYNAMIC_MINOR;
- kcs_bmc->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s%u",
- DEVICE_NAME, channel);
+ kcs_bmc->miscdev.name = devm_kasprintf(kcs_bmc->dev, GFP_KERNEL, "%s%u",
+ DEVICE_NAME, kcs_bmc->channel);
if (!kcs_bmc->data_in || !kcs_bmc->data_out || !kcs_bmc->kbuffer ||
!kcs_bmc->miscdev.name)
- return NULL;
- kcs_bmc->miscdev.fops = &kcs_bmc_fops;
+ return -ENOMEM;
+
+ kcs_bmc->miscdev.fops = &kcs_bmc_ipmi_fops;
+
+ rc = misc_register(&kcs_bmc->miscdev);
+ if (rc) {
+ dev_err(kcs_bmc->dev, "Unable to register device: %d\n", rc);
+ return rc;
+ }
+
+ dev_info(kcs_bmc->dev, "Initialised IPMI client for channel %d", kcs_bmc->channel);
+
+ return 0;
+}
+EXPORT_SYMBOL(kcs_bmc_ipmi_add_device);
- return kcs_bmc;
+int kcs_bmc_ipmi_remove_device(struct kcs_bmc *kcs_bmc);
+int kcs_bmc_ipmi_remove_device(struct kcs_bmc *kcs_bmc)
+{
+ misc_deregister(&kcs_bmc->miscdev);
+
+ spin_lock_irq(&kcs_bmc->lock);
+ kcs_bmc->running = 0;
+ kcs_bmc_ipmi_force_abort(kcs_bmc);
+ spin_unlock_irq(&kcs_bmc->lock);
+
+ devm_kfree(kcs_bmc->dev, kcs_bmc->kbuffer);
+ devm_kfree(kcs_bmc->dev, kcs_bmc->data_out);
+ devm_kfree(kcs_bmc->dev, kcs_bmc->data_in);
+ devm_kfree(kcs_bmc->dev, kcs_bmc);
+
+ return 0;
}
-EXPORT_SYMBOL(kcs_bmc_ipmi_alloc);
+EXPORT_SYMBOL(kcs_bmc_ipmi_remove_device);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");