<feed xmlns='http://www.w3.org/2005/Atom'>
<title>kernel/drivers/pci/hotplug/pciehp_pci.c, branch linux-6.5.y</title>
<subtitle>Hosts the 0x221E linux distro kernel.</subtitle>
<id>https://universe.0xinfinity.dev/distro/kernel/atom?h=linux-6.5.y</id>
<link rel='self' href='https://universe.0xinfinity.dev/distro/kernel/atom?h=linux-6.5.y'/>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/'/>
<updated>2023-04-11T18:18:30Z</updated>
<entry>
<title>PCI: pciehp: Fix AB-BA deadlock between reset_lock and device_lock</title>
<updated>2023-04-11T18:18:30Z</updated>
<author>
<name>Lukas Wunner</name>
<email>lukas@wunner.de</email>
</author>
<published>2023-04-11T06:21:02Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=f5eff5591b8f9c5effd25c92c758a127765f74c1'/>
<id>urn:sha1:f5eff5591b8f9c5effd25c92c758a127765f74c1</id>
<content type='text'>
In 2013, commits

  2e35afaefe64 ("PCI: pciehp: Add reset_slot() method")
  608c388122c7 ("PCI: Add slot reset option to pci_dev_reset()")

amended PCIe hotplug to mask Presence Detect Changed events during a
Secondary Bus Reset.  The reset thus no longer causes gratuitous slot
bringdown and bringup.

However the commits neglected to serialize reset with code paths reading
slot registers.  For instance, a slot bringup due to an earlier hotplug
event may see the Presence Detect State bit cleared during a concurrent
Secondary Bus Reset.

In 2018, commit

  5b3f7b7d062b ("PCI: pciehp: Avoid slot access during reset")

retrofitted the missing locking.  It introduced a reset_lock which
serializes a Secondary Bus Reset with other parts of pciehp.

Unfortunately the locking turns out to be overzealous:  reset_lock is
held for the entire enumeration and de-enumeration of hotplugged devices,
including driver binding and unbinding.

Driver binding and unbinding acquires device_lock while the reset_lock
of the ancestral hotplug port is held.  A concurrent Secondary Bus Reset
acquires the ancestral reset_lock while already holding the device_lock.
The asymmetric locking order in the two code paths can lead to AB-BA
deadlocks.

Michael Haeuptle reports such deadlocks on simultaneous hot-removal and
vfio release (the latter implies a Secondary Bus Reset):

  pciehp_ist()                                    # down_read(reset_lock)
    pciehp_handle_presence_or_link_change()
      pciehp_disable_slot()
        __pciehp_disable_slot()
          remove_board()
            pciehp_unconfigure_device()
              pci_stop_and_remove_bus_device()
                pci_stop_bus_device()
                  pci_stop_dev()
                    device_release_driver()
                      device_release_driver_internal()
                        __device_driver_lock()    # device_lock()

  SYS_munmap()
    vfio_device_fops_release()
      vfio_device_group_close()
        vfio_device_close()
          vfio_device_last_close()
            vfio_pci_core_close_device()
              vfio_pci_core_disable()             # device_lock()
                __pci_reset_function_locked()
                  pci_reset_bus_function()
                    pci_dev_reset_slot_function()
                      pci_reset_hotplug_slot()
                        pciehp_reset_slot()       # down_write(reset_lock)

Ian May reports the same deadlock on simultaneous hot-removal and an
AER-induced Secondary Bus Reset:

  aer_recover_work_func()
    pcie_do_recovery()
      aer_root_reset()
        pci_bus_error_reset()
          pci_slot_reset()
            pci_slot_lock()                       # device_lock()
            pci_reset_hotplug_slot()
              pciehp_reset_slot()                 # down_write(reset_lock)

Fix by releasing the reset_lock during driver binding and unbinding,
thereby splitting and shrinking the critical section.

Driver binding and unbinding is protected by the device_lock() and thus
serialized with a Secondary Bus Reset.  There's no need to additionally
protect it with the reset_lock.  However, pciehp does not bind and
unbind devices directly, but rather invokes PCI core functions which
also perform certain enumeration and de-enumeration steps.

The reset_lock's purpose is to protect slot registers, not enumeration
and de-enumeration of hotplugged devices.  That would arguably be the
job of the PCI core, not the PCIe hotplug driver.  After all, an
AER-induced Secondary Bus Reset may as well happen during boot-time
enumeration of the PCI hierarchy and there's no locking to prevent that
either.

Exempting *de-enumeration* from the reset_lock is relatively harmless:
A concurrent Secondary Bus Reset may foil config space accesses such as
PME interrupt disablement.  But if the device is physically gone, those
accesses are pointless anyway.  If the device is physically present and
only logically removed through an Attention Button press or the sysfs
"power" attribute, PME interrupts as well as DMA cannot come through
because pciehp_unconfigure_device() disables INTx and Bus Master bits.
That's still protected by the reset_lock in the present commit.

Exempting *enumeration* from the reset_lock also has limited impact:
The exempted call to pci_bus_add_device() may perform device accesses
through pcibios_bus_add_device() and pci_fixup_device() which are now
no longer protected from a concurrent Secondary Bus Reset.  Otherwise
there should be no impact.

In essence, the present commit seeks to fix the AB-BA deadlocks while
still retaining a best-effort reset protection for enumeration and
de-enumeration of hotplugged devices -- until a general solution is
implemented in the PCI core.

Link: https://lore.kernel.org/linux-pci/CS1PR8401MB0728FC6FDAB8A35C22BD90EC95F10@CS1PR8401MB0728.NAMPRD84.PROD.OUTLOOK.COM
Link: https://lore.kernel.org/linux-pci/20200615143250.438252-1-ian.may@canonical.com
Link: https://lore.kernel.org/linux-pci/ce878dab-c0c4-5bd0-a725-9805a075682d@amd.com
Link: https://lore.kernel.org/linux-pci/ed831249-384a-6d35-0831-70af191e9bce@huawei.com
Link: https://bugzilla.kernel.org/show_bug.cgi?id=215590
Fixes: 5b3f7b7d062b ("PCI: pciehp: Avoid slot access during reset")
Link: https://lore.kernel.org/r/fef2b2e9edf245c049a8c5b94743c0f74ff5008a.1681191902.git.lukas@wunner.de
Reported-by: Michael Haeuptle &lt;michael.haeuptle@hpe.com&gt;
Reported-by: Ian May &lt;ian.may@canonical.com&gt;
Reported-by: Andrey Grodzovsky &lt;andrey2805@gmail.com&gt;
Reported-by: Rahul Kumar &lt;rahul.kumar1@amd.com&gt;
Reported-by: Jialin Zhang &lt;zhangjialin11@huawei.com&gt;
Tested-by: Anatoli Antonovitch &lt;Anatoli.Antonovitch@amd.com&gt;
Signed-off-by: Lukas Wunner &lt;lukas@wunner.de&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;
Cc: stable@vger.kernel.org # v4.19+
Cc: Dan Stein &lt;dstein@hpe.com&gt;
Cc: Ashok Raj &lt;ashok.raj@intel.com&gt;
Cc: Alex Michon &lt;amichon@kalrayinc.com&gt;
Cc: Xiongfeng Wang &lt;wangxiongfeng2@huawei.com&gt;
Cc: Alex Williamson &lt;alex.williamson@redhat.com&gt;
Cc: Mika Westerberg &lt;mika.westerberg@linux.intel.com&gt;
Cc: Sathyanarayanan Kuppuswamy &lt;sathyanarayanan.kuppuswamy@linux.intel.com&gt;
</content>
</entry>
<entry>
<title>PCI: pciehp: Log messages with pci_dev, not pcie_device</title>
<updated>2019-05-09T21:45:20Z</updated>
<author>
<name>Frederick Lawler</name>
<email>fred@fredlawl.com</email>
</author>
<published>2019-05-07T23:24:51Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=94dbc9562edc745d0549f1744ca1bd75e644473e'/>
<id>urn:sha1:94dbc9562edc745d0549f1744ca1bd75e644473e</id>
<content type='text'>
Log messages with pci_dev, not pcie_device.  Factor out common message
prefixes with dev_fmt().

Example output change:

  - pciehp 0000:00:06.0:pcie004: Slot(0) Powering on due to button press
  + pcieport 0000:00:06.0: pciehp: Slot(0) Powering on due to button press

Link: https://lore.kernel.org/lkml/20190509141456.223614-8-helgaas@kernel.org
Signed-off-by: Frederick Lawler &lt;fred@fredlawl.com&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;
Reviewed-by: Keith Busch &lt;keith.busch@intel.com&gt;
Reviewed-by: Andy Shevchenko &lt;andy.shevchenko@gmail.com&gt;
</content>
</entry>
<entry>
<title>PCI: pciehp: Unify controller and slot structs</title>
<updated>2018-09-18T22:52:15Z</updated>
<author>
<name>Lukas Wunner</name>
<email>lukas@wunner.de</email>
</author>
<published>2018-09-18T19:46:17Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=5790a9c78e78aa2c35bb7439bee434301dff004c'/>
<id>urn:sha1:5790a9c78e78aa2c35bb7439bee434301dff004c</id>
<content type='text'>
pciehp was originally introduced together with shpchp in a single
commit, c16b4b14d980 ("PCI Hotplug: Add SHPC and PCI Express hot-plug
drivers"):
https://git.kernel.org/tglx/history/c/c16b4b14d980

shpchp supports up to 31 slots per controller, hence uses separate slot
and controller structs.  pciehp has a 1:1 relationship between slot and
controller and therefore never required this separation.  Nevertheless,
because much of the code had been copy-pasted between the two drivers,
pciehp likewise uses separate structs to this very day.

The artificial separation of data structures adds unnecessary complexity
and bloat to pciehp and requires constantly chasing pointers at runtime.

Simplify the driver by merging struct slot into struct controller.
Merge the slot constructor pcie_init_slot() and the destructor
pcie_cleanup_slot() into the controller counterparts.

No functional change intended.

Signed-off-by: Lukas Wunner &lt;lukas@wunner.de&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;</content>
</entry>
<entry>
<title>PCI: pciehp: Drop unnecessary includes</title>
<updated>2018-09-17T21:34:36Z</updated>
<author>
<name>Lukas Wunner</name>
<email>lukas@wunner.de</email>
</author>
<published>2018-08-19T14:29:00Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=7d4ba52317c4aab6bbb266f31e28713d397e570c'/>
<id>urn:sha1:7d4ba52317c4aab6bbb266f31e28713d397e570c</id>
<content type='text'>
Drop the following includes from pciehp source files which no longer use
any of the included symbols:

* &lt;linux/sched/signal.h&gt; in pciehp.h
  &lt;linux/signal.h&gt; in pciehp_hpc.c
  Added by commit de25968cc87c ("fix more missing includes") to
  accommodate for a call to signal_pending().
  The call was removed by commit 262303fe329a ("pciehp: fix wait command
  completion").

* &lt;linux/interrupt.h&gt; in pciehp_core.c
  Added by historic commit f308a2dfbe63 ("PCI: add PCI Express Port Bus
  Driver subsystem") to accommodate for a call to free_irq():
  https://git.kernel.org/tglx/history/c/f308a2dfbe63
  The call was removed by commit 407f452b05f9 ("pciehp: remove
  unnecessary free_irq").

* &lt;linux/time.h&gt; in pciehp_core.c and pciehp_hpc.c
  Added by commit 34d03419f03b ("PCIEHP: Add Electro Mechanical
  Interlock (EMI) support to the PCIE hotplug driver."),
  which was reverted by commit bd3d99c17039 ("PCI: Remove untested
  Electromechanical Interlock (EMI) support in pciehp.").

* &lt;linux/module.h&gt; in pciehp_ctrl.c, pciehp_hpc.c and pciehp_pci.c
  Added by historic commit c16b4b14d980 ("PCI Hotplug: Add SHPC and PCI
  Express hot-plug drivers"):
  https://git.kernel.org/tglx/history/c/c16b4b14d980
  Module-related symbols were neither used back then in those files,
  nor are they used today.

* &lt;linux/slab.h&gt; in pciehp_ctrl.c
  Added by commit 5a0e3ad6af86 ("include cleanup: Update gfp.h and
  slab.h includes to prepare for breaking implicit slab.h inclusion from
  percpu.h") to accommodate for calls to kmalloc().
  The calls were removed by commit 0e94916e6091 ("PCI: pciehp: Handle
  events synchronously").

* "../pci.h" in pciehp_ctrl.c
  Added by historic commit 67f4660b72f2 ("PCI: ASPM patch for") to
  accommodate for usage of the global variable pcie_mch_quirk:
  https://git.kernel.org/tglx/history/c/67f4660b72f2
  The global variable was removed by commit 0ba379ec0fb1 ("PCI: Simplify
  hotplug mch quirk").

Signed-off-by: Lukas Wunner &lt;lukas@wunner.de&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;</content>
</entry>
<entry>
<title>PCI: pciehp: Differentiate between surprise and safe removal</title>
<updated>2018-09-17T21:34:35Z</updated>
<author>
<name>Lukas Wunner</name>
<email>lukas@wunner.de</email>
</author>
<published>2018-07-31T05:50:37Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=11e87702be65780be92fb1f0a5b7b293954185f7'/>
<id>urn:sha1:11e87702be65780be92fb1f0a5b7b293954185f7</id>
<content type='text'>
When removing PCI devices below a hotplug bridge, pciehp marks them as
disconnected if the card is no longer present in the slot or it quiesces
them if the card is still present (by disabling INTx interrupts, bus
mastering and SERR# reporting).

To detect whether the card is still present, pciehp checks the Presence
Detect State bit in the Slot Status register.  The problem with this
approach is that even if the card is present, the link to it may be
down, and it that case it would be better to mark the devices as
disconnected instead of trying to quiesce them.  Moreover, if the card
in the slot was quickly replaced by another one, the Presence Detect
State bit would be set, yet trying to quiesce the new card's devices
would be wrong and the correct thing to do is to mark the previous
card's devices as disconnected.

Instead of looking at the Presence Detect State bit, it is better to
differentiate whether the card was surprise removed versus safely
removed (via sysfs or an Attention Button press).  On surprise removal,
the devices should be marked as disconnected, whereas on safe removal it
is correct to quiesce the devices.

The knowledge whether a surprise removal or a safe removal is at hand
does exist further up in the call stack:  A surprise removal is
initiated by pciehp_handle_presence_or_link_change(), a safe removal by
pciehp_handle_disable_request().

Pass that information down to pciehp_unconfigure_device() and use it in
lieu of the Presence Detect State bit.  While there, add kernel-doc to
pciehp_unconfigure_device() and pciehp_configure_device().

Tested-by: Alexandru Gagniuc &lt;mr.nuke.me@gmail.com&gt;
Signed-off-by: Lukas Wunner &lt;lukas@wunner.de&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;
Cc: Keith Busch &lt;keith.busch@intel.com&gt;</content>
</entry>
<entry>
<title>PCI: Simplify disconnected marking</title>
<updated>2018-09-17T21:34:35Z</updated>
<author>
<name>Lukas Wunner</name>
<email>lukas@wunner.de</email>
</author>
<published>2018-08-19T14:29:00Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=a50ac6bfd6042b16e0de4ac3264c407e678c9b10'/>
<id>urn:sha1:a50ac6bfd6042b16e0de4ac3264c407e678c9b10</id>
<content type='text'>
Commit 89ee9f768003 ("PCI: Add device disconnected state") iterates over
the devices on a parent bus, marks each as disconnected, then marks
each device's children as disconnected using pci_walk_bus().

The same can be achieved more succinctly by calling pci_walk_bus() on
the parent bus.  Moreover, this does not need to wait until acquiring
pci_lock_rescan_remove(), so move it out of that critical section.

The critical section in err.c contains a pci_dev_get() / pci_dev_put()
pair which was apparently copy-pasted from pciehp_pci.c.  In the latter
it serves the purpose of holding the struct pci_dev in place until the
Command register is updated.  err.c doesn't do anything like that, hence
the pair is unnecessary.  Remove it.

Signed-off-by: Lukas Wunner &lt;lukas@wunner.de&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;
Cc: Keith Busch &lt;keith.busch@intel.com&gt;
Cc: Oza Pawandeep &lt;poza@codeaurora.org&gt;
Cc: Sinan Kaya &lt;okaya@kernel.org&gt;
Cc: Benjamin Herrenschmidt &lt;benh@kernel.crashing.org&gt;</content>
</entry>
<entry>
<title>PCI: pciehp: Declare pciehp_unconfigure_device() void</title>
<updated>2018-07-23T22:04:11Z</updated>
<author>
<name>Lukas Wunner</name>
<email>lukas@wunner.de</email>
</author>
<published>2018-07-19T22:27:36Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=1d2e2673dc5b9b374513fd58d5909f0332b47407'/>
<id>urn:sha1:1d2e2673dc5b9b374513fd58d5909f0332b47407</id>
<content type='text'>
Since commit 0f4bd8014db5 ("PCI: hotplug: Drop checking of PCI_BRIDGE_
CONTROL in *_unconfigure_device()"), pciehp_unconfigure_device() can no
longer fail, so declare it and its sole caller remove_board() void, in
keeping with the usual kernel pattern that enablement can fail, but
disablement cannot.  No functional change intended.

Signed-off-by: Lukas Wunner &lt;lukas@wunner.de&gt;
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;
Cc: Mika Westerberg &lt;mika.westerberg@linux.intel.com&gt;
</content>
</entry>
<entry>
<title>Merge branch 'pci/spdx' into next</title>
<updated>2018-02-01T17:40:07Z</updated>
<author>
<name>Bjorn Helgaas</name>
<email>bhelgaas@google.com</email>
</author>
<published>2018-02-01T17:40:07Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=ab8c609356fbe8dbcd44df11e884ce8cddf3739e'/>
<id>urn:sha1:ab8c609356fbe8dbcd44df11e884ce8cddf3739e</id>
<content type='text'>
* pci/spdx:
  PCI: Add SPDX GPL-2.0+ to replace implicit GPL v2 or later statement
  PCI: Add SPDX GPL-2.0+ to replace GPL v2 or later boilerplate
  PCI: Add SPDX GPL-2.0 to replace COPYING boilerplate
  PCI: Add SPDX GPL-2.0 to replace GPL v2 boilerplate
  PCI: Add SPDX GPL-2.0 when no license was specified
</content>
</entry>
<entry>
<title>PCI: Add SPDX GPL-2.0+ to replace GPL v2 or later boilerplate</title>
<updated>2018-01-28T21:49:06Z</updated>
<author>
<name>Bjorn Helgaas</name>
<email>bhelgaas@google.com</email>
</author>
<published>2018-01-26T20:22:04Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=736759ef59d86a7bcefb1cdb629abecafc645a46'/>
<id>urn:sha1:736759ef59d86a7bcefb1cdb629abecafc645a46</id>
<content type='text'>
Add SPDX GPL-2.0+ to all PCI files that specified the GPL and allowed
either GPL version 2 or any later version.

Remove the boilerplate GPL version 2 or later language, relying on the
assertion in b24413180f56 ("License cleanup: add SPDX GPL-2.0 license
identifier to files with no license") that the SPDX identifier may be used
instead of the full boilerplate text.

Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;
Reviewed-by: Greg Kroah-Hartman &lt;gregkh@linuxfoundation.org&gt;</content>
</entry>
<entry>
<title>PCI: hotplug: Drop checking of PCI_BRIDGE_CONTROL in *_unconfigure_device()</title>
<updated>2017-12-19T05:05:18Z</updated>
<author>
<name>Mika Westerberg</name>
<email>mika.westerberg@linux.intel.com</email>
</author>
<published>2017-11-09T11:15:08Z</published>
<link rel='alternate' type='text/html' href='https://universe.0xinfinity.dev/distro/kernel/commit/?id=0f4bd8014db515999493baaa75d506cc8026c462'/>
<id>urn:sha1:0f4bd8014db515999493baaa75d506cc8026c462</id>
<content type='text'>
When removing a bridge, pciehp_unconfigure_device() reads the
PCI_BRIDGE_CONTROL byte.  If this is a surprise hot-unplug, the device is
already gone and the read returns ~0, which pciehp_unconfigure_device()
interprets as having PCI_BRIDGE_CTL_VGA set.  This results in failure of
the remove operation:

  pciehp 0000:00:1c.0:pcie004: Slot(0): Link Down
  pciehp 0000:00:1c.0:pcie004: Slot(0): Card present
  pciehp 0000:00:1c.0:pcie004: Cannot remove display device 0000:01:00.0

Because of this the hierarchy is left untouched preventing further hotplug
operations.

Now, it is not clear why the check is there in the first place and why we
would like to prevent removing a bridge if it has PCI_BRIDGE_CTL_VGA set.
In case of PCIe surprise hot-unplug, it would not even be possible to
prevent the removal.

Given this and the issue described above, I think it makes sense to drop
the whole PCI_BRIDGE_CONTROL check from pciehp_unconfigure_device().  While
there do the same for shpchp_configure_device() based on the same reasoning
and the fact that the same bug might trigger in standard PCI hotplug as
well.

Signed-off-by: Mika Westerberg &lt;mika.westerberg@linux.intel.com&gt;
[bhelgaas: changelog]
Signed-off-by: Bjorn Helgaas &lt;bhelgaas@google.com&gt;</content>
</entry>
</feed>
