diff --git a/arch/x86_64/include/irq.h b/arch/x86_64/include/irq.h index e45b25ea9e..76de330d94 100644 --- a/arch/x86_64/include/irq.h +++ b/arch/x86_64/include/irq.h @@ -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 } diff --git a/arch/x86_64/src/common/x86_64_pci.c b/arch/x86_64/src/common/x86_64_pci.c index a84bc73898..4d1b456c12 100644 --- a/arch/x86_64/src/common/x86_64_pci.c +++ b/arch/x86_64/src/common/x86_64_pci.c @@ -27,6 +27,8 @@ #include #include +#include + #include #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 ****************************************************************************/ diff --git a/arch/x86_64/src/intel64/intel64_irq.c b/arch/x86_64/src/intel64/intel64_irq.c index f4d5320d1e..f617d98f42 100644 --- a/arch/x86_64/src/intel64/intel64_irq.c +++ b/arch/x86_64/src/intel64/intel64_irq.c @@ -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); +}