Skip to content

Commit 0e888ad

Browse files
kkaneshigegregkh
authored andcommitted
[PATCH] ACPI based I/O APIC hot-plug: ia64 support
This is an ia64 implementation of acpi_register_ioapic() and acpi_unregister_ioapic() interfaces. Signed-off-by: Kenji Kaneshige <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b1bb248 commit 0e888ad

File tree

3 files changed

+135
-32
lines changed

3 files changed

+135
-32
lines changed

arch/ia64/kernel/acpi.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
236236
if (BAD_MADT_ENTRY(iosapic, end))
237237
return -EINVAL;
238238

239-
iosapic_init(iosapic->address, iosapic->global_irq_base);
240-
241-
return 0;
239+
return iosapic_init(iosapic->address, iosapic->global_irq_base);
242240
}
243241

244242

@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
772770

773771

774772
#ifdef CONFIG_ACPI_NUMA
775-
acpi_status __init
773+
acpi_status __devinit
776774
acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
777775
{
778776
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -829,16 +827,23 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
829827
int
830828
acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
831829
{
832-
/* TBD */
833-
return -EINVAL;
830+
int err;
831+
832+
if ((err = iosapic_init(phys_addr, gsi_base)))
833+
return err;
834+
835+
#if CONFIG_ACPI_NUMA
836+
acpi_map_iosapic(handle, 0, NULL, NULL);
837+
#endif /* CONFIG_ACPI_NUMA */
838+
839+
return 0;
834840
}
835841
EXPORT_SYMBOL(acpi_register_ioapic);
836842

837843
int
838844
acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
839845
{
840-
/* TBD */
841-
return -EINVAL;
846+
return iosapic_remove(gsi_base);
842847
}
843848
EXPORT_SYMBOL(acpi_unregister_ioapic);
844849

arch/ia64/kernel/iosapic.c

Lines changed: 113 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,13 @@ static struct iosapic {
129129
char __iomem *addr; /* base address of IOSAPIC */
130130
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
131131
unsigned short num_rte; /* number of RTE in this IOSAPIC */
132+
int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
132133
#ifdef CONFIG_NUMA
133134
unsigned short node; /* numa node association via pxm */
134135
#endif
135136
} iosapic_lists[NR_IOSAPICS];
136137

137-
static int num_iosapic;
138-
139-
static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
138+
static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
140139

141140
static int iosapic_kmalloc_ok;
142141
static LIST_HEAD(free_rte_list);
@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
149148
{
150149
int i;
151150

152-
for (i = 0; i < num_iosapic; i++) {
151+
for (i = 0; i < NR_IOSAPICS; i++) {
153152
if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
154153
return i;
155154
}
@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
598597
rte->refcnt++;
599598
list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
600599
iosapic_intr_info[vector].count++;
600+
iosapic_lists[index].rtes_inuse++;
601601
}
602602
else if (vector_is_shared(vector)) {
603603
struct iosapic_intr_info *info = &iosapic_intr_info[vector];
@@ -778,7 +778,7 @@ void
778778
iosapic_unregister_intr (unsigned int gsi)
779779
{
780780
unsigned long flags;
781-
int irq, vector;
781+
int irq, vector, index;
782782
irq_desc_t *idesc;
783783
u32 low32;
784784
unsigned long trigger, polarity;
@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)
819819
list_del(&rte->rte_list);
820820
iosapic_intr_info[vector].count--;
821821
iosapic_free_rte(rte);
822+
index = find_iosapic(gsi);
823+
iosapic_lists[index].rtes_inuse--;
824+
WARN_ON(iosapic_lists[index].rtes_inuse < 0);
822825

823826
trigger = iosapic_intr_info[vector].trigger;
824827
polarity = iosapic_intr_info[vector].polarity;
@@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat)
952955
}
953956
}
954957

955-
void __init
958+
static inline int
959+
iosapic_alloc (void)
960+
{
961+
int index;
962+
963+
for (index = 0; index < NR_IOSAPICS; index++)
964+
if (!iosapic_lists[index].addr)
965+
return index;
966+
967+
printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
968+
return -1;
969+
}
970+
971+
static inline void
972+
iosapic_free (int index)
973+
{
974+
memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
975+
}
976+
977+
static inline int
978+
iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
979+
{
980+
int index;
981+
unsigned int gsi_end, base, end;
982+
983+
/* check gsi range */
984+
gsi_end = gsi_base + ((ver >> 16) & 0xff);
985+
for (index = 0; index < NR_IOSAPICS; index++) {
986+
if (!iosapic_lists[index].addr)
987+
continue;
988+
989+
base = iosapic_lists[index].gsi_base;
990+
end = base + iosapic_lists[index].num_rte - 1;
991+
992+
if (gsi_base < base && gsi_end < base)
993+
continue;/* OK */
994+
995+
if (gsi_base > end && gsi_end > end)
996+
continue; /* OK */
997+
998+
return -EBUSY;
999+
}
1000+
return 0;
1001+
}
1002+
1003+
int __devinit
9561004
iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
9571005
{
958-
int num_rte;
1006+
int num_rte, err, index;
9591007
unsigned int isa_irq, ver;
9601008
char __iomem *addr;
1009+
unsigned long flags;
1010+
1011+
spin_lock_irqsave(&iosapic_lock, flags);
1012+
{
1013+
addr = ioremap(phys_addr, 0);
1014+
ver = iosapic_version(addr);
9611015

962-
addr = ioremap(phys_addr, 0);
963-
ver = iosapic_version(addr);
1016+
if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
1017+
iounmap(addr);
1018+
spin_unlock_irqrestore(&iosapic_lock, flags);
1019+
return err;
1020+
}
9641021

965-
/*
966-
* The MAX_REDIR register holds the highest input pin
967-
* number (starting from 0).
968-
* We add 1 so that we can use it for number of pins (= RTEs)
969-
*/
970-
num_rte = ((ver >> 16) & 0xff) + 1;
1022+
/*
1023+
* The MAX_REDIR register holds the highest input pin
1024+
* number (starting from 0).
1025+
* We add 1 so that we can use it for number of pins (= RTEs)
1026+
*/
1027+
num_rte = ((ver >> 16) & 0xff) + 1;
9711028

972-
iosapic_lists[num_iosapic].addr = addr;
973-
iosapic_lists[num_iosapic].gsi_base = gsi_base;
974-
iosapic_lists[num_iosapic].num_rte = num_rte;
1029+
index = iosapic_alloc();
1030+
iosapic_lists[index].addr = addr;
1031+
iosapic_lists[index].gsi_base = gsi_base;
1032+
iosapic_lists[index].num_rte = num_rte;
9751033
#ifdef CONFIG_NUMA
976-
iosapic_lists[num_iosapic].node = MAX_NUMNODES;
1034+
iosapic_lists[index].node = MAX_NUMNODES;
9771035
#endif
978-
num_iosapic++;
1036+
}
1037+
spin_unlock_irqrestore(&iosapic_lock, flags);
9791038

9801039
if ((gsi_base == 0) && pcat_compat) {
9811040
/*
@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
9861045
for (isa_irq = 0; isa_irq < 16; ++isa_irq)
9871046
iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
9881047
}
1048+
return 0;
1049+
}
1050+
1051+
#ifdef CONFIG_HOTPLUG
1052+
int
1053+
iosapic_remove (unsigned int gsi_base)
1054+
{
1055+
int index, err = 0;
1056+
unsigned long flags;
1057+
1058+
spin_lock_irqsave(&iosapic_lock, flags);
1059+
{
1060+
index = find_iosapic(gsi_base);
1061+
if (index < 0) {
1062+
printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
1063+
__FUNCTION__, gsi_base);
1064+
goto out;
1065+
}
1066+
1067+
if (iosapic_lists[index].rtes_inuse) {
1068+
err = -EBUSY;
1069+
printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
1070+
__FUNCTION__, gsi_base);
1071+
goto out;
1072+
}
1073+
1074+
iounmap(iosapic_lists[index].addr);
1075+
iosapic_free(index);
1076+
}
1077+
out:
1078+
spin_unlock_irqrestore(&iosapic_lock, flags);
1079+
return err;
9891080
}
1081+
#endif /* CONFIG_HOTPLUG */
9901082

9911083
#ifdef CONFIG_NUMA
992-
void __init
1084+
void __devinit
9931085
map_iosapic_to_node(unsigned int gsi_base, int node)
9941086
{
9951087
int index;

include/asm-ia64/iosapic.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
7171
}
7272

7373
extern void __init iosapic_system_init (int pcat_compat);
74-
extern void __init iosapic_init (unsigned long address,
74+
extern int __devinit iosapic_init (unsigned long address,
7575
unsigned int gsi_base);
76+
#ifdef CONFIG_HOTPLUG
77+
extern int iosapic_remove (unsigned int gsi_base);
78+
#endif /* CONFIG_HOTPLUG */
7679
extern int gsi_to_vector (unsigned int gsi);
7780
extern int gsi_to_irq (unsigned int gsi);
7881
extern void iosapic_enable_intr (unsigned int vector);
@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);
9497

9598
extern void iosapic_pci_fixup (int);
9699
#ifdef CONFIG_NUMA
97-
extern void __init map_iosapic_to_node (unsigned int, int);
100+
extern void __devinit map_iosapic_to_node (unsigned int, int);
98101
#endif
99102
#else
100103
#define iosapic_system_init(pcat_compat) do { } while (0)
101-
#define iosapic_init(address,gsi_base) do { } while (0)
104+
#define iosapic_init(address,gsi_base) (-EINVAL)
105+
#ifdef CONFIG_HOTPLUG
106+
#define iosapic_remove(gsi_base) (-ENODEV)
107+
#endif /* CONFIG_HOTPLUG */
102108
#define iosapic_register_intr(gsi,polarity,trigger) (gsi)
103109
#define iosapic_unregister_intr(irq) do { } while (0)
104110
#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)

0 commit comments

Comments
 (0)