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:
p-szafonimateusz 2024-03-11 17:14:52 +01:00 committed by Xiang Xiao
parent db6d0bd356
commit 0659b333b4
3 changed files with 245 additions and 5 deletions

View File

@ -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
}

View File

@ -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
****************************************************************************/

View File

@ -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);
}