typedef void (*isr_cb)(const struct hart_state*);
-typedef struct {
- ptr_t msi_addr;
- reg_t msi_data;
- int mapped_iv;
-} msi_vector_t;
-#define msi_addr(msiv) ((msiv).msi_addr)
-#define msi_data(msiv) ((msiv).msi_data)
-#define msi_vect(msiv) ((msiv).mapped_iv)
-
-typedef void* msienv_t;
-
void
isrm_init();
-/**
- * @brief Release a iv resource
- *
- * @param iv
- */
-void
-isrm_ivfree(int iv);
-
-/**
- * @brief Begin MSI allocation for given device
- *
- * @param iv
- */
-msienv_t
-isrm_msi_start(struct device* dev);
-
-/**
- * @brief Query number of msi avaliable for the device
- */
-int
-isrm_msi_avaliable(msienv_t msienv);
-
-/**
- * @brief Allocate a msi resource within defined msi resource list
- * for the device, indexed by `index`
- */
-msi_vector_t
-isrm_msi_alloc(msienv_t msienv, cpu_t cpu, int index, isr_cb handler);
-
-/**
- * @brief Set the sideband information will be used for upcoming
- * allocations
- */
-void
-isrm_msi_set_sideband(msienv_t msienv, ptr_t sideband);
-
-/**
- * @brief Done MSI allocation
- */
-void
-isrm_msi_done(msienv_t msienv);
-
-static inline must_inline msi_vector_t
-isrm_msi_alloc_simple(struct device* dev, cpu_t cpu, isr_cb handler)
-{
- msi_vector_t v;
- msienv_t env;
-
- env = isrm_msi_start(dev);
- v = isrm_msi_alloc(env, cpu, 0, handler);
- isrm_msi_done(env);
-
- return v;
-}
-
-/**
- * @brief Bind the iv according to given device tree node
- *
- * @param node
- */
-int
-isrm_bind_dtn(struct dtn_intr* node);
-
-/**
- * @brief Get the handler associated with the given iv
- *
- * @param iv
- * @return isr_cb
- */
-isr_cb
-isrm_get(int iv);
-
-ptr_t
-isrm_get_payload(const struct hart_state*);
-
-void
-isrm_set_payload(int iv, ptr_t);
-
/**
* @brief Notify end of interrupt event
*
void
isrm_notify_eoi(cpu_t id, int iv);
-/**
- * @brief Notify end of scheduling event
- *
- * @param id
- */
-void
-isrm_notify_eos(cpu_t id);
-
#endif /* __LUNAIX_ISRM_H */
void
intr_routine_apic_error(const struct hart_state* state)
{
- u32_t error_reg = apic_read_reg(APIC_ESR);
- char buf[32];
- ksprintf(buf, "APIC error, ESR=0x%x", error_reg);
-
+ ERROR("APIC error");
failsafe_diagnostic();
}
void
intr_routine_sched(const struct hart_state* state)
{
+ isrm_notify_eoi(0, LUNAIX_SCHED);
schedule();
}
#include <lunaix/spike.h>
-#include <lunaix/device.h>
#include <asm/x86_isrm.h>
#include "asm/x86.h"
-#include "asm/soc/ioapic.h"
#include "asm/soc/apic.h"
/*
static isr_cb handlers[TOTAL_IV];
static ptr_t ivhand_payload[TOTAL_IV];
-static struct x86_intc arch_intc_ctx;
-
extern void
intr_routine_fallback(const struct hart_state* state);
handlers[iv] = intr_routine_fallback;
}
-int
-isrm_bindirq(int irq, isr_cb irq_handler)
-{
- int iv;
- if (!(iv = isrm_ivexalloc(irq_handler))) {
- fail("out of IV resource.");
- return 0; // never reach
- }
-
- // fixed, edge trigged, polarity=high
- isrm_irq_attach(irq, iv, 0, IRQ_DEFAULT);
-
- return iv;
-}
-
void
isrm_bindiv(int iv, isr_cb handler)
{
assert(iv < 256);
ivhand_payload[iv] = payload;
-}
-
-void
-isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags)
-{
- arch_intc_ctx.irq_attach(&arch_intc_ctx, irq, iv, dest, flags);
-}
-
-void
-isrm_notify_eoi(cpu_t id, int iv)
-{
- arch_intc_ctx.notify_eoi(&arch_intc_ctx, id, iv);
-}
-
-void
-isrm_notify_eos(cpu_t id)
-{
- isrm_notify_eoi(id, LUNAIX_SCHED);
-}
-
-msienv_t
-isrm_msi_start(struct device* dev)
-{
- /*
- * In x86, the MSI topology is rather simple, as the only
- * source is the PCI itself, and the write destination is
- * explictly defined in specification, so we don't need the
- * msienv to hold dynamically probed address
- */
- return NULL;
-}
-
-int
-isrm_msi_avaliable(msienv_t msienv)
-{
- return 1;
-}
-
-msi_vector_t
-isrm_msi_alloc(msienv_t msienv, cpu_t cpu, int index, isr_cb handler)
-{
- unsigned int iv = isrm_ivexalloc(handler);
-
- // we ignore the cpu redirection for now.
- return (msi_vector_t){
- .msi_addr = __APIC_BASE_PADDR,
- .msi_data = iv,
- .mapped_iv = iv
- };
-}
-
-void
-isrm_msi_set_sideband(msienv_t msienv, ptr_t sideband)
-{
- return;
-}
-
-void
-isrm_msi_done(msienv_t msienv)
-{
- return;
-}
-
-
-
-int
-isrm_bind_dtn(struct dtn_intr* node)
-{
- fail("not supported");
-}
-
-
-static int
-__intc_create(struct device_def* devdef, morph_t* obj)
-{
- apic_init();
- ioapic_init();
-
- arch_intc_ctx.name = "i386_apic";
- arch_intc_ctx.irq_attach = ioapic_irq_remap;
- arch_intc_ctx.notify_eoi = apic_on_eoi;
-
- return 0;
-}
-
-
-static struct device_def i386_intc = {
- def_device_class(INTEL, CFG, INTC),
- def_device_name("i386 apic"),
- def_on_create(__intc_create)
-};
-EXPORT_DEVICE(i386_intc, &i386_intc, load_sysconf);
\ No newline at end of file
+}
\ No newline at end of file
"cpu.c",
"ps2kbd.c",
"apic_timer.c",
- "ioapic.c",
"mc146818a.c",
"pci.c"
])
\ No newline at end of file
#include "asm/x86.h"
#include "asm/x86_cpu.h"
-
#include "asm/soc/apic.h"
+
#include <asm/hart.h>
+#include <asm/x86_isrm.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
+isrm_notify_eoi(cpu_t id, int iv)
+{
+ // 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;
+ }
+}
+
+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
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 void
+__external_irq_dispatch(const struct hart_state* state)
{
- return *(unsigned int*)(_apic_base + (reg));
+ irq_t irq;
+
+ irq = irq_find(irq_get_default_domain(), hart_vector_stamp(state));
+
+ assert(irq);
+ irq_serve(irq, state);
}
-void
-apic_write_reg(unsigned int reg, unsigned int val)
+static int
+__ioapic_install_irq(struct irq_domain *domain, irq_t irq)
{
- *(unsigned int*)(_apic_base + reg) = val;
-}
\ No newline at end of file
+ irq->vector = isrm_ivexalloc(__external_irq_dispatch);
+
+ if (irq->type == IRQ_MESSAGE) {
+ irq->msi->wr_addr = __APIC_BASE_PADDR;
+ }
+ else {
+ __ioapic_install_line(domain, irq);
+ }
+
+ irq_record(domain, irq);
+
+ return 0;
+}
+
+
+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)
+{
+ 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
+++ /dev/null
-#include <hal/acpi/acpi.h>
-
-#include <lunaix/mm/mmio.h>
-
-#include <asm/hart.h>
-#include "asm/soc/ioapic.h"
-#include "asm/x86.h"
-
-#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))
-
-static volatile ptr_t _ioapic_base;
-
-void
-ioapic_init()
-{
- // Remapping the IRQs
-
- acpi_context* acpi_ctx = acpi_get_context();
-
- _ioapic_base =
- ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096);
-}
-
-void
-ioapic_write(u8_t sel, u32_t val)
-{
- IOAPIC_REG_SEL = sel;
- IOAPIC_REG_WIN = val;
-}
-
-u32_t
-ioapic_read(u8_t sel)
-{
- IOAPIC_REG_SEL = sel;
- return IOAPIC_REG_WIN;
-}
-
-void
-ioapic_irq_remap(struct x86_intc* intc, int irq, int iv, cpu_t dest, u32_t flags)
-{
- /*
- FIXME move it to HAL level. since every platform might have their own
- wiring, thus gsi mapping is required all the time
- */
- irq = acpi_gsimap(irq);
- u8_t reg_sel = IOAPIC_IOREDTBL_BASE + irq * 2;
-
- u32_t ioapic_fg = 0;
-
- if ((flags & IRQ_TYPE) == IRQ_TYPE_FIXED) {
- ioapic_fg |= IOAPIC_DELMOD_FIXED;
- } else {
- ioapic_fg |= IOAPIC_DELMOD_NMI;
- }
-
- if ((flags & IRQ_TRIG_LEVEL)) {
- ioapic_fg |= IOAPIC_TRIG_LEVEL;
- }
-
- if (!(flags & IRQ_VE_HI)) {
- ioapic_fg |= IOAPIC_INTPOL_L;
- }
-
- // Write low 32 bits
- ioapic_write(reg_sel, (iv | ioapic_fg) & 0x1FFFF);
-
- // Write high 32 bits
- ioapic_write(reg_sel + 1, (dest << 24));
-}
\ No newline at end of file
#include <lunaix/hart_state.h>
#include <hal/hwrtc.h>
+#include <hal/irq.h>
#include <klibc/string.h>
struct mc146818
{
struct hwrtc_potens* rtc_context;
- u32_t rtc_iv;
+ irq_t irq;
};
#define rtc_state(data) ((struct mc146818*)(data))
}
static void
-__rtc_tick(const struct hart_state* hstate)
+__rtc_tick(irq_t irq, const struct hart_state* hstate)
{
- struct mc146818* state = (struct mc146818*)isrm_get_payload(hstate);
+ struct mc146818* state;
+ state = irq_payload(irq, struct mc146818);
state->rtc_context->live++;
(void)rtc_read_reg(RTC_REG_C);
__rtc_calibrate(struct hwrtc_potens* pot)
{
struct mc146818* state;
+ struct device* rtc_dev;
+ u8_t reg;
+
+ rtc_dev = potens_dev(pot);
- u8_t reg = rtc_read_reg(RTC_REG_A);
+ reg = rtc_read_reg(RTC_REG_A);
reg = (reg & ~0x7f) | RTC_FREQUENCY_1024HZ | RTC_DIVIDER_33KHZ;
rtc_write_reg(RTC_REG_A, reg);
pot->base_freq = RTC_TIMER_BASE_FREQUENCY;
- state = (struct mc146818*)potens_dev(pot)->underlay;
- state->rtc_iv = isrm_bindirq(PC_AT_IRQ_RTC, __rtc_tick);
- isrm_set_payload(state->rtc_iv, __ptr(state));
+ state = (struct mc146818*)rtc_dev->underlay;
+
+ state->irq = irq_declare_line(__rtc_tick, PC_AT_IRQ_RTC, NULL);
+ irq_set_payload(state->irq, state);
+
+ irq_assign(irq_owning_domain(rtc_dev), state->irq);
return 0;
}
#include <lunaix/timer.h>
#include <lunaix/hart_state.h>
+#include <hal/irq.h>
+
#include "asm/x86.h"
#include <klibc/string.h>
// #define KBD_DBGLOG
static void
-intr_ps2_kbd_handler(const struct hart_state* hstate);
+intr_ps2_kbd_handler(irq_t irq, const struct hart_state* hstate);
static u8_t
ps2_issue_cmd_wretry(char cmd, u16_t arg);
*
* 所以,保险的方法是:在初始化后才去设置ioapic,这样一来我们就能有一个稳定的IRQ#1以放心使用。
*/
- isrm_bindirq(PC_AT_IRQ_KBD, intr_ps2_kbd_handler);
+
+ irq_t irq = irq_declare_line(intr_ps2_kbd_handler, PC_AT_IRQ_KBD, NULL);
+ irq_assign(irq_owning_domain(kbd_idev->dev_if), irq);
return 0;
}
static void
-intr_ps2_kbd_handler(const struct hart_state* hstate)
+intr_ps2_kbd_handler(irq_t irq, const struct hart_state* hstate)
{
// This is important! Don't believe me? try comment it out and run on Bochs!
void
apic_write_reg(unsigned int reg, unsigned int val);
-void
-apic_init();
-
-void
-apic_on_eoi(struct x86_intc* intc_ctx, cpu_t cpu, int iv);
-
#endif /* __LUNAIX_APIC_H */
+++ /dev/null
-#ifndef __LUNAIX_IOAPIC_H
-#define __LUNAIX_IOAPIC_H
-
-#include "asm/x86.h"
-
-void
-ioapic_init();
-
-void
-ioapic_irq_remap(struct x86_intc*,
- int irq,
- int iv,
- cpu_t dest,
- u32_t flags);
-
-#endif /* __LUNAIX_IOAPIC_H */
#include <asm-generic/isrm.h>
-/**
- * @brief Bind a given irq and associated handler to an iv
- *
- * @param iv iv allocated by system
- */
-int
-isrm_bindirq(int irq, isr_cb irq_handler);
-
/**
* @brief Bind given iv with it's associated handler
*
int
isrm_ivexalloc(isr_cb handler);
+/**
+ * @brief Release a iv resource
+ *
+ * @param iv
+ */
+void
+isrm_ivfree(int iv);
+
+/**
+ * @brief Get the handler associated with the given iv
+ *
+ * @param iv
+ * @return isr_cb
+ */
+isr_cb
+isrm_get(int iv);
+
+ptr_t
+isrm_get_payload(const struct hart_state*);
+
+void
+isrm_set_payload(int iv, ptr_t);
+
+
#endif /* __LUNAIX_X86_ISRM_H */
use("bus")
if config("use_devicetree"):
- use("devtree")
\ No newline at end of file
+ use("devtree")
+
+sources([
+ "irq.c"
+])
\ No newline at end of file
LOG_MODULE("AHCI")
-DEFINE_LLIST(ahcis);
+static DEFINE_LLIST(ahcis);
static char sata_ifs[][20] = { "Not detected",
"SATA I (1.5Gbps)",
{
struct ahci_driver* ahci_drv = vzalloc(sizeof(*ahci_drv));
struct ahci_hba* hba = &ahci_drv->hba;
- ahci_drv->id = param->ahci_iv;
-
- isrm_set_payload(param->ahci_iv, (ptr_t)&ahcis);
+ ahci_drv->id = param->irq->vector;
+ irq_set_payload(param->irq, &ahcis);
llist_append(&ahcis, &ahci_drv->ahci_drvs);
hba->base = (hba_reg_t*)ioremap(param->mmio_base, param->mmio_size);
struct device* dev;
struct pci_base_addr* bar6;
struct ahci_driver* ahci_drv;
- msi_vector_t msiv;
+ irq_t irq;
probe = changeling_try_reveal(morphed, pci_probe_morpher);
if (!probe) {
assert(pci_capability_msi(probe));
- msiv = pci_msi_setup_simple(probe, ahci_hba_isr);
+ irq = pci_declare_msi_irq(ahci_hba_isr, probe, NULL);
+ pci_assign_msi(probe, irq);
struct ahci_driver_param param = {
.mmio_base = bar6->start,
.mmio_size = bar6->size,
- .ahci_iv = msi_vect(msiv),
+ .irq = irq,
};
ahci_drv = ahci_driver_init(¶m);
LOG_MODULE("io_evt")
void
-ahci_hba_isr(const struct hart_state* hstate)
+ahci_hba_isr(irq_t irq, const struct hart_state* hstate)
{
struct ahci_hba* hba;
struct ahci_driver *pos, *n;
- struct llist_header* ahcis = (struct llist_header*)isrm_get_payload(hstate);
+ struct llist_header* ahcis;
+ ahcis = irq_payload(irq, struct llist_header);
llist_for_each(pos, n, ahcis, ahci_drvs)
{
if (pos->id == hart_vector_stamp(hstate)) {
prober->cspace_base = pci_base;
prober->intr_info = intr;
prober->loc = loc;
+ prober->irq_domain = irq_get_domain(pci_bridge);
changeling_morph_anon(pci_probers, prober->mobj, pci_probe_morpher);
}
static void
-__pci_config_msi(struct pci_probe* probe, msi_vector_t msiv)
+__pci_config_msi(struct pci_probe* probe, irq_t irq)
{
// PCI LB Spec. (Rev 3) Section 6.8 & 6.8.1
- ptr_t msi_addr = msi_addr(msiv);
- u32_t msi_data = msi_data(msiv);
+ ptr_t msi_addr = irq->msi->wr_addr;
+ u32_t msi_data = irq->msi->message;
pci_reg_t reg1 = pci_read_cspace(probe->cspace_base, probe->msi_loc);
pci_reg_t msg_ctl = reg1 >> 16;
pci_write_cspace(probe->cspace_base, probe->msi_loc, reg1);
}
-msienv_t
-pci_msi_start(struct pci_probe* probe)
+irq_t
+pci_declare_msi_irq(irq_servant callback,
+ struct pci_probe* probe, void *irq_extra)
{
- /*
- As a PCI bridge/root complex can be initialised from device tree node,
- in that case, general information such as routing, rid remapping,
- are vital to all msi setup of all peripherals under it.
-
- Therefore, a wrapper around isrm_msi_* is needed in order to
- improve overall readability and usability, where the bridge
- device instance that contain these information will be
- automatically passed to the underlay as credential to perform
- configuration.
- */
-
- msienv_t env;
-
- env = isrm_msi_start(pci_bridge);
- isrm_msi_set_sideband(env, pci_requester_id(probe));
-
- return env;
+ return irq_declare_msg(callback, probe->loc, probe->loc, irq_extra);
}
-msi_vector_t
-pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe,
- int i, isr_cb handler)
+int
+pci_assign_msi(struct pci_probe* probe, irq_t irq)
{
- msi_vector_t msiv;
+ int err = 0;
- msiv = isrm_msi_alloc(msienv, 0, i, handler);
- __pci_config_msi(probe, msiv);
+ assert(irq->type == IRQ_MESSAGE);
- return msiv;
+ err = irq_assign(probe->irq_domain, irq);
+ if (err) {
+ return err;
+ }
+
+ __pci_config_msi(probe, irq);
+ return 0;
}
size_t
/*---------- PCI 3.0 HBA device definition ----------*/
+static int
+__pci_irq_install(struct irq_domain* domain, irq_t irq)
+{
+ struct irq_domain* parent;
+ int err;
+
+ parent = domain->parent;
+ err = parent->ops->install_irq(parent, irq);
+ if (err) {
+ return err;
+ }
+
+ if (irq->type == IRQ_MESSAGE) {
+ irq->msi->message = irq->vector;
+ }
+
+ return 0;
+}
+
+static struct irq_domain_ops pci_irq_ops = {
+ .install_irq = __pci_irq_install
+};
+
static int
pci_register(struct device_def* def)
{
static int
pci_create(struct device_def* def, morph_t* obj)
{
- devtree_link_t devtree_node;
+ struct irq_domain *pci_domain;
+ pci_bridge = device_allocsys(NULL, NULL);
+#ifdef CONFIG_USE_DEVICETREE
+ devtree_link_t devtree_node;
devtree_node = changeling_try_reveal(obj, dt_node_morpher);
-
- pci_bridge = device_allocsys(NULL, NULL);
device_set_devtree_node(pci_bridge, devtree_node);
+#endif
- register_device(pci_bridge, &def->class, "pci_bridge");
+ pci_domain = irq_create_domain(pci_bridge, &pci_irq_ops);
+ irq_attach_domain(irq_get_default_domain(), pci_domain);
+ register_device(pci_bridge, &def->class, "pci_bridge");
pci_scan();
return 0;
def_on_register(pci_register),
def_on_create(pci_create)
};
-EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf);
+EXPORT_DEVICE(pci3hba, &pci_def, load_onboot);
#define __LUNAIX_16550_H
#include <hal/serial.h>
+#include <hal/irq.h>
#include <lunaix/types.h>
#define UART_rRxTX 0
struct serial_dev* sdev;
ptr_t base_addr;
unsigned int base_clk;
- int iv;
+ irq_t irq;
struct
{
uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len);
void
-uart_handle_irq_overlap(int iv, struct llist_header* ports);
+uart_handle_irq_overlap(irq_t irq, struct llist_header* ports);
void
-uart_handle_irq(int iv, struct uart16550 *uart);
+uart_handle_irq(irq_t irq, struct uart16550 *uart);
static inline struct serial_dev*
uart_create_serial(struct uart16550* uart, struct devclass* class,
}
void
-uart_handle_irq_overlap(int iv, struct llist_header* ports)
+uart_handle_irq_overlap(irq_t irq, struct llist_header* ports)
{
struct uart16550 *pos, *n;
llist_for_each(pos, n, ports, local_ports)
{
int is = uart_intr_identify(pos);
- if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
+ if (irq == pos->irq && (is == UART_CHR_TIMEOUT)) {
goto done;
}
}
return;
done:
- uart_handle_irq(iv, pos);
+ uart_handle_irq(irq, pos);
}
void
-uart_handle_irq(int iv, struct uart16550 *uart)
+uart_handle_irq(irq_t irq, struct uart16550 *uart)
{
char tmpbuf[32];
char recv;
static DEFINE_LLIST(com_ports);
static void
-com_irq_handler(const struct hart_state* hstate)
+com_irq_handler(irq_t irq, const struct hart_state* hstate)
{
- int vector = hart_vector_stamp(hstate);
- uart_handle_irq_overlap(vector, &com_ports);
+ uart_handle_irq_overlap(irq, &com_ports);
}
int
int* irqs[] = { &irq4, &irq3, &irq4, &irq3 };
struct uart16550* uart = NULL;
+ struct serial_dev* sdev;
ptr_t base;
// COM 1...4
continue;
}
+ sdev = uart_create_serial(uart, &def->class, &com_ports, "S");
+
int irq = *irqs[i];
if (irq) {
/*
* Since these irqs are overlapped, this particular setup is needed
* to avoid double-bind
*/
- uart->iv = isrm_bindirq(irq, com_irq_handler);
+ uart->irq = irq_declare_line(com_irq_handler, irq, NULL);
+ irq_assign(irq_owning_domain(sdev->dev), uart->irq);
*((volatile int*)irqs[i]) = 0;
}
-
- INFO("base: 0x%x, irq=%d",
- base, irq, uart->iv);
-
- uart_create_serial(uart, &def->class, &com_ports, "S");
+
+ INFO("base: 0x%x, irq=%d", base, irq);
}
return 0;
static void
-uart_msi_irq_handler(const struct hart_state* hstate)
+uart_msi_irq_handler(irq_t irq, const struct hart_state* hstate)
{
- int vector;
struct uart16550* uart;
- vector = hart_vector_stamp(hstate);
- uart = (struct uart16550*)isrm_get_payload(hstate);
+ uart = irq_payload(irq, struct uart16550);
assert(uart);
- uart_handle_irq(vector, uart);
-}
-
-static void
-uart_intx_irq_handler(const struct hart_state* hstate)
-{
- int vector = hart_vector_stamp(hstate);
- uart_handle_irq_overlap(vector, &pci_ports);
+ uart_handle_irq(irq, uart);
}
static bool
struct pci_probe* probe;
struct uart16550* uart;
struct serial_dev* sdev;
- msi_vector_t msiv;
+ irq_t irq;
probe = changeling_reveal(obj, pci_probe_morpher);
sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
- msiv = pci_msi_setup_simple(probe, uart_msi_irq_handler);
- isrm_set_payload(msi_vect(msiv), __ptr(uart));
+ irq = pci_declare_msi_irq(uart_msi_irq_handler, probe, NULL);
+ irq_set_payload(irq, uart);
+ pci_assign_msi(probe, irq);
- INFO("base: 0x%x (%s), irq=%d (%s)",
+ INFO("base: 0x%x (%s), %s",
bar->start,
pci_bar_mmio_space(bar) ? "mmio" : "pmio",
- msi_vect(msiv),
pci_capability_msi(probe) ? "msi" : "intx, re-routed");
- uart->iv = msi_vect(msiv);
+ uart->irq = irq;
pci_bind_instance(probe, sdev->dev);
}
--- /dev/null
+#include <hal/irq.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/owloysius.h>
+
+static struct irq_domain* default_domain = NULL;
+static DEFINE_LLIST(irq_domains);
+
+static void
+__default_servant(irq_t irq, const struct hart_state* state)
+{
+ return;
+}
+
+struct irq_domain*
+irq_create_domain(struct device* intc_dev, const struct irq_domain_ops* ops)
+{
+ struct irq_domain* domain;
+
+ assert(ops->install_irq);
+
+ domain = new_potens(potens(INT_DOMAIN), struct irq_domain);
+ device_grant_potens(intc_dev, potens_meta(domain));
+
+ btrie_init(&domain->irq_map, ilog2(8));
+ llist_append(&irq_domains, &domain->list);
+ domain->ops = ops;
+
+ return domain;
+}
+
+struct irq_domain*
+irq_owning_domain(struct device* dev)
+{
+#ifdef CONFIG_USE_DEVICETREE
+ struct device* intc;
+ struct dtn* intr_parent;
+ struct potens_meta* domain_m;
+
+ intr_parent = dev->devtree_node->intr.parent;
+ intc = resolve_device_morph(dt_mobj(intr_parent));
+
+ if (!intc) {
+ return NULL;
+ }
+
+ domain_m = device_get_potens(intc, potens(INT_DOMAIN));
+ return !domain_m ?: get_potens(domain_m, struct irq_domain);
+#else
+ return default_domain;
+#endif
+}
+
+int
+irq_attach_domain(struct irq_domain* parent, struct irq_domain* child)
+{
+#ifndef CONFIG_USE_DEVICETREE
+ parent = parent ?: default_domain;
+ child->parent = parent;
+#endif
+ return 0;
+}
+
+static void
+__irq_create_line(irq_t irq, ptr_t local_int)
+{
+ struct irq_line_wire *line;
+
+ line = valloc(sizeof(*line));
+ line->domain_local = local_int;
+ line->domain_mapped = local_int;
+
+ irq->line = line;
+}
+
+static void
+__irq_create_msi(irq_t irq, ptr_t message)
+{
+ struct irq_msi_wire *msi;
+
+ msi = valloc(sizeof(*msi));
+ msi->message = message;
+
+ irq->msi = msi;
+}
+
+irq_t
+irq_declare(enum irq_type type, irq_servant callback,
+ ptr_t data, void* irq_extra)
+{
+ irq_t irq;
+
+ irq = valloc(sizeof(*irq));
+ *irq = (struct irq_object) {
+ .type = type,
+ .serve = callback ?: __default_servant,
+ .irq_extra = irq_extra
+ };
+
+ if (type == IRQ_LINE) {
+ __irq_create_line(irq, data);
+ }
+
+ else if (type == IRQ_MESSAGE) {
+ __irq_create_msi(irq, data);
+ }
+
+ return irq;
+}
+
+void
+irq_revoke(irq_t irq)
+{
+ if (--(irq->ref) > 0) {
+ return;
+ }
+ vfree(irq);
+}
+
+int
+irq_assign(struct irq_domain* domain, irq_t irq)
+{
+ int err = 0;
+ if (domain->ops->map_irq) {
+ err = domain->ops->map_irq(domain, irq, irq->irq_extra);
+ if (err) {
+ return err;
+ }
+ }
+
+ /*
+ A domain controller may choose to forward the interrupt
+ (i.e., irq became transparent and belongs to the higher domain)
+ We allow controller decide whether to record the irq under its wing
+ */
+ err = domain->ops->install_irq(domain, irq);
+ if (err) {
+ return err;
+ }
+
+ irq->domain = domain;
+ return 0;
+}
+
+irq_t
+irq_find(struct irq_domain* domain, int local_irq)
+{
+ irq_t irq = NULL;
+ struct irq_domain* current;
+
+ // Find recursively, in case of irq forwarding
+
+ current = domain ?: default_domain;
+ while (current && !irq) {
+ irq = (irq_t)btrie_get(¤t->irq_map, local_irq);
+ current = irq_parent_domain(current);
+ }
+
+ return irq;
+}
+
+void
+irq_record(struct irq_domain* domain, irq_t irq)
+{
+ irq->ref++;
+ btrie_set(&domain->irq_map, irq->vector, irq);
+}
+
+void
+irq_set_default_domain(struct irq_domain* domain)
+{
+ assert(!default_domain);
+ default_domain = domain;
+}
+
+int
+irq_forward_install(struct irq_domain* current, irq_t irq)
+{
+ struct irq_domain* parent;
+
+ parent = irq_parent_domain(current);
+
+ if (irq->type == IRQ_LINE) {
+ irq->line->domain_local = irq->line->domain_mapped;
+ }
+
+ irq->domain = parent;
+ return parent->ops->install_irq(parent, irq);
+}
+
+struct irq_domain*
+irq_get_default_domain()
+{
+ assert(default_domain);
+ return default_domain;
+}
#include "hba.h"
#include <asm-generic/isrm.h>
+#include <hal/irq.h>
/*
* Macro naming rule:
{
ptr_t mmio_base;
size_t mmio_size;
- int ahci_iv;
+ irq_t irq;
};
void
ahci_driver_init(struct ahci_driver_param* param);
void
-ahci_hba_isr(const struct hart_state* hstate);
+ahci_hba_isr(irq_t irq, const struct hart_state* hstate);
#endif /* __LUNAIX_AHCI_H */
#ifndef __LUNAIX_DEVTREE_H
#define __LUNAIX_DEVTREE_H
+#ifdef CONFIG_USE_DEVICETREE
#include <lunaix/types.h>
#include <lunaix/ds/llist.h>
#include <lunaix/ds/hstr.h>
return true;
}
+#endif
#endif /* __LUNAIX_DEVTREE_H */
typedef struct dtn* devtree_link_t;
-#define dt_node_morpher morphable_attrs(dt_node, mobj)
+#define dt_node_morpher morphable_attrs(dtn, mobj)
struct dtm_driver_info
{
--- /dev/null
+#ifndef __LUNAIX_IRQ_H
+#define __LUNAIX_IRQ_H
+
+#include <lunaix/changeling.h>
+#include <lunaix/device.h>
+#include <lunaix/ds/btrie.h>
+#include <asm/hart.h>
+
+struct irq_domain;
+typedef struct irq_object* irq_t;
+typedef void (*irq_servant)(irq_t, const struct hart_state*);
+
+struct irq_domain_ops
+{
+ int
+ (*install_irq)(struct irq_domain*, irq_t);
+
+ int
+ (*map_irq)(struct irq_domain*, irq_t, void* irq_extra);
+
+ int
+ (*remove_irq)(struct irq_domain*, irq_t);
+};
+
+struct irq_domain
+{
+ POTENS_META;
+
+ struct llist_header list;
+
+ struct irq_domain* parent;
+ struct btrie irq_map;
+ const struct irq_domain_ops* ops;
+ void* object;
+};
+
+enum irq_type
+{
+ IRQ_LINE,
+ IRQ_MESSAGE
+};
+
+struct irq_line_wire
+{
+ ptr_t domain_local;
+ ptr_t domain_mapped;
+};
+
+struct irq_msi_wire
+{
+ ptr_t message;
+ ptr_t sideband;
+ ptr_t wr_addr;
+};
+
+struct irq_object
+{
+ enum irq_type type;
+ unsigned int vector;
+
+ union {
+ struct irq_line_wire* line;
+ struct irq_msi_wire* msi;
+ };
+
+ irq_servant serve;
+ void* payload;
+
+ struct irq_domain* domain;
+ void* irq_extra;
+ int ref;
+};
+
+#define SZ sizeof(struct irq_object)
+
+struct irq_domain*
+irq_create_domain(struct device* intc_dev, const struct irq_domain_ops* ops);
+
+struct irq_domain*
+irq_owning_domain(struct device* dev);
+
+int
+irq_attach_domain(struct irq_domain* parent, struct irq_domain* child);
+
+irq_t
+irq_declare(enum irq_type, irq_servant, ptr_t, void*);
+
+void
+irq_revoke(irq_t);
+
+int
+irq_assign(struct irq_domain* domain, irq_t);
+
+irq_t
+irq_find(struct irq_domain* domain, int local_irq);
+
+void
+irq_record(struct irq_domain* domain, irq_t irq);
+
+void
+irq_set_default_domain(struct irq_domain*);
+
+struct irq_domain*
+irq_get_default_domain();
+
+int
+irq_forward_install(struct irq_domain* current, irq_t irq);
+
+static inline void
+irq_serve(irq_t irq, struct hart_state* state)
+{
+ irq->serve(irq, state);
+}
+
+static inline void
+irq_set_payload(irq_t irq, void* payload)
+{
+ irq->payload = payload;
+}
+
+static inline void
+irq_set_domain_object(struct irq_domain* domain, void* obj)
+{
+ domain->object = obj;
+}
+
+#define irq_payload(irq, type) ((type*)(irq)->payload)
+#define irq_domain_obj(domain, type) ((type*)(domain)->object)
+
+static inline irq_t
+irq_declare_line(irq_servant callback, int local_irq, void* irq_extra)
+{
+ return irq_declare(IRQ_LINE, callback, (int)local_irq, irq_extra);
+}
+
+static inline irq_t
+irq_declare_msg(irq_servant callback,
+ ptr_t message, ptr_t sideband, void* irq_extra)
+{
+ irq_t irq;
+ irq = irq_declare(IRQ_MESSAGE, callback, message, irq_extra);
+ irq->msi->sideband = sideband;
+
+ return irq;
+}
+
+static inline struct irq_domain*
+irq_get_domain(struct device* maybe_intc)
+{
+ struct potens_meta* domain_m;
+
+ domain_m = device_get_potens(maybe_intc, potens(INT_DOMAIN));
+ return domain_m ? get_potens(domain_m, struct irq_domain) : NULL;
+}
+
+static inline struct irq_domain*
+irq_parent_domain(struct irq_domain* domain)
+{
+ return domain->parent;
+}
+
+#endif /* __LUNAIX_IRQ_H */
#include <asm-generic/isrm.h>
+#include "irq.h"
+
#define PCI_VENDOR_INVLD 0xffff
#define PCI_REG_VENDOR_DEV 0
struct pci_base_addr bar[6];
struct device* bind;
+ struct irq_domain* irq_domain;
};
#define pci_probe_morpher morphable_attrs(pci_probe, mobj)
size_t
pci_bar_sizing(struct pci_probe* probe, u32_t* bar_out, u32_t bar_num);
+irq_t
+pci_declare_msi_irq(irq_servant callback,
+ struct pci_probe* probe, void *irq_extra);
+
+int
+pci_assign_msi(struct pci_probe* probe, irq_t irq);
+
/**
* @brief Bind an abstract device instance to the pci device
*
}
-msienv_t
-pci_msi_start(struct pci_probe* probe);
-
-msi_vector_t
-pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe,
- int i, isr_cb handler);
-
-static inline void
-pci_msi_done(msienv_t env)
-{
- isrm_msi_done(env);
-}
-
-static inline msi_vector_t
-pci_msi_setup_simple(struct pci_probe* probe, isr_cb handler)
-{
- msienv_t env;
- msi_vector_t msiv;
-
- env = pci_msi_start(probe);
- msiv = pci_msi_setup_at(env, probe, 0, handler);
- pci_msi_done(env);
-
- return msiv;
-}
-
int
pci_bind_driver(struct pci_registry* reg);
morphable(device_meta),
morphable(device_cat),
morphable(device_alias),
-morphable(device),
\ No newline at end of file
+morphable(device),
+morphable(irq_object),
\ No newline at end of file
* @brief RTC capability.
*
*/
-potens(HWRTC),
\ No newline at end of file
+potens(HWRTC),
+
+/**
+ * @brief Interrupt controller (domain) capability
+ *
+ */
+potens(INT_DOMAIN),
\ No newline at end of file
struct device*
device_alloc(struct device_meta* parent, u32_t type, void* underlay);
+#ifdef CONFIG_USE_DEVICETREE
static inline void
device_set_devtree_node(struct device* dev, devtree_link_t node)
{
dev->devtree_node = node;
}
+#endif
static inline struct device* must_inline
device_allocsys(struct device_meta* parent, void* underlay)
sched_ctx.procs_index = to_check->process->pid;
done:
- isrm_notify_eos(0);
run(to_check);
fail("unexpected return from scheduler");