arch/x86_64/intel64: add MSI/MSI-X support
Add MSI and MSI-X support for intel64 Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
parent
db6d0bd356
commit
0659b333b4
@ -147,6 +147,18 @@ static inline_function bool up_interrupt_context(void)
|
||||
return up_current_regs() != NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_alloc_irq_msi
|
||||
* Name: up_release_irq_msi
|
||||
*
|
||||
* Description:
|
||||
* Reserve/release vector for MSI
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_alloc_irq_msi(int *num);
|
||||
void up_release_irq_msi(int *irq, int num);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/pci/pci.h>
|
||||
|
||||
#include "x86_64_internal.h"
|
||||
@ -39,6 +41,9 @@
|
||||
#define PCI_DATA_ADDR 0xcfc
|
||||
#define PCI_CFG_EN (1 << 31)
|
||||
|
||||
#define X86_64_MAR_DEST 0xfee00000
|
||||
#define X86_64_MDR_TYPE 0x4000
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions Definitions
|
||||
****************************************************************************/
|
||||
@ -54,17 +59,31 @@ static int x86_64_pci_read_io(struct pci_bus_s *bus, uintptr_t addr,
|
||||
static int x86_64_pci_write_io(struct pci_bus_s *bus, uintptr_t addr,
|
||||
int size, uint32_t val);
|
||||
|
||||
static int x86_64_pci_get_irq(struct pci_bus_s *bus, uint8_t line);
|
||||
|
||||
static int x86_64_pci_alloc_irq(struct pci_bus_s *bus,
|
||||
int *irq, int num);
|
||||
static void x86_64_pci_release_irq(struct pci_bus_s *bus,
|
||||
int *irq, int num);
|
||||
static int x86_64_pci_connect_irq(struct pci_bus_s *bus,
|
||||
int *irq, int num,
|
||||
uintptr_t *mar, uint32_t *mdr);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct pci_ops_s g_x86_64_pci_ops =
|
||||
{
|
||||
.write = x86_64_pci_write,
|
||||
.read = x86_64_pci_read,
|
||||
.map = x86_64_pci_map,
|
||||
.read_io = x86_64_pci_read_io,
|
||||
.write_io = x86_64_pci_write_io,
|
||||
.write = x86_64_pci_write,
|
||||
.read = x86_64_pci_read,
|
||||
.map = x86_64_pci_map,
|
||||
.read_io = x86_64_pci_read_io,
|
||||
.write_io = x86_64_pci_write_io,
|
||||
.get_irq = x86_64_pci_get_irq,
|
||||
.alloc_irq = x86_64_pci_alloc_irq,
|
||||
.release_irq = x86_64_pci_release_irq,
|
||||
.connect_irq = x86_64_pci_connect_irq,
|
||||
};
|
||||
|
||||
static struct pci_controller_s g_x86_64_pci =
|
||||
@ -281,6 +300,126 @@ static uintptr_t x86_64_pci_map(struct pci_bus_s *bus, uintptr_t start,
|
||||
return ret < 0 ? 0 : start;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_pci_get_irq
|
||||
*
|
||||
* Description:
|
||||
* Get interrupt number associated with a given INTx line.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus - Bus that PCI device resides
|
||||
* line - activated PCI legacy interrupt line
|
||||
*
|
||||
* Returned Value:
|
||||
* Return interrupt number associated with a given INTx
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int x86_64_pci_get_irq(struct pci_bus_s *bus, uint8_t line)
|
||||
{
|
||||
UNUSED(bus);
|
||||
|
||||
return IRQ0 + line;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_pci_alloc_irq
|
||||
*
|
||||
* Description:
|
||||
* Allocate interrupts for MSI/MSI-X vector.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus - Bus that PCI device resides
|
||||
* irq - allocated vectors array
|
||||
* num - number of vectors to allocate
|
||||
*
|
||||
* Returned Value:
|
||||
* >0: success, return number of allocated vectors,
|
||||
* <0: A negative value errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int x86_64_pci_alloc_irq(struct pci_bus_s *bus, int *irq, int num)
|
||||
{
|
||||
int tmp = 0;
|
||||
int i = 0;
|
||||
|
||||
/* Try to get irq */
|
||||
|
||||
tmp = up_alloc_irq_msi(&num);
|
||||
if (tmp < 0)
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Copy allocated interrupts */
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
irq[i] = tmp++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_pci_release_irq
|
||||
*
|
||||
* Description:
|
||||
* Allocate interrupts for MSI/MSI-X vector.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus - Bus that PCI device resides
|
||||
* irq - vectors array to release
|
||||
* num - number of vectors in array
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void x86_64_pci_release_irq(struct pci_bus_s *bus, int *irq, int num)
|
||||
{
|
||||
up_release_irq_msi(irq, num);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_pci_connect_irq
|
||||
*
|
||||
* Description:
|
||||
* Connect interrupt for MSI/MSI-X.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus - Bus that PCI device resides
|
||||
* irq - vectors array
|
||||
* num - number of vectors in array
|
||||
* mar - returned value for Message Address Register
|
||||
* mdr - returned value for Message Data Register
|
||||
*
|
||||
* Returned Value:
|
||||
* >0: success, 0: A positive value errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int x86_64_pci_connect_irq(struct pci_bus_s *bus, int *irq, int num,
|
||||
uintptr_t *mar, uint32_t *mdr)
|
||||
{
|
||||
UNUSED(num);
|
||||
|
||||
if (mar != NULL)
|
||||
{
|
||||
*mar = X86_64_MAR_DEST |
|
||||
(up_apic_cpu_id() << PCI_MSI_DATA_CPUID_SHIFT);
|
||||
}
|
||||
|
||||
if (mdr != NULL)
|
||||
{
|
||||
*mdr = X86_64_MDR_TYPE | irq[0];
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -47,6 +47,8 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define IRQ_MSI_START IRQ32
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
@ -54,6 +56,7 @@
|
||||
struct intel64_irq_priv_s
|
||||
{
|
||||
cpu_set_t busy;
|
||||
bool msi;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -75,6 +78,7 @@ static inline void up_idtinit(void);
|
||||
|
||||
static struct idt_entry_s g_idt_entries[NR_IRQS];
|
||||
static struct intel64_irq_priv_s g_irq_priv[NR_IRQS];
|
||||
static int g_msi_now = IRQ_MSI_START;
|
||||
static spinlock_t g_irq_spinlock;
|
||||
|
||||
/****************************************************************************
|
||||
@ -491,6 +495,14 @@ void up_disable_irq(int irq)
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
/* Do nothing if this is MSI/MSI-X */
|
||||
|
||||
if (g_irq_priv[irq].msi)
|
||||
{
|
||||
spin_unlock_irqrestore(&g_irq_spinlock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_irq_priv[irq].busy > 0)
|
||||
{
|
||||
g_irq_priv[irq].busy -= 1;
|
||||
@ -534,6 +546,14 @@ void up_enable_irq(int irq)
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Do nothing if this is MSI/MSI-X */
|
||||
|
||||
if (g_irq_priv[irq].msi)
|
||||
{
|
||||
spin_unlock_irqrestore(&g_irq_spinlock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (irq > IRQ255)
|
||||
{
|
||||
/* Not supported yet */
|
||||
@ -601,3 +621,72 @@ void up_trigger_irq(int irq, cpu_set_t cpuset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_alloc_irq_msi
|
||||
*
|
||||
* Description:
|
||||
* Reserve vector for MSI/MSI-X
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_alloc_irq_msi(int *num)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave(&g_irq_spin);
|
||||
int irq = 0;
|
||||
int i = 0;
|
||||
|
||||
/* Limit requested number of vectors */
|
||||
|
||||
if (g_msi_now + *num > IRQ255)
|
||||
{
|
||||
*num = IRQ255 - g_msi_now;
|
||||
}
|
||||
|
||||
if (*num <= 0)
|
||||
{
|
||||
spin_unlock_irqrestore(&g_irq_spin, flags);
|
||||
|
||||
/* No IRQs available */
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
irq = g_msi_now;
|
||||
g_msi_now += *num;
|
||||
|
||||
/* Mark IRQs as MSI/MSI-X */
|
||||
|
||||
for (i = 0; i < *num; i++)
|
||||
{
|
||||
ASSERT(g_irq_priv[irq + i].busy == 0);
|
||||
g_irq_priv[irq + i].msi = true;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&g_irq_spin, flags);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_release_irq_msi
|
||||
*
|
||||
* Description:
|
||||
* Release MSI/MSI-X vector
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_release_irq_msi(int *irq, int num)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave(&g_irq_spin);
|
||||
int i = 0;
|
||||
|
||||
/* Mark IRQ as MSI/MSI-X */
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
g_irq_priv[irq[i]].msi = false;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&g_irq_spin, flags);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user