Skip to content

Commit ce00322

Browse files
Chiqijunbjorn-helgaas
authored andcommitted
PCI: Work around Huawei Intelligent NIC VF FLR erratum
pcie_flr() starts a Function Level Reset (FLR), waits 100ms (the maximum time allowed for FLR completion by PCIe r5.0, sec 6.6.2), and waits for the FLR to complete. It assumes the FLR is complete when a config read returns valid data. When we do an FLR on several Huawei Intelligent NIC VFs at the same time, firmware on the NIC processes them serially. The VF may respond to config reads before the firmware has completed its reset processing. If we bind a driver to the VF (e.g., by assigning the VF to a virtual machine) in the interval between the successful config read and completion of the firmware reset processing, the NIC VF driver may fail to load. Prevent this driver failure by waiting for the NIC firmware to complete its reset processing. Not all NIC firmware supports this feature. [bhelgaas: commit log] Link: https://support.huawei.com/enterprise/en/doc/EDOC1100063073/87950645/vm-oss-occasionally-fail-to-load-the-in200-driver-when-the-vf-performs-flr Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Chiqijun <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Alex Williamson <[email protected]> Cc: [email protected]
1 parent 4c207e7 commit ce00322

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

drivers/pci/quirks.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3923,6 +3923,69 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
39233923
return 0;
39243924
}
39253925

3926+
#define PCI_DEVICE_ID_HINIC_VF 0x375E
3927+
#define HINIC_VF_FLR_TYPE 0x1000
3928+
#define HINIC_VF_FLR_CAP_BIT (1UL << 30)
3929+
#define HINIC_VF_OP 0xE80
3930+
#define HINIC_VF_FLR_PROC_BIT (1UL << 18)
3931+
#define HINIC_OPERATION_TIMEOUT 15000 /* 15 seconds */
3932+
3933+
/* Device-specific reset method for Huawei Intelligent NIC virtual functions */
3934+
static int reset_hinic_vf_dev(struct pci_dev *pdev, int probe)
3935+
{
3936+
unsigned long timeout;
3937+
void __iomem *bar;
3938+
u32 val;
3939+
3940+
if (probe)
3941+
return 0;
3942+
3943+
bar = pci_iomap(pdev, 0, 0);
3944+
if (!bar)
3945+
return -ENOTTY;
3946+
3947+
/* Get and check firmware capabilities */
3948+
val = ioread32be(bar + HINIC_VF_FLR_TYPE);
3949+
if (!(val & HINIC_VF_FLR_CAP_BIT)) {
3950+
pci_iounmap(pdev, bar);
3951+
return -ENOTTY;
3952+
}
3953+
3954+
/* Set HINIC_VF_FLR_PROC_BIT for the start of FLR */
3955+
val = ioread32be(bar + HINIC_VF_OP);
3956+
val = val | HINIC_VF_FLR_PROC_BIT;
3957+
iowrite32be(val, bar + HINIC_VF_OP);
3958+
3959+
pcie_flr(pdev);
3960+
3961+
/*
3962+
* The device must recapture its Bus and Device Numbers after FLR
3963+
* in order generate Completions. Issue a config write to let the
3964+
* device capture this information.
3965+
*/
3966+
pci_write_config_word(pdev, PCI_VENDOR_ID, 0);
3967+
3968+
/* Firmware clears HINIC_VF_FLR_PROC_BIT when reset is complete */
3969+
timeout = jiffies + msecs_to_jiffies(HINIC_OPERATION_TIMEOUT);
3970+
do {
3971+
val = ioread32be(bar + HINIC_VF_OP);
3972+
if (!(val & HINIC_VF_FLR_PROC_BIT))
3973+
goto reset_complete;
3974+
msleep(20);
3975+
} while (time_before(jiffies, timeout));
3976+
3977+
val = ioread32be(bar + HINIC_VF_OP);
3978+
if (!(val & HINIC_VF_FLR_PROC_BIT))
3979+
goto reset_complete;
3980+
3981+
pci_warn(pdev, "Reset dev timeout, FLR ack reg: %#010x\n", val);
3982+
3983+
reset_complete:
3984+
pci_iounmap(pdev, bar);
3985+
3986+
return 0;
3987+
}
3988+
39263989
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
39273990
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
39283991
reset_intel_82599_sfp_virtfn },
@@ -3935,6 +3998,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
39353998
{ PCI_VENDOR_ID_INTEL, 0x0a54, delay_250ms_after_flr },
39363999
{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
39374000
reset_chelsio_generic_dev },
4001+
{ PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
4002+
reset_hinic_vf_dev },
39384003
{ 0 }
39394004
};
39404005

0 commit comments

Comments
 (0)