Skip to content

Commit a0d399a

Browse files
kkaneshigegregkh
authored andcommitted
[PATCH] ACPI based I/O APIC hot-plug: acpiphp support
This patch adds PCI based I/O xAPIC hot-add support to ACPIPHP driver. When PCI root bridge is hot-added, all PCI based I/O xAPICs under the root bridge are hot-added by this patch. Hot-remove support is TBD. Signed-off-by: Kenji Kaneshige <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0e888ad commit a0d399a

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

drivers/pci/hotplug/acpiphp_glue.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,132 @@ static void remove_bridge(acpi_handle handle)
552552
}
553553
}
554554

555+
static struct pci_dev * get_apic_pci_info(acpi_handle handle)
556+
{
557+
struct acpi_pci_id id;
558+
struct pci_bus *bus;
559+
struct pci_dev *dev;
560+
561+
if (ACPI_FAILURE(acpi_get_pci_id(handle, &id)))
562+
return NULL;
563+
564+
bus = pci_find_bus(id.segment, id.bus);
565+
if (!bus)
566+
return NULL;
567+
568+
dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function));
569+
if (!dev)
570+
return NULL;
571+
572+
if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) &&
573+
(dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC))
574+
{
575+
pci_dev_put(dev);
576+
return NULL;
577+
}
578+
579+
return dev;
580+
}
581+
582+
static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
583+
{
584+
acpi_status status;
585+
int result = -1;
586+
unsigned long gsb;
587+
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
588+
union acpi_object *obj;
589+
void *table;
590+
591+
status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
592+
if (ACPI_SUCCESS(status)) {
593+
*gsi_base = (u32)gsb;
594+
return 0;
595+
}
596+
597+
status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer);
598+
if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer)
599+
return -1;
600+
601+
obj = buffer.pointer;
602+
if (obj->type != ACPI_TYPE_BUFFER)
603+
goto out;
604+
605+
table = obj->buffer.pointer;
606+
switch (((acpi_table_entry_header *)table)->type) {
607+
case ACPI_MADT_IOSAPIC:
608+
*gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
609+
result = 0;
610+
break;
611+
case ACPI_MADT_IOAPIC:
612+
*gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
613+
result = 0;
614+
break;
615+
default:
616+
break;
617+
}
618+
out:
619+
acpi_os_free(buffer.pointer);
620+
return result;
621+
}
622+
623+
static acpi_status
624+
ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
625+
{
626+
acpi_status status;
627+
unsigned long sta;
628+
acpi_handle tmp;
629+
struct pci_dev *pdev;
630+
u32 gsi_base;
631+
u64 phys_addr;
632+
633+
/* Evaluate _STA if present */
634+
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
635+
if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
636+
return AE_CTRL_DEPTH;
637+
638+
/* Scan only PCI bus scope */
639+
status = acpi_get_handle(handle, "_HID", &tmp);
640+
if (ACPI_SUCCESS(status))
641+
return AE_CTRL_DEPTH;
642+
643+
if (get_gsi_base(handle, &gsi_base))
644+
return AE_OK;
645+
646+
pdev = get_apic_pci_info(handle);
647+
if (!pdev)
648+
return AE_OK;
649+
650+
if (pci_enable_device(pdev)) {
651+
pci_dev_put(pdev);
652+
return AE_OK;
653+
}
654+
655+
pci_set_master(pdev);
656+
657+
if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) {
658+
pci_disable_device(pdev);
659+
pci_dev_put(pdev);
660+
return AE_OK;
661+
}
662+
663+
phys_addr = pci_resource_start(pdev, 0);
664+
if (acpi_register_ioapic(handle, phys_addr, gsi_base)) {
665+
pci_release_region(pdev, 0);
666+
pci_disable_device(pdev);
667+
pci_dev_put(pdev);
668+
return AE_OK;
669+
}
670+
671+
return AE_OK;
672+
}
673+
674+
static int acpiphp_configure_ioapics(acpi_handle handle)
675+
{
676+
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
677+
ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
678+
return 0;
679+
}
680+
555681
static int power_on_slot(struct acpiphp_slot *slot)
556682
{
557683
acpi_status status;
@@ -942,6 +1068,7 @@ static int acpiphp_configure_bridge (acpi_handle handle)
9421068
acpiphp_sanitize_bus(bus);
9431069
acpiphp_set_hpp_values(handle, bus);
9441070
pci_enable_bridges(bus);
1071+
acpiphp_configure_ioapics(handle);
9451072
return 0;
9461073
}
9471074

include/linux/pci_ids.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262

6363
#define PCI_BASE_CLASS_SYSTEM 0x08
6464
#define PCI_CLASS_SYSTEM_PIC 0x0800
65+
#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010
66+
#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020
6567
#define PCI_CLASS_SYSTEM_DMA 0x0801
6668
#define PCI_CLASS_SYSTEM_TIMER 0x0802
6769
#define PCI_CLASS_SYSTEM_RTC 0x0803

0 commit comments

Comments
 (0)