Before commit cfc4c189bc70 ("pwm: Read initial hardware state at request
time"), a driver's get_state callback would get called once per PWM from
pwmchip_add().
pwm-lpss' runtime-pm code was relying on this, getting a runtime-pm ref for
PWMs which are enabled at probe time from within its get_state callback,
before enabling runtime-pm.
The change to calling get_state at request time causes a number of
problems:
1. PWMs enabled at probe time may get runtime suspended before they are
requested, causing e.g. a LCD backlight controlled by the PWM to turn off.
2. When the request happens when the PWM has been runtime suspended, the
ctrl register will read all 1 / 0xffffffff, causing get_state to store
bogus values in the pwm_state.
3. get_state was using an async pm_runtime_get() call, because it assumed
that runtime-pm has not been enabled yet. If shortly after the request an
apply call is made, then the pwm_lpss_is_updating() check may trigger
because the resume triggered by the pm_runtime_get() call is not complete
yet, so the ctrl register still reads all 1 / 0xffffffff.
This commit fixes these issues by moving the initial pm_runtime_get() call
for PWMs which are enabled at probe time to the pwm_lpss_probe() function;
and by making get_state take a runtime-pm ref before reading the ctrl reg.
BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1828927
Fixes: cfc4c189bc70 ("pwm: Read initial hardware state at request time")
Cc: stable(a)vger.kernel.org
Signed-off-by: Hans de Goede <hdegoede(a)redhat.com>
---
drivers/pwm/pwm-lpss.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 75bbfe5f3bc2..9d965ffe66d1 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -158,7 +158,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
-/* This function gets called once from pwmchip_add to get the initial state */
static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
@@ -167,6 +166,8 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long base_unit, freq, on_time_div;
u32 ctrl;
+ pm_runtime_get_sync(chip->dev);
+
base_unit_range = BIT(lpwm->info->base_unit_bits);
ctrl = pwm_lpss_read(pwm);
@@ -187,8 +188,7 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->polarity = PWM_POLARITY_NORMAL;
state->enabled = !!(ctrl & PWM_ENABLE);
- if (state->enabled)
- pm_runtime_get(chip->dev);
+ pm_runtime_put(chip->dev);
}
static const struct pwm_ops pwm_lpss_ops = {
@@ -202,7 +202,8 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
{
struct pwm_lpss_chip *lpwm;
unsigned long c;
- int ret;
+ int i, ret;
+ u32 ctrl;
if (WARN_ON(info->npwm > MAX_PWMS))
return ERR_PTR(-ENODEV);
@@ -232,6 +233,12 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
return ERR_PTR(ret);
}
+ for (i = 0; i < lpwm->info->npwm; i++) {
+ ctrl = pwm_lpss_read(&lpwm->chip.pwms[i]);
+ if (ctrl & PWM_ENABLE)
+ pm_runtime_get(dev);
+ }
+
return lpwm;
}
EXPORT_SYMBOL_GPL(pwm_lpss_probe);
--
2.26.0
This is the start of the stable review cycle for the 4.4.226 release.
There are 48 patches in this series, all will be posted as a response
to this one. If anyone has any issues with these being applied, please
let me know.
Responses should be made by Wed, 03 Jun 2020 17:38:19 +0000.
Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.4.226-rc…
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.4.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Linux 4.4.226-rc1
Ben Hutchings <ben.hutchings(a)codethink.co.uk>
drm/msm: Fix possible null dereference on failure of get_pages()
Guoqing Jiang <gqjiang(a)suse.com>
sc16is7xx: move label 'err_spi' to correct section
Michal Marek <mmarek(a)suse.com>
asm-prototypes: Clear any CPP defines before declaring the functions
Liviu Dudau <liviu(a)dudau.co.uk>
mm/vmalloc.c: don't dereference possible NULL pointer in __vunmap()
Roopa Prabhu <roopa(a)cumulusnetworks.com>
net: rtnl_configure_link: fix dev flags changes arg to __dev_notify_flags
Sudip Mukherjee <sudip(a)vectorindia.org>
mac80211: fix memory leak
Yoshihiro Shimoda <yoshihiro.shimoda.uh(a)renesas.com>
usb: renesas_usbhs: gadget: fix spin_lock_init() for &uep->lock
Thomas Gleixner <tglx(a)linutronix.de>
genirq/generic_pending: Do not lose pending affinity update
Matt Roper <matthew.d.roper(a)intel.com>
drm/fb-helper: Use proper plane mask for fb cleanup
Konstantin Khlebnikov <khlebnikov(a)yandex-team.ru>
mm: remove VM_BUG_ON(PageSlab()) from page_mapcount()
Pablo Neira Ayuso <pablo(a)netfilter.org>
netfilter: nf_conntrack_pptp: fix compilation warning with W=1 build
Dmitry Torokhov <dmitry.torokhov(a)gmail.com>
Revert "Input: i8042 - add ThinkPad S230u to i8042 nomux list"
Qiushi Wu <wu000273(a)umn.edu>
bonding: Fix reference count leak in bond_sysfs_slave_add.
Qiushi Wu <wu000273(a)umn.edu>
qlcnic: fix missing release in qlcnic_83xx_interrupt_test.
Pablo Neira Ayuso <pablo(a)netfilter.org>
netfilter: nf_conntrack_pptp: prevent buffer overflows in debug code
Phil Sutter <phil(a)nwl.cc>
netfilter: ipset: Fix subcounter update skip
Michael Braun <michael-dev(a)fami-braun.de>
netfilter: nft_reject_bridge: enable reject with bridge vlan
Xin Long <lucien.xin(a)gmail.com>
ip_vti: receive ipip packet by calling ip_tunnel_rcv
Jeremy Sowden <jeremy(a)azazel.net>
vti4: eliminated some duplicate code.
Xin Long <lucien.xin(a)gmail.com>
xfrm: fix a NULL-ptr deref in xfrm_local_error
Xin Long <lucien.xin(a)gmail.com>
xfrm: fix a warning in xfrm_policy_insert_list
Xin Long <lucien.xin(a)gmail.com>
xfrm: allow to accept packets with ipv6 NEXTHDR_HOP in xfrm_input
Alexander Dahl <post(a)lespocky.de>
x86/dma: Fix max PFN arithmetic overflow on 32 bit systems
Helge Deller <deller(a)gmx.de>
parisc: Fix kernel panic in mem_init()
Qiushi Wu <wu000273(a)umn.edu>
iommu: Fix reference count leak in iommu_group_alloc.
Arnd Bergmann <arnd(a)arndb.de>
include/asm-generic/topology.h: guard cpumask_of_node() macro argument
Alexander Potapenko <glider(a)google.com>
fs/binfmt_elf.c: allocate initialized memory in fill_thread_core_info()
Eric W. Biederman <ebiederm(a)xmission.com>
exec: Always set cap_ambient in cap_bprm_set_creds
Chris Chiu <chiu(a)endlessm.com>
ALSA: usb-audio: mixer: volume quirk for ESS Technology Asus USB DAC
Changming Liu <liu.changm(a)northeastern.edu>
ALSA: hwdep: fix a left shifting 1 by 31 UB bug
Kaike Wan <kaike.wan(a)intel.com>
IB/qib: Call kobject_put() when kobject_init_and_add() fails
Kevin Locke <kevin(a)kevinlocke.name>
Input: i8042 - add ThinkPad S230u to i8042 reset list
Łukasz Patron <priv.luk(a)gmail.com>
Input: xpad - add custom init packet for Xbox One S controllers
Brendan Shanks <bshanks(a)codeweavers.com>
Input: evdev - call input_flush_device() on release(), not flush()
Kevin Locke <kevin(a)kevinlocke.name>
Input: i8042 - add ThinkPad S230u to i8042 nomux list
James Hilliard <james.hilliard1(a)gmail.com>
Input: usbtouchscreen - add support for BonXeon TP
Steve French <stfrench(a)microsoft.com>
cifs: Fix null pointer check in cifs_read
Masahiro Yamada <masahiroy(a)kernel.org>
usb: gadget: legacy: fix redundant initialization warnings
Lei Xue <carmark.dlut(a)gmail.com>
cachefiles: Fix race between read_waiter and read_copier involving op->to_do
Bob Peterson <rpeterso(a)redhat.com>
gfs2: don't call quota_unhold if quotas are not locked
Kalderon, Michal <Michal.Kalderon(a)cavium.com>
IB/cma: Fix reference count leak when no ipv4 addresses are set
Dmitry V. Levin <ldv(a)altlinux.org>
uapi: fix linux/if_pppol2tp.h userspace compilation errors
Qiushi Wu <wu000273(a)umn.edu>
net/mlx4_core: fix a memory leak bug.
Qiushi Wu <wu000273(a)umn.edu>
net: sun: fix missing release regions in cas_init_one().
Moshe Shemesh <moshe(a)mellanox.com>
net/mlx5: Add command entry handling completion
Jere Leppänen <jere.leppanen(a)nokia.com>
sctp: Start shutdown on association restart if in SHUTDOWN-SENT state and socket is closed
Yuqi Jin <jinyuqi(a)huawei.com>
net: revert "net: get rid of an signed integer overflow in ip_idents_reserve()"
Eric Dumazet <edumazet(a)google.com>
ax25: fix setsockopt(SO_BINDTODEVICE)
-------------
Diffstat:
Makefile | 4 +-
arch/parisc/mm/init.c | 2 +-
arch/x86/include/asm/dma.h | 2 +-
drivers/gpu/drm/drm_fb_helper.c | 2 +-
drivers/gpu/drm/msm/msm_gem.c | 20 +++---
drivers/infiniband/hw/qib/qib_sysfs.c | 9 +--
drivers/input/evdev.c | 19 ++----
drivers/input/joystick/xpad.c | 12 ++++
drivers/input/serio/i8042-x86ia64io.h | 7 ++
drivers/input/touchscreen/usbtouchscreen.c | 1 +
drivers/iommu/iommu.c | 2 +-
drivers/net/bonding/bond_sysfs_slave.c | 4 +-
drivers/net/ethernet/mellanox/mlx4/fw.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 15 +++++
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 4 +-
drivers/net/ethernet/sun/cassini.c | 3 +-
drivers/tty/serial/sc16is7xx.c | 2 +
drivers/usb/gadget/legacy/inode.c | 3 +-
drivers/usb/renesas_usbhs/mod_gadget.c | 2 +-
fs/binfmt_elf.c | 2 +-
fs/cachefiles/rdwr.c | 2 +-
fs/cifs/file.c | 2 +-
fs/gfs2/quota.c | 3 +-
include/asm-generic/asm-prototypes.h | 6 ++
include/asm-generic/topology.h | 2 +-
include/linux/mlx5/driver.h | 1 +
include/linux/mm.h | 1 -
include/linux/netfilter/nf_conntrack_pptp.h | 2 +-
include/rdma/ib_addr.h | 6 +-
include/uapi/linux/l2tp.h | 7 +-
kernel/irq/migration.c | 26 ++++++--
mm/vmalloc.c | 2 +-
net/ax25/af_ax25.c | 6 +-
net/bridge/netfilter/nft_reject_bridge.c | 6 ++
net/core/rtnetlink.c | 2 +-
net/ipv4/ip_vti.c | 75 ++++++++++++----------
net/ipv4/netfilter/nf_nat_pptp.c | 7 +-
net/ipv4/route.c | 14 ++--
net/mac80211/sta_info.c | 1 +
net/netfilter/ipset/ip_set_list_set.c | 2 +-
net/netfilter/nf_conntrack_pptp.c | 62 ++++++++++--------
net/sctp/sm_statefuns.c | 9 +--
net/xfrm/xfrm_input.c | 2 +-
net/xfrm/xfrm_output.c | 3 +-
net/xfrm/xfrm_policy.c | 7 +-
security/commoncap.c | 1 +
sound/core/hwdep.c | 4 +-
sound/usb/mixer.c | 8 +++
48 files changed, 229 insertions(+), 157 deletions(-)
From: James Bottomley <James.Bottomley(a)HansenPartnership.com>
BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1881710
It has been reported that some TIS based TPMs are giving unexpected
errors when using the O_NONBLOCK path of the TPM device. The problem
is that some TPMs don't like it when you get and then relinquish a
locality (as the tpm_try_get_ops()/tpm_put_ops() pair does) without
sending a command. This currently happens all the time in the
O_NONBLOCK write path. Fix this by moving the tpm_try_get_ops()
further down the code to after the O_NONBLOCK determination is made.
This is safe because the priv->buffer_mutex still protects the priv
state being modified.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206275
Fixes: d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")
Reported-by: Mario Limonciello <Mario.Limonciello(a)dell.com>
Tested-by: Alex Guzman <alex(a)guzman.io>
Cc: stable(a)vger.kernel.org
Reviewed-by: Jerry Snitselaar <jsnitsel(a)redhat.com>
Signed-off-by: James Bottomley <James.Bottomley(a)HansenPartnership.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen(a)linux.intel.com>
Signed-off-by: Ivan Hu <ivan.hu(a)canonical.com>
---
drivers/char/tpm/tpm-dev-common.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index 10b9f63701e6..de55205d3a11 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -164,15 +164,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
goto out;
}
- /* atomic tpm command send and result receive. We only hold the ops
- * lock during this period so that the tpm can be unregistered even if
- * the char dev is held open.
- */
- if (tpm_try_get_ops(priv->chip)) {
- ret = -EPIPE;
- goto out;
- }
-
priv->response_length = 0;
priv->response_read = false;
*off = 0;
@@ -186,11 +177,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
if (file->f_flags & O_NONBLOCK) {
priv->command_enqueued = true;
queue_work(tpm_dev_wq, &priv->async_work);
- tpm_put_ops(priv->chip);
mutex_unlock(&priv->buffer_mutex);
return size;
}
+ /* atomic tpm command send and result receive. We only hold the ops
+ * lock during this period so that the tpm can be unregistered even if
+ * the char dev is held open.
+ */
+ if (tpm_try_get_ops(priv->chip)) {
+ ret = -EPIPE;
+ goto out;
+ }
+
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer), 0);
tpm_put_ops(priv->chip);
--
2.17.1
From: Steven Price <steven.price(a)arm.com>
Subject: x86: mm: ptdump: calculate effective permissions correctly
Patch series "Fix W+X debug feature on x86"
Jan alerted me[1] that the W+X detection debug feature was broken in x86
by my change[2] to switch x86 to use the generic ptdump infrastructure.
Fundamentally the approach of trying to move the calculation of effective
permissions into note_page() was broken because note_page() is only called
for 'leaf' entries and the effective permissions are passed down via the
internal nodes of the page tree. The solution I've taken here is to
create a new (optional) callback which is called for all nodes of the page
tree and therefore can calculate the effective permissions.
Secondly on some configurations (32 bit with PAE) "unsigned long" is not
large enough to store the table entries. The fix here is simple - let's
just use a u64.
[1] https://lore.kernel.org/lkml/d573dc7e-e742-84de-473d-f971142fa319@suse.com/
[2] 2ae27137b2db ("x86: mm: convert dump_pagetables to use walk_page_range")
This patch (of 2):
By switching the x86 page table dump code to use the generic code the
effective permissions are no longer calculated correctly because the
note_page() function is only called for *leaf* entries. To calculate the
actual effective permissions it is necessary to observe the full hierarchy
of the page tree.
Introduce a new callback for ptdump which is called for every entry and
can therefore update the prot_levels array correctly. note_page() can
then simply access the appropriate element in the array.
[steven.price(a)arm.com: make the assignment conditional on val != 0]
Link: http://lkml.kernel.org/r/430c8ab4-e7cd-6933-dde6-087fac6db872@arm.com
Link: http://lkml.kernel.org/r/20200521152308.33096-1-steven.price@arm.com
Link: http://lkml.kernel.org/r/20200521152308.33096-2-steven.price@arm.com
Fixes: 2ae27137b2db ("x86: mm: convert dump_pagetables to use walk_page_range")
Signed-off-by: Steven Price <steven.price(a)arm.com>
Reported-by: Jan Beulich <jbeulich(a)suse.com>
Cc: Qian Cai <cai(a)lca.pw>
Cc: Andy Lutomirski <luto(a)kernel.org>
Cc: Borislav Petkov <bp(a)alien8.de>
Cc: Dave Hansen <dave.hansen(a)linux.intel.com>
Cc: Ingo Molnar <mingo(a)redhat.com>
Cc: Peter Zijlstra <peterz(a)infradead.org>
Cc: Thomas Gleixner <tglx(a)linutronix.de>
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Andrew Morton <akpm(a)linux-foundation.org>
---
arch/x86/mm/dump_pagetables.c | 33 +++++++++++++++++++-------------
include/linux/ptdump.h | 1
mm/ptdump.c | 17 +++++++++++++++-
3 files changed, 37 insertions(+), 14 deletions(-)
--- a/arch/x86/mm/dump_pagetables.c~x86-mm-ptdump-calculate-effective-permissions-correctly
+++ a/arch/x86/mm/dump_pagetables.c
@@ -249,10 +249,22 @@ static void note_wx(struct pg_state *st,
(void *)st->start_address);
}
-static inline pgprotval_t effective_prot(pgprotval_t prot1, pgprotval_t prot2)
+static void effective_prot(struct ptdump_state *pt_st, int level, u64 val)
{
- return (prot1 & prot2 & (_PAGE_USER | _PAGE_RW)) |
- ((prot1 | prot2) & _PAGE_NX);
+ struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
+ pgprotval_t prot = val & PTE_FLAGS_MASK;
+ pgprotval_t effective;
+
+ if (level > 0) {
+ pgprotval_t higher_prot = st->prot_levels[level - 1];
+
+ effective = (higher_prot & prot & (_PAGE_USER | _PAGE_RW)) |
+ ((higher_prot | prot) & _PAGE_NX);
+ } else {
+ effective = prot;
+ }
+
+ st->prot_levels[level] = effective;
}
/*
@@ -270,16 +282,10 @@ static void note_page(struct ptdump_stat
struct seq_file *m = st->seq;
new_prot = val & PTE_FLAGS_MASK;
-
- if (level > 0) {
- new_eff = effective_prot(st->prot_levels[level - 1],
- new_prot);
- } else {
- new_eff = new_prot;
- }
-
- if (level >= 0)
- st->prot_levels[level] = new_eff;
+ if (!val)
+ new_eff = 0;
+ else
+ new_eff = st->prot_levels[level];
/*
* If we have a "break" in the series, we need to flush the state that
@@ -374,6 +380,7 @@ static void ptdump_walk_pgd_level_core(s
struct pg_state st = {
.ptdump = {
.note_page = note_page,
+ .effective_prot = effective_prot,
.range = ptdump_ranges
},
.level = -1,
--- a/include/linux/ptdump.h~x86-mm-ptdump-calculate-effective-permissions-correctly
+++ a/include/linux/ptdump.h
@@ -14,6 +14,7 @@ struct ptdump_state {
/* level is 0:PGD to 4:PTE, or -1 if unknown */
void (*note_page)(struct ptdump_state *st, unsigned long addr,
int level, unsigned long val);
+ void (*effective_prot)(struct ptdump_state *st, int level, u64 val);
const struct ptdump_range *range;
};
--- a/mm/ptdump.c~x86-mm-ptdump-calculate-effective-permissions-correctly
+++ a/mm/ptdump.c
@@ -36,6 +36,9 @@ static int ptdump_pgd_entry(pgd_t *pgd,
return note_kasan_page_table(walk, addr);
#endif
+ if (st->effective_prot)
+ st->effective_prot(st, 0, pgd_val(val));
+
if (pgd_leaf(val))
st->note_page(st, addr, 0, pgd_val(val));
@@ -53,6 +56,9 @@ static int ptdump_p4d_entry(p4d_t *p4d,
return note_kasan_page_table(walk, addr);
#endif
+ if (st->effective_prot)
+ st->effective_prot(st, 1, p4d_val(val));
+
if (p4d_leaf(val))
st->note_page(st, addr, 1, p4d_val(val));
@@ -70,6 +76,9 @@ static int ptdump_pud_entry(pud_t *pud,
return note_kasan_page_table(walk, addr);
#endif
+ if (st->effective_prot)
+ st->effective_prot(st, 2, pud_val(val));
+
if (pud_leaf(val))
st->note_page(st, addr, 2, pud_val(val));
@@ -87,6 +96,8 @@ static int ptdump_pmd_entry(pmd_t *pmd,
return note_kasan_page_table(walk, addr);
#endif
+ if (st->effective_prot)
+ st->effective_prot(st, 3, pmd_val(val));
if (pmd_leaf(val))
st->note_page(st, addr, 3, pmd_val(val));
@@ -97,8 +108,12 @@ static int ptdump_pte_entry(pte_t *pte,
unsigned long next, struct mm_walk *walk)
{
struct ptdump_state *st = walk->private;
+ pte_t val = READ_ONCE(*pte);
+
+ if (st->effective_prot)
+ st->effective_prot(st, 4, pte_val(val));
- st->note_page(st, addr, 4, pte_val(READ_ONCE(*pte)));
+ st->note_page(st, addr, 4, pte_val(val));
return 0;
}
_