mirror of
https://github.com/torvalds/linux
synced 2024-09-16 00:58:07 +00:00
pci-v6.8-fixes-1
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmW9VMkUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vxvHxAArZVA5jXNLYdqCcygHe4KdXFAJofj N0xt5SIEbFKYFi2FOWcP6S3y8tDe79EqmeEy78jINrBcQoA0nt3y5zbXcaTw/1A1 3GCx3vqNMFsdNOCJWTzgrMF0FRAgWQX5uTHFlR0hoB9iZqpXyMdGZcQi9WyPBpdE wcE/tlcxQ0450U+5Uo4qk+l3Dd6XBuXLMN3lTAcy5aNdbQcMZi6ckZ63l6TVMoz1 aa3aDiiDprS+cSEggcvhlgm9ICB3E9ddMWis3uCXIgjPILlutlh0e+5exwQxzpnA QjQiiNKByY/NeDVqvIE9ElYbokx8NYpbwCwiHK/Vq2DFDbqwqmhCNjrcAZR7Ibyv qA7q4bs6oZYjZ3rA/BgD8crr3kX5gGOL9/nyalDPMSn3ldcVCGdyFhCpsqMHIDEo 7HVeHnJo4G3+2guwpI7N2kak26PwRCgCNe6HpvSHM5jlkfMwpWv5htA+W++K81gI G/ufOn/g3/yhBmf3/Br+Eq6cwattoYkhHE/e8DSbyyYphqoERc1H1p0DvOcZNddT mCMPZ3VoHb9QBLrUC5MJaf/W34qlXJ1ITOEXj0pt6Golou1A12F48MvNpvj2mQfj ti46mirgvDu2vfoQ9ZuEvvLsvXVNhXVaErP3VWroLoGqmGZJenchdwDE4I4Fer29 fBmjjC1kgvq3Yw8= =KA4D -----END PGP SIGNATURE----- Merge tag 'pci-v6.8-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci Pull pci fixes from Bjorn Helgaas: - Fix a potential deadlock that was reintroduced by an ASPM revert merged for v6.8 (Johan Hovold) - Add Manivannan Sadhasivam as PCI Endpoint maintainer (Lorenzo Pieralisi) * tag 'pci-v6.8-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: MAINTAINERS: Add Manivannan Sadhasivam as PCI Endpoint maintainer PCI/ASPM: Fix deadlock when enabling ASPM
This commit is contained in:
commit
b1dd6c26bc
|
@ -16862,9 +16862,8 @@ F: Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
|
|||
F: drivers/pci/controller/pcie-xilinx-cpm.c
|
||||
|
||||
PCI ENDPOINT SUBSYSTEM
|
||||
M: Lorenzo Pieralisi <lpieralisi@kernel.org>
|
||||
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
M: Krzysztof Wilczyński <kw@linux.com>
|
||||
R: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
R: Kishon Vijay Abraham I <kishon@kernel.org>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Supported
|
||||
|
|
|
@ -386,21 +386,8 @@ void pci_bus_add_devices(const struct pci_bus *bus)
|
|||
}
|
||||
EXPORT_SYMBOL(pci_bus_add_devices);
|
||||
|
||||
/** pci_walk_bus - walk devices on/under bus, calling callback.
|
||||
* @top bus whose devices should be walked
|
||||
* @cb callback to be called for each device found
|
||||
* @userdata arbitrary pointer to be passed to callback.
|
||||
*
|
||||
* Walk the given bus, including any bridged devices
|
||||
* on buses under this bus. Call the provided callback
|
||||
* on each device found.
|
||||
*
|
||||
* We check the return of @cb each time. If it returns anything
|
||||
* other than 0, we break out.
|
||||
*
|
||||
*/
|
||||
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata)
|
||||
static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata, bool locked)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus;
|
||||
|
@ -408,7 +395,8 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
|||
int retval;
|
||||
|
||||
bus = top;
|
||||
down_read(&pci_bus_sem);
|
||||
if (!locked)
|
||||
down_read(&pci_bus_sem);
|
||||
next = top->devices.next;
|
||||
for (;;) {
|
||||
if (next == &bus->devices) {
|
||||
|
@ -431,10 +419,37 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
|||
if (retval)
|
||||
break;
|
||||
}
|
||||
up_read(&pci_bus_sem);
|
||||
if (!locked)
|
||||
up_read(&pci_bus_sem);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_walk_bus - walk devices on/under bus, calling callback.
|
||||
* @top: bus whose devices should be walked
|
||||
* @cb: callback to be called for each device found
|
||||
* @userdata: arbitrary pointer to be passed to callback
|
||||
*
|
||||
* Walk the given bus, including any bridged devices
|
||||
* on buses under this bus. Call the provided callback
|
||||
* on each device found.
|
||||
*
|
||||
* We check the return of @cb each time. If it returns anything
|
||||
* other than 0, we break out.
|
||||
*/
|
||||
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
|
||||
{
|
||||
__pci_walk_bus(top, cb, userdata, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_walk_bus);
|
||||
|
||||
void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
|
||||
{
|
||||
lockdep_assert_held(&pci_bus_sem);
|
||||
|
||||
__pci_walk_bus(top, cb, userdata, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_walk_bus_locked);
|
||||
|
||||
struct pci_bus *pci_bus_get(struct pci_bus *bus)
|
||||
{
|
||||
if (bus)
|
||||
|
|
|
@ -972,7 +972,7 @@ static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata)
|
|||
* Downstream devices need to be in D0 state before enabling PCI PM
|
||||
* substates.
|
||||
*/
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_set_power_state_locked(pdev, PCI_D0);
|
||||
pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1354,6 +1354,7 @@ int pci_power_up(struct pci_dev *dev)
|
|||
/**
|
||||
* pci_set_full_power_state - Put a PCI device into D0 and update its state
|
||||
* @dev: PCI device to power up
|
||||
* @locked: whether pci_bus_sem is held
|
||||
*
|
||||
* Call pci_power_up() to put @dev into D0, read from its PCI_PM_CTRL register
|
||||
* to confirm the state change, restore its BARs if they might be lost and
|
||||
|
@ -1363,7 +1364,7 @@ int pci_power_up(struct pci_dev *dev)
|
|||
* to D0, it is more efficient to use pci_power_up() directly instead of this
|
||||
* function.
|
||||
*/
|
||||
static int pci_set_full_power_state(struct pci_dev *dev)
|
||||
static int pci_set_full_power_state(struct pci_dev *dev, bool locked)
|
||||
{
|
||||
u16 pmcsr;
|
||||
int ret;
|
||||
|
@ -1399,7 +1400,7 @@ static int pci_set_full_power_state(struct pci_dev *dev)
|
|||
}
|
||||
|
||||
if (dev->bus->self)
|
||||
pcie_aspm_pm_state_change(dev->bus->self);
|
||||
pcie_aspm_pm_state_change(dev->bus->self, locked);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1428,10 +1429,22 @@ void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
|
|||
pci_walk_bus(bus, __pci_dev_set_current_state, &state);
|
||||
}
|
||||
|
||||
static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state, bool locked)
|
||||
{
|
||||
if (!bus)
|
||||
return;
|
||||
|
||||
if (locked)
|
||||
pci_walk_bus_locked(bus, __pci_dev_set_current_state, &state);
|
||||
else
|
||||
pci_walk_bus(bus, __pci_dev_set_current_state, &state);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_set_low_power_state - Put a PCI device into a low-power state.
|
||||
* @dev: PCI device to handle.
|
||||
* @state: PCI power state (D1, D2, D3hot) to put the device into.
|
||||
* @locked: whether pci_bus_sem is held
|
||||
*
|
||||
* Use the device's PCI_PM_CTRL register to put it into a low-power state.
|
||||
*
|
||||
|
@ -1442,7 +1455,7 @@ void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
|
|||
* 0 if device already is in the requested state.
|
||||
* 0 if device's power state has been successfully changed.
|
||||
*/
|
||||
static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state)
|
||||
static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool locked)
|
||||
{
|
||||
u16 pmcsr;
|
||||
|
||||
|
@ -1496,29 +1509,12 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state)
|
|||
pci_power_name(state));
|
||||
|
||||
if (dev->bus->self)
|
||||
pcie_aspm_pm_state_change(dev->bus->self);
|
||||
pcie_aspm_pm_state_change(dev->bus->self, locked);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_set_power_state - Set the power state of a PCI device
|
||||
* @dev: PCI device to handle.
|
||||
* @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
|
||||
*
|
||||
* Transition a device to a new power state, using the platform firmware and/or
|
||||
* the device's PCI PM registers.
|
||||
*
|
||||
* RETURN VALUE:
|
||||
* -EINVAL if the requested state is invalid.
|
||||
* -EIO if device does not support PCI PM or its PM capabilities register has a
|
||||
* wrong version, or device doesn't support the requested state.
|
||||
* 0 if the transition is to D1 or D2 but D1 and D2 are not supported.
|
||||
* 0 if device already is in the requested state.
|
||||
* 0 if the transition is to D3 but D3 is not supported.
|
||||
* 0 if device's power state has been successfully changed.
|
||||
*/
|
||||
int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||
static int __pci_set_power_state(struct pci_dev *dev, pci_power_t state, bool locked)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
@ -1542,7 +1538,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
|||
return 0;
|
||||
|
||||
if (state == PCI_D0)
|
||||
return pci_set_full_power_state(dev);
|
||||
return pci_set_full_power_state(dev, locked);
|
||||
|
||||
/*
|
||||
* This device is quirked not to be put into D3, so don't put it in
|
||||
|
@ -1556,16 +1552,16 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
|||
* To put the device in D3cold, put it into D3hot in the native
|
||||
* way, then put it into D3cold using platform ops.
|
||||
*/
|
||||
error = pci_set_low_power_state(dev, PCI_D3hot);
|
||||
error = pci_set_low_power_state(dev, PCI_D3hot, locked);
|
||||
|
||||
if (pci_platform_power_transition(dev, PCI_D3cold))
|
||||
return error;
|
||||
|
||||
/* Powering off a bridge may power off the whole hierarchy */
|
||||
if (dev->current_state == PCI_D3cold)
|
||||
pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
|
||||
__pci_bus_set_current_state(dev->subordinate, PCI_D3cold, locked);
|
||||
} else {
|
||||
error = pci_set_low_power_state(dev, state);
|
||||
error = pci_set_low_power_state(dev, state, locked);
|
||||
|
||||
if (pci_platform_power_transition(dev, state))
|
||||
return error;
|
||||
|
@ -1573,8 +1569,38 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_set_power_state - Set the power state of a PCI device
|
||||
* @dev: PCI device to handle.
|
||||
* @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
|
||||
*
|
||||
* Transition a device to a new power state, using the platform firmware and/or
|
||||
* the device's PCI PM registers.
|
||||
*
|
||||
* RETURN VALUE:
|
||||
* -EINVAL if the requested state is invalid.
|
||||
* -EIO if device does not support PCI PM or its PM capabilities register has a
|
||||
* wrong version, or device doesn't support the requested state.
|
||||
* 0 if the transition is to D1 or D2 but D1 and D2 are not supported.
|
||||
* 0 if device already is in the requested state.
|
||||
* 0 if the transition is to D3 but D3 is not supported.
|
||||
* 0 if device's power state has been successfully changed.
|
||||
*/
|
||||
int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||
{
|
||||
return __pci_set_power_state(dev, state, false);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_set_power_state);
|
||||
|
||||
int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state)
|
||||
{
|
||||
lockdep_assert_held(&pci_bus_sem);
|
||||
|
||||
return __pci_set_power_state(dev, state, true);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_set_power_state_locked);
|
||||
|
||||
#define PCI_EXP_SAVE_REGS 7
|
||||
|
||||
static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
|
||||
|
|
|
@ -571,12 +571,12 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt);
|
|||
#ifdef CONFIG_PCIEASPM
|
||||
void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked);
|
||||
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked) { }
|
||||
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1003,8 +1003,11 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
|
|||
up_read(&pci_bus_sem);
|
||||
}
|
||||
|
||||
/* @pdev: the root port or switch downstream port */
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev)
|
||||
/*
|
||||
* @pdev: the root port or switch downstream port
|
||||
* @locked: whether pci_bus_sem is held
|
||||
*/
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked)
|
||||
{
|
||||
struct pcie_link_state *link = pdev->link_state;
|
||||
|
||||
|
@ -1014,12 +1017,14 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
|
|||
* Devices changed PM state, we should recheck if latency
|
||||
* meets all functions' requirement
|
||||
*/
|
||||
down_read(&pci_bus_sem);
|
||||
if (!locked)
|
||||
down_read(&pci_bus_sem);
|
||||
mutex_lock(&aspm_lock);
|
||||
pcie_update_aspm_capable(link->root);
|
||||
pcie_config_aspm_path(link);
|
||||
mutex_unlock(&aspm_lock);
|
||||
up_read(&pci_bus_sem);
|
||||
if (!locked)
|
||||
up_read(&pci_bus_sem);
|
||||
}
|
||||
|
||||
void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
|
||||
|
|
|
@ -1422,6 +1422,7 @@ int pci_load_and_free_saved_state(struct pci_dev *dev,
|
|||
struct pci_saved_state **state);
|
||||
int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state);
|
||||
int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
|
||||
int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state);
|
||||
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
|
||||
bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
|
||||
void pci_pme_active(struct pci_dev *dev, bool enable);
|
||||
|
@ -1625,6 +1626,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
|
|||
|
||||
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata);
|
||||
void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata);
|
||||
int pci_cfg_space_size(struct pci_dev *dev);
|
||||
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
||||
void pci_setup_bridge(struct pci_bus *bus);
|
||||
|
@ -2025,6 +2028,8 @@ static inline int pci_save_state(struct pci_dev *dev) { return 0; }
|
|||
static inline void pci_restore_state(struct pci_dev *dev) { }
|
||||
static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||
{ return 0; }
|
||||
static inline int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state)
|
||||
{ return 0; }
|
||||
static inline int pci_wake_from_d3(struct pci_dev *dev, bool enable)
|
||||
{ return 0; }
|
||||
static inline pci_power_t pci_choose_state(struct pci_dev *dev,
|
||||
|
|
Loading…
Reference in a new issue