From patchwork Tue Jul 24 05:05:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Herrenschmidt X-Patchwork-Id: 948216 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41ZRFy0ynjz9s3Z for ; Tue, 24 Jul 2018 15:08:22 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=kernel.crashing.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 41ZRFx6w3wzDr0y for ; Tue, 24 Jul 2018 15:08:21 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=kernel.crashing.org X-Original-To: linux-aspeed@lists.ozlabs.org Delivered-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=permerror (mailfrom) smtp.mailfrom=kernel.crashing.org (client-ip=63.228.1.57; helo=gate.crashing.org; envelope-from=benh@kernel.crashing.org; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=kernel.crashing.org Received: from gate.crashing.org (gate.crashing.org [63.228.1.57]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 41ZRCD5XkwzDrC5; Tue, 24 Jul 2018 15:06:00 +1000 (AEST) Received: from pasglop.ozlabs.ibm.com (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.14.1) with ESMTP id w6O55JLI028169; Tue, 24 Jul 2018 00:05:27 -0500 From: Benjamin Herrenschmidt To: openbmc@lists.ozlabs.org Subject: [PATCH 2/5] fsi: sbefifo: Convert to use the new chardev Date: Tue, 24 Jul 2018 15:05:16 +1000 Message-Id: <20180724050519.31920-3-benh@kernel.crashing.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180724050519.31920-1-benh@kernel.crashing.org> References: <20180724050519.31920-1-benh@kernel.crashing.org> X-BeenThere: linux-aspeed@lists.ozlabs.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: Linux ASPEED SoC development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-aspeed@lists.ozlabs.org, Eddie James , Linux Kernel Mailing List Errors-To: linux-aspeed-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Linux-aspeed" This converts FSI sbefifo to use the new fsi-core controlled chardev allocator and use a real cdev instead of a miscdev. One side effect is to fix the object lifetime by removing the use of devm_kzalloc() for something that contains kobjects, and using proper reference counting. Signed-off-by: Benjamin Herrenschmidt --- drivers/fsi/fsi-sbefifo.c | 84 +++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c index 33a5d9a43a07..8a185f53c9d8 100644 --- a/drivers/fsi/fsi-sbefifo.c +++ b/drivers/fsi/fsi-sbefifo.c @@ -17,9 +17,8 @@ #include #include #include -#include #include -#include +#include #include #include #include @@ -118,11 +117,11 @@ struct sbefifo { uint32_t magic; #define SBEFIFO_MAGIC 0x53424546 /* "SBEF" */ struct fsi_device *fsi_dev; - struct miscdevice mdev; + struct device dev; + struct cdev cdev; struct mutex lock; - char name[32]; - int idx; bool broken; + bool dead; bool async_ffdc; }; @@ -133,9 +132,9 @@ struct sbefifo_user { size_t pending_len; }; -static DEFINE_IDA(sbefifo_ida); static DEFINE_MUTEX(sbefifo_ffdc_mutex); + static void __sbefifo_dump_ffdc(struct device *dev, const __be32 *ffdc, size_t ffdc_sz, bool internal) { @@ -667,6 +666,9 @@ static int __sbefifo_submit(struct sbefifo *sbefifo, struct device *dev = &sbefifo->fsi_dev->dev; int rc; + if (sbefifo->dead) + return -ENODEV; + if (cmd_len < 2 || be32_to_cpu(command[0]) != cmd_len) { dev_vdbg(dev, "Invalid command len %zd (header: %d)\n", cmd_len, be32_to_cpu(command[0])); @@ -751,8 +753,7 @@ EXPORT_SYMBOL_GPL(sbefifo_submit); */ static int sbefifo_user_open(struct inode *inode, struct file *file) { - struct sbefifo *sbefifo = container_of(file->private_data, - struct sbefifo, mdev); + struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev); struct sbefifo_user *user; user = kzalloc(sizeof(struct sbefifo_user), GFP_KERNEL); @@ -889,6 +890,14 @@ static const struct file_operations sbefifo_fops = { .release = sbefifo_user_release, }; +static void sbefifo_free(struct device *dev) +{ + struct sbefifo *sbefifo = container_of(dev, struct sbefifo, dev); + + put_device(&sbefifo->fsi_dev->dev); + kfree(sbefifo); +} + /* * Probe/remove */ @@ -900,15 +909,23 @@ static int sbefifo_probe(struct device *dev) struct device_node *np; struct platform_device *child; char child_name[32]; - int rc, child_idx = 0; + int rc, didx, child_idx = 0; dev_dbg(dev, "Found sbefifo device\n"); - sbefifo = devm_kzalloc(dev, sizeof(*sbefifo), GFP_KERNEL); + sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL); if (!sbefifo) return -ENOMEM; + + /* Grab a reference to the device (parent of our cdev), we'll drop it later */ + if (!get_device(dev)) { + return -ENODEV; + kfree(sbefifo); + } + sbefifo->magic = SBEFIFO_MAGIC; sbefifo->fsi_dev = fsi_dev; + dev_set_drvdata(dev, sbefifo); mutex_init(&sbefifo->lock); /* @@ -919,28 +936,30 @@ static int sbefifo_probe(struct device *dev) if (rc && rc != -ESHUTDOWN) dev_err(dev, "Initial HW cleanup failed, will retry later\n"); - sbefifo->idx = ida_simple_get(&sbefifo_ida, 1, INT_MAX, GFP_KERNEL); - snprintf(sbefifo->name, sizeof(sbefifo->name), "sbefifo%d", - sbefifo->idx); + /* Create chardev for userspace access */ + sbefifo->dev.type = &fsi_cdev_type; + sbefifo->dev.parent = dev; + sbefifo->dev.release = sbefifo_free; + device_initialize(&sbefifo->dev); - dev_set_drvdata(dev, sbefifo); + /* Allocate a minor in the FSI space */ + rc = fsi_get_new_minor(fsi_dev, fsi_dev_sbefifo, &sbefifo->dev.devt, &didx); + if (rc) + goto err; - /* Create misc chardev for userspace access */ - sbefifo->mdev.minor = MISC_DYNAMIC_MINOR; - sbefifo->mdev.fops = &sbefifo_fops; - sbefifo->mdev.name = sbefifo->name; - sbefifo->mdev.parent = dev; - rc = misc_register(&sbefifo->mdev); + dev_set_name(&sbefifo->dev, "sbefifo%d", didx); + cdev_init(&sbefifo->cdev, &sbefifo_fops); + rc = cdev_device_add(&sbefifo->cdev, &sbefifo->dev); if (rc) { - dev_err(dev, "Failed to register miscdevice: %d\n", rc); - ida_simple_remove(&sbefifo_ida, sbefifo->idx); - return rc; + dev_err(dev, "Error %d creating char device %s\n", + rc, dev_name(&sbefifo->dev)); + goto err_free_minor; } /* Create platform devs for dts child nodes (occ, etc) */ for_each_available_child_of_node(dev->of_node, np) { snprintf(child_name, sizeof(child_name), "%s-dev%d", - sbefifo->name, child_idx++); + dev_name(&sbefifo->dev), child_idx++); child = of_platform_device_create(np, child_name, dev); if (!child) dev_warn(dev, "failed to create child %s dev\n", @@ -948,6 +967,11 @@ static int sbefifo_probe(struct device *dev) } return 0; + err_free_minor: + fsi_free_minor(sbefifo->dev.devt); + err: + put_device(&sbefifo->dev); + return rc; } static int sbefifo_unregister_child(struct device *dev, void *data) @@ -967,10 +991,14 @@ static int sbefifo_remove(struct device *dev) dev_dbg(dev, "Removing sbefifo device...\n"); - misc_deregister(&sbefifo->mdev); - device_for_each_child(dev, NULL, sbefifo_unregister_child); + mutex_lock(&sbefifo->lock); + sbefifo->dead = true; + mutex_unlock(&sbefifo->lock); - ida_simple_remove(&sbefifo_ida, sbefifo->idx); + cdev_device_del(&sbefifo->cdev, &sbefifo->dev); + fsi_free_minor(sbefifo->dev.devt); + device_for_each_child(dev, NULL, sbefifo_unregister_child); + put_device(&sbefifo->dev); return 0; } @@ -1001,8 +1029,6 @@ static int sbefifo_init(void) static void sbefifo_exit(void) { fsi_driver_unregister(&sbefifo_drv); - - ida_destroy(&sbefifo_ida); } module_init(sbefifo_init);