Newer
Older
int __init io_apic_get_version(int ioapic)
{
union IO_APIC_reg_01 reg_01;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
int ioapic, pin, idx;
if (skip_ioapic_setup)
return -1;
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0)
pin = mp_find_ioapic_pin(ioapic, gsi);
if (pin < 0)
return -1;
idx = find_irq_entry(ioapic, pin, mp_INT);
if (idx < 0)
*trigger = irq_trigger(idx);
*polarity = irq_polarity(idx);
/*
* This function currently is only a helper for the i386 smp boot process where
* we need to reprogram the ioredtbls to cater for the cpus which have come online
* so mask in all cases should simply be apic->target_cpus()
*/
#ifdef CONFIG_SMP
void __init setup_ioapic_dest(void)
{
struct irq_desc *desc;
if (skip_ioapic_setup == 1)
return;
for (ioapic = 0; ioapic < nr_ioapics; ioapic++)
for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
irq_entry = find_irq_entry(ioapic, pin, mp_INT);
if (irq_entry == -1)
continue;
irq = pin_2_irq(irq_entry, ioapic, pin);
if ((ioapic > 0) && (irq > 16))
continue;
desc = irq_to_desc(irq);
/*
* Honour affinities which have been set in early boot
*/
if (desc->status &
(IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
mask = desc->affinity;
else
mask = apic->target_cpus();
if (intr_remapping_enabled)
set_ir_ioapic_affinity_irq_desc(desc, mask);
else
set_ioapic_affinity_irq_desc(desc, mask);
#define IOAPIC_RESOURCE_NAME_SIZE 11
static struct resource *ioapic_resources;

Cyrill Gorcunov
committed
static struct resource * __init ioapic_setup_resources(int nr_ioapics)
{
unsigned long n;
struct resource *res;
char *mem;
int i;
if (nr_ioapics <= 0)
return NULL;
n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
n *= nr_ioapics;
mem = alloc_bootmem(n);
res = (void *)mem;

Cyrill Gorcunov
committed
mem += sizeof(struct resource) * nr_ioapics;

Cyrill Gorcunov
committed
for (i = 0; i < nr_ioapics; i++) {
res[i].name = mem;
res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);

Cyrill Gorcunov
committed
mem += IOAPIC_RESOURCE_NAME_SIZE;
}
ioapic_resources = res;
return res;
}
void __init ioapic_init_mappings(void)
{
unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
struct resource *ioapic_res;

Cyrill Gorcunov
committed
ioapic_res = ioapic_setup_resources(nr_ioapics);
for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) {
ioapic_phys = mp_ioapics[i].apicaddr;
if (!ioapic_phys) {
printk(KERN_ERR
"WARNING: bogus zero IO-APIC "
"address found in MPTABLE, "
"disabling IO/APIC support!\n");
smp_found_config = 0;
skip_ioapic_setup = 1;
goto fake_ioapic_page;
}
ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
ioapic_phys = __pa(ioapic_phys);
}
set_fixmap_nocache(idx, ioapic_phys);
apic_printk(APIC_VERBOSE, "mapped IOAPIC to %08lx (%08lx)\n",
__fix_to_virt(idx) + (ioapic_phys & ~PAGE_MASK),
ioapic_phys);

Cyrill Gorcunov
committed
ioapic_res->start = ioapic_phys;
ioapic_res->end = ioapic_phys + IO_APIC_SLOT_SIZE - 1;

Cyrill Gorcunov
committed
ioapic_res++;
void __init ioapic_insert_resources(void)
{
int i;
struct resource *r = ioapic_resources;
if (!r) {
if (nr_ioapics > 0)
printk(KERN_ERR
"IO APIC resources couldn't be allocated.\n");
return;
}
for (i = 0; i < nr_ioapics; i++) {
insert_resource(&iomem_resource, r);
r++;
}
}
int mp_find_ioapic(u32 gsi)
{
int i = 0;
/* Find the IOAPIC that manages this GSI. */
for (i = 0; i < nr_ioapics; i++) {
if ((gsi >= mp_gsi_routing[i].gsi_base)
&& (gsi <= mp_gsi_routing[i].gsi_end))
return i;
}
printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
return -1;
}
int mp_find_ioapic_pin(int ioapic, u32 gsi)
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
{
if (WARN_ON(ioapic == -1))
return -1;
if (WARN_ON(gsi > mp_gsi_routing[ioapic].gsi_end))
return -1;
return gsi - mp_gsi_routing[ioapic].gsi_base;
}
static int bad_ioapic(unsigned long address)
{
if (nr_ioapics >= MAX_IO_APICS) {
printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded "
"(found %d), skipping\n", MAX_IO_APICS, nr_ioapics);
return 1;
}
if (!address) {
printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address"
" found in table, skipping!\n");
return 1;
}
void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
{
int idx = 0;

Eric W. Biederman
committed
int entries;
if (bad_ioapic(address))
return;
idx = nr_ioapics;
mp_ioapics[idx].type = MP_IOAPIC;
mp_ioapics[idx].flags = MPC_APIC_USABLE;
mp_ioapics[idx].apicaddr = address;
set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
mp_ioapics[idx].apicid = io_apic_unique_id(id);
mp_ioapics[idx].apicver = io_apic_get_version(idx);
/*
* Build basic GSI lookup table to facilitate gsi->io_apic lookups
* and to prevent reprogramming of IOAPIC pins (PCI GSIs).
*/

Eric W. Biederman
committed
entries = io_apic_get_redir_entries(idx);
mp_gsi_routing[idx].gsi_base = gsi_base;

Eric W. Biederman
committed
mp_gsi_routing[idx].gsi_end = gsi_base + entries - 1;
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
nr_ioapic_registers[idx] = entries;
if (mp_gsi_routing[idx].gsi_end >= gsi_top)
gsi_top = mp_gsi_routing[idx].gsi_end + 1;
printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
"GSI %d-%d\n", idx, mp_ioapics[idx].apicid,
mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr,
mp_gsi_routing[idx].gsi_base, mp_gsi_routing[idx].gsi_end);
nr_ioapics++;
}
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
/* Enable IOAPIC early just for system timer */
void __init pre_init_apic_IRQ0(void)
{
struct irq_cfg *cfg;
struct irq_desc *desc;
printk(KERN_INFO "Early APIC setup for system timer0\n");
#ifndef CONFIG_SMP
phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
#endif
desc = irq_to_desc_alloc_node(0, 0);
setup_local_APIC();
cfg = irq_cfg(0);
add_pin_to_irq_node(cfg, 0, 0, 0);
set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
setup_IO_APIC_irq(0, 0, 0, desc, 0, 0);
}