Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: [POWERPC] Fix return value from memcpy [POWERPC] iseries: Define insw et al. so libata/ide will compile [POWERPC] Fix irq enable/disable in smp_generic_take_timebase [POWERPC] Fix problem with time not advancing on 32-bit platforms [POWERPC] Restore copyright notice in arch/powerpc/kernel/fpu.S [POWERPC] Fix up ibm_architecture_vec definition [POWERPC] Make OF irq map code detect more error cases [POWERPC] Support for "weird" MPICs and fixup mpc7448_hpc2 [POWERPC] Fix MPIC sense codes in documentation [POWERPC] Fix performance regression in IRQ radix tree locking [POWERPC] Add mpc7448hpc2 device tree source file [POWERPC] Add MPC8349E MDS device tree source file to arch/powerpc/boot/dts [POWERPC] modify mpc83xx platforms to use new IRQ layer [POWERPC] Adapt ipic driver to new host_ops interface, add set_irq_type to set IRQ sense [POWERPC] back up old school ipic.[hc] to arch/ppc [POWERPC] Use mpc8641hpcn PIC base address from dev tree. [POWERPC] Allow MPC8641 HPCN to build with CONFIG_PCI disabled too. [POWERPC] Fix powerpc 44x_mmu build [POWERPC] Remove flush_dcache_all export
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
* FPU support code, moved here from head.S so that it can be used
|
||||
* by chips which use other head-whatever.S files.
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
* Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
|
||||
* Copyright (C) 1996 Paul Mackerras.
|
||||
* Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
|
@@ -322,7 +322,8 @@ EXPORT_SYMBOL(do_softirq);
|
||||
|
||||
static LIST_HEAD(irq_hosts);
|
||||
static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
|
||||
static unsigned int irq_radix_writer;
|
||||
struct irq_map_entry irq_map[NR_IRQS];
|
||||
static unsigned int irq_virq_count = NR_IRQS;
|
||||
static struct irq_host *irq_default_host;
|
||||
@@ -455,6 +456,58 @@ void irq_set_virq_count(unsigned int count)
|
||||
irq_virq_count = count;
|
||||
}
|
||||
|
||||
/* radix tree not lockless safe ! we use a brlock-type mecanism
|
||||
* for now, until we can use a lockless radix tree
|
||||
*/
|
||||
static void irq_radix_wrlock(unsigned long *flags)
|
||||
{
|
||||
unsigned int cpu, ok;
|
||||
|
||||
spin_lock_irqsave(&irq_big_lock, *flags);
|
||||
irq_radix_writer = 1;
|
||||
smp_mb();
|
||||
do {
|
||||
barrier();
|
||||
ok = 1;
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (per_cpu(irq_radix_reader, cpu)) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
cpu_relax();
|
||||
} while(!ok);
|
||||
}
|
||||
|
||||
static void irq_radix_wrunlock(unsigned long flags)
|
||||
{
|
||||
smp_wmb();
|
||||
irq_radix_writer = 0;
|
||||
spin_unlock_irqrestore(&irq_big_lock, flags);
|
||||
}
|
||||
|
||||
static void irq_radix_rdlock(unsigned long *flags)
|
||||
{
|
||||
local_irq_save(*flags);
|
||||
__get_cpu_var(irq_radix_reader) = 1;
|
||||
smp_mb();
|
||||
if (likely(irq_radix_writer == 0))
|
||||
return;
|
||||
__get_cpu_var(irq_radix_reader) = 0;
|
||||
smp_wmb();
|
||||
spin_lock(&irq_big_lock);
|
||||
__get_cpu_var(irq_radix_reader) = 1;
|
||||
spin_unlock(&irq_big_lock);
|
||||
}
|
||||
|
||||
static void irq_radix_rdunlock(unsigned long flags)
|
||||
{
|
||||
__get_cpu_var(irq_radix_reader) = 0;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
unsigned int irq_create_mapping(struct irq_host *host,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
@@ -604,13 +657,9 @@ void irq_dispose_mapping(unsigned int virq)
|
||||
/* Check if radix tree allocated yet */
|
||||
if (host->revmap_data.tree.gfp_mask == 0)
|
||||
break;
|
||||
/* XXX radix tree not safe ! remove lock whem it becomes safe
|
||||
* and use some RCU sync to make sure everything is ok before we
|
||||
* can re-use that map entry
|
||||
*/
|
||||
spin_lock_irqsave(&irq_big_lock, flags);
|
||||
irq_radix_wrlock(&flags);
|
||||
radix_tree_delete(&host->revmap_data.tree, hwirq);
|
||||
spin_unlock_irqrestore(&irq_big_lock, flags);
|
||||
irq_radix_wrunlock(flags);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -677,25 +726,24 @@ unsigned int irq_radix_revmap(struct irq_host *host,
|
||||
if (tree->gfp_mask == 0)
|
||||
return irq_find_mapping(host, hwirq);
|
||||
|
||||
/* XXX Current radix trees are NOT SMP safe !!! Remove that lock
|
||||
* when that is fixed (when Nick's patch gets in
|
||||
*/
|
||||
spin_lock_irqsave(&irq_big_lock, flags);
|
||||
|
||||
/* Now try to resolve */
|
||||
irq_radix_rdlock(&flags);
|
||||
ptr = radix_tree_lookup(tree, hwirq);
|
||||
irq_radix_rdunlock(flags);
|
||||
|
||||
/* Found it, return */
|
||||
if (ptr) {
|
||||
virq = ptr - irq_map;
|
||||
goto bail;
|
||||
return virq;
|
||||
}
|
||||
|
||||
/* If not there, try to insert it */
|
||||
virq = irq_find_mapping(host, hwirq);
|
||||
if (virq != NO_IRQ)
|
||||
if (virq != NO_IRQ) {
|
||||
irq_radix_wrlock(&flags);
|
||||
radix_tree_insert(tree, hwirq, &irq_map[virq]);
|
||||
bail:
|
||||
spin_unlock_irqrestore(&irq_big_lock, flags);
|
||||
irq_radix_wrunlock(flags);
|
||||
}
|
||||
return virq;
|
||||
}
|
||||
|
||||
@@ -806,12 +854,12 @@ static int irq_late_init(void)
|
||||
struct irq_host *h;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irq_big_lock, flags);
|
||||
irq_radix_wrlock(&flags);
|
||||
list_for_each_entry(h, &irq_hosts, link) {
|
||||
if (h->revmap_type == IRQ_HOST_MAP_TREE)
|
||||
INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);
|
||||
}
|
||||
spin_unlock_irqrestore(&irq_big_lock, flags);
|
||||
irq_radix_wrunlock(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1289,6 +1289,9 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
|
||||
|
||||
DBG("Try to map irq for %s...\n", pci_name(pci_dev));
|
||||
|
||||
#ifdef DEBUG
|
||||
memset(&oirq, 0xff, sizeof(oirq));
|
||||
#endif
|
||||
/* Try to get a mapping from the device-tree */
|
||||
if (of_irq_map_pci(pci_dev, &oirq)) {
|
||||
u8 line, pin;
|
||||
@@ -1314,8 +1317,9 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
|
||||
if (virq != NO_IRQ)
|
||||
set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
|
||||
} else {
|
||||
DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
|
||||
oirq.size, oirq.specifier[0], oirq.controller->full_name);
|
||||
DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
|
||||
oirq.size, oirq.specifier[0], oirq.specifier[1],
|
||||
oirq.controller->full_name);
|
||||
|
||||
virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
oirq.size);
|
||||
@@ -1324,6 +1328,9 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
|
||||
DBG(" -> failed to map !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DBG(" -> mapped to linux irq %d\n", virq);
|
||||
|
||||
pci_dev->irq = virq;
|
||||
pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
|
||||
|
||||
|
@@ -126,10 +126,6 @@ EXPORT_SYMBOL(pci_bus_mem_base_phys);
|
||||
EXPORT_SYMBOL(pci_bus_to_hose);
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#ifdef CONFIG_NOT_COHERENT_CACHE
|
||||
EXPORT_SYMBOL(flush_dcache_all);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(start_thread);
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
|
@@ -646,13 +646,13 @@ static unsigned char ibm_architecture_vec[] = {
|
||||
5 - 1, /* 5 option vectors */
|
||||
|
||||
/* option vector 1: processor architectures supported */
|
||||
3 - 1, /* length */
|
||||
3 - 2, /* length */
|
||||
0, /* don't ignore, don't halt */
|
||||
OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
|
||||
OV1_PPC_2_04 | OV1_PPC_2_05,
|
||||
|
||||
/* option vector 2: Open Firmware options supported */
|
||||
34 - 1, /* length */
|
||||
34 - 2, /* length */
|
||||
OV2_REAL_MODE,
|
||||
0, 0,
|
||||
W(0xffffffff), /* real_base */
|
||||
@@ -666,16 +666,16 @@ static unsigned char ibm_architecture_vec[] = {
|
||||
48, /* max log_2(hash table size) */
|
||||
|
||||
/* option vector 3: processor options supported */
|
||||
3 - 1, /* length */
|
||||
3 - 2, /* length */
|
||||
0, /* don't ignore, don't halt */
|
||||
OV3_FP | OV3_VMX,
|
||||
|
||||
/* option vector 4: IBM PAPR implementation */
|
||||
2 - 1, /* length */
|
||||
2 - 2, /* length */
|
||||
0, /* don't halt */
|
||||
|
||||
/* option vector 5: PAPR/OF options */
|
||||
3 - 1, /* length */
|
||||
3 - 2, /* length */
|
||||
0, /* don't ignore, don't halt */
|
||||
OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
|
||||
};
|
||||
|
@@ -639,14 +639,17 @@ void of_irq_map_init(unsigned int flags)
|
||||
|
||||
}
|
||||
|
||||
int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 *addr,
|
||||
struct of_irq *out_irq)
|
||||
int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 ointsize,
|
||||
u32 *addr, struct of_irq *out_irq)
|
||||
{
|
||||
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
|
||||
u32 *tmp, *imap, *imask;
|
||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||
int imaplen, match, i;
|
||||
|
||||
DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
|
||||
parent->full_name, intspec[0], intspec[1], ointsize);
|
||||
|
||||
ipar = of_node_get(parent);
|
||||
|
||||
/* First get the #interrupt-cells property of the current cursor
|
||||
@@ -670,6 +673,9 @@ int of_irq_map_raw(struct device_node *parent, u32 *intspec, u32 *addr,
|
||||
|
||||
DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);
|
||||
|
||||
if (ointsize != intsize)
|
||||
return -EINVAL;
|
||||
|
||||
/* Look for this #address-cells. We have to implement the old linux
|
||||
* trick of looking for the parent here as some device-trees rely on it
|
||||
*/
|
||||
@@ -875,12 +881,15 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
|
||||
}
|
||||
intsize = *tmp;
|
||||
|
||||
DBG(" intsize=%d intlen=%d\n", intsize, intlen);
|
||||
|
||||
/* Check index */
|
||||
if ((index + 1) * intsize > intlen)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get new specifier and map it */
|
||||
res = of_irq_map_raw(p, intspec + index * intsize, addr, out_irq);
|
||||
res = of_irq_map_raw(p, intspec + index * intsize, intsize,
|
||||
addr, out_irq);
|
||||
of_node_put(p);
|
||||
return res;
|
||||
}
|
||||
@@ -965,7 +974,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
|
||||
laddr[0] = (pdev->bus->number << 16)
|
||||
| (pdev->devfn << 8);
|
||||
laddr[1] = laddr[2] = 0;
|
||||
return of_irq_map_raw(ppnode, &lspec, laddr, out_irq);
|
||||
return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_irq_map_pci);
|
||||
#endif /* CONFIG_PCI */
|
||||
|
@@ -45,8 +45,9 @@ void __devinit smp_generic_take_timebase(void)
|
||||
{
|
||||
int cmd;
|
||||
u64 tb;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_disable();
|
||||
local_irq_save(flags);
|
||||
while (!running)
|
||||
barrier();
|
||||
rmb();
|
||||
@@ -70,7 +71,7 @@ void __devinit smp_generic_take_timebase(void)
|
||||
set_tb(tb >> 32, tb & 0xfffffffful);
|
||||
enter_contest(tbsync->mark, -1);
|
||||
}
|
||||
local_irq_enable();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int __devinit start_contest(int cmd, long offset, int num)
|
||||
|
Reference in New Issue
Block a user