Skip to content

Commit

Permalink
ioapic: Save I/O APIC information for later configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Sepherosa Ziehau committed Mar 17, 2011
1 parent 0471bb0 commit ebf4f41
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 6 deletions.
101 changes: 99 additions & 2 deletions sys/platform/pc32/apic/mpapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ extern pt_entry_t *SMPpt;
#define ELCR0 0x4d0 /* eisa irq 0-7 */
#define ELCR1 0x4d1 /* eisa irq 8-15 */

struct ioapic_info {
int io_idx;
int io_apic_id;
void *io_addr;
int io_npin;
int io_gsi_base;

TAILQ_ENTRY(ioapic_info) io_link;
};
TAILQ_HEAD(ioapic_info_list, ioapic_info);

struct ioapic_conf {
struct ioapic_info_list ioc_list;
int ioc_intsrc[16]; /* XXX magic number */
};

static void lapic_timer_calibrate(void);
static void lapic_timer_set_divisor(int);
static void lapic_timer_fixup_handler(void *);
Expand Down Expand Up @@ -92,6 +108,8 @@ static const uint32_t lapic_timer_divisors[] = {

int lapic_id_max;

static struct ioapic_conf ioapic_conf;

/*
* Enable LAPIC, configure interrupts.
*/
Expand Down Expand Up @@ -1052,7 +1070,12 @@ void
ioapic_config(void)
{
struct ioapic_enumerator *e;
int error;
int error, i;

TAILQ_INIT(&ioapic_conf.ioc_list);
/* XXX magic number */
for (i = 0; i < 16; ++i)
ioapic_conf.ioc_intsrc[i] = -1;

TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
error = e->ioapic_probe(e);
Expand All @@ -1070,8 +1093,42 @@ ioapic_config(void)

e->ioapic_enumerate(e);

if (!ioapic_use_old)
if (!ioapic_use_old) {
struct ioapic_info *info;

i = 0;
TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
const struct ioapic_info *prev_info;

info->io_idx = i++;
info->io_apic_id = info->io_idx + lapic_id_max + 1;

/* TODO set apic id, config all pins */

if (bootverbose) {
kprintf("IOAPIC: idx %d, apic id %d, "
"gsi base %d, npin %d\n",
info->io_idx,
info->io_apic_id,
info->io_gsi_base,
info->io_npin);
}

/* Warning about possible GSI hole */
prev_info = TAILQ_PREV(info, ioapic_info_list, io_link);
if (prev_info != NULL) {
if (info->io_gsi_base !=
prev_info->io_gsi_base + prev_info->io_npin) {
kprintf("IOAPIC: warning gsi hole "
"[%d, %d]\n",
prev_info->io_gsi_base +
prev_info->io_npin,
info->io_gsi_base - 1);
}
}
}
panic("ioapic_config: new ioapic not working yet\n");
}
}

void
Expand All @@ -1087,3 +1144,43 @@ ioapic_enumerator_register(struct ioapic_enumerator *ne)
}
TAILQ_INSERT_TAIL(&ioapic_enumerators, ne, ioapic_link);
}

void
ioapic_add(void *addr, int gsi_base, int npin)
{
struct ioapic_info *info, *ninfo;
int gsi_end;

gsi_end = gsi_base + npin - 1;
TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
if ((gsi_base >= info->io_gsi_base &&
gsi_base < info->io_gsi_base + info->io_npin) ||
(gsi_end >= info->io_gsi_base &&
gsi_end < info->io_gsi_base + info->io_npin)) {
panic("ioapic_add: overlapped gsi, base %d npin %d, "
"hit base %d, npin %d\n", gsi_base, npin,
info->io_gsi_base, info->io_npin);
}
if (info->io_addr == addr)
panic("ioapic_add: duplicated addr %p\n", addr);
}

ninfo = kmalloc(sizeof(*ninfo), M_DEVBUF, M_WAITOK | M_ZERO);
ninfo->io_addr = addr;
ninfo->io_npin = npin;
ninfo->io_gsi_base = gsi_base;

/*
* Create IOAPIC list in ascending order of GSI base
*/
TAILQ_FOREACH_REVERSE(info, &ioapic_conf.ioc_list,
ioapic_info_list, io_link) {
if (ninfo->io_gsi_base > info->io_gsi_base) {
TAILQ_INSERT_AFTER(&ioapic_conf.ioc_list,
info, ninfo, io_link);
break;
}
}
if (info == NULL)
TAILQ_INSERT_HEAD(&ioapic_conf.ioc_list, ninfo, io_link);
}
3 changes: 2 additions & 1 deletion sys/platform/pc32/i386/mp_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -3633,7 +3633,8 @@ mptable_ioapic_enumerate(struct ioapic_enumerator *e)
prev_ioapic->mio_gsi_base +
prev_ioapic->mio_npin;
}
/* TODO */
ioapic_add(addr, ioapic->mio_gsi_base,
ioapic->mio_npin);
}
if (bootverbose) {
kprintf("MPTABLE: IOAPIC addr 0x%08x, "
Expand Down
14 changes: 14 additions & 0 deletions sys/platform/pc32/i386/mp_madt.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,20 @@ madt_ioapic_enum_callback(void *xarg, const struct acpi_madt_ent *ent)
MADT_VPRINTF("IOAPIC addr 0x%08x, apic id %d, gsi base %u\n",
ioapic_ent->mio_addr, ioapic_ent->mio_apic_id,
ioapic_ent->mio_gsi_base);

if (!ioapic_use_old) {
uint32_t ver;
void *addr;
int npin;

addr = ioapic_map(ioapic_ent->mio_addr);

ver = ioapic_read(addr, IOAPIC_VER);
npin = ((ver & IOART_VER_MAXREDIR) >>
MAXREDIRSHIFT) + 1;

ioapic_add(addr, ioapic_ent->mio_gsi_base, npin);
}
}
return 0;
}
Expand Down
1 change: 1 addition & 0 deletions sys/platform/pc32/include/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ void lapic_config(void);
void lapic_enumerator_register(struct lapic_enumerator *);
void ioapic_config(void);
void ioapic_enumerator_register(struct ioapic_enumerator *);
void ioapic_add(void *, int, int);
extern int apic_io_enable;
extern int ioapic_use_old;

Expand Down
100 changes: 98 additions & 2 deletions sys/platform/pc64/apic/mpapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@
#define ELCR0 0x4d0 /* eisa irq 0-7 */
#define ELCR1 0x4d1 /* eisa irq 8-15 */

struct ioapic_info {
int io_idx;
int io_apic_id;
void *io_addr;
int io_npin;
int io_gsi_base;

TAILQ_ENTRY(ioapic_info) io_link;
};
TAILQ_HEAD(ioapic_info_list, ioapic_info);

struct ioapic_conf {
struct ioapic_info_list ioc_list;
int ioc_intsrc[16]; /* XXX magic number */
};

volatile lapic_t *lapic;

static void lapic_timer_calibrate(void);
Expand Down Expand Up @@ -92,6 +108,7 @@ static const uint32_t lapic_timer_divisors[] = {
#define APIC_TIMER_NDIVISORS (int)(NELEM(lapic_timer_divisors))

int lapic_id_max;
static struct ioapic_conf ioapic_conf;

void
lapic_eoi(void)
Expand Down Expand Up @@ -1115,7 +1132,12 @@ void
ioapic_config(void)
{
struct ioapic_enumerator *e;
int error;
int error, i;

TAILQ_INIT(&ioapic_conf.ioc_list);
/* XXX magic number */
for (i = 0; i < 16; ++i)
ioapic_conf.ioc_intsrc[i] = -1;

TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
error = e->ioapic_probe(e);
Expand All @@ -1133,8 +1155,42 @@ ioapic_config(void)

e->ioapic_enumerate(e);

if (!ioapic_use_old)
if (!ioapic_use_old) {
struct ioapic_info *info;

i = 0;
TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
const struct ioapic_info *prev_info;

info->io_idx = i++;
info->io_apic_id = info->io_idx + lapic_id_max + 1;

/* TODO set apic id, config all pins */

if (bootverbose) {
kprintf("IOAPIC: idx %d, apic id %d, "
"gsi base %d, npin %d\n",
info->io_idx,
info->io_apic_id,
info->io_gsi_base,
info->io_npin);
}

/* Warning about possible GSI hole */
prev_info = TAILQ_PREV(info, ioapic_info_list, io_link);
if (prev_info != NULL) {
if (info->io_gsi_base !=
prev_info->io_gsi_base + prev_info->io_npin) {
kprintf("IOAPIC: warning gsi hole "
"[%d, %d]\n",
prev_info->io_gsi_base +
prev_info->io_npin,
info->io_gsi_base - 1);
}
}
}
panic("ioapic_config: new ioapic not working yet\n");
}
}

void
Expand All @@ -1150,3 +1206,43 @@ ioapic_enumerator_register(struct ioapic_enumerator *ne)
}
TAILQ_INSERT_TAIL(&ioapic_enumerators, ne, ioapic_link);
}

void
ioapic_add(void *addr, int gsi_base, int npin)
{
struct ioapic_info *info, *ninfo;
int gsi_end;

gsi_end = gsi_base + npin - 1;
TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
if ((gsi_base >= info->io_gsi_base &&
gsi_base < info->io_gsi_base + info->io_npin) ||
(gsi_end >= info->io_gsi_base &&
gsi_end < info->io_gsi_base + info->io_npin)) {
panic("ioapic_add: overlapped gsi, base %d npin %d, "
"hit base %d, npin %d\n", gsi_base, npin,
info->io_gsi_base, info->io_npin);
}
if (info->io_addr == addr)
panic("ioapic_add: duplicated addr %p\n", addr);
}

ninfo = kmalloc(sizeof(*ninfo), M_DEVBUF, M_WAITOK | M_ZERO);
ninfo->io_addr = addr;
ninfo->io_npin = npin;
ninfo->io_gsi_base = gsi_base;

/*
* Create IOAPIC list in ascending order of GSI base
*/
TAILQ_FOREACH_REVERSE(info, &ioapic_conf.ioc_list,
ioapic_info_list, io_link) {
if (ninfo->io_gsi_base > info->io_gsi_base) {
TAILQ_INSERT_AFTER(&ioapic_conf.ioc_list,
info, ninfo, io_link);
break;
}
}
if (info == NULL)
TAILQ_INSERT_HEAD(&ioapic_conf.ioc_list, ninfo, io_link);
}
1 change: 1 addition & 0 deletions sys/platform/pc64/include/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ void lapic_config(void);
void lapic_enumerator_register(struct lapic_enumerator *);
void ioapic_config(void);
void ioapic_enumerator_register(struct ioapic_enumerator *);
void ioapic_add(void *, int, int);

#if defined(READY)
void clr_io_apic_mask24 (int, u_int32_t);
Expand Down
3 changes: 2 additions & 1 deletion sys/platform/pc64/x86_64/mp_machdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -3628,7 +3628,8 @@ mptable_ioapic_enumerate(struct ioapic_enumerator *e)
prev_ioapic->mio_gsi_base +
prev_ioapic->mio_npin;
}
/* TODO */
ioapic_add(addr, ioapic->mio_gsi_base,
ioapic->mio_npin);
}
if (bootverbose) {
kprintf("MPTABLE: IOAPIC addr 0x%08x, "
Expand Down
14 changes: 14 additions & 0 deletions sys/platform/pc64/x86_64/mp_madt.c
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,20 @@ madt_ioapic_enum_callback(void *xarg, const struct acpi_madt_ent *ent)
MADT_VPRINTF("IOAPIC addr 0x%08x, apic id %d, gsi base %u\n",
ioapic_ent->mio_addr, ioapic_ent->mio_apic_id,
ioapic_ent->mio_gsi_base);

if (!ioapic_use_old) {
uint32_t ver;
void *addr;
int npin;

addr = ioapic_map(ioapic_ent->mio_addr);

ver = ioapic_read(addr, IOAPIC_VER);
npin = ((ver & IOART_VER_MAXREDIR) >>
MAXREDIRSHIFT) + 1;

ioapic_add(addr, ioapic_ent->mio_gsi_base, npin);
}
}
return 0;
}
Expand Down

0 comments on commit ebf4f41

Please sign in to comment.