Merge branch 'pci/reset'

- Add pci_reset_bus_function() Secondary Bus Reset interface (Raphael
  Norwitz)

- Work around Huawei Intelligent NIC VF FLR erratum (Chiqijun)

* pci/reset:
  PCI: Work around Huawei Intelligent NIC VF FLR erratum
  PCI: Add pci_reset_bus_function() Secondary Bus Reset interface
This commit is contained in:
Bjorn Helgaas 2021-07-06 10:56:24 -05:00
commit 76d826c32f
2 changed files with 77 additions and 8 deletions

View File

@ -5020,6 +5020,16 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
}
static int pci_reset_bus_function(struct pci_dev *dev, int probe)
{
int rc;
rc = pci_dev_reset_slot_function(dev, probe);
if (rc != -ENOTTY)
return rc;
return pci_parent_bus_reset(dev, probe);
}
static void pci_dev_lock(struct pci_dev *dev)
{
pci_cfg_access_lock(dev);
@ -5140,10 +5150,7 @@ int __pci_reset_function_locked(struct pci_dev *dev)
rc = pci_pm_reset(dev, 0);
if (rc != -ENOTTY)
return rc;
rc = pci_dev_reset_slot_function(dev, 0);
if (rc != -ENOTTY)
return rc;
return pci_parent_bus_reset(dev, 0);
return pci_reset_bus_function(dev, 0);
}
EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
@ -5173,13 +5180,10 @@ int pci_probe_reset_function(struct pci_dev *dev)
if (rc != -ENOTTY)
return rc;
rc = pci_pm_reset(dev, 1);
if (rc != -ENOTTY)
return rc;
rc = pci_dev_reset_slot_function(dev, 1);
if (rc != -ENOTTY)
return rc;
return pci_parent_bus_reset(dev, 1);
return pci_reset_bus_function(dev, 1);
}
/**

View File

@ -3912,6 +3912,69 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
return 0;
}
#define PCI_DEVICE_ID_HINIC_VF 0x375E
#define HINIC_VF_FLR_TYPE 0x1000
#define HINIC_VF_FLR_CAP_BIT (1UL << 30)
#define HINIC_VF_OP 0xE80
#define HINIC_VF_FLR_PROC_BIT (1UL << 18)
#define HINIC_OPERATION_TIMEOUT 15000 /* 15 seconds */
/* Device-specific reset method for Huawei Intelligent NIC virtual functions */
static int reset_hinic_vf_dev(struct pci_dev *pdev, int probe)
{
unsigned long timeout;
void __iomem *bar;
u32 val;
if (probe)
return 0;
bar = pci_iomap(pdev, 0, 0);
if (!bar)
return -ENOTTY;
/* Get and check firmware capabilities */
val = ioread32be(bar + HINIC_VF_FLR_TYPE);
if (!(val & HINIC_VF_FLR_CAP_BIT)) {
pci_iounmap(pdev, bar);
return -ENOTTY;
}
/* Set HINIC_VF_FLR_PROC_BIT for the start of FLR */
val = ioread32be(bar + HINIC_VF_OP);
val = val | HINIC_VF_FLR_PROC_BIT;
iowrite32be(val, bar + HINIC_VF_OP);
pcie_flr(pdev);
/*
* The device must recapture its Bus and Device Numbers after FLR
* in order generate Completions. Issue a config write to let the
* device capture this information.
*/
pci_write_config_word(pdev, PCI_VENDOR_ID, 0);
/* Firmware clears HINIC_VF_FLR_PROC_BIT when reset is complete */
timeout = jiffies + msecs_to_jiffies(HINIC_OPERATION_TIMEOUT);
do {
val = ioread32be(bar + HINIC_VF_OP);
if (!(val & HINIC_VF_FLR_PROC_BIT))
goto reset_complete;
msleep(20);
} while (time_before(jiffies, timeout));
val = ioread32be(bar + HINIC_VF_OP);
if (!(val & HINIC_VF_FLR_PROC_BIT))
goto reset_complete;
pci_warn(pdev, "Reset dev timeout, FLR ack reg: %#010x\n", val);
reset_complete:
pci_iounmap(pdev, bar);
return 0;
}
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
@ -3924,6 +3987,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, 0x0a54, delay_250ms_after_flr },
{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
reset_chelsio_generic_dev },
{ PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
reset_hinic_vf_dev },
{ 0 }
};