*
*/
-#include "sys/x86_isa.h"
-#include <sys/cpu.h>
+#include "asm/x86.h"
+#include "asm/x86_cpu.h"
+#include "asm/soc/apic.h"
-#include "sys/apic.h"
-#include <sys/hart.h>
+#include <asm/hart.h>
#include <lunaix/mm/mmio.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
+#include <lunaix/device.h>
+
+#include <hal/irq.h>
+#include <hal/acpi/acpi.h>
#include "pic.h"
LOG_MODULE("APIC")
+#define IOAPIC_IOREGSEL 0x00
+#define IOAPIC_IOWIN 0x10
+#define IOAPIC_IOREDTBL_BASE 0x10
+
+#define IOAPIC_REG_ID 0x00
+#define IOAPIC_REG_VER 0x01
+#define IOAPIC_REG_ARB 0x02
+
+#define IOAPIC_DELMOD_FIXED 0b000
+#define IOAPIC_DELMOD_LPRIO 0b001
+#define IOAPIC_DELMOD_NMI 0b100
+
+#define IOAPIC_MASKED (1 << 16)
+#define IOAPIC_TRIG_LEVEL (1 << 15)
+#define IOAPIC_INTPOL_L (1 << 13)
+#define IOAPIC_DESTMOD_LOGIC (1 << 11)
+
+#define IOAPIC_BASE_VADDR 0x2000
+
+#define IOAPIC_REG_SEL *((volatile u32_t*)(_ioapic_base + IOAPIC_IOREGSEL))
+#define IOAPIC_REG_WIN *((volatile u32_t*)(_ioapic_base + IOAPIC_IOWIN))
+
+
+#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector)
+
+// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think
+// it is too early for that
+// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14)
+#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE)
+#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector)
+
+
+static volatile ptr_t _ioapic_base;
static volatile ptr_t _apic_base;
void
-apic_setup_lvts();
+apic_write_reg(unsigned int reg, unsigned int val)
+{
+ *(unsigned int*)(_apic_base + reg) = val;
+}
void
+apic_ack_interrupt(irq_t irq)
+{
+ *(unsigned int*)(_apic_base + APIC_EOI) = 0;
+}
+
+unsigned int
+apic_read_reg(unsigned int reg)
+{
+ return *(unsigned int*)(_apic_base + (reg));
+}
+
+
+static void
+apic_setup_lvts()
+{
+ apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV));
+ apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1);
+ apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV));
+}
+
+static void
apic_init()
{
// ensure that external interrupt is disabled
// As we are going to use APIC, disable the old 8259 PIC
pic_disable();
- _apic_base = (ptr_t)ioremap(__APIC_BASE_PADDR, 4096);
+ _apic_base = ioremap(__APIC_BASE_PADDR, 4096);
// Hardware enable the APIC
// By setting bit 11 of IA32_APIC_BASE register
apic_write_reg(APIC_SPIVR, spiv);
}
-#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector)
+static void
+ioapic_init()
+{
+ acpi_context* acpi_ctx = acpi_get_context();
-// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think
-// it is too early for that
-// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14)
-#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE)
-#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector)
+ _ioapic_base =
+ ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096);
+}
-void
-apic_setup_lvts()
+static void
+ioapic_write(u8_t sel, u32_t val)
{
- apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV));
- apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1);
- apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV));
+ IOAPIC_REG_SEL = sel;
+ IOAPIC_REG_WIN = val;
}
-void
-apic_on_eoi(struct x86_intc* intc_ctx, cpu_t cpu, int iv)
+static u32_t
+ioapic_read(u8_t sel)
{
- // for all external interrupts except the spurious interrupt
- // this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5
- if (iv >= IV_EX_BEGIN && iv != APIC_SPIV_IV) {
- *(unsigned int*)(_apic_base + APIC_EOI) = 0;
+ IOAPIC_REG_SEL = sel;
+ return IOAPIC_REG_WIN;
+}
+
+static void
+__ioapic_install_line(struct irq_domain *domain, irq_t irq)
+{
+ struct irq_line_wire *line;
+ u8_t reg_sel;
+ u32_t ioapic_fg;
+
+ line = irq->line;
+ reg_sel = IOAPIC_IOREDTBL_BASE + line->domain_mapped * 2;
+ ioapic_fg = IOAPIC_DELMOD_FIXED;
+
+ // Write low 32 bits
+ ioapic_write(reg_sel, (irq->vector | ioapic_fg) & 0x1FFFF);
+
+ // Write high 32 bits
+ ioapic_write(reg_sel + 1, 0);
+}
+
+static int
+__ioapic_translate_irq(struct irq_domain *domain, irq_t irq, void *irq_extra)
+{
+ struct irq_line_wire *line;
+
+ if (irq->type == IRQ_LINE) {
+ line = irq->line;
+ line->domain_mapped = acpi_gsimap(line->domain_local);
}
+
+ return 0;
}
-unsigned int
-apic_read_reg(unsigned int reg)
+static int
+__ioapic_install_irq(struct irq_domain *domain, irq_t irq)
{
- return *(unsigned int*)(_apic_base + (reg));
+ if (irq->vector == IRQ_VECTOR_UNSET) {
+ irq->vector = btrie_map(&domain->irq_map, IV_EX_BEGIN, IV_EX_END, irq);
+ }
+ else {
+ irq_record(domain, irq);
+ }
+
+ if (irq->type == IRQ_MESSAGE) {
+ irq->msi->wr_addr = __APIC_BASE_PADDR;
+ }
+ else {
+ __ioapic_install_line(domain, irq);
+ }
+
+ return 0;
}
-void
-apic_write_reg(unsigned int reg, unsigned int val)
+
+static struct irq_domain_ops apic_domain_ops = {
+ .map_irq = __ioapic_translate_irq,
+ .install_irq = __ioapic_install_irq
+};
+
+static int
+apic_device_create(struct device_def* def, morph_t* morph)
{
- *(unsigned int*)(_apic_base + reg) = val;
-}
\ No newline at end of file
+ int err;
+ struct device* dev;
+ struct irq_domain* domain;
+
+ apic_init();
+ ioapic_init();
+
+ dev = device_allocsys(NULL, NULL);
+ domain = irq_create_domain(dev, &apic_domain_ops);
+
+ irq_set_default_domain(domain);
+ register_device(dev, &def->class, "apic");
+ irq_attach_domain(NULL, domain);
+
+ return 0;
+}
+
+static struct device_def apic_devdef = {
+ def_device_class(INTEL, CFG, INTC),
+ def_device_name("x86 APIC"),
+ def_on_create(apic_device_create)
+};
+EXPORT_DEVICE(x86_apic, &apic_devdef, load_sysconf);
\ No newline at end of file