diff options
Diffstat (limited to 'drivers/thunderbolt/nhi.c')
-rw-r--r-- | drivers/thunderbolt/nhi.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index e58beac44295..4b7bec74e89f 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -46,6 +46,10 @@ #define QUIRK_AUTO_CLEAR_INT BIT(0) #define QUIRK_E2E BIT(1) +static bool host_reset = true; +module_param(host_reset, bool, 0444); +MODULE_PARM_DESC(host_reset, "reset USBv2 host router (default: true)"); + static int ring_interrupt_index(const struct tb_ring *ring) { int bit = ring->hop; @@ -1217,6 +1221,37 @@ static void nhi_check_iommu(struct tb_nhi *nhi) str_enabled_disabled(port_ok)); } +static void nhi_reset(struct tb_nhi *nhi) +{ + ktime_t timeout; + u32 val; + + val = ioread32(nhi->iobase + REG_CAPS); + /* Reset only v2 and later routers */ + if (FIELD_GET(REG_CAPS_VERSION_MASK, val) < REG_CAPS_VERSION_2) + return; + + if (!host_reset) { + dev_dbg(&nhi->pdev->dev, "skipping host router reset\n"); + return; + } + + iowrite32(REG_RESET_HRR, nhi->iobase + REG_RESET); + msleep(100); + + timeout = ktime_add_ms(ktime_get(), 500); + do { + val = ioread32(nhi->iobase + REG_RESET); + if (!(val & REG_RESET_HRR)) { + dev_warn(&nhi->pdev->dev, "host router reset successful\n"); + return; + } + usleep_range(10, 20); + } while (ktime_before(ktime_get(), timeout)); + + dev_warn(&nhi->pdev->dev, "timeout resetting host router\n"); +} + static int nhi_init_msi(struct tb_nhi *nhi) { struct pci_dev *pdev = nhi->pdev; @@ -1317,7 +1352,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) nhi->ops = (const struct tb_nhi_ops *)id->driver_data; /* cannot fail - table is allocated in pcim_iomap_regions */ nhi->iobase = pcim_iomap_table(pdev)[0]; - nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff; + nhi->hop_count = ioread32(nhi->iobase + REG_CAPS) & 0x3ff; dev_dbg(dev, "total paths: %d\n", nhi->hop_count); nhi->tx_rings = devm_kcalloc(&pdev->dev, nhi->hop_count, @@ -1330,6 +1365,8 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) nhi_check_quirks(nhi); nhi_check_iommu(nhi); + nhi_reset(nhi); + res = nhi_init_msi(nhi); if (res) return dev_err_probe(dev, res, "cannot enable MSI, aborting\n"); @@ -1480,6 +1517,8 @@ static struct pci_device_id nhi_ids[] = { .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI) }, /* Any USB4 compliant host */ { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) }, @@ -1488,6 +1527,7 @@ static struct pci_device_id nhi_ids[] = { }; MODULE_DEVICE_TABLE(pci, nhi_ids); +MODULE_DESCRIPTION("Thunderbolt/USB4 core driver"); MODULE_LICENSE("GPL"); static struct pci_driver nhi_driver = { |