mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
thunderbolt: Add vendor specific NHI quirk for auto-clearing interrupt status
Introduce nhi_check_quirks() routine to handle any vendor specific quirks to manage a hardware specific implementation. On Intel hardware the USB4 controller supports clearing the interrupt status register automatically right after it is being issued. For this reason add a new quirk that does that on all Intel hardware. Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> Signed-off-by: Sanjay R Mehta <sanju.mehta@amd.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
parent
1651d9e781
commit
e390909ac7
@ -35,6 +35,8 @@
|
||||
|
||||
#define NHI_MAILBOX_TIMEOUT 500 /* ms */
|
||||
|
||||
#define QUIRK_AUTO_CLEAR_INT BIT(0)
|
||||
|
||||
static int ring_interrupt_index(struct tb_ring *ring)
|
||||
{
|
||||
int bit = ring->hop;
|
||||
@ -66,14 +68,17 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active)
|
||||
else
|
||||
index = ring->hop + ring->nhi->hop_count;
|
||||
|
||||
/*
|
||||
* Ask the hardware to clear interrupt status bits automatically
|
||||
* since we already know which interrupt was triggered.
|
||||
*/
|
||||
misc = ioread32(ring->nhi->iobase + REG_DMA_MISC);
|
||||
if (!(misc & REG_DMA_MISC_INT_AUTO_CLEAR)) {
|
||||
misc |= REG_DMA_MISC_INT_AUTO_CLEAR;
|
||||
iowrite32(misc, ring->nhi->iobase + REG_DMA_MISC);
|
||||
if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT) {
|
||||
/*
|
||||
* Ask the hardware to clear interrupt status
|
||||
* bits automatically since we already know
|
||||
* which interrupt was triggered.
|
||||
*/
|
||||
misc = ioread32(ring->nhi->iobase + REG_DMA_MISC);
|
||||
if (!(misc & REG_DMA_MISC_INT_AUTO_CLEAR)) {
|
||||
misc |= REG_DMA_MISC_INT_AUTO_CLEAR;
|
||||
iowrite32(misc, ring->nhi->iobase + REG_DMA_MISC);
|
||||
}
|
||||
}
|
||||
|
||||
ivr_base = ring->nhi->iobase + REG_INT_VEC_ALLOC_BASE;
|
||||
@ -1074,6 +1079,16 @@ static void nhi_shutdown(struct tb_nhi *nhi)
|
||||
nhi->ops->shutdown(nhi);
|
||||
}
|
||||
|
||||
static void nhi_check_quirks(struct tb_nhi *nhi)
|
||||
{
|
||||
/*
|
||||
* Intel hardware supports auto clear of the interrupt status
|
||||
* reqister right after interrupt is being issued.
|
||||
*/
|
||||
if (nhi->pdev->vendor == PCI_VENDOR_ID_INTEL)
|
||||
nhi->quirks |= QUIRK_AUTO_CLEAR_INT;
|
||||
}
|
||||
|
||||
static int nhi_init_msi(struct tb_nhi *nhi)
|
||||
{
|
||||
struct pci_dev *pdev = nhi->pdev;
|
||||
@ -1190,6 +1205,8 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
if (!nhi->tx_rings || !nhi->rx_rings)
|
||||
return -ENOMEM;
|
||||
|
||||
nhi_check_quirks(nhi);
|
||||
|
||||
res = nhi_init_msi(nhi);
|
||||
if (res) {
|
||||
dev_err(&pdev->dev, "cannot enable MSI, aborting\n");
|
||||
|
@ -468,6 +468,7 @@ static inline struct tb_xdomain *tb_service_parent(struct tb_service *svc)
|
||||
* @interrupt_work: Work scheduled to handle ring interrupt when no
|
||||
* MSI-X is used.
|
||||
* @hop_count: Number of rings (end point hops) supported by NHI.
|
||||
* @quirks: NHI specific quirks if any
|
||||
*/
|
||||
struct tb_nhi {
|
||||
spinlock_t lock;
|
||||
@ -480,6 +481,7 @@ struct tb_nhi {
|
||||
bool going_away;
|
||||
struct work_struct interrupt_work;
|
||||
u32 hop_count;
|
||||
unsigned long quirks;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user