Processing SDIO interrupts while dw_mmc is suspended (or partly
suspended) seems like a bad idea. We really don't want to be
processing them until we've gotten ourselves fully powered up.
You might be wondering how it's even possible to become suspended when
an SDIO interrupt is active. As can be seen in
dw_mci_enable_sdio_irq(), we explicitly keep dw_mmc out of runtime
suspend when the SDIO interrupt is enabled. ...but even though we
stop normal runtime suspend transitions when SDIO interrupts are
enabled, the dw_mci_runtime_suspend() can still get called for a full
system suspend.
Let's handle all this by explicitly masking SDIO interrupts in the
suspend call and unmasking them later in the resume call. To do this
cleanly I'll keep track of whether the client requested that SDIO
interrupts be enabled so that we can reliably restore them regardless
of whether we're masking them for one reason or another.
It should be noted that if dw_mci_enable_sdio_irq() is never called
(for instance, if we don't have an SDIO card plugged in) that
"client_sdio_enb" will always be false. In those cases this patch
adds a tiny bit of overhead to suspend/resume (a spinlock and a
read/write of INTMASK) but other than that is a no-op. The
SDMMC_INT_SDIO bit should always be clear and clearing it again won't
hurt.
Without this fix it can be seen that rk3288-veyron Chromebooks with
Marvell WiFi would sometimes fail to resume WiFi even after picking my
recent mwifiex patch [1]. Specifically you'd see messages like this:
mwifiex_sdio mmc1:0001:1: Firmware wakeup failed
mwifiex_sdio mmc1:0001:1: PREP_CMD: FW in reset state
...and tracing through the resume code in the failing cases showed
that we were processing a SDIO interrupt really early in the resume
call.
NOTE: downstream in Chrome OS 3.14 and 3.18 kernels (both of which
support the Marvell SDIO WiFi card) we had a patch ("CHROMIUM: sdio:
Defer SDIO interrupt handling until after resume") [2]. Presumably
this is the same problem that was solved by that patch.
[1] https://lkml.kernel.org/r/20190404040106.40519-1-dianders@chromium.org
[2] https://crrev.com/c/230765
Cc: <stable(a)vger.kernel.org> # 4.14.x
Signed-off-by: Douglas Anderson <dianders(a)chromium.org>
---
I didn't put any "Fixes" tag here, but presumably this could be
backported to whichever kernels folks found it useful for. I have at
least confirmed that kernels v4.14 and v4.19 (as well as v5.1-rc2)
show the problem. It is very easy to pick this to v4.19 and it
definitely fixes the problem there.
I haven't spent the time to pick this to 4.14 myself, but presumably
it wouldn't be too hard to backport this as far as v4.13 since that
contains commit 32dba73772f8 ("mmc: dw_mmc: Convert to use
MMC_CAP2_SDIO_IRQ_NOTHREAD for SDIO IRQs"). Prior to that it might
make sense for anyone experiencing this problem to just pick the old
CHROMIUM patch to fix them.
Changes in v2:
- Suggested 4.14+ in the stable tag (Sasha-bot)
- Extra note that this is a noop on non-SDIO (Shawn / Emil)
- Make boolean logic cleaner as per https://crrev.com/c/1586207/1
- Hopefully clear comments as per https://crrev.com/c/1586207/1
drivers/mmc/host/dw_mmc.c | 27 +++++++++++++++++++++++----
drivers/mmc/host/dw_mmc.h | 3 +++
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 80dc2fd6576c..480067b87a94 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1664,7 +1664,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
}
}
-static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
+static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, bool enb,
+ bool client_requested)
{
struct dw_mci *host = slot->host;
unsigned long irqflags;
@@ -1672,6 +1673,20 @@ static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
spin_lock_irqsave(&host->irq_lock, irqflags);
+ /*
+ * If we're being called directly from dw_mci_enable_sdio_irq()
+ * (which means that the client driver actually wants to enable or
+ * disable interrupts) then save the request. Otherwise this
+ * wasn't directly requested by the client and we should logically
+ * AND it with the client request since we want to disable if
+ * _either_ the client disabled OR we have some other reason to
+ * disable temporarily.
+ */
+ if (client_requested)
+ host->client_sdio_enb = enb;
+ else
+ enb &= host->client_sdio_enb;
+
/* Enable/disable Slot Specific SDIO interrupt */
int_mask = mci_readl(host, INTMASK);
if (enb)
@@ -1688,7 +1703,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
- __dw_mci_enable_sdio_irq(slot, enb);
+ __dw_mci_enable_sdio_irq(slot, enb, true);
/* Avoid runtime suspending the device when SDIO IRQ is enabled */
if (enb)
@@ -1701,7 +1716,7 @@ static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
- __dw_mci_enable_sdio_irq(slot, 1);
+ __dw_mci_enable_sdio_irq(slot, true, false);
}
static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
@@ -2734,7 +2749,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
mci_writel(host, RINTSTS,
SDMMC_INT_SDIO(slot->sdio_id));
- __dw_mci_enable_sdio_irq(slot, 0);
+ __dw_mci_enable_sdio_irq(slot, false, false);
sdio_signal_irq(slot->mmc);
}
@@ -3424,6 +3439,8 @@ int dw_mci_runtime_suspend(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
+ __dw_mci_enable_sdio_irq(host->slot, false, false);
+
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
@@ -3490,6 +3507,8 @@ int dw_mci_runtime_resume(struct device *dev)
/* Now that slots are all setup, we can enable card detect */
dw_mci_enable_cd(host);
+ __dw_mci_enable_sdio_irq(host->slot, true, false);
+
return 0;
err:
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 46e9f8ec5398..dfbace0f5043 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -127,6 +127,7 @@ struct dw_mci_dma_slave {
* @cmd11_timer: Timer for SD3.0 voltage switch over scheme.
* @cto_timer: Timer for broken command transfer over scheme.
* @dto_timer: Timer for broken data transfer over scheme.
+ * @client_sdio_enb: The value last passed to enable_sdio_irq.
*
* Locking
* =======
@@ -234,6 +235,8 @@ struct dw_mci {
struct timer_list cmd11_timer;
struct timer_list cto_timer;
struct timer_list dto_timer;
+
+ bool client_sdio_enb;
};
/* DMA ops for Internal/External DMAC interface */
--
2.21.0.593.g511ec345e18-goog
In the case of a normal sync update, the preparation of framebuffers (be
it calling drm_atomic_helper_prepare_planes() or doing setups with
drm_framebuffer_get()) are performed in the new_state and the respective
cleanups are performed in the old_state.
In the case of async updates, the preparation is also done in the
new_state but the cleanups are done in the new_state (because updates
are performed in place, i.e. in the current state).
The current code blocks async udpates when the fb is changed, turning
async updates into sync updates, slowing down cursor updates and
introducing regressions in igt tests with errors of type:
"CRITICAL: completed 97 cursor updated in a period of 30 flips, we
expect to complete approximately 15360 updates, with the threshold set
at 7680"
Fb changes in async updates were prevented to avoid the following scenario:
- Async update, oldfb = NULL, newfb = fb1, prepare fb1, cleanup fb1
- Async update, oldfb = fb1, newfb = fb2, prepare fb2, cleanup fb2
- Non-async commit, oldfb = fb2, newfb = fb1, prepare fb1, cleanup fb2 (wrong)
Where we have a single call to prepare fb2 but double cleanup call to fb2.
To solve the above problems, instead of blocking async fb changes, we
place the old framebuffer in the new_state object, so when the code
performs cleanups in the new_state it will cleanup the old_fb and we
will have the following scenario instead:
- Async update, oldfb = NULL, newfb = fb1, prepare fb1, no cleanup
- Async update, oldfb = fb1, newfb = fb2, prepare fb2, cleanup fb1
- Non-async commit, oldfb = fb2, newfb = fb1, prepare fb1, cleanup fb2
Where calls to prepare/cleanup are balanced.
Cc: <stable(a)vger.kernel.org> # v4.14+
Fixes: 25dc194b34dd ("drm: Block fb changes for async plane updates")
Suggested-by: Boris Brezillon <boris.brezillon(a)collabora.com>
Signed-off-by: Helen Koike <helen.koike(a)collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon(a)collabora.com>
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas(a)amd.com>
---
Hello,
I added a TODO in drm_atomic_helper_async_commit() regarding doing a
full state swap(), Boris and Nicholas, let me know if this is ok and if
I can keep your Reviewed-by tags)
As mentioned in the cover letter, I tested in almost all platforms with
igt plane_cursor_legacy and kms_cursor_legacy and I didn't see any
regressions. But I couldn't test on MSM and AMD because I don't have
the hardware I would appreciate if anyone could help me testing those.
Thanks!
Helen
Changes in v3:
- Add Reviewed-by tags
- Add TODO in drm_atomic_helper_async_commit()
Changes in v2:
- Change the order of the patch in the series, add this as the last one.
- Add documentation
- s/ballanced/balanced
drivers/gpu/drm/drm_atomic_helper.c | 22 ++++++++++++----------
include/drm/drm_modeset_helper_vtables.h | 5 +++++
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2453678d1186..de5812c362b5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1608,15 +1608,6 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
old_plane_state->crtc != new_plane_state->crtc)
return -EINVAL;
- /*
- * FIXME: Since prepare_fb and cleanup_fb are always called on
- * the new_plane_state for async updates we need to block framebuffer
- * changes. This prevents use of a fb that's been cleaned up and
- * double cleanups from occuring.
- */
- if (old_plane_state->fb != new_plane_state->fb)
- return -EINVAL;
-
funcs = plane->helper_private;
if (!funcs->atomic_async_update)
return -EINVAL;
@@ -1647,6 +1638,8 @@ EXPORT_SYMBOL(drm_atomic_helper_async_check);
* drm_atomic_async_check() succeeds. Async commits are not supposed to swap
* the states like normal sync commits, but just do in-place changes on the
* current state.
+ *
+ * TODO: Implement full swap instead of doing in-place changes.
*/
void drm_atomic_helper_async_commit(struct drm_device *dev,
struct drm_atomic_state *state)
@@ -1657,6 +1650,9 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
int i;
for_each_new_plane_in_state(state, plane, plane_state, i) {
+ struct drm_framebuffer *new_fb = plane_state->fb;
+ struct drm_framebuffer *old_fb = plane->state->fb;
+
funcs = plane->helper_private;
funcs->atomic_async_update(plane, plane_state);
@@ -1665,11 +1661,17 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
* plane->state in-place, make sure at least common
* properties have been properly updated.
*/
- WARN_ON_ONCE(plane->state->fb != plane_state->fb);
+ WARN_ON_ONCE(plane->state->fb != new_fb);
WARN_ON_ONCE(plane->state->crtc_x != plane_state->crtc_x);
WARN_ON_ONCE(plane->state->crtc_y != plane_state->crtc_y);
WARN_ON_ONCE(plane->state->src_x != plane_state->src_x);
WARN_ON_ONCE(plane->state->src_y != plane_state->src_y);
+
+ /*
+ * Make sure the FBs have been swapped so that cleanups in the
+ * new_state performs a cleanup in the old FB.
+ */
+ WARN_ON_ONCE(plane_state->fb != old_fb);
}
}
EXPORT_SYMBOL(drm_atomic_helper_async_commit);
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index cfb7be40bed7..ce582e8e8f2f 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1174,6 +1174,11 @@ struct drm_plane_helper_funcs {
* current one with the new plane configurations in the new
* plane_state.
*
+ * Drivers should also swap the framebuffers between plane state
+ * and new_state. This is required because prepare and cleanup calls
+ * are performed on the new_state object, then to cleanup the old
+ * framebuffer, it needs to be placed inside the new_state object.
+ *
* FIXME:
* - It only works for single plane updates
* - Async Pageflips are not supported yet
--
2.20.1
Async update callbacks are expected to set the old_fb in the new_state
so prepare/cleanup framebuffers are balanced.
Cc: <stable(a)vger.kernel.org> # v4.14+
Fixes: 224a4c970987 ("drm/msm: update cursors asynchronously through atomic")
Suggested-by: Boris Brezillon <boris.brezillon(a)collabora.com>
Signed-off-by: Helen Koike <helen.koike(a)collabora.com>
---
Hello,
As mentioned in the cover letter,
But I couldn't test on MSM because I don't have the hardware and I would
appreciate if anyone could test it.
In other platforms (VC4, AMD, Rockchip), there is a hidden
drm_framebuffer_get(new_fb)/drm_framebuffer_put(old_fb) in async_update
that is wrong, but I couldn't identify those here, not sure if it is hidden
somewhere else, but if tests fail this is probably the cause.
Thanks!
Helen
Changes in v3: None
Changes in v2:
- update CC stable and Fixes tag
drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
index be13140967b4..b854f471e9e5 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -502,6 +502,8 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
+ struct drm_framebuffer *old_fb = plane->state->fb;
+
plane->state->src_x = new_state->src_x;
plane->state->src_y = new_state->src_y;
plane->state->crtc_x = new_state->crtc_x;
@@ -524,6 +526,8 @@ static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
*to_mdp5_plane_state(plane->state) =
*to_mdp5_plane_state(new_state);
+
+ new_state->fb = old_fb;
}
static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
--
2.20.1
On Thu, Apr 18, 2019 at 4:39 PM Gilad Ben-Yossef <gilad(a)benyossef.com> wrote:
>
> A set of new features, mostly support for CryptoCell 713
> features including protected keys, security disable mode and
> new HW revision indetification interface alongside many bug fixes.
FYI,
A port of those patches from this patch series which have been marked
for stable is available at
https://github.com/gby/linux/tree/4.19-ccree
Gilad
--
Gilad Ben-Yossef
Chief Coffee Drinker
values of β will give rise to dom!
Commit 37f9579f4c31 ("blk-mq: Avoid that submitting a bio concurrently
with device removal triggers a crash") introduced a NULL pointer
dereference in generic_make_request(). The patch sets q to NULL and
enter_succeeded to false; right after, there's an 'if (enter_succeeded)'
which is not taken, and then the 'else' will dereference q in
blk_queue_dying(q).
This patch just moves the 'q = NULL' to a point in which it won't trigger
the oops, although the semantics of this NULLification remains untouched.
A simple test case/reproducer is as follows:
a) Build kernel v5.1-rc7 with CONFIG_BLK_CGROUP=n.
b) Create a raid0 md array with 2 NVMe devices as members, and mount it
with an ext4 filesystem.
c) Run the following oneliner (supposing the raid0 is mounted in /mnt):
(dd of=/mnt/tmp if=/dev/zero bs=1M count=999 &); sleep 0.3;
echo 1 > /sys/block/nvme0n1/device/device/remove
(whereas nvme0n1 is the 2nd array member)
This will trigger the following oops:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000078
PGD 0 P4D 0
Oops: 0000 [#1] SMP PTI
RIP: 0010:generic_make_request+0x32b/0x400
Call Trace:
submit_bio+0x73/0x140
ext4_io_submit+0x4d/0x60
ext4_writepages+0x626/0xe90
do_writepages+0x4b/0xe0
[...]
This patch has no functional changes and preserves the md/raid0 behavior
when a member is removed before kernel v4.17.
Cc: Bart Van Assche <bvanassche(a)acm.org>
Cc: stable(a)vger.kernel.org # v4.17
Fixes: 37f9579f4c31 ("blk-mq: Avoid that submitting a bio concurrently with device removal triggers a crash")
Signed-off-by: Guilherme G. Piccoli <gpiccoli(a)canonical.com>
---
block/blk-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index a55389ba8779..e21856a7f3fa 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1076,7 +1076,6 @@ blk_qc_t generic_make_request(struct bio *bio)
flags = BLK_MQ_REQ_NOWAIT;
if (blk_queue_enter(q, flags) < 0) {
enter_succeeded = false;
- q = NULL;
}
}
@@ -1108,6 +1107,7 @@ blk_qc_t generic_make_request(struct bio *bio)
bio_wouldblock_error(bio);
else
bio_io_error(bio);
+ q = NULL;
}
bio = bio_list_pop(&bio_list_on_stack[0]);
} while (bio);
--
2.21.0
From: Jason Gerecke <jason.gerecke(a)wacom.com>
The serial number and tool type information that is reported by the tablet
while a pen is merely "in prox" instead of fully "in range" can be stale
and cause us to report incorrect tool information. Serial number, tool
type, and other information is only valid once the pen comes fully in range
so we should be careful to not use this information until that point.
In particular, this issue may cause the driver to incorectly report
BTN_TOOL_RUBBER after switching from the eraser tool back to the pen.
Fixes: a48324de6d ("HID: wacom: Bluetooth IRQ for Intuos Pro should handle prox/range")
Cc: <stable(a)vger.kernel.org> # 4.11+
Signed-off-by: Jason Gerecke <jason.gerecke(a)wacom.com>
Reviewed-by: Aaron Armstrong Skomra <aaron.skomra(a)wacom.com>
---
drivers/hid/wacom_wac.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 747730d32ab6..4c1bc239207e 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1236,13 +1236,13 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
/* Add back in missing bits of ID for non-USI pens */
wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
}
- wacom->tool[0] = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0]));
for (i = 0; i < pen_frames; i++) {
unsigned char *frame = &data[i*pen_frame_len + 1];
bool valid = frame[0] & 0x80;
bool prox = frame[0] & 0x40;
bool range = frame[0] & 0x20;
+ bool invert = frame[0] & 0x10;
if (!valid)
continue;
@@ -1251,9 +1251,24 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
wacom->shared->stylus_in_proximity = false;
wacom_exit_report(wacom);
input_sync(pen_input);
+
+ wacom->tool[0] = 0;
+ wacom->id[0] = 0;
+ wacom->serial[0] = 0;
return;
}
+
if (range) {
+ if (!wacom->tool[0]) { /* first in range */
+ /* Going into range select tool */
+ if (invert)
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ else if (wacom->id[0])
+ wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0]);
+ else
+ wacom->tool[0] = BTN_TOOL_PEN;
+ }
+
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
--
2.21.0
On Mon, 29 Apr 2019 16:01:29 +1000
Alexey Kardashevskiy <aik(a)ozlabs.ru> wrote:
> On 20/04/2019 01:34, Greg Kurz wrote:
> > Since 902bdc57451c, get_pci_dev() calls pci_get_domain_bus_and_slot(). This
> > has the effect of incrementing the reference count of the PCI device, as
> > explained in drivers/pci/search.c:
> >
> > * Given a PCI domain, bus, and slot/function number, the desired PCI
> > * device is located in the list of PCI devices. If the device is
> > * found, its reference count is increased and this function returns a
> > * pointer to its data structure. The caller must decrement the
> > * reference count by calling pci_dev_put(). If no device is found,
> > * %NULL is returned.
> >
> > Nothing was done to call pci_dev_put() and the reference count of GPU and
> > NPU PCI devices rockets up.
> >
> > A natural way to fix this would be to teach the callers about the change,
> > so that they call pci_dev_put() when done with the pointer. This turns
> > out to be quite intrusive, as it affects many paths in npu-dma.c,
> > pci-ioda.c and vfio_pci_nvlink2.c.
>
>
> afaict this referencing is only done to protect the current traverser
> and what you've done is actually a natural way (and the generic
> pci_get_dev_by_id() does exactly the same), although this looks a bit weird.
>
Not exactly the same: pci_get_dev_by_id() always increment the refcount
of the returned PCI device. The refcount is only decremented when this
device is passed to pci_get_dev_by_id() to continue searching.
That means that the users of the PCI device pointer returned by
pci_get_dev_by_id() or its exported variants pci_get_subsys(),
pci_get_device() and pci_get_class() do handle the refcount. They
all pass the pointer to pci_dev_put() or continue the search,
which calls pci_dev_put() internally.
Direct and indirect callers of get_pci_dev() don't care for the
refcount at all unless I'm missing something.
>
> > Also, the issue appeared in 4.16 and
> > some affected code got moved around since then: it would be problematic
> > to backport the fix to stable releases.
> >
> > All that code never cared for reference counting anyway. Call pci_dev_put()
> > from get_pci_dev() to revert to the previous behavior.
> >> Fixes: 902bdc57451c ("powerpc/powernv/idoa: Remove unnecessary pcidev
> from pci_dn")
> > Cc: stable(a)vger.kernel.org # v4.16
> > Signed-off-by: Greg Kurz <groug(a)kaod.org>
> > ---
> > arch/powerpc/platforms/powernv/npu-dma.c | 15 ++++++++++++++-
> > 1 file changed, 14 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
> > index e713ade30087..d8f3647e8fb2 100644
> > --- a/arch/powerpc/platforms/powernv/npu-dma.c
> > +++ b/arch/powerpc/platforms/powernv/npu-dma.c
> > @@ -31,9 +31,22 @@ static DEFINE_SPINLOCK(npu_context_lock);
> > static struct pci_dev *get_pci_dev(struct device_node *dn)
> > {
> > struct pci_dn *pdn = PCI_DN(dn);
> > + struct pci_dev *pdev;
> >
> > - return pci_get_domain_bus_and_slot(pci_domain_nr(pdn->phb->bus),
> > + pdev = pci_get_domain_bus_and_slot(pci_domain_nr(pdn->phb->bus),
> > pdn->busno, pdn->devfn);
> > +
> > + /*
> > + * pci_get_domain_bus_and_slot() increased the reference count of
> > + * the PCI device, but callers don't need that actually as the PE
> > + * already holds a reference to the device.
>
> Imho this would be just enough.
>
> Anyway,
>
> Reviewed-by: Alexey Kardashevskiy <aik(a)ozlabs.ru>
>
Thanks !
I now realize that I forgot to add the --cc option for stable on my stgit
command line :-\.
Cc'ing now.
>
> How did you find it? :)
>
While reading code to find some inspiration for OpenCAPI passthrough. :)
I saw the following in vfio_pci_ibm_npu2_init():
if (!pnv_pci_get_gpu_dev(vdev->pdev))
return -ENODEV;
and simply followed the function calls.
>
> > Since callers aren't
> > + * aware of the reference count change, call pci_dev_put() now to
> > + * avoid leaks.
> > + */
> > + if (pdev)
> > + pci_dev_put(pdev);
> > +
> > + return pdev;
> > }
> >
> > /* Given a NPU device get the associated PCI device. */
> >
>