Skip to content

Commit 0fc7088

Browse files
committed
thunderbolt: Reset USB4 v2 host router
USB4 v2 added a bit that can be used to reset the host router so we use this to trigger reset when the driver probes. This will reset the already connected topology as well but doing this simplifies things a lot if for instance the link is already set to asymmetric. We also add a module parameter to prevent this in case of problems. While there rename the REG_HOP_COUNT to REG_CAPS to match the USB4 spec naming better. Signed-off-by: Mika Westerberg <[email protected]>
1 parent 235d019 commit 0fc7088

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

drivers/thunderbolt/nhi.c

+38-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
#define QUIRK_AUTO_CLEAR_INT BIT(0)
4747
#define QUIRK_E2E BIT(1)
4848

49+
static bool host_reset = true;
50+
module_param(host_reset, bool, 0444);
51+
MODULE_PARM_DESC(host_reset, "reset USBv2 host router (default: true)");
52+
4953
static int ring_interrupt_index(const struct tb_ring *ring)
5054
{
5155
int bit = ring->hop;
@@ -1217,6 +1221,37 @@ static void nhi_check_iommu(struct tb_nhi *nhi)
12171221
str_enabled_disabled(port_ok));
12181222
}
12191223

1224+
static void nhi_reset(struct tb_nhi *nhi)
1225+
{
1226+
ktime_t timeout;
1227+
u32 val;
1228+
1229+
val = ioread32(nhi->iobase + REG_CAPS);
1230+
/* Reset only v2 and later routers */
1231+
if (FIELD_GET(REG_CAPS_VERSION_MASK, val) < REG_CAPS_VERSION_2)
1232+
return;
1233+
1234+
if (!host_reset) {
1235+
dev_dbg(&nhi->pdev->dev, "skipping host router reset\n");
1236+
return;
1237+
}
1238+
1239+
iowrite32(REG_RESET_HRR, nhi->iobase + REG_RESET);
1240+
msleep(100);
1241+
1242+
timeout = ktime_add_ms(ktime_get(), 500);
1243+
do {
1244+
val = ioread32(nhi->iobase + REG_RESET);
1245+
if (!(val & REG_RESET_HRR)) {
1246+
dev_warn(&nhi->pdev->dev, "host router reset successful\n");
1247+
return;
1248+
}
1249+
usleep_range(10, 20);
1250+
} while (ktime_before(ktime_get(), timeout));
1251+
1252+
dev_warn(&nhi->pdev->dev, "timeout resetting host router\n");
1253+
}
1254+
12201255
static int nhi_init_msi(struct tb_nhi *nhi)
12211256
{
12221257
struct pci_dev *pdev = nhi->pdev;
@@ -1317,7 +1352,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
13171352
nhi->ops = (const struct tb_nhi_ops *)id->driver_data;
13181353
/* cannot fail - table is allocated in pcim_iomap_regions */
13191354
nhi->iobase = pcim_iomap_table(pdev)[0];
1320-
nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff;
1355+
nhi->hop_count = ioread32(nhi->iobase + REG_CAPS) & 0x3ff;
13211356
dev_dbg(dev, "total paths: %d\n", nhi->hop_count);
13221357

13231358
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)
13301365
nhi_check_quirks(nhi);
13311366
nhi_check_iommu(nhi);
13321367

1368+
nhi_reset(nhi);
1369+
13331370
res = nhi_init_msi(nhi);
13341371
if (res)
13351372
return dev_err_probe(dev, res, "cannot enable MSI, aborting\n");

drivers/thunderbolt/nhi_regs.h

+12-7
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct ring_desc {
3737
/* NHI registers in bar 0 */
3838

3939
/*
40-
* 16 bytes per entry, one entry for every hop (REG_HOP_COUNT)
40+
* 16 bytes per entry, one entry for every hop (REG_CAPS)
4141
* 00: physical pointer to an array of struct ring_desc
4242
* 08: ring tail (set by NHI)
4343
* 10: ring head (index of first non posted descriptor)
@@ -46,7 +46,7 @@ struct ring_desc {
4646
#define REG_TX_RING_BASE 0x00000
4747

4848
/*
49-
* 16 bytes per entry, one entry for every hop (REG_HOP_COUNT)
49+
* 16 bytes per entry, one entry for every hop (REG_CAPS)
5050
* 00: physical pointer to an array of struct ring_desc
5151
* 08: ring head (index of first not posted descriptor)
5252
* 10: ring tail (set by NHI)
@@ -56,15 +56,15 @@ struct ring_desc {
5656
#define REG_RX_RING_BASE 0x08000
5757

5858
/*
59-
* 32 bytes per entry, one entry for every hop (REG_HOP_COUNT)
59+
* 32 bytes per entry, one entry for every hop (REG_CAPS)
6060
* 00: enum_ring_flags
6161
* 04: isoch time stamp ?? (write 0)
6262
* ..: unknown
6363
*/
6464
#define REG_TX_OPTIONS_BASE 0x19800
6565

6666
/*
67-
* 32 bytes per entry, one entry for every hop (REG_HOP_COUNT)
67+
* 32 bytes per entry, one entry for every hop (REG_CAPS)
6868
* 00: enum ring_flags
6969
* If RING_FLAG_E2E_FLOW_CONTROL is set then bits 13-23 must be set to
7070
* the corresponding TX hop id.
@@ -77,7 +77,7 @@ struct ring_desc {
7777

7878
/*
7979
* three bitfields: tx, rx, rx overflow
80-
* Every bitfield contains one bit for every hop (REG_HOP_COUNT).
80+
* Every bitfield contains one bit for every hop (REG_CAPS).
8181
* New interrupts are fired only after ALL registers have been
8282
* read (even those containing only disabled rings).
8383
*/
@@ -87,7 +87,7 @@ struct ring_desc {
8787

8888
/*
8989
* two bitfields: rx, tx
90-
* Both bitfields contains one bit for every hop (REG_HOP_COUNT). To
90+
* Both bitfields contains one bit for every hop (REG_CAPS). To
9191
* enable/disable interrupts set/clear the corresponding bits.
9292
*/
9393
#define REG_RING_INTERRUPT_BASE 0x38200
@@ -104,12 +104,17 @@ struct ring_desc {
104104
#define REG_INT_VEC_ALLOC_REGS (32 / REG_INT_VEC_ALLOC_BITS)
105105

106106
/* The last 11 bits contain the number of hops supported by the NHI port. */
107-
#define REG_HOP_COUNT 0x39640
107+
#define REG_CAPS 0x39640
108+
#define REG_CAPS_VERSION_MASK GENMASK(23, 16)
109+
#define REG_CAPS_VERSION_2 0x40
108110

109111
#define REG_DMA_MISC 0x39864
110112
#define REG_DMA_MISC_INT_AUTO_CLEAR BIT(2)
111113
#define REG_DMA_MISC_DISABLE_AUTO_CLEAR BIT(17)
112114

115+
#define REG_RESET 0x39898
116+
#define REG_RESET_HRR BIT(0)
117+
113118
#define REG_INMAIL_DATA 0x39900
114119

115120
#define REG_INMAIL_CMD 0x39904

0 commit comments

Comments
 (0)