Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e888adc authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Greg Kroah-Hartman
Browse files

[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: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b1bb248a
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
	if (BAD_MADT_ENTRY(iosapic, end))
		return -EINVAL;

	iosapic_init(iosapic->address, iosapic->global_irq_base);

	return 0;
	return iosapic_init(iosapic->address, iosapic->global_irq_base);
}


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

#ifdef CONFIG_ACPI_NUMA
acpi_status __init
acpi_status __devinit
acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
{
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -829,16 +827,23 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
int
acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
{
	/* TBD */
	return -EINVAL;
	int err;

	if ((err = iosapic_init(phys_addr, gsi_base)))
		return err;

#if CONFIG_ACPI_NUMA
	acpi_map_iosapic(handle, 0, NULL, NULL);
#endif /* CONFIG_ACPI_NUMA */

	return 0;
}
EXPORT_SYMBOL(acpi_register_ioapic);

int
acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
{
	/* TBD */
	return -EINVAL;
	return iosapic_remove(gsi_base);
}
EXPORT_SYMBOL(acpi_unregister_ioapic);

+113 −21
Original line number Diff line number Diff line
@@ -129,14 +129,13 @@ static struct iosapic {
	char __iomem	*addr;		/* base address of IOSAPIC */
	unsigned int 	gsi_base;	/* first GSI assigned to this IOSAPIC */
	unsigned short 	num_rte;	/* number of RTE in this IOSAPIC */
	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
#ifdef CONFIG_NUMA
	unsigned short	node;		/* numa node association via pxm */
#endif
} iosapic_lists[NR_IOSAPICS];

static int num_iosapic;

static unsigned char pcat_compat __initdata;	/* 8259 compatibility flag */
static unsigned char pcat_compat __devinitdata;	/* 8259 compatibility flag */

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

	for (i = 0; i < num_iosapic; i++) {
	for (i = 0; i < NR_IOSAPICS; i++) {
		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
			return i;
	}
@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
		rte->refcnt++;
		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
		iosapic_intr_info[vector].count++;
		iosapic_lists[index].rtes_inuse++;
	}
	else if (vector_is_shared(vector)) {
		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
@@ -778,7 +778,7 @@ void
iosapic_unregister_intr (unsigned int gsi)
{
	unsigned long flags;
	int irq, vector;
	int irq, vector, index;
	irq_desc_t *idesc;
	u32 low32;
	unsigned long trigger, polarity;
@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)
		list_del(&rte->rte_list);
		iosapic_intr_info[vector].count--;
		iosapic_free_rte(rte);
		index = find_iosapic(gsi);
		iosapic_lists[index].rtes_inuse--;
		WARN_ON(iosapic_lists[index].rtes_inuse < 0);

		trigger	 = iosapic_intr_info[vector].trigger;
		polarity = iosapic_intr_info[vector].polarity;
@@ -952,16 +955,70 @@ iosapic_system_init (int system_pcat_compat)
	}
}

void __init
static inline int
iosapic_alloc (void)
{
	int index;

	for (index = 0; index < NR_IOSAPICS; index++)
		if (!iosapic_lists[index].addr)
			return index;

	printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
	return -1;
}

static inline void
iosapic_free (int index)
{
	memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
}

static inline int
iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
{
	int index;
	unsigned int gsi_end, base, end;

	/* check gsi range */
	gsi_end = gsi_base + ((ver >> 16) & 0xff);
	for (index = 0; index < NR_IOSAPICS; index++) {
		if (!iosapic_lists[index].addr)
			continue;

		base = iosapic_lists[index].gsi_base;
		end  = base + iosapic_lists[index].num_rte - 1;

		if (gsi_base < base && gsi_end < base)
			continue;/* OK */

		if (gsi_base > end && gsi_end > end)
			continue; /* OK */

		return -EBUSY;
	}
	return 0;
}

int __devinit
iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
{
	int num_rte;
	int num_rte, err, index;
	unsigned int isa_irq, ver;
	char __iomem *addr;
	unsigned long flags;

	spin_lock_irqsave(&iosapic_lock, flags);
	{
		addr = ioremap(phys_addr, 0);
		ver = iosapic_version(addr);

		if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
			iounmap(addr);
			spin_unlock_irqrestore(&iosapic_lock, flags);
			return err;
		}

		/*
		 * The MAX_REDIR register holds the highest input pin
		 * number (starting from 0).
@@ -969,13 +1026,15 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
		 */
		num_rte = ((ver >> 16) & 0xff) + 1;

	iosapic_lists[num_iosapic].addr = addr;
	iosapic_lists[num_iosapic].gsi_base = gsi_base;
	iosapic_lists[num_iosapic].num_rte = num_rte;
		index = iosapic_alloc();
		iosapic_lists[index].addr = addr;
		iosapic_lists[index].gsi_base = gsi_base;
		iosapic_lists[index].num_rte = num_rte;
#ifdef CONFIG_NUMA
	iosapic_lists[num_iosapic].node = MAX_NUMNODES;
		iosapic_lists[index].node = MAX_NUMNODES;
#endif
	num_iosapic++;
	}
	spin_unlock_irqrestore(&iosapic_lock, flags);

	if ((gsi_base == 0) && pcat_compat) {
		/*
@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
	}
	return 0;
}

#ifdef CONFIG_HOTPLUG
int
iosapic_remove (unsigned int gsi_base)
{
	int index, err = 0;
	unsigned long flags;

	spin_lock_irqsave(&iosapic_lock, flags);
	{
		index = find_iosapic(gsi_base);
		if (index < 0) {
			printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
			       __FUNCTION__, gsi_base);
			goto out;
		}

		if (iosapic_lists[index].rtes_inuse) {
			err = -EBUSY;
			printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
			       __FUNCTION__, gsi_base);
			goto out;
		}

		iounmap(iosapic_lists[index].addr);
		iosapic_free(index);
	}
 out:
	spin_unlock_irqrestore(&iosapic_lock, flags);
	return err;
}
#endif /* CONFIG_HOTPLUG */

#ifdef CONFIG_NUMA
void __init
void __devinit
map_iosapic_to_node(unsigned int gsi_base, int node)
{
	int index;
+9 −3
Original line number Diff line number Diff line
@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
}

extern void __init iosapic_system_init (int pcat_compat);
extern void __init iosapic_init (unsigned long address,
extern int __devinit iosapic_init (unsigned long address,
				    unsigned int gsi_base);
#ifdef CONFIG_HOTPLUG
extern int iosapic_remove (unsigned int gsi_base);
#endif /* CONFIG_HOTPLUG */
extern int gsi_to_vector (unsigned int gsi);
extern int gsi_to_irq (unsigned int gsi);
extern void iosapic_enable_intr (unsigned int vector);
@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);

extern void iosapic_pci_fixup (int);
#ifdef CONFIG_NUMA
extern void __init map_iosapic_to_node (unsigned int, int);
extern void __devinit map_iosapic_to_node (unsigned int, int);
#endif
#else
#define iosapic_system_init(pcat_compat)			do { } while (0)
#define iosapic_init(address,gsi_base)				do { } while (0)
#define iosapic_init(address,gsi_base)				(-EINVAL)
#ifdef CONFIG_HOTPLUG
#define iosapic_remove(gsi_base)				(-ENODEV)
#endif /* CONFIG_HOTPLUG */
#define iosapic_register_intr(gsi,polarity,trigger)		(gsi)
#define iosapic_unregister_intr(irq)				do { } while (0)
#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger)	do { } while (0)