From patchwork Sun Jan 31 02:05:42 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 576143 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41061140C21 for ; Sun, 31 Jan 2016 13:06:16 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1aPhOv-0000cE-UX; Sun, 31 Jan 2016 02:06:05 +0000 Received: from sog-mx-2.v43.ch3.sourceforge.com ([172.29.43.192] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1aPhOu-0000c2-91 for tpmdd-devel@lists.sourceforge.net; Sun, 31 Jan 2016 02:06:04 +0000 X-ACL-Warn: Received: from mga04.intel.com ([192.55.52.120]) by sog-mx-2.v43.ch3.sourceforge.com with esmtp (Exim 4.76) id 1aPhOs-0005b0-Vm for tpmdd-devel@lists.sourceforge.net; Sun, 31 Jan 2016 02:06:04 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga104.fm.intel.com with ESMTP; 30 Jan 2016 18:05:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,372,1449561600"; d="scan'208";a="872965120" Received: from escrouch-mobl.amr.corp.intel.com (HELO localhost) ([10.255.75.142]) by orsmga001.jf.intel.com with ESMTP; 30 Jan 2016 18:05:57 -0800 From: Jarkko Sakkinen To: Peter Huewe Date: Sat, 30 Jan 2016 18:05:42 -0800 Message-Id: <1454205942-13033-1-git-send-email-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.7.0 X-Spam-Score: -0.0 (/) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain X-Headers-End: 1aPhOs-0005b0-Vm Cc: stable@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org Subject: [tpmdd-devel] [PATCH] tpm: fix rollback/cleanup before tpm_chip_register() X-BeenThere: tpmdd-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Tpm Device Driver maintainance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: tpmdd-devel-bounces@lists.sourceforge.net The release-callback is not used before the device is attached to the device hierarchy. This caused resources not to cleanup properly if the device driver initialization failed before tpm_chip_register(). This patch fixes the issue by adding the cleanup function to the devres list of the platform device in tpmm_chip_alloc(). Fixes: 313d21eeab ("tpm: device class for tpm") Signed-off-by: Jarkko Sakkinen cc: stable@vger.kernel.org --- drivers/char/tpm/tpm-chip.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 1a9dcee..cf2b351 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -75,16 +75,15 @@ static void tpm_dev_release(struct device *dev) } /** - * tpmm_chip_alloc() - allocate a new struct tpm_chip instance - * @dev: device to which the chip is associated + * tpmm_chip_alloc() - allocate and initialize a TPM chip + * @pdev: the platform device who is the parent of the chip * @ops: struct tpm_class_ops instance * - * Allocates a new struct tpm_chip instance and assigns a free - * device number for it. Caller does not have to worry about - * freeing the allocated resources. When the devices is removed - * devres calls tpmm_chip_remove() to do the job. + * Allocates a new struct tpm_chip instance, prepares the character device and + * assigns a free device number for it. The memory is freed automatically when + * the platform device is detached. */ -struct tpm_chip *tpmm_chip_alloc(struct device *dev, +struct tpm_chip *tpmm_chip_alloc(struct device *pdev, const struct tpm_class_ops *ops) { struct tpm_chip *chip; @@ -103,7 +102,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, spin_unlock(&driver_lock); if (chip->dev_num >= TPM_NUM_DEVICES) { - dev_err(dev, "No available tpm device numbers\n"); + dev_err(pdev, "No available tpm device numbers\n"); kfree(chip); return ERR_PTR(-ENOMEM); } @@ -112,9 +111,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); - chip->pdev = dev; - - dev_set_drvdata(dev, chip); + chip->pdev = pdev; chip->dev.class = tpm_class; chip->dev.release = tpm_dev_release; @@ -136,6 +133,12 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, chip->cdev.owner = chip->pdev->driver->owner; chip->cdev.kobj.parent = &chip->dev.kobj; + /* Associate character device with the platform device only after + * it is properly initialized. + */ + dev_set_drvdata(pdev, chip); + devm_add_action(pdev, (void (*)(void *)) tpm_dev_release, &chip->dev); + return chip; } EXPORT_SYMBOL_GPL(tpmm_chip_alloc); @@ -162,7 +165,10 @@ static int tpm_add_char_device(struct tpm_chip *chip) MINOR(chip->dev.devt), rc); cdev_del(&chip->cdev); - return rc; + } else { + devm_remove_action(chip->dev.parent, + (void (*)(void *)) tpm_dev_release, + &chip->dev); } return rc; @@ -202,15 +208,14 @@ static void tpm1_chip_unregister(struct tpm_chip *chip) } /* - * tpm_chip_register() - create a character device for the TPM chip - * @chip: TPM chip to use. + * tpm_chip_register() - add a TPM chip to the device hierarchy + * @chip: the TPM chip to be added * - * Creates a character device for the TPM chip and adds sysfs attributes for - * the device. As the last step this function adds the chip to the list of TPM - * chips available for in-kernel use. + * Adds a TPM chip to the device hierarchy and makes it available to for + * in-kernel use. * - * This function should be only called after the chip initialization is - * complete. + * This function should be called only after the device driver is otherwise + * initialized because it will become available for client access. */ int tpm_chip_register(struct tpm_chip *chip) {