summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 09:59:34 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 09:59:34 -0700
commit07281a257a6868b900da5de1eda808c9e20253f1 (patch)
treed27ca47d0c6a7f4aec24c8da4768deb4121cd64b /drivers/thunderbolt
parent7c314bdfb64e4bb8d2f829376ed56ce663483752 (diff)
parent9c1587d99f9305aa4f10b47fcf1981012aa5381f (diff)
Merge tag 'usb-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH: "Here is the big set of USB and Thunderbolt patches for 5.15-rc1. Nothing huge in here, just lots of constant forward progress on a number of different drivers and hardware support: - more USB 4/Thunderbolt support added - dwc3 driver updates and additions - usb gadget fixes and addtions for new types - udc gadget driver updates - host controller updates - removal of obsolete drivers - other minor driver updates All of these have been in linux-next for a while with no reported issues" * tag 'usb-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (148 commits) usb: isp1760: otg control register access usb: isp1760: use the right irq status bit usb: isp1760: write to status and address register usb: isp1760: fix qtd fill length usb: isp1760: fix memory pool initialization usb: typec: tcpm: Fix spelling mistake "atleast" -> "at least" usb: dwc2: Fix spelling mistake "was't" -> "wasn't" usb: renesas_usbhs: Fix spelling mistake "faile" -> "failed" usb: host: xhci-rcar: Don't reload firmware after the completion usb: xhci-mtk: allow bandwidth table rollover usb: mtu3: fix random remote wakeup usb: mtu3: return successful suspend status usb: xhci-mtk: Do not use xhci's virt_dev in drop_endpoint usb: xhci-mtk: modify the SOF/ITP interval for mt8195 usb: xhci-mtk: add a member of num_esit usb: xhci-mtk: check boundary before check tt usb: xhci-mtk: update fs bus bandwidth by bw_budget_table usb: xhci-mtk: fix issue of out-of-bounds array access usb: xhci-mtk: support option to disable usb2 ports usb: xhci-mtk: fix use-after-free of mtk->hcd ...
Diffstat (limited to 'drivers/thunderbolt')
-rw-r--r--drivers/thunderbolt/nhi.c46
-rw-r--r--drivers/thunderbolt/switch.c28
2 files changed, 57 insertions, 17 deletions
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index fa44332845a1..c73da0532be4 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -35,6 +35,8 @@
#define NHI_MAILBOX_TIMEOUT 500 /* ms */
+#define QUIRK_AUTO_CLEAR_INT BIT(0)
+
static int ring_interrupt_index(struct tb_ring *ring)
{
int bit = ring->hop;
@@ -66,14 +68,17 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active)
else
index = ring->hop + ring->nhi->hop_count;
- /*
- * Ask the hardware to clear interrupt status bits automatically
- * since we already know which interrupt was triggered.
- */
- misc = ioread32(ring->nhi->iobase + REG_DMA_MISC);
- if (!(misc & REG_DMA_MISC_INT_AUTO_CLEAR)) {
- misc |= REG_DMA_MISC_INT_AUTO_CLEAR;
- iowrite32(misc, ring->nhi->iobase + REG_DMA_MISC);
+ if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT) {
+ /*
+ * Ask the hardware to clear interrupt status
+ * bits automatically since we already know
+ * which interrupt was triggered.
+ */
+ misc = ioread32(ring->nhi->iobase + REG_DMA_MISC);
+ if (!(misc & REG_DMA_MISC_INT_AUTO_CLEAR)) {
+ misc |= REG_DMA_MISC_INT_AUTO_CLEAR;
+ iowrite32(misc, ring->nhi->iobase + REG_DMA_MISC);
+ }
}
ivr_base = ring->nhi->iobase + REG_INT_VEC_ALLOC_BASE;
@@ -377,11 +382,24 @@ void tb_ring_poll_complete(struct tb_ring *ring)
}
EXPORT_SYMBOL_GPL(tb_ring_poll_complete);
+static void ring_clear_msix(const struct tb_ring *ring)
+{
+ if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT)
+ return;
+
+ if (ring->is_tx)
+ ioread32(ring->nhi->iobase + REG_RING_NOTIFY_BASE);
+ else
+ ioread32(ring->nhi->iobase + REG_RING_NOTIFY_BASE +
+ 4 * (ring->nhi->hop_count / 32));
+}
+
static irqreturn_t ring_msix(int irq, void *data)
{
struct tb_ring *ring = data;
spin_lock(&ring->nhi->lock);
+ ring_clear_msix(ring);
spin_lock(&ring->lock);
__ring_interrupt(ring);
spin_unlock(&ring->lock);
@@ -1074,6 +1092,16 @@ static void nhi_shutdown(struct tb_nhi *nhi)
nhi->ops->shutdown(nhi);
}
+static void nhi_check_quirks(struct tb_nhi *nhi)
+{
+ /*
+ * Intel hardware supports auto clear of the interrupt status
+ * reqister right after interrupt is being issued.
+ */
+ if (nhi->pdev->vendor == PCI_VENDOR_ID_INTEL)
+ nhi->quirks |= QUIRK_AUTO_CLEAR_INT;
+}
+
static int nhi_init_msi(struct tb_nhi *nhi)
{
struct pci_dev *pdev = nhi->pdev;
@@ -1190,6 +1218,8 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!nhi->tx_rings || !nhi->rx_rings)
return -ENOMEM;
+ nhi_check_quirks(nhi);
+
res = nhi_init_msi(nhi);
if (res) {
dev_err(&pdev->dev, "cannot enable MSI, aborting\n");
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 10d6b228cc94..3014146081c1 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -724,6 +724,12 @@ static int tb_init_port(struct tb_port *port)
int res;
int cap;
+ INIT_LIST_HEAD(&port->list);
+
+ /* Control adapter does not have configuration space */
+ if (!port->port)
+ return 0;
+
res = tb_port_read(port, &port->config, TB_CFG_PORT, 0, 8);
if (res) {
if (res == -ENODEV) {
@@ -736,7 +742,7 @@ static int tb_init_port(struct tb_port *port)
}
/* Port 0 is the switch itself and has no PHY. */
- if (port->config.type == TB_TYPE_PORT && port->port != 0) {
+ if (port->config.type == TB_TYPE_PORT) {
cap = tb_port_find_cap(port, TB_PORT_CAP_PHY);
if (cap > 0)
@@ -762,7 +768,7 @@ static int tb_init_port(struct tb_port *port)
if (!port->ctl_credits)
port->ctl_credits = 2;
- } else if (port->port != 0) {
+ } else {
cap = tb_port_find_cap(port, TB_PORT_CAP_ADAP);
if (cap > 0)
port->cap_adap = cap;
@@ -773,10 +779,7 @@ static int tb_init_port(struct tb_port *port)
ADP_CS_4_TOTAL_BUFFERS_SHIFT;
tb_dump_port(port->sw->tb, port);
-
- INIT_LIST_HEAD(&port->list);
return 0;
-
}
static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid,
@@ -1498,6 +1501,7 @@ static ssize_t authorized_show(struct device *dev,
static int disapprove_switch(struct device *dev, void *not_used)
{
+ char *envp[] = { "AUTHORIZED=0", NULL };
struct tb_switch *sw;
sw = tb_to_switch(dev);
@@ -1514,7 +1518,7 @@ static int disapprove_switch(struct device *dev, void *not_used)
return ret;
sw->authorized = 0;
- kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE);
+ kobject_uevent_env(&sw->dev.kobj, KOBJ_CHANGE, envp);
}
return 0;
@@ -1522,7 +1526,9 @@ static int disapprove_switch(struct device *dev, void *not_used)
static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
{
+ char envp_string[13];
int ret = -EINVAL;
+ char *envp[] = { envp_string, NULL };
if (!mutex_trylock(&sw->tb->lock))
return restart_syscall();
@@ -1559,8 +1565,12 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
if (!ret) {
sw->authorized = val;
- /* Notify status change to the userspace */
- kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE);
+ /*
+ * Notify status change to the userspace, informing the new
+ * value of /sys/bus/thunderbolt/devices/.../authorized.
+ */
+ sprintf(envp_string, "AUTHORIZED=%u", sw->authorized);
+ kobject_uevent_env(&sw->dev.kobj, KOBJ_CHANGE, envp);
}
unlock:
@@ -2443,7 +2453,7 @@ static void tb_switch_default_link_ports(struct tb_switch *sw)
{
int i;
- for (i = 1; i <= sw->config.max_port_number; i += 2) {
+ for (i = 1; i <= sw->config.max_port_number; i++) {
struct tb_port *port = &sw->ports[i];
struct tb_port *subordinate;