162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Thunderbolt driver - NHI driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * The NHI (native host interface) is the pci device that allows us to send and
662306a36Sopenharmony_ci * receive frames from the thunderbolt bus.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
962306a36Sopenharmony_ci * Copyright (C) 2018, Intel Corporation
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/iommu.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/delay.h>
2162306a36Sopenharmony_ci#include <linux/property.h>
2262306a36Sopenharmony_ci#include <linux/string_helpers.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "nhi.h"
2562306a36Sopenharmony_ci#include "nhi_regs.h"
2662306a36Sopenharmony_ci#include "tb.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define RING_TYPE(ring) ((ring)->is_tx ? "TX ring" : "RX ring")
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define RING_FIRST_USABLE_HOPID	1
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * Used with QUIRK_E2E to specify an unused HopID the Rx credits are
3362306a36Sopenharmony_ci * transferred.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci#define RING_E2E_RESERVED_HOPID	RING_FIRST_USABLE_HOPID
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Minimal number of vectors when we use MSI-X. Two for control channel
3862306a36Sopenharmony_ci * Rx/Tx and the rest four are for cross domain DMA paths.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci#define MSIX_MIN_VECS		6
4162306a36Sopenharmony_ci#define MSIX_MAX_VECS		16
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define NHI_MAILBOX_TIMEOUT	500 /* ms */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Host interface quirks */
4662306a36Sopenharmony_ci#define QUIRK_AUTO_CLEAR_INT	BIT(0)
4762306a36Sopenharmony_ci#define QUIRK_E2E		BIT(1)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic bool host_reset = true;
5062306a36Sopenharmony_cimodule_param(host_reset, bool, 0444);
5162306a36Sopenharmony_ciMODULE_PARM_DESC(host_reset, "reset USBv2 host router (default: true)");
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int ring_interrupt_index(const struct tb_ring *ring)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	int bit = ring->hop;
5662306a36Sopenharmony_ci	if (!ring->is_tx)
5762306a36Sopenharmony_ci		bit += ring->nhi->hop_count;
5862306a36Sopenharmony_ci	return bit;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void nhi_mask_interrupt(struct tb_nhi *nhi, int mask, int ring)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	if (nhi->quirks & QUIRK_AUTO_CLEAR_INT) {
6462306a36Sopenharmony_ci		u32 val;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		val = ioread32(nhi->iobase + REG_RING_INTERRUPT_BASE + ring);
6762306a36Sopenharmony_ci		iowrite32(val & ~mask, nhi->iobase + REG_RING_INTERRUPT_BASE + ring);
6862306a36Sopenharmony_ci	} else {
6962306a36Sopenharmony_ci		iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring);
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void nhi_clear_interrupt(struct tb_nhi *nhi, int ring)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	if (nhi->quirks & QUIRK_AUTO_CLEAR_INT)
7662306a36Sopenharmony_ci		ioread32(nhi->iobase + REG_RING_NOTIFY_BASE + ring);
7762306a36Sopenharmony_ci	else
7862306a36Sopenharmony_ci		iowrite32(~0, nhi->iobase + REG_RING_INT_CLEAR + ring);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/*
8262306a36Sopenharmony_ci * ring_interrupt_active() - activate/deactivate interrupts for a single ring
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * ring->nhi->lock must be held.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic void ring_interrupt_active(struct tb_ring *ring, bool active)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	int index = ring_interrupt_index(ring) / 32 * 4;
8962306a36Sopenharmony_ci	int reg = REG_RING_INTERRUPT_BASE + index;
9062306a36Sopenharmony_ci	int interrupt_bit = ring_interrupt_index(ring) & 31;
9162306a36Sopenharmony_ci	int mask = 1 << interrupt_bit;
9262306a36Sopenharmony_ci	u32 old, new;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (ring->irq > 0) {
9562306a36Sopenharmony_ci		u32 step, shift, ivr, misc;
9662306a36Sopenharmony_ci		void __iomem *ivr_base;
9762306a36Sopenharmony_ci		int auto_clear_bit;
9862306a36Sopenharmony_ci		int index;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		if (ring->is_tx)
10162306a36Sopenharmony_ci			index = ring->hop;
10262306a36Sopenharmony_ci		else
10362306a36Sopenharmony_ci			index = ring->hop + ring->nhi->hop_count;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		/*
10662306a36Sopenharmony_ci		 * Intel routers support a bit that isn't part of
10762306a36Sopenharmony_ci		 * the USB4 spec to ask the hardware to clear
10862306a36Sopenharmony_ci		 * interrupt status bits automatically since
10962306a36Sopenharmony_ci		 * we already know which interrupt was triggered.
11062306a36Sopenharmony_ci		 *
11162306a36Sopenharmony_ci		 * Other routers explicitly disable auto-clear
11262306a36Sopenharmony_ci		 * to prevent conditions that may occur where two
11362306a36Sopenharmony_ci		 * MSIX interrupts are simultaneously active and
11462306a36Sopenharmony_ci		 * reading the register clears both of them.
11562306a36Sopenharmony_ci		 */
11662306a36Sopenharmony_ci		misc = ioread32(ring->nhi->iobase + REG_DMA_MISC);
11762306a36Sopenharmony_ci		if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT)
11862306a36Sopenharmony_ci			auto_clear_bit = REG_DMA_MISC_INT_AUTO_CLEAR;
11962306a36Sopenharmony_ci		else
12062306a36Sopenharmony_ci			auto_clear_bit = REG_DMA_MISC_DISABLE_AUTO_CLEAR;
12162306a36Sopenharmony_ci		if (!(misc & auto_clear_bit))
12262306a36Sopenharmony_ci			iowrite32(misc | auto_clear_bit,
12362306a36Sopenharmony_ci				  ring->nhi->iobase + REG_DMA_MISC);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		ivr_base = ring->nhi->iobase + REG_INT_VEC_ALLOC_BASE;
12662306a36Sopenharmony_ci		step = index / REG_INT_VEC_ALLOC_REGS * REG_INT_VEC_ALLOC_BITS;
12762306a36Sopenharmony_ci		shift = index % REG_INT_VEC_ALLOC_REGS * REG_INT_VEC_ALLOC_BITS;
12862306a36Sopenharmony_ci		ivr = ioread32(ivr_base + step);
12962306a36Sopenharmony_ci		ivr &= ~(REG_INT_VEC_ALLOC_MASK << shift);
13062306a36Sopenharmony_ci		if (active)
13162306a36Sopenharmony_ci			ivr |= ring->vector << shift;
13262306a36Sopenharmony_ci		iowrite32(ivr, ivr_base + step);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	old = ioread32(ring->nhi->iobase + reg);
13662306a36Sopenharmony_ci	if (active)
13762306a36Sopenharmony_ci		new = old | mask;
13862306a36Sopenharmony_ci	else
13962306a36Sopenharmony_ci		new = old & ~mask;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	dev_dbg(&ring->nhi->pdev->dev,
14262306a36Sopenharmony_ci		"%s interrupt at register %#x bit %d (%#x -> %#x)\n",
14362306a36Sopenharmony_ci		active ? "enabling" : "disabling", reg, interrupt_bit, old, new);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (new == old)
14662306a36Sopenharmony_ci		dev_WARN(&ring->nhi->pdev->dev,
14762306a36Sopenharmony_ci					 "interrupt for %s %d is already %s\n",
14862306a36Sopenharmony_ci					 RING_TYPE(ring), ring->hop,
14962306a36Sopenharmony_ci					 active ? "enabled" : "disabled");
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (active)
15262306a36Sopenharmony_ci		iowrite32(new, ring->nhi->iobase + reg);
15362306a36Sopenharmony_ci	else
15462306a36Sopenharmony_ci		nhi_mask_interrupt(ring->nhi, mask, index);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/*
15862306a36Sopenharmony_ci * nhi_disable_interrupts() - disable interrupts for all rings
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci * Use only during init and shutdown.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_cistatic void nhi_disable_interrupts(struct tb_nhi *nhi)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int i = 0;
16562306a36Sopenharmony_ci	/* disable interrupts */
16662306a36Sopenharmony_ci	for (i = 0; i < RING_INTERRUPT_REG_COUNT(nhi); i++)
16762306a36Sopenharmony_ci		nhi_mask_interrupt(nhi, ~0, 4 * i);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* clear interrupt status bits */
17062306a36Sopenharmony_ci	for (i = 0; i < RING_NOTIFY_REG_COUNT(nhi); i++)
17162306a36Sopenharmony_ci		nhi_clear_interrupt(nhi, 4 * i);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/* ring helper methods */
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic void __iomem *ring_desc_base(struct tb_ring *ring)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	void __iomem *io = ring->nhi->iobase;
17962306a36Sopenharmony_ci	io += ring->is_tx ? REG_TX_RING_BASE : REG_RX_RING_BASE;
18062306a36Sopenharmony_ci	io += ring->hop * 16;
18162306a36Sopenharmony_ci	return io;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void __iomem *ring_options_base(struct tb_ring *ring)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	void __iomem *io = ring->nhi->iobase;
18762306a36Sopenharmony_ci	io += ring->is_tx ? REG_TX_OPTIONS_BASE : REG_RX_OPTIONS_BASE;
18862306a36Sopenharmony_ci	io += ring->hop * 32;
18962306a36Sopenharmony_ci	return io;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic void ring_iowrite_cons(struct tb_ring *ring, u16 cons)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	/*
19562306a36Sopenharmony_ci	 * The other 16-bits in the register is read-only and writes to it
19662306a36Sopenharmony_ci	 * are ignored by the hardware so we can save one ioread32() by
19762306a36Sopenharmony_ci	 * filling the read-only bits with zeroes.
19862306a36Sopenharmony_ci	 */
19962306a36Sopenharmony_ci	iowrite32(cons, ring_desc_base(ring) + 8);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void ring_iowrite_prod(struct tb_ring *ring, u16 prod)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	/* See ring_iowrite_cons() above for explanation */
20562306a36Sopenharmony_ci	iowrite32(prod << 16, ring_desc_base(ring) + 8);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void ring_iowrite32desc(struct tb_ring *ring, u32 value, u32 offset)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	iowrite32(value, ring_desc_base(ring) + offset);
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic void ring_iowrite64desc(struct tb_ring *ring, u64 value, u32 offset)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	iowrite32(value, ring_desc_base(ring) + offset);
21662306a36Sopenharmony_ci	iowrite32(value >> 32, ring_desc_base(ring) + offset + 4);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic void ring_iowrite32options(struct tb_ring *ring, u32 value, u32 offset)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	iowrite32(value, ring_options_base(ring) + offset);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic bool ring_full(struct tb_ring *ring)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return ((ring->head + 1) % ring->size) == ring->tail;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic bool ring_empty(struct tb_ring *ring)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	return ring->head == ring->tail;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/*
23562306a36Sopenharmony_ci * ring_write_descriptors() - post frames from ring->queue to the controller
23662306a36Sopenharmony_ci *
23762306a36Sopenharmony_ci * ring->lock is held.
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic void ring_write_descriptors(struct tb_ring *ring)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct ring_frame *frame, *n;
24262306a36Sopenharmony_ci	struct ring_desc *descriptor;
24362306a36Sopenharmony_ci	list_for_each_entry_safe(frame, n, &ring->queue, list) {
24462306a36Sopenharmony_ci		if (ring_full(ring))
24562306a36Sopenharmony_ci			break;
24662306a36Sopenharmony_ci		list_move_tail(&frame->list, &ring->in_flight);
24762306a36Sopenharmony_ci		descriptor = &ring->descriptors[ring->head];
24862306a36Sopenharmony_ci		descriptor->phys = frame->buffer_phy;
24962306a36Sopenharmony_ci		descriptor->time = 0;
25062306a36Sopenharmony_ci		descriptor->flags = RING_DESC_POSTED | RING_DESC_INTERRUPT;
25162306a36Sopenharmony_ci		if (ring->is_tx) {
25262306a36Sopenharmony_ci			descriptor->length = frame->size;
25362306a36Sopenharmony_ci			descriptor->eof = frame->eof;
25462306a36Sopenharmony_ci			descriptor->sof = frame->sof;
25562306a36Sopenharmony_ci		}
25662306a36Sopenharmony_ci		ring->head = (ring->head + 1) % ring->size;
25762306a36Sopenharmony_ci		if (ring->is_tx)
25862306a36Sopenharmony_ci			ring_iowrite_prod(ring, ring->head);
25962306a36Sopenharmony_ci		else
26062306a36Sopenharmony_ci			ring_iowrite_cons(ring, ring->head);
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/*
26562306a36Sopenharmony_ci * ring_work() - progress completed frames
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * If the ring is shutting down then all frames are marked as canceled and
26862306a36Sopenharmony_ci * their callbacks are invoked.
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * Otherwise we collect all completed frame from the ring buffer, write new
27162306a36Sopenharmony_ci * frame to the ring buffer and invoke the callbacks for the completed frames.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_cistatic void ring_work(struct work_struct *work)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct tb_ring *ring = container_of(work, typeof(*ring), work);
27662306a36Sopenharmony_ci	struct ring_frame *frame;
27762306a36Sopenharmony_ci	bool canceled = false;
27862306a36Sopenharmony_ci	unsigned long flags;
27962306a36Sopenharmony_ci	LIST_HEAD(done);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	spin_lock_irqsave(&ring->lock, flags);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (!ring->running) {
28462306a36Sopenharmony_ci		/*  Move all frames to done and mark them as canceled. */
28562306a36Sopenharmony_ci		list_splice_tail_init(&ring->in_flight, &done);
28662306a36Sopenharmony_ci		list_splice_tail_init(&ring->queue, &done);
28762306a36Sopenharmony_ci		canceled = true;
28862306a36Sopenharmony_ci		goto invoke_callback;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	while (!ring_empty(ring)) {
29262306a36Sopenharmony_ci		if (!(ring->descriptors[ring->tail].flags
29362306a36Sopenharmony_ci				& RING_DESC_COMPLETED))
29462306a36Sopenharmony_ci			break;
29562306a36Sopenharmony_ci		frame = list_first_entry(&ring->in_flight, typeof(*frame),
29662306a36Sopenharmony_ci					 list);
29762306a36Sopenharmony_ci		list_move_tail(&frame->list, &done);
29862306a36Sopenharmony_ci		if (!ring->is_tx) {
29962306a36Sopenharmony_ci			frame->size = ring->descriptors[ring->tail].length;
30062306a36Sopenharmony_ci			frame->eof = ring->descriptors[ring->tail].eof;
30162306a36Sopenharmony_ci			frame->sof = ring->descriptors[ring->tail].sof;
30262306a36Sopenharmony_ci			frame->flags = ring->descriptors[ring->tail].flags;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci		ring->tail = (ring->tail + 1) % ring->size;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	ring_write_descriptors(ring);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ciinvoke_callback:
30962306a36Sopenharmony_ci	/* allow callbacks to schedule new work */
31062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->lock, flags);
31162306a36Sopenharmony_ci	while (!list_empty(&done)) {
31262306a36Sopenharmony_ci		frame = list_first_entry(&done, typeof(*frame), list);
31362306a36Sopenharmony_ci		/*
31462306a36Sopenharmony_ci		 * The callback may reenqueue or delete frame.
31562306a36Sopenharmony_ci		 * Do not hold on to it.
31662306a36Sopenharmony_ci		 */
31762306a36Sopenharmony_ci		list_del_init(&frame->list);
31862306a36Sopenharmony_ci		if (frame->callback)
31962306a36Sopenharmony_ci			frame->callback(ring, frame, canceled);
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ciint __tb_ring_enqueue(struct tb_ring *ring, struct ring_frame *frame)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	unsigned long flags;
32662306a36Sopenharmony_ci	int ret = 0;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	spin_lock_irqsave(&ring->lock, flags);
32962306a36Sopenharmony_ci	if (ring->running) {
33062306a36Sopenharmony_ci		list_add_tail(&frame->list, &ring->queue);
33162306a36Sopenharmony_ci		ring_write_descriptors(ring);
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci		ret = -ESHUTDOWN;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->lock, flags);
33662306a36Sopenharmony_ci	return ret;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__tb_ring_enqueue);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/**
34162306a36Sopenharmony_ci * tb_ring_poll() - Poll one completed frame from the ring
34262306a36Sopenharmony_ci * @ring: Ring to poll
34362306a36Sopenharmony_ci *
34462306a36Sopenharmony_ci * This function can be called when @start_poll callback of the @ring
34562306a36Sopenharmony_ci * has been called. It will read one completed frame from the ring and
34662306a36Sopenharmony_ci * return it to the caller. Returns %NULL if there is no more completed
34762306a36Sopenharmony_ci * frames.
34862306a36Sopenharmony_ci */
34962306a36Sopenharmony_cistruct ring_frame *tb_ring_poll(struct tb_ring *ring)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct ring_frame *frame = NULL;
35262306a36Sopenharmony_ci	unsigned long flags;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	spin_lock_irqsave(&ring->lock, flags);
35562306a36Sopenharmony_ci	if (!ring->running)
35662306a36Sopenharmony_ci		goto unlock;
35762306a36Sopenharmony_ci	if (ring_empty(ring))
35862306a36Sopenharmony_ci		goto unlock;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (ring->descriptors[ring->tail].flags & RING_DESC_COMPLETED) {
36162306a36Sopenharmony_ci		frame = list_first_entry(&ring->in_flight, typeof(*frame),
36262306a36Sopenharmony_ci					 list);
36362306a36Sopenharmony_ci		list_del_init(&frame->list);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		if (!ring->is_tx) {
36662306a36Sopenharmony_ci			frame->size = ring->descriptors[ring->tail].length;
36762306a36Sopenharmony_ci			frame->eof = ring->descriptors[ring->tail].eof;
36862306a36Sopenharmony_ci			frame->sof = ring->descriptors[ring->tail].sof;
36962306a36Sopenharmony_ci			frame->flags = ring->descriptors[ring->tail].flags;
37062306a36Sopenharmony_ci		}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		ring->tail = (ring->tail + 1) % ring->size;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ciunlock:
37662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->lock, flags);
37762306a36Sopenharmony_ci	return frame;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_poll);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic void __ring_interrupt_mask(struct tb_ring *ring, bool mask)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	int idx = ring_interrupt_index(ring);
38462306a36Sopenharmony_ci	int reg = REG_RING_INTERRUPT_BASE + idx / 32 * 4;
38562306a36Sopenharmony_ci	int bit = idx % 32;
38662306a36Sopenharmony_ci	u32 val;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	val = ioread32(ring->nhi->iobase + reg);
38962306a36Sopenharmony_ci	if (mask)
39062306a36Sopenharmony_ci		val &= ~BIT(bit);
39162306a36Sopenharmony_ci	else
39262306a36Sopenharmony_ci		val |= BIT(bit);
39362306a36Sopenharmony_ci	iowrite32(val, ring->nhi->iobase + reg);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/* Both @nhi->lock and @ring->lock should be held */
39762306a36Sopenharmony_cistatic void __ring_interrupt(struct tb_ring *ring)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	if (!ring->running)
40062306a36Sopenharmony_ci		return;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (ring->start_poll) {
40362306a36Sopenharmony_ci		__ring_interrupt_mask(ring, true);
40462306a36Sopenharmony_ci		ring->start_poll(ring->poll_data);
40562306a36Sopenharmony_ci	} else {
40662306a36Sopenharmony_ci		schedule_work(&ring->work);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/**
41162306a36Sopenharmony_ci * tb_ring_poll_complete() - Re-start interrupt for the ring
41262306a36Sopenharmony_ci * @ring: Ring to re-start the interrupt
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci * This will re-start (unmask) the ring interrupt once the user is done
41562306a36Sopenharmony_ci * with polling.
41662306a36Sopenharmony_ci */
41762306a36Sopenharmony_civoid tb_ring_poll_complete(struct tb_ring *ring)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	unsigned long flags;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	spin_lock_irqsave(&ring->nhi->lock, flags);
42262306a36Sopenharmony_ci	spin_lock(&ring->lock);
42362306a36Sopenharmony_ci	if (ring->start_poll)
42462306a36Sopenharmony_ci		__ring_interrupt_mask(ring, false);
42562306a36Sopenharmony_ci	spin_unlock(&ring->lock);
42662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ring->nhi->lock, flags);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_poll_complete);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void ring_clear_msix(const struct tb_ring *ring)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	int bit;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT)
43562306a36Sopenharmony_ci		return;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	bit = ring_interrupt_index(ring) & 31;
43862306a36Sopenharmony_ci	if (ring->is_tx)
43962306a36Sopenharmony_ci		iowrite32(BIT(bit), ring->nhi->iobase + REG_RING_INT_CLEAR);
44062306a36Sopenharmony_ci	else
44162306a36Sopenharmony_ci		iowrite32(BIT(bit), ring->nhi->iobase + REG_RING_INT_CLEAR +
44262306a36Sopenharmony_ci			  4 * (ring->nhi->hop_count / 32));
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic irqreturn_t ring_msix(int irq, void *data)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct tb_ring *ring = data;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	spin_lock(&ring->nhi->lock);
45062306a36Sopenharmony_ci	ring_clear_msix(ring);
45162306a36Sopenharmony_ci	spin_lock(&ring->lock);
45262306a36Sopenharmony_ci	__ring_interrupt(ring);
45362306a36Sopenharmony_ci	spin_unlock(&ring->lock);
45462306a36Sopenharmony_ci	spin_unlock(&ring->nhi->lock);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return IRQ_HANDLED;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int ring_request_msix(struct tb_ring *ring, bool no_suspend)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct tb_nhi *nhi = ring->nhi;
46262306a36Sopenharmony_ci	unsigned long irqflags;
46362306a36Sopenharmony_ci	int ret;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (!nhi->pdev->msix_enabled)
46662306a36Sopenharmony_ci		return 0;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	ret = ida_simple_get(&nhi->msix_ida, 0, MSIX_MAX_VECS, GFP_KERNEL);
46962306a36Sopenharmony_ci	if (ret < 0)
47062306a36Sopenharmony_ci		return ret;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	ring->vector = ret;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	ret = pci_irq_vector(ring->nhi->pdev, ring->vector);
47562306a36Sopenharmony_ci	if (ret < 0)
47662306a36Sopenharmony_ci		goto err_ida_remove;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	ring->irq = ret;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	irqflags = no_suspend ? IRQF_NO_SUSPEND : 0;
48162306a36Sopenharmony_ci	ret = request_irq(ring->irq, ring_msix, irqflags, "thunderbolt", ring);
48262306a36Sopenharmony_ci	if (ret)
48362306a36Sopenharmony_ci		goto err_ida_remove;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	return 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cierr_ida_remove:
48862306a36Sopenharmony_ci	ida_simple_remove(&nhi->msix_ida, ring->vector);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return ret;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic void ring_release_msix(struct tb_ring *ring)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	if (ring->irq <= 0)
49662306a36Sopenharmony_ci		return;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	free_irq(ring->irq, ring);
49962306a36Sopenharmony_ci	ida_simple_remove(&ring->nhi->msix_ida, ring->vector);
50062306a36Sopenharmony_ci	ring->vector = 0;
50162306a36Sopenharmony_ci	ring->irq = 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	unsigned int start_hop = RING_FIRST_USABLE_HOPID;
50762306a36Sopenharmony_ci	int ret = 0;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (nhi->quirks & QUIRK_E2E) {
51062306a36Sopenharmony_ci		start_hop = RING_FIRST_USABLE_HOPID + 1;
51162306a36Sopenharmony_ci		if (ring->flags & RING_FLAG_E2E && !ring->is_tx) {
51262306a36Sopenharmony_ci			dev_dbg(&nhi->pdev->dev, "quirking E2E TX HopID %u -> %u\n",
51362306a36Sopenharmony_ci				ring->e2e_tx_hop, RING_E2E_RESERVED_HOPID);
51462306a36Sopenharmony_ci			ring->e2e_tx_hop = RING_E2E_RESERVED_HOPID;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	spin_lock_irq(&nhi->lock);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (ring->hop < 0) {
52162306a36Sopenharmony_ci		unsigned int i;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		/*
52462306a36Sopenharmony_ci		 * Automatically allocate HopID from the non-reserved
52562306a36Sopenharmony_ci		 * range 1 .. hop_count - 1.
52662306a36Sopenharmony_ci		 */
52762306a36Sopenharmony_ci		for (i = start_hop; i < nhi->hop_count; i++) {
52862306a36Sopenharmony_ci			if (ring->is_tx) {
52962306a36Sopenharmony_ci				if (!nhi->tx_rings[i]) {
53062306a36Sopenharmony_ci					ring->hop = i;
53162306a36Sopenharmony_ci					break;
53262306a36Sopenharmony_ci				}
53362306a36Sopenharmony_ci			} else {
53462306a36Sopenharmony_ci				if (!nhi->rx_rings[i]) {
53562306a36Sopenharmony_ci					ring->hop = i;
53662306a36Sopenharmony_ci					break;
53762306a36Sopenharmony_ci				}
53862306a36Sopenharmony_ci			}
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (ring->hop > 0 && ring->hop < start_hop) {
54362306a36Sopenharmony_ci		dev_warn(&nhi->pdev->dev, "invalid hop: %d\n", ring->hop);
54462306a36Sopenharmony_ci		ret = -EINVAL;
54562306a36Sopenharmony_ci		goto err_unlock;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci	if (ring->hop < 0 || ring->hop >= nhi->hop_count) {
54862306a36Sopenharmony_ci		dev_warn(&nhi->pdev->dev, "invalid hop: %d\n", ring->hop);
54962306a36Sopenharmony_ci		ret = -EINVAL;
55062306a36Sopenharmony_ci		goto err_unlock;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci	if (ring->is_tx && nhi->tx_rings[ring->hop]) {
55362306a36Sopenharmony_ci		dev_warn(&nhi->pdev->dev, "TX hop %d already allocated\n",
55462306a36Sopenharmony_ci			 ring->hop);
55562306a36Sopenharmony_ci		ret = -EBUSY;
55662306a36Sopenharmony_ci		goto err_unlock;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci	if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
55962306a36Sopenharmony_ci		dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n",
56062306a36Sopenharmony_ci			 ring->hop);
56162306a36Sopenharmony_ci		ret = -EBUSY;
56262306a36Sopenharmony_ci		goto err_unlock;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (ring->is_tx)
56662306a36Sopenharmony_ci		nhi->tx_rings[ring->hop] = ring;
56762306a36Sopenharmony_ci	else
56862306a36Sopenharmony_ci		nhi->rx_rings[ring->hop] = ring;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cierr_unlock:
57162306a36Sopenharmony_ci	spin_unlock_irq(&nhi->lock);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return ret;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
57762306a36Sopenharmony_ci				     bool transmit, unsigned int flags,
57862306a36Sopenharmony_ci				     int e2e_tx_hop, u16 sof_mask, u16 eof_mask,
57962306a36Sopenharmony_ci				     void (*start_poll)(void *),
58062306a36Sopenharmony_ci				     void *poll_data)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct tb_ring *ring = NULL;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	dev_dbg(&nhi->pdev->dev, "allocating %s ring %d of size %d\n",
58562306a36Sopenharmony_ci		transmit ? "TX" : "RX", hop, size);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
58862306a36Sopenharmony_ci	if (!ring)
58962306a36Sopenharmony_ci		return NULL;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	spin_lock_init(&ring->lock);
59262306a36Sopenharmony_ci	INIT_LIST_HEAD(&ring->queue);
59362306a36Sopenharmony_ci	INIT_LIST_HEAD(&ring->in_flight);
59462306a36Sopenharmony_ci	INIT_WORK(&ring->work, ring_work);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ring->nhi = nhi;
59762306a36Sopenharmony_ci	ring->hop = hop;
59862306a36Sopenharmony_ci	ring->is_tx = transmit;
59962306a36Sopenharmony_ci	ring->size = size;
60062306a36Sopenharmony_ci	ring->flags = flags;
60162306a36Sopenharmony_ci	ring->e2e_tx_hop = e2e_tx_hop;
60262306a36Sopenharmony_ci	ring->sof_mask = sof_mask;
60362306a36Sopenharmony_ci	ring->eof_mask = eof_mask;
60462306a36Sopenharmony_ci	ring->head = 0;
60562306a36Sopenharmony_ci	ring->tail = 0;
60662306a36Sopenharmony_ci	ring->running = false;
60762306a36Sopenharmony_ci	ring->start_poll = start_poll;
60862306a36Sopenharmony_ci	ring->poll_data = poll_data;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	ring->descriptors = dma_alloc_coherent(&ring->nhi->pdev->dev,
61162306a36Sopenharmony_ci			size * sizeof(*ring->descriptors),
61262306a36Sopenharmony_ci			&ring->descriptors_dma, GFP_KERNEL | __GFP_ZERO);
61362306a36Sopenharmony_ci	if (!ring->descriptors)
61462306a36Sopenharmony_ci		goto err_free_ring;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (ring_request_msix(ring, flags & RING_FLAG_NO_SUSPEND))
61762306a36Sopenharmony_ci		goto err_free_descs;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (nhi_alloc_hop(nhi, ring))
62062306a36Sopenharmony_ci		goto err_release_msix;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return ring;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cierr_release_msix:
62562306a36Sopenharmony_ci	ring_release_msix(ring);
62662306a36Sopenharmony_cierr_free_descs:
62762306a36Sopenharmony_ci	dma_free_coherent(&ring->nhi->pdev->dev,
62862306a36Sopenharmony_ci			  ring->size * sizeof(*ring->descriptors),
62962306a36Sopenharmony_ci			  ring->descriptors, ring->descriptors_dma);
63062306a36Sopenharmony_cierr_free_ring:
63162306a36Sopenharmony_ci	kfree(ring);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return NULL;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/**
63762306a36Sopenharmony_ci * tb_ring_alloc_tx() - Allocate DMA ring for transmit
63862306a36Sopenharmony_ci * @nhi: Pointer to the NHI the ring is to be allocated
63962306a36Sopenharmony_ci * @hop: HopID (ring) to allocate
64062306a36Sopenharmony_ci * @size: Number of entries in the ring
64162306a36Sopenharmony_ci * @flags: Flags for the ring
64262306a36Sopenharmony_ci */
64362306a36Sopenharmony_cistruct tb_ring *tb_ring_alloc_tx(struct tb_nhi *nhi, int hop, int size,
64462306a36Sopenharmony_ci				 unsigned int flags)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	return tb_ring_alloc(nhi, hop, size, true, flags, 0, 0, 0, NULL, NULL);
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_alloc_tx);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci/**
65162306a36Sopenharmony_ci * tb_ring_alloc_rx() - Allocate DMA ring for receive
65262306a36Sopenharmony_ci * @nhi: Pointer to the NHI the ring is to be allocated
65362306a36Sopenharmony_ci * @hop: HopID (ring) to allocate. Pass %-1 for automatic allocation.
65462306a36Sopenharmony_ci * @size: Number of entries in the ring
65562306a36Sopenharmony_ci * @flags: Flags for the ring
65662306a36Sopenharmony_ci * @e2e_tx_hop: Transmit HopID when E2E is enabled in @flags
65762306a36Sopenharmony_ci * @sof_mask: Mask of PDF values that start a frame
65862306a36Sopenharmony_ci * @eof_mask: Mask of PDF values that end a frame
65962306a36Sopenharmony_ci * @start_poll: If not %NULL the ring will call this function when an
66062306a36Sopenharmony_ci *		interrupt is triggered and masked, instead of callback
66162306a36Sopenharmony_ci *		in each Rx frame.
66262306a36Sopenharmony_ci * @poll_data: Optional data passed to @start_poll
66362306a36Sopenharmony_ci */
66462306a36Sopenharmony_cistruct tb_ring *tb_ring_alloc_rx(struct tb_nhi *nhi, int hop, int size,
66562306a36Sopenharmony_ci				 unsigned int flags, int e2e_tx_hop,
66662306a36Sopenharmony_ci				 u16 sof_mask, u16 eof_mask,
66762306a36Sopenharmony_ci				 void (*start_poll)(void *), void *poll_data)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	return tb_ring_alloc(nhi, hop, size, false, flags, e2e_tx_hop, sof_mask, eof_mask,
67062306a36Sopenharmony_ci			     start_poll, poll_data);
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_alloc_rx);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/**
67562306a36Sopenharmony_ci * tb_ring_start() - enable a ring
67662306a36Sopenharmony_ci * @ring: Ring to start
67762306a36Sopenharmony_ci *
67862306a36Sopenharmony_ci * Must not be invoked in parallel with tb_ring_stop().
67962306a36Sopenharmony_ci */
68062306a36Sopenharmony_civoid tb_ring_start(struct tb_ring *ring)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	u16 frame_size;
68362306a36Sopenharmony_ci	u32 flags;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	spin_lock_irq(&ring->nhi->lock);
68662306a36Sopenharmony_ci	spin_lock(&ring->lock);
68762306a36Sopenharmony_ci	if (ring->nhi->going_away)
68862306a36Sopenharmony_ci		goto err;
68962306a36Sopenharmony_ci	if (ring->running) {
69062306a36Sopenharmony_ci		dev_WARN(&ring->nhi->pdev->dev, "ring already started\n");
69162306a36Sopenharmony_ci		goto err;
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci	dev_dbg(&ring->nhi->pdev->dev, "starting %s %d\n",
69462306a36Sopenharmony_ci		RING_TYPE(ring), ring->hop);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (ring->flags & RING_FLAG_FRAME) {
69762306a36Sopenharmony_ci		/* Means 4096 */
69862306a36Sopenharmony_ci		frame_size = 0;
69962306a36Sopenharmony_ci		flags = RING_FLAG_ENABLE;
70062306a36Sopenharmony_ci	} else {
70162306a36Sopenharmony_ci		frame_size = TB_FRAME_SIZE;
70262306a36Sopenharmony_ci		flags = RING_FLAG_ENABLE | RING_FLAG_RAW;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	ring_iowrite64desc(ring, ring->descriptors_dma, 0);
70662306a36Sopenharmony_ci	if (ring->is_tx) {
70762306a36Sopenharmony_ci		ring_iowrite32desc(ring, ring->size, 12);
70862306a36Sopenharmony_ci		ring_iowrite32options(ring, 0, 4); /* time releated ? */
70962306a36Sopenharmony_ci		ring_iowrite32options(ring, flags, 0);
71062306a36Sopenharmony_ci	} else {
71162306a36Sopenharmony_ci		u32 sof_eof_mask = ring->sof_mask << 16 | ring->eof_mask;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		ring_iowrite32desc(ring, (frame_size << 16) | ring->size, 12);
71462306a36Sopenharmony_ci		ring_iowrite32options(ring, sof_eof_mask, 4);
71562306a36Sopenharmony_ci		ring_iowrite32options(ring, flags, 0);
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/*
71962306a36Sopenharmony_ci	 * Now that the ring valid bit is set we can configure E2E if
72062306a36Sopenharmony_ci	 * enabled for the ring.
72162306a36Sopenharmony_ci	 */
72262306a36Sopenharmony_ci	if (ring->flags & RING_FLAG_E2E) {
72362306a36Sopenharmony_ci		if (!ring->is_tx) {
72462306a36Sopenharmony_ci			u32 hop;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci			hop = ring->e2e_tx_hop << REG_RX_OPTIONS_E2E_HOP_SHIFT;
72762306a36Sopenharmony_ci			hop &= REG_RX_OPTIONS_E2E_HOP_MASK;
72862306a36Sopenharmony_ci			flags |= hop;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci			dev_dbg(&ring->nhi->pdev->dev,
73162306a36Sopenharmony_ci				"enabling E2E for %s %d with TX HopID %d\n",
73262306a36Sopenharmony_ci				RING_TYPE(ring), ring->hop, ring->e2e_tx_hop);
73362306a36Sopenharmony_ci		} else {
73462306a36Sopenharmony_ci			dev_dbg(&ring->nhi->pdev->dev, "enabling E2E for %s %d\n",
73562306a36Sopenharmony_ci				RING_TYPE(ring), ring->hop);
73662306a36Sopenharmony_ci		}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		flags |= RING_FLAG_E2E_FLOW_CONTROL;
73962306a36Sopenharmony_ci		ring_iowrite32options(ring, flags, 0);
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	ring_interrupt_active(ring, true);
74362306a36Sopenharmony_ci	ring->running = true;
74462306a36Sopenharmony_cierr:
74562306a36Sopenharmony_ci	spin_unlock(&ring->lock);
74662306a36Sopenharmony_ci	spin_unlock_irq(&ring->nhi->lock);
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_start);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/**
75162306a36Sopenharmony_ci * tb_ring_stop() - shutdown a ring
75262306a36Sopenharmony_ci * @ring: Ring to stop
75362306a36Sopenharmony_ci *
75462306a36Sopenharmony_ci * Must not be invoked from a callback.
75562306a36Sopenharmony_ci *
75662306a36Sopenharmony_ci * This method will disable the ring. Further calls to
75762306a36Sopenharmony_ci * tb_ring_tx/tb_ring_rx will return -ESHUTDOWN until ring_stop has been
75862306a36Sopenharmony_ci * called.
75962306a36Sopenharmony_ci *
76062306a36Sopenharmony_ci * All enqueued frames will be canceled and their callbacks will be executed
76162306a36Sopenharmony_ci * with frame->canceled set to true (on the callback thread). This method
76262306a36Sopenharmony_ci * returns only after all callback invocations have finished.
76362306a36Sopenharmony_ci */
76462306a36Sopenharmony_civoid tb_ring_stop(struct tb_ring *ring)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	spin_lock_irq(&ring->nhi->lock);
76762306a36Sopenharmony_ci	spin_lock(&ring->lock);
76862306a36Sopenharmony_ci	dev_dbg(&ring->nhi->pdev->dev, "stopping %s %d\n",
76962306a36Sopenharmony_ci		RING_TYPE(ring), ring->hop);
77062306a36Sopenharmony_ci	if (ring->nhi->going_away)
77162306a36Sopenharmony_ci		goto err;
77262306a36Sopenharmony_ci	if (!ring->running) {
77362306a36Sopenharmony_ci		dev_WARN(&ring->nhi->pdev->dev, "%s %d already stopped\n",
77462306a36Sopenharmony_ci			 RING_TYPE(ring), ring->hop);
77562306a36Sopenharmony_ci		goto err;
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci	ring_interrupt_active(ring, false);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	ring_iowrite32options(ring, 0, 0);
78062306a36Sopenharmony_ci	ring_iowrite64desc(ring, 0, 0);
78162306a36Sopenharmony_ci	ring_iowrite32desc(ring, 0, 8);
78262306a36Sopenharmony_ci	ring_iowrite32desc(ring, 0, 12);
78362306a36Sopenharmony_ci	ring->head = 0;
78462306a36Sopenharmony_ci	ring->tail = 0;
78562306a36Sopenharmony_ci	ring->running = false;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cierr:
78862306a36Sopenharmony_ci	spin_unlock(&ring->lock);
78962306a36Sopenharmony_ci	spin_unlock_irq(&ring->nhi->lock);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/*
79262306a36Sopenharmony_ci	 * schedule ring->work to invoke callbacks on all remaining frames.
79362306a36Sopenharmony_ci	 */
79462306a36Sopenharmony_ci	schedule_work(&ring->work);
79562306a36Sopenharmony_ci	flush_work(&ring->work);
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_stop);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/*
80062306a36Sopenharmony_ci * tb_ring_free() - free ring
80162306a36Sopenharmony_ci *
80262306a36Sopenharmony_ci * When this method returns all invocations of ring->callback will have
80362306a36Sopenharmony_ci * finished.
80462306a36Sopenharmony_ci *
80562306a36Sopenharmony_ci * Ring must be stopped.
80662306a36Sopenharmony_ci *
80762306a36Sopenharmony_ci * Must NOT be called from ring_frame->callback!
80862306a36Sopenharmony_ci */
80962306a36Sopenharmony_civoid tb_ring_free(struct tb_ring *ring)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	spin_lock_irq(&ring->nhi->lock);
81262306a36Sopenharmony_ci	/*
81362306a36Sopenharmony_ci	 * Dissociate the ring from the NHI. This also ensures that
81462306a36Sopenharmony_ci	 * nhi_interrupt_work cannot reschedule ring->work.
81562306a36Sopenharmony_ci	 */
81662306a36Sopenharmony_ci	if (ring->is_tx)
81762306a36Sopenharmony_ci		ring->nhi->tx_rings[ring->hop] = NULL;
81862306a36Sopenharmony_ci	else
81962306a36Sopenharmony_ci		ring->nhi->rx_rings[ring->hop] = NULL;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (ring->running) {
82262306a36Sopenharmony_ci		dev_WARN(&ring->nhi->pdev->dev, "%s %d still running\n",
82362306a36Sopenharmony_ci			 RING_TYPE(ring), ring->hop);
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci	spin_unlock_irq(&ring->nhi->lock);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	ring_release_msix(ring);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	dma_free_coherent(&ring->nhi->pdev->dev,
83062306a36Sopenharmony_ci			  ring->size * sizeof(*ring->descriptors),
83162306a36Sopenharmony_ci			  ring->descriptors, ring->descriptors_dma);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	ring->descriptors = NULL;
83462306a36Sopenharmony_ci	ring->descriptors_dma = 0;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	dev_dbg(&ring->nhi->pdev->dev, "freeing %s %d\n", RING_TYPE(ring),
83862306a36Sopenharmony_ci		ring->hop);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/*
84162306a36Sopenharmony_ci	 * ring->work can no longer be scheduled (it is scheduled only
84262306a36Sopenharmony_ci	 * by nhi_interrupt_work, ring_stop and ring_msix). Wait for it
84362306a36Sopenharmony_ci	 * to finish before freeing the ring.
84462306a36Sopenharmony_ci	 */
84562306a36Sopenharmony_ci	flush_work(&ring->work);
84662306a36Sopenharmony_ci	kfree(ring);
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tb_ring_free);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci/**
85162306a36Sopenharmony_ci * nhi_mailbox_cmd() - Send a command through NHI mailbox
85262306a36Sopenharmony_ci * @nhi: Pointer to the NHI structure
85362306a36Sopenharmony_ci * @cmd: Command to send
85462306a36Sopenharmony_ci * @data: Data to be send with the command
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci * Sends mailbox command to the firmware running on NHI. Returns %0 in
85762306a36Sopenharmony_ci * case of success and negative errno in case of failure.
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_ciint nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	ktime_t timeout;
86262306a36Sopenharmony_ci	u32 val;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	iowrite32(data, nhi->iobase + REG_INMAIL_DATA);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	val = ioread32(nhi->iobase + REG_INMAIL_CMD);
86762306a36Sopenharmony_ci	val &= ~(REG_INMAIL_CMD_MASK | REG_INMAIL_ERROR);
86862306a36Sopenharmony_ci	val |= REG_INMAIL_OP_REQUEST | cmd;
86962306a36Sopenharmony_ci	iowrite32(val, nhi->iobase + REG_INMAIL_CMD);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	timeout = ktime_add_ms(ktime_get(), NHI_MAILBOX_TIMEOUT);
87262306a36Sopenharmony_ci	do {
87362306a36Sopenharmony_ci		val = ioread32(nhi->iobase + REG_INMAIL_CMD);
87462306a36Sopenharmony_ci		if (!(val & REG_INMAIL_OP_REQUEST))
87562306a36Sopenharmony_ci			break;
87662306a36Sopenharmony_ci		usleep_range(10, 20);
87762306a36Sopenharmony_ci	} while (ktime_before(ktime_get(), timeout));
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (val & REG_INMAIL_OP_REQUEST)
88062306a36Sopenharmony_ci		return -ETIMEDOUT;
88162306a36Sopenharmony_ci	if (val & REG_INMAIL_ERROR)
88262306a36Sopenharmony_ci		return -EIO;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	return 0;
88562306a36Sopenharmony_ci}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci/**
88862306a36Sopenharmony_ci * nhi_mailbox_mode() - Return current firmware operation mode
88962306a36Sopenharmony_ci * @nhi: Pointer to the NHI structure
89062306a36Sopenharmony_ci *
89162306a36Sopenharmony_ci * The function reads current firmware operation mode using NHI mailbox
89262306a36Sopenharmony_ci * registers and returns it to the caller.
89362306a36Sopenharmony_ci */
89462306a36Sopenharmony_cienum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	u32 val;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	val = ioread32(nhi->iobase + REG_OUTMAIL_CMD);
89962306a36Sopenharmony_ci	val &= REG_OUTMAIL_CMD_OPMODE_MASK;
90062306a36Sopenharmony_ci	val >>= REG_OUTMAIL_CMD_OPMODE_SHIFT;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	return (enum nhi_fw_mode)val;
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic void nhi_interrupt_work(struct work_struct *work)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct tb_nhi *nhi = container_of(work, typeof(*nhi), interrupt_work);
90862306a36Sopenharmony_ci	int value = 0; /* Suppress uninitialized usage warning. */
90962306a36Sopenharmony_ci	int bit;
91062306a36Sopenharmony_ci	int hop = -1;
91162306a36Sopenharmony_ci	int type = 0; /* current interrupt type 0: TX, 1: RX, 2: RX overflow */
91262306a36Sopenharmony_ci	struct tb_ring *ring;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	spin_lock_irq(&nhi->lock);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/*
91762306a36Sopenharmony_ci	 * Starting at REG_RING_NOTIFY_BASE there are three status bitfields
91862306a36Sopenharmony_ci	 * (TX, RX, RX overflow). We iterate over the bits and read a new
91962306a36Sopenharmony_ci	 * dwords as required. The registers are cleared on read.
92062306a36Sopenharmony_ci	 */
92162306a36Sopenharmony_ci	for (bit = 0; bit < 3 * nhi->hop_count; bit++) {
92262306a36Sopenharmony_ci		if (bit % 32 == 0)
92362306a36Sopenharmony_ci			value = ioread32(nhi->iobase
92462306a36Sopenharmony_ci					 + REG_RING_NOTIFY_BASE
92562306a36Sopenharmony_ci					 + 4 * (bit / 32));
92662306a36Sopenharmony_ci		if (++hop == nhi->hop_count) {
92762306a36Sopenharmony_ci			hop = 0;
92862306a36Sopenharmony_ci			type++;
92962306a36Sopenharmony_ci		}
93062306a36Sopenharmony_ci		if ((value & (1 << (bit % 32))) == 0)
93162306a36Sopenharmony_ci			continue;
93262306a36Sopenharmony_ci		if (type == 2) {
93362306a36Sopenharmony_ci			dev_warn(&nhi->pdev->dev,
93462306a36Sopenharmony_ci				 "RX overflow for ring %d\n",
93562306a36Sopenharmony_ci				 hop);
93662306a36Sopenharmony_ci			continue;
93762306a36Sopenharmony_ci		}
93862306a36Sopenharmony_ci		if (type == 0)
93962306a36Sopenharmony_ci			ring = nhi->tx_rings[hop];
94062306a36Sopenharmony_ci		else
94162306a36Sopenharmony_ci			ring = nhi->rx_rings[hop];
94262306a36Sopenharmony_ci		if (ring == NULL) {
94362306a36Sopenharmony_ci			dev_warn(&nhi->pdev->dev,
94462306a36Sopenharmony_ci				 "got interrupt for inactive %s ring %d\n",
94562306a36Sopenharmony_ci				 type ? "RX" : "TX",
94662306a36Sopenharmony_ci				 hop);
94762306a36Sopenharmony_ci			continue;
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		spin_lock(&ring->lock);
95162306a36Sopenharmony_ci		__ring_interrupt(ring);
95262306a36Sopenharmony_ci		spin_unlock(&ring->lock);
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci	spin_unlock_irq(&nhi->lock);
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic irqreturn_t nhi_msi(int irq, void *data)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct tb_nhi *nhi = data;
96062306a36Sopenharmony_ci	schedule_work(&nhi->interrupt_work);
96162306a36Sopenharmony_ci	return IRQ_HANDLED;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic int __nhi_suspend_noirq(struct device *dev, bool wakeup)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
96762306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
96862306a36Sopenharmony_ci	struct tb_nhi *nhi = tb->nhi;
96962306a36Sopenharmony_ci	int ret;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	ret = tb_domain_suspend_noirq(tb);
97262306a36Sopenharmony_ci	if (ret)
97362306a36Sopenharmony_ci		return ret;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (nhi->ops && nhi->ops->suspend_noirq) {
97662306a36Sopenharmony_ci		ret = nhi->ops->suspend_noirq(tb->nhi, wakeup);
97762306a36Sopenharmony_ci		if (ret)
97862306a36Sopenharmony_ci			return ret;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return 0;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_cistatic int nhi_suspend_noirq(struct device *dev)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	return __nhi_suspend_noirq(dev, device_may_wakeup(dev));
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic int nhi_freeze_noirq(struct device *dev)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
99262306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	return tb_domain_freeze_noirq(tb);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic int nhi_thaw_noirq(struct device *dev)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
100062306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	return tb_domain_thaw_noirq(tb);
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic bool nhi_wake_supported(struct pci_dev *pdev)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	u8 val;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	/*
101062306a36Sopenharmony_ci	 * If power rails are sustainable for wakeup from S4 this
101162306a36Sopenharmony_ci	 * property is set by the BIOS.
101262306a36Sopenharmony_ci	 */
101362306a36Sopenharmony_ci	if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
101462306a36Sopenharmony_ci		return !!val;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return true;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic int nhi_poweroff_noirq(struct device *dev)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
102262306a36Sopenharmony_ci	bool wakeup;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	wakeup = device_may_wakeup(dev) && nhi_wake_supported(pdev);
102562306a36Sopenharmony_ci	return __nhi_suspend_noirq(dev, wakeup);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic void nhi_enable_int_throttling(struct tb_nhi *nhi)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	/* Throttling is specified in 256ns increments */
103162306a36Sopenharmony_ci	u32 throttle = DIV_ROUND_UP(128 * NSEC_PER_USEC, 256);
103262306a36Sopenharmony_ci	unsigned int i;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/*
103562306a36Sopenharmony_ci	 * Configure interrupt throttling for all vectors even if we
103662306a36Sopenharmony_ci	 * only use few.
103762306a36Sopenharmony_ci	 */
103862306a36Sopenharmony_ci	for (i = 0; i < MSIX_MAX_VECS; i++) {
103962306a36Sopenharmony_ci		u32 reg = REG_INT_THROTTLING_RATE + i * 4;
104062306a36Sopenharmony_ci		iowrite32(throttle, nhi->iobase + reg);
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic int nhi_resume_noirq(struct device *dev)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
104762306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
104862306a36Sopenharmony_ci	struct tb_nhi *nhi = tb->nhi;
104962306a36Sopenharmony_ci	int ret;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/*
105262306a36Sopenharmony_ci	 * Check that the device is still there. It may be that the user
105362306a36Sopenharmony_ci	 * unplugged last device which causes the host controller to go
105462306a36Sopenharmony_ci	 * away on PCs.
105562306a36Sopenharmony_ci	 */
105662306a36Sopenharmony_ci	if (!pci_device_is_present(pdev)) {
105762306a36Sopenharmony_ci		nhi->going_away = true;
105862306a36Sopenharmony_ci	} else {
105962306a36Sopenharmony_ci		if (nhi->ops && nhi->ops->resume_noirq) {
106062306a36Sopenharmony_ci			ret = nhi->ops->resume_noirq(nhi);
106162306a36Sopenharmony_ci			if (ret)
106262306a36Sopenharmony_ci				return ret;
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci		nhi_enable_int_throttling(tb->nhi);
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return tb_domain_resume_noirq(tb);
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic int nhi_suspend(struct device *dev)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
107362306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	return tb_domain_suspend(tb);
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic void nhi_complete(struct device *dev)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
108162306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/*
108462306a36Sopenharmony_ci	 * If we were runtime suspended when system suspend started,
108562306a36Sopenharmony_ci	 * schedule runtime resume now. It should bring the domain back
108662306a36Sopenharmony_ci	 * to functional state.
108762306a36Sopenharmony_ci	 */
108862306a36Sopenharmony_ci	if (pm_runtime_suspended(&pdev->dev))
108962306a36Sopenharmony_ci		pm_runtime_resume(&pdev->dev);
109062306a36Sopenharmony_ci	else
109162306a36Sopenharmony_ci		tb_domain_complete(tb);
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_cistatic int nhi_runtime_suspend(struct device *dev)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
109762306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
109862306a36Sopenharmony_ci	struct tb_nhi *nhi = tb->nhi;
109962306a36Sopenharmony_ci	int ret;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	ret = tb_domain_runtime_suspend(tb);
110262306a36Sopenharmony_ci	if (ret)
110362306a36Sopenharmony_ci		return ret;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (nhi->ops && nhi->ops->runtime_suspend) {
110662306a36Sopenharmony_ci		ret = nhi->ops->runtime_suspend(tb->nhi);
110762306a36Sopenharmony_ci		if (ret)
110862306a36Sopenharmony_ci			return ret;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci	return 0;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int nhi_runtime_resume(struct device *dev)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
111662306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
111762306a36Sopenharmony_ci	struct tb_nhi *nhi = tb->nhi;
111862306a36Sopenharmony_ci	int ret;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	if (nhi->ops && nhi->ops->runtime_resume) {
112162306a36Sopenharmony_ci		ret = nhi->ops->runtime_resume(nhi);
112262306a36Sopenharmony_ci		if (ret)
112362306a36Sopenharmony_ci			return ret;
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	nhi_enable_int_throttling(nhi);
112762306a36Sopenharmony_ci	return tb_domain_runtime_resume(tb);
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic void nhi_shutdown(struct tb_nhi *nhi)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	int i;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	dev_dbg(&nhi->pdev->dev, "shutdown\n");
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	for (i = 0; i < nhi->hop_count; i++) {
113762306a36Sopenharmony_ci		if (nhi->tx_rings[i])
113862306a36Sopenharmony_ci			dev_WARN(&nhi->pdev->dev,
113962306a36Sopenharmony_ci				 "TX ring %d is still active\n", i);
114062306a36Sopenharmony_ci		if (nhi->rx_rings[i])
114162306a36Sopenharmony_ci			dev_WARN(&nhi->pdev->dev,
114262306a36Sopenharmony_ci				 "RX ring %d is still active\n", i);
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci	nhi_disable_interrupts(nhi);
114562306a36Sopenharmony_ci	/*
114662306a36Sopenharmony_ci	 * We have to release the irq before calling flush_work. Otherwise an
114762306a36Sopenharmony_ci	 * already executing IRQ handler could call schedule_work again.
114862306a36Sopenharmony_ci	 */
114962306a36Sopenharmony_ci	if (!nhi->pdev->msix_enabled) {
115062306a36Sopenharmony_ci		devm_free_irq(&nhi->pdev->dev, nhi->pdev->irq, nhi);
115162306a36Sopenharmony_ci		flush_work(&nhi->interrupt_work);
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci	ida_destroy(&nhi->msix_ida);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (nhi->ops && nhi->ops->shutdown)
115662306a36Sopenharmony_ci		nhi->ops->shutdown(nhi);
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic void nhi_check_quirks(struct tb_nhi *nhi)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	if (nhi->pdev->vendor == PCI_VENDOR_ID_INTEL) {
116262306a36Sopenharmony_ci		/*
116362306a36Sopenharmony_ci		 * Intel hardware supports auto clear of the interrupt
116462306a36Sopenharmony_ci		 * status register right after interrupt is being
116562306a36Sopenharmony_ci		 * issued.
116662306a36Sopenharmony_ci		 */
116762306a36Sopenharmony_ci		nhi->quirks |= QUIRK_AUTO_CLEAR_INT;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		switch (nhi->pdev->device) {
117062306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI:
117162306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI:
117262306a36Sopenharmony_ci			/*
117362306a36Sopenharmony_ci			 * Falcon Ridge controller needs the end-to-end
117462306a36Sopenharmony_ci			 * flow control workaround to avoid losing Rx
117562306a36Sopenharmony_ci			 * packets when RING_FLAG_E2E is set.
117662306a36Sopenharmony_ci			 */
117762306a36Sopenharmony_ci			nhi->quirks |= QUIRK_E2E;
117862306a36Sopenharmony_ci			break;
117962306a36Sopenharmony_ci		}
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic int nhi_check_iommu_pdev(struct pci_dev *pdev, void *data)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	if (!pdev->external_facing ||
118662306a36Sopenharmony_ci	    !device_iommu_capable(&pdev->dev, IOMMU_CAP_PRE_BOOT_PROTECTION))
118762306a36Sopenharmony_ci		return 0;
118862306a36Sopenharmony_ci	*(bool *)data = true;
118962306a36Sopenharmony_ci	return 1; /* Stop walking */
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic void nhi_check_iommu(struct tb_nhi *nhi)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	struct pci_bus *bus = nhi->pdev->bus;
119562306a36Sopenharmony_ci	bool port_ok = false;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/*
119862306a36Sopenharmony_ci	 * Ideally what we'd do here is grab every PCI device that
119962306a36Sopenharmony_ci	 * represents a tunnelling adapter for this NHI and check their
120062306a36Sopenharmony_ci	 * status directly, but unfortunately USB4 seems to make it
120162306a36Sopenharmony_ci	 * obnoxiously difficult to reliably make any correlation.
120262306a36Sopenharmony_ci	 *
120362306a36Sopenharmony_ci	 * So for now we'll have to bodge it... Hoping that the system
120462306a36Sopenharmony_ci	 * is at least sane enough that an adapter is in the same PCI
120562306a36Sopenharmony_ci	 * segment as its NHI, if we can find *something* on that segment
120662306a36Sopenharmony_ci	 * which meets the requirements for Kernel DMA Protection, we'll
120762306a36Sopenharmony_ci	 * take that to imply that firmware is aware and has (hopefully)
120862306a36Sopenharmony_ci	 * done the right thing in general. We need to know that the PCI
120962306a36Sopenharmony_ci	 * layer has seen the ExternalFacingPort property which will then
121062306a36Sopenharmony_ci	 * inform the IOMMU layer to enforce the complete "untrusted DMA"
121162306a36Sopenharmony_ci	 * flow, but also that the IOMMU driver itself can be trusted not
121262306a36Sopenharmony_ci	 * to have been subverted by a pre-boot DMA attack.
121362306a36Sopenharmony_ci	 */
121462306a36Sopenharmony_ci	while (bus->parent)
121562306a36Sopenharmony_ci		bus = bus->parent;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	pci_walk_bus(bus, nhi_check_iommu_pdev, &port_ok);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	nhi->iommu_dma_protection = port_ok;
122062306a36Sopenharmony_ci	dev_dbg(&nhi->pdev->dev, "IOMMU DMA protection is %s\n",
122162306a36Sopenharmony_ci		str_enabled_disabled(port_ok));
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cistatic void nhi_reset(struct tb_nhi *nhi)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	ktime_t timeout;
122762306a36Sopenharmony_ci	u32 val;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	val = ioread32(nhi->iobase + REG_CAPS);
123062306a36Sopenharmony_ci	/* Reset only v2 and later routers */
123162306a36Sopenharmony_ci	if (FIELD_GET(REG_CAPS_VERSION_MASK, val) < REG_CAPS_VERSION_2)
123262306a36Sopenharmony_ci		return;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	if (!host_reset) {
123562306a36Sopenharmony_ci		dev_dbg(&nhi->pdev->dev, "skipping host router reset\n");
123662306a36Sopenharmony_ci		return;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	iowrite32(REG_RESET_HRR, nhi->iobase + REG_RESET);
124062306a36Sopenharmony_ci	msleep(100);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	timeout = ktime_add_ms(ktime_get(), 500);
124362306a36Sopenharmony_ci	do {
124462306a36Sopenharmony_ci		val = ioread32(nhi->iobase + REG_RESET);
124562306a36Sopenharmony_ci		if (!(val & REG_RESET_HRR)) {
124662306a36Sopenharmony_ci			dev_warn(&nhi->pdev->dev, "host router reset successful\n");
124762306a36Sopenharmony_ci			return;
124862306a36Sopenharmony_ci		}
124962306a36Sopenharmony_ci		usleep_range(10, 20);
125062306a36Sopenharmony_ci	} while (ktime_before(ktime_get(), timeout));
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	dev_warn(&nhi->pdev->dev, "timeout resetting host router\n");
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic int nhi_init_msi(struct tb_nhi *nhi)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct pci_dev *pdev = nhi->pdev;
125862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
125962306a36Sopenharmony_ci	int res, irq, nvec;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	/* In case someone left them on. */
126262306a36Sopenharmony_ci	nhi_disable_interrupts(nhi);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	nhi_enable_int_throttling(nhi);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	ida_init(&nhi->msix_ida);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	/*
126962306a36Sopenharmony_ci	 * The NHI has 16 MSI-X vectors or a single MSI. We first try to
127062306a36Sopenharmony_ci	 * get all MSI-X vectors and if we succeed, each ring will have
127162306a36Sopenharmony_ci	 * one MSI-X. If for some reason that does not work out, we
127262306a36Sopenharmony_ci	 * fallback to a single MSI.
127362306a36Sopenharmony_ci	 */
127462306a36Sopenharmony_ci	nvec = pci_alloc_irq_vectors(pdev, MSIX_MIN_VECS, MSIX_MAX_VECS,
127562306a36Sopenharmony_ci				     PCI_IRQ_MSIX);
127662306a36Sopenharmony_ci	if (nvec < 0) {
127762306a36Sopenharmony_ci		nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
127862306a36Sopenharmony_ci		if (nvec < 0)
127962306a36Sopenharmony_ci			return nvec;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci		INIT_WORK(&nhi->interrupt_work, nhi_interrupt_work);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		irq = pci_irq_vector(nhi->pdev, 0);
128462306a36Sopenharmony_ci		if (irq < 0)
128562306a36Sopenharmony_ci			return irq;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		res = devm_request_irq(&pdev->dev, irq, nhi_msi,
128862306a36Sopenharmony_ci				       IRQF_NO_SUSPEND, "thunderbolt", nhi);
128962306a36Sopenharmony_ci		if (res)
129062306a36Sopenharmony_ci			return dev_err_probe(dev, res, "request_irq failed, aborting\n");
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return 0;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic bool nhi_imr_valid(struct pci_dev *pdev)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	u8 val;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	if (!device_property_read_u8(&pdev->dev, "IMR_VALID", &val))
130162306a36Sopenharmony_ci		return !!val;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	return true;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistatic struct tb *nhi_select_cm(struct tb_nhi *nhi)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct tb *tb;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	/*
131162306a36Sopenharmony_ci	 * USB4 case is simple. If we got control of any of the
131262306a36Sopenharmony_ci	 * capabilities, we use software CM.
131362306a36Sopenharmony_ci	 */
131462306a36Sopenharmony_ci	if (tb_acpi_is_native())
131562306a36Sopenharmony_ci		return tb_probe(nhi);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/*
131862306a36Sopenharmony_ci	 * Either firmware based CM is running (we did not get control
131962306a36Sopenharmony_ci	 * from the firmware) or this is pre-USB4 PC so try first
132062306a36Sopenharmony_ci	 * firmware CM and then fallback to software CM.
132162306a36Sopenharmony_ci	 */
132262306a36Sopenharmony_ci	tb = icm_probe(nhi);
132362306a36Sopenharmony_ci	if (!tb)
132462306a36Sopenharmony_ci		tb = tb_probe(nhi);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	return tb;
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
133262306a36Sopenharmony_ci	struct tb_nhi *nhi;
133362306a36Sopenharmony_ci	struct tb *tb;
133462306a36Sopenharmony_ci	int res;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (!nhi_imr_valid(pdev))
133762306a36Sopenharmony_ci		return dev_err_probe(dev, -ENODEV, "firmware image not valid, aborting\n");
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	res = pcim_enable_device(pdev);
134062306a36Sopenharmony_ci	if (res)
134162306a36Sopenharmony_ci		return dev_err_probe(dev, res, "cannot enable PCI device, aborting\n");
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	res = pcim_iomap_regions(pdev, 1 << 0, "thunderbolt");
134462306a36Sopenharmony_ci	if (res)
134562306a36Sopenharmony_ci		return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n");
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	nhi = devm_kzalloc(&pdev->dev, sizeof(*nhi), GFP_KERNEL);
134862306a36Sopenharmony_ci	if (!nhi)
134962306a36Sopenharmony_ci		return -ENOMEM;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	nhi->pdev = pdev;
135262306a36Sopenharmony_ci	nhi->ops = (const struct tb_nhi_ops *)id->driver_data;
135362306a36Sopenharmony_ci	/* cannot fail - table is allocated in pcim_iomap_regions */
135462306a36Sopenharmony_ci	nhi->iobase = pcim_iomap_table(pdev)[0];
135562306a36Sopenharmony_ci	nhi->hop_count = ioread32(nhi->iobase + REG_CAPS) & 0x3ff;
135662306a36Sopenharmony_ci	dev_dbg(dev, "total paths: %d\n", nhi->hop_count);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	nhi->tx_rings = devm_kcalloc(&pdev->dev, nhi->hop_count,
135962306a36Sopenharmony_ci				     sizeof(*nhi->tx_rings), GFP_KERNEL);
136062306a36Sopenharmony_ci	nhi->rx_rings = devm_kcalloc(&pdev->dev, nhi->hop_count,
136162306a36Sopenharmony_ci				     sizeof(*nhi->rx_rings), GFP_KERNEL);
136262306a36Sopenharmony_ci	if (!nhi->tx_rings || !nhi->rx_rings)
136362306a36Sopenharmony_ci		return -ENOMEM;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	nhi_check_quirks(nhi);
136662306a36Sopenharmony_ci	nhi_check_iommu(nhi);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	nhi_reset(nhi);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	res = nhi_init_msi(nhi);
137162306a36Sopenharmony_ci	if (res)
137262306a36Sopenharmony_ci		return dev_err_probe(dev, res, "cannot enable MSI, aborting\n");
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	spin_lock_init(&nhi->lock);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	res = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
137762306a36Sopenharmony_ci	if (res)
137862306a36Sopenharmony_ci		return dev_err_probe(dev, res, "failed to set DMA mask\n");
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	pci_set_master(pdev);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	if (nhi->ops && nhi->ops->init) {
138362306a36Sopenharmony_ci		res = nhi->ops->init(nhi);
138462306a36Sopenharmony_ci		if (res)
138562306a36Sopenharmony_ci			return res;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	tb = nhi_select_cm(nhi);
138962306a36Sopenharmony_ci	if (!tb)
139062306a36Sopenharmony_ci		return dev_err_probe(dev, -ENODEV,
139162306a36Sopenharmony_ci			"failed to determine connection manager, aborting\n");
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	dev_dbg(dev, "NHI initialized, starting thunderbolt\n");
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	res = tb_domain_add(tb);
139662306a36Sopenharmony_ci	if (res) {
139762306a36Sopenharmony_ci		/*
139862306a36Sopenharmony_ci		 * At this point the RX/TX rings might already have been
139962306a36Sopenharmony_ci		 * activated. Do a proper shutdown.
140062306a36Sopenharmony_ci		 */
140162306a36Sopenharmony_ci		tb_domain_put(tb);
140262306a36Sopenharmony_ci		nhi_shutdown(nhi);
140362306a36Sopenharmony_ci		return res;
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci	pci_set_drvdata(pdev, tb);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	device_wakeup_enable(&pdev->dev);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	pm_runtime_allow(&pdev->dev);
141062306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, TB_AUTOSUSPEND_DELAY);
141162306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
141262306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&pdev->dev);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	return 0;
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic void nhi_remove(struct pci_dev *pdev)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	struct tb *tb = pci_get_drvdata(pdev);
142062306a36Sopenharmony_ci	struct tb_nhi *nhi = tb->nhi;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
142362306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
142462306a36Sopenharmony_ci	pm_runtime_forbid(&pdev->dev);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	tb_domain_remove(tb);
142762306a36Sopenharmony_ci	nhi_shutdown(nhi);
142862306a36Sopenharmony_ci}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci/*
143162306a36Sopenharmony_ci * The tunneled pci bridges are siblings of us. Use resume_noirq to reenable
143262306a36Sopenharmony_ci * the tunnels asap. A corresponding pci quirk blocks the downstream bridges
143362306a36Sopenharmony_ci * resume_noirq until we are done.
143462306a36Sopenharmony_ci */
143562306a36Sopenharmony_cistatic const struct dev_pm_ops nhi_pm_ops = {
143662306a36Sopenharmony_ci	.suspend_noirq = nhi_suspend_noirq,
143762306a36Sopenharmony_ci	.resume_noirq = nhi_resume_noirq,
143862306a36Sopenharmony_ci	.freeze_noirq = nhi_freeze_noirq,  /*
143962306a36Sopenharmony_ci					    * we just disable hotplug, the
144062306a36Sopenharmony_ci					    * pci-tunnels stay alive.
144162306a36Sopenharmony_ci					    */
144262306a36Sopenharmony_ci	.thaw_noirq = nhi_thaw_noirq,
144362306a36Sopenharmony_ci	.restore_noirq = nhi_resume_noirq,
144462306a36Sopenharmony_ci	.suspend = nhi_suspend,
144562306a36Sopenharmony_ci	.poweroff_noirq = nhi_poweroff_noirq,
144662306a36Sopenharmony_ci	.poweroff = nhi_suspend,
144762306a36Sopenharmony_ci	.complete = nhi_complete,
144862306a36Sopenharmony_ci	.runtime_suspend = nhi_runtime_suspend,
144962306a36Sopenharmony_ci	.runtime_resume = nhi_runtime_resume,
145062306a36Sopenharmony_ci};
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic struct pci_device_id nhi_ids[] = {
145362306a36Sopenharmony_ci	/*
145462306a36Sopenharmony_ci	 * We have to specify class, the TB bridges use the same device and
145562306a36Sopenharmony_ci	 * vendor (sub)id on gen 1 and gen 2 controllers.
145662306a36Sopenharmony_ci	 */
145762306a36Sopenharmony_ci	{
145862306a36Sopenharmony_ci		.class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
145962306a36Sopenharmony_ci		.vendor = PCI_VENDOR_ID_INTEL,
146062306a36Sopenharmony_ci		.device = PCI_DEVICE_ID_INTEL_LIGHT_RIDGE,
146162306a36Sopenharmony_ci		.subvendor = 0x2222, .subdevice = 0x1111,
146262306a36Sopenharmony_ci	},
146362306a36Sopenharmony_ci	{
146462306a36Sopenharmony_ci		.class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
146562306a36Sopenharmony_ci		.vendor = PCI_VENDOR_ID_INTEL,
146662306a36Sopenharmony_ci		.device = PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C,
146762306a36Sopenharmony_ci		.subvendor = 0x2222, .subdevice = 0x1111,
146862306a36Sopenharmony_ci	},
146962306a36Sopenharmony_ci	{
147062306a36Sopenharmony_ci		.class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
147162306a36Sopenharmony_ci		.vendor = PCI_VENDOR_ID_INTEL,
147262306a36Sopenharmony_ci		.device = PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI,
147362306a36Sopenharmony_ci		.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
147462306a36Sopenharmony_ci	},
147562306a36Sopenharmony_ci	{
147662306a36Sopenharmony_ci		.class = PCI_CLASS_SYSTEM_OTHER << 8, .class_mask = ~0,
147762306a36Sopenharmony_ci		.vendor = PCI_VENDOR_ID_INTEL,
147862306a36Sopenharmony_ci		.device = PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI,
147962306a36Sopenharmony_ci		.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
148062306a36Sopenharmony_ci	},
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	/* Thunderbolt 3 */
148362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_NHI) },
148462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_NHI) },
148562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_USBONLY_NHI) },
148662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_NHI) },
148762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_USBONLY_NHI) },
148862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_NHI) },
148962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_NHI) },
149062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_USBONLY_NHI) },
149162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_NHI) },
149262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI) },
149362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICL_NHI0),
149462306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
149562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICL_NHI1),
149662306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
149762306a36Sopenharmony_ci	/* Thunderbolt 4 */
149862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI0),
149962306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
150062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI1),
150162306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
150262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_H_NHI0),
150362306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
150462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_H_NHI1),
150562306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
150662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_NHI0),
150762306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
150862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_NHI1),
150962306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
151062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI0),
151162306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
151262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI1),
151362306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
151462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_M_NHI0),
151562306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
151662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI0),
151762306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
151862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1),
151962306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
152062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI) },
152162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI) },
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	/* Any USB4 compliant host */
152462306a36Sopenharmony_ci	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) },
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	{ 0,}
152762306a36Sopenharmony_ci};
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nhi_ids);
153062306a36Sopenharmony_ciMODULE_DESCRIPTION("Thunderbolt/USB4 core driver");
153162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_cistatic struct pci_driver nhi_driver = {
153462306a36Sopenharmony_ci	.name = "thunderbolt",
153562306a36Sopenharmony_ci	.id_table = nhi_ids,
153662306a36Sopenharmony_ci	.probe = nhi_probe,
153762306a36Sopenharmony_ci	.remove = nhi_remove,
153862306a36Sopenharmony_ci	.shutdown = nhi_remove,
153962306a36Sopenharmony_ci	.driver.pm = &nhi_pm_ops,
154062306a36Sopenharmony_ci};
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_cistatic int __init nhi_init(void)
154362306a36Sopenharmony_ci{
154462306a36Sopenharmony_ci	int ret;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	ret = tb_domain_init();
154762306a36Sopenharmony_ci	if (ret)
154862306a36Sopenharmony_ci		return ret;
154962306a36Sopenharmony_ci	ret = pci_register_driver(&nhi_driver);
155062306a36Sopenharmony_ci	if (ret)
155162306a36Sopenharmony_ci		tb_domain_exit();
155262306a36Sopenharmony_ci	return ret;
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_cistatic void __exit nhi_unload(void)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	pci_unregister_driver(&nhi_driver);
155862306a36Sopenharmony_ci	tb_domain_exit();
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cirootfs_initcall(nhi_init);
156262306a36Sopenharmony_cimodule_exit(nhi_unload);
1563