From: Alexander Duyck <alexander.h.duyck(a)linux.intel.com>
commit 3451a495ef244a88ed6317a035299d835554d579 upstream.
Add an additional bit flag to the device_private struct named "dead".
This additional flag provides a guarantee that when a device_del is
executed on a given interface an async worker will not attempt to attach
the driver following the earlier device_del call. Previously this
guarantee was not present and could result in the device_del call
attempting to remove a driver from an interface only to have the async
worker attempt to probe the driver later when it finally completes the
asynchronous probe call.
One additional change added was that I pulled the check for dev->driver
out of the __device_attach_driver call and instead placed it in the
__device_attach_async_helper call. This was motivated by the fact that the
only other caller of this, __device_attach, had already taken the
device_lock() and checked for dev->driver. Instead of testing for this
twice in this path it makes more sense to just consolidate the dev->dead
and dev->driver checks together into one set of checks.
Reviewed-by: Dan Williams <dan.j.williams(a)intel.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki(a)intel.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck(a)linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
---
drivers/base/base.h | 4 ++++
drivers/base/core.c | 11 +++++++++++
drivers/base/dd.c | 22 +++++++++++-----------
3 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 7a419a7a6235..559b047de9f7 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -66,6 +66,9 @@ struct driver_private {
* probed first.
* @device - pointer back to the struct device that this structure is
* associated with.
+ * @dead - This device is currently either in the process of or has been
+ * removed from the system. Any asynchronous events scheduled for this
+ * device should exit without taking any action.
*
* Nothing outside of the driver core should ever touch these fields.
*/
@@ -76,6 +79,7 @@ struct device_private {
struct klist_node knode_bus;
struct list_head deferred_probe;
struct device *device;
+ u8 dead:1;
};
#define to_device_private_parent(obj) \
container_of(obj, struct device_private, knode_parent)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 92e2c32c2227..37a90d72f373 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2050,6 +2050,17 @@ void device_del(struct device *dev)
struct kobject *glue_dir = NULL;
struct class_interface *class_intf;
+ /*
+ * Hold the device lock and set the "dead" flag to guarantee that
+ * the update behavior is consistent with the other bitfields near
+ * it and that we cannot have an asynchronous probe routine trying
+ * to run while we are tearing out the bus/class/sysfs from
+ * underneath the device.
+ */
+ device_lock(dev);
+ dev->p->dead = true;
+ device_unlock(dev);
+
/* Notify clients of device removal. This call must come
* before dpm_sysfs_remove().
*/
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index d48b310c4760..11d24a552ee4 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -725,15 +725,6 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
bool async_allowed;
int ret;
- /*
- * Check if device has already been claimed. This may
- * happen with driver loading, device discovery/registration,
- * and deferred probe processing happens all at once with
- * multiple threads.
- */
- if (dev->driver)
- return -EBUSY;
-
ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
@@ -768,6 +759,15 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
device_lock(dev);
+ /*
+ * Check if device has already been removed or claimed. This may
+ * happen with driver loading, device discovery/registration,
+ * and deferred probe processing happens all at once with
+ * multiple threads.
+ */
+ if (dev->p->dead || dev->driver)
+ goto out_unlock;
+
if (dev->parent)
pm_runtime_get_sync(dev->parent);
@@ -778,7 +778,7 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
if (dev->parent)
pm_runtime_put(dev->parent);
-
+out_unlock:
device_unlock(dev);
put_device(dev);
@@ -891,7 +891,7 @@ static int __driver_attach(struct device *dev, void *data)
if (dev->parent && dev->bus->need_parent_lock)
device_lock(dev->parent);
device_lock(dev);
- if (!dev->driver)
+ if (!dev->p->dead && !dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent && dev->bus->need_parent_lock)
From: Vadim Sukhomlinov <sukhomlinov(a)google.com>
commit db4d8cb9c9f2af71c4d087817160d866ed572cc9 upstream.
TPM 2.0 Shutdown involve sending TPM2_Shutdown to TPM chip and disabling
future TPM operations. TPM 1.2 behavior was different, future TPM
operations weren't disabled, causing rare issues. This patch ensures
that future TPM operations are disabled.
Fixes: d1bd4a792d39 ("tpm: Issue a TPM2_Shutdown for TPM2 devices.")
Cc: stable(a)vger.kernel.org
Signed-off-by: Vadim Sukhomlinov <sukhomlinov(a)google.com>
[dianders: resolved merge conflicts with mainline]
Signed-off-by: Douglas Anderson <dianders(a)chromium.org>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen(a)linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen(a)linux.intel.com>
---
This is the backport of the patch referenced above to 4.19 as was done
in Chrome OS. See <https://crrev.com/c/1495114> for details. It
presumably applies to some older kernels. NOTE that the problem
itself has existed for a long time, but continuing to backport this
exact solution to super old kernels is out of scope for me. For those
truly interested feel free to reference the past discussion [1].
Reason for backport: mainline has commit a3fbfae82b4c ("tpm: take TPM
chip power gating out of tpm_transmit()") and commit 719b7d81f204
("tpm: introduce tpm_chip_start() and tpm_chip_stop()") and it didn't
seem like a good idea to backport 17 patches to avoid the conflict.
[1] https://lkml.kernel.org/r/CAD=FV=UoSV9LKOTMuXKRfgFir+7_qPkuhSLN6XJEKPiRPuJJ…
drivers/char/tpm/tpm-chip.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 46caadca916a..f784b6fd93b4 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -187,12 +187,11 @@ static int tpm_class_shutdown(struct device *dev)
{
struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
- if (chip->flags & TPM_CHIP_FLAG_TPM2) {
- down_write(&chip->ops_sem);
+ down_write(&chip->ops_sem);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_CLEAR);
- chip->ops = NULL;
- up_write(&chip->ops_sem);
- }
+ chip->ops = NULL;
+ up_write(&chip->ops_sem);
return 0;
}
--
2.22.0.410.gd8fdbe21b5-goog
As reported by the OpenWRT team, write requests sometimes fail on some
platforms.
Currently to check the state chip_ready() is used correctly as described by
the flash memory S29GL256P11TFI01 datasheet.
Also chip_good() is used to check if the write is succeeded and it was
implemented by the commit fb4a90bfcd6d8 ("[MTD] CFI-0002 - Improve error
checking").
But actually the write failure is caused on some platforms and also it can
be fixed by using chip_good() to check the state and retry instead.
Also it seems that it is caused after repeated about 1,000 times to retry
the write one word with the reset command.
By using chip_good() to check the state to be done it can be reduced the
retry with reset.
It is depended on the actual flash chip behavior so the root cause is
unknown.
Signed-off-by: Tokunori Ikegami <ikegami.t(a)gmail.com>
Signed-off-by: Felix Fietkau <nbd(a)nbd.name>
Signed-off-by: Hauke Mehrtens <hauke(a)hauke-m.de>
Reported-by: Fabio Bettoni <fbettoni(a)gmail.com>
Cc: Chris Packham <chris.packham(a)alliedtelesis.co.nz>
Cc: Joakim Tjernlund <Joakim.Tjernlund(a)infinera.com>
Cc: linux-mtd(a)lists.infradead.org
Cc: stable(a)vger.kernel.org
---
Changes since v7:
Rebased on top of polling status register support in master.
Changes since v6:
- Change the tag of Hauke Mehrtens to Signed-off-by as confirmed with him.
- Removed the tag of Koen Vandeputte as confirmed with him.
- Address the ./scripts/checkpatch.pl issues.
- Fix to remain the file type as 100644.
Changes since v5:
- Rebased on top of Liu Jian's fixes in master.
- Change to follow Liu Jian's fixes in master for the write buffer.
- Change the email address of Tokunori Ikegami to ikegami.t(a)gmail.com.
Changes since v4:
- None.
Changes since v3:
- Update the commit message for the comments.
- Drop the addition of blanks lines around xip_enable().
- Delete unnecessary setting the ret variable to -EIO.
- Change the email address of Tokunori Ikegami to ikegami_to(a)yahoo.co.jp.
Changes since v2:
- Just update the commit message for the comment.
Changes since v1:
- Just update the commit message.
Background:
This is required for OpenWrt Project to result the flash write issue as
below patche.
<https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=ddc11c3932c7b…>
Also the original patch in OpenWRT is below.
<https://github.com/openwrt/openwrt/blob/v18.06.0/target/linux/ar71xx/patche…>
The reason to use chip_good() is that just actually fix the issue.
And also in the past I had fixed the erase function also as same way by the
patch below.
<https://patchwork.ozlabs.org/patch/922656/>
Note: The reason for the patch for erase is same.
In my understanding the chip_ready() is just checked the value twice from
flash.
So I think that sometimes incorrect value is read twice and it is depended
on the flash device behavior but not sure..
So change to use chip_good() instead of chip_ready().
drivers/mtd/chips/cfi_cmdset_0002.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index f4da7bd552e9..19787a14350b 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1717,31 +1717,36 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
continue;
}
- if (time_after(jiffies, timeo) &&
- !chip_ready(map, chip, adr)) {
+ /*
+ * We check "time_after" and "!chip_good" before checking
+ * "chip_good" to avoid the failure due to scheduling.
+ */
+ if (time_after(jiffies, timeo) && !chip_good(map, chip, adr, datum)) {
xip_enable(map, chip, adr);
printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
xip_disable(map, chip, adr);
+ ret = -EIO;
break;
}
- if (chip_ready(map, chip, adr))
+ if (chip_good(map, chip, adr, datum))
break;
/* Latency issues. Drop the lock, wait a while and retry */
UDELAY(map, chip, adr, 1);
}
+
/* Did we succeed? */
- if (!chip_good(map, chip, adr, datum)) {
+ if (ret) {
/* reset on all failures. */
cfi_check_err_status(map, chip, adr);
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
- if (++retry_cnt <= MAX_RETRIES)
+ if (++retry_cnt <= MAX_RETRIES) {
+ ret = 0;
goto retry;
-
- ret = -EIO;
+ }
}
xip_enable(map, chip, adr);
op_done:
--
2.11.0