summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2023-09-21 10:58:03 +0200
committerJohannes Berg <johannes.berg@intel.com>2023-09-25 09:14:59 +0200
commit54d1e8b27e8652c369d0e70eda3ea38b97836c1d (patch)
tree2a69b98bdfd1f9365bdd2c8c80ba024eb5aefe11 /drivers/net/wireless/intel/iwlwifi/pcie/trans.c
parentwifi: iwlwifi: implement enable/disable for China 2022 regulatory (diff)
downloadlinux-54d1e8b27e8652c369d0e70eda3ea38b97836c1d.tar.xz
linux-54d1e8b27e8652c369d0e70eda3ea38b97836c1d.zip
wifi: iwlwifi: pcie: (re-)assign BAR0 on driver bind
There's a race with runtime PM getting enabled by userspace: - we rescan the PCI bus - this creates the new PCI device including its sysfs representation - udev sees the new device, and the (OS-specific?) scripting enables runtime PM by writing to power/control; this can happen _before_ the next step - this will runtime-suspend the device which saves the config space, including the BAR0 that wasn't assigned yet - the bus rescan assigns resources to the devices and writes them to the config space of the device (but not the runtime-pm saved copy) - the driver binds and this disallows runtime PM, so the device is resumed, restoring the (incomplete!) config space - the driver cannot work due to BAR0 not being configured Fixing the actual race is hard and deep in the PCI layer, though probably should be done for upstream as well; perhaps runtime PM should only be allowed after resource assignment, or some other TBD way. Work around this in the driver for now by simply (re-)assigning BAR0 when the driver initializes, if it's unset. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Gregory Greenman <gregory.greenman@intel.com> Link: https://lore.kernel.org/r/20230921110726.5f5f782a4e97.I4b7bf5c52ba44a8c7f9878009021689bbfa9c5ef@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/pcie/trans.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 849ea1851508..5020ae4493c6 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -3610,10 +3610,19 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
int ret, addr_size;
const struct iwl_trans_ops *ops = &trans_ops_pcie_gen2;
void __iomem * const *table;
+ u32 bar0;
if (!cfg_trans->gen2)
ops = &trans_ops_pcie;
+ /* reassign our BAR 0 if invalid due to possible runtime PM races */
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0);
+ if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ ret = pci_assign_resource(pdev, 0);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
ret = pcim_enable_device(pdev);
if (ret)
return ERR_PTR(ret);