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