LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: arch/powerpc/sysdev: dumping ground or only for shared drivers?
From: Christian Krafft @ 2007-05-15  9:53 UTC (permalink / raw)
  To: Kumar Gala; +Cc: Olof Johansson, linuxppc-dev, paulus
In-Reply-To: <A903CF97-CD70-4F26-9AB3-E3194F391448@kernel.crashing.org>

[-- Attachment #1: Type: text/plain, Size: 627 bytes --]

Hi,

On Thu, 10 May 2007 17:06:48 -0500
Kumar Gala <galak@kernel.crashing.org> wrote:

> unknown:
> pmi.c	(should this be in drivers somewhere?)

This driver does the communication with the BMC (baseboard management controller)
via a couple of FPGA registers on some future powerpc hardware. 


> 
> - k
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev


-- 
Mit freundlichen Grüssen,
kind regards,

Christian Krafft
IBM Systems & Technology Group, 
Linux Kernel Development
IT Specialist

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH] pasemi: Electra CF driver
From: Arnd Bergmann @ 2007-05-15  9:52 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Olof Johansson, Russell King, linux-pcmcia, paulus, linux-kernel
In-Reply-To: <20070515044515.GA6731@lixom.net>

On Tuesday 15 May 2007, Olof Johansson wrote:
> Driver for the CompactFlash slot on the PA Semi Electra eval board. It's
> a simple device sitting on localbus, with interrupts and detect/voltage
> control over GPIO.

The driver looks really good, there is nothing for me to complain about.

> The driver is implemented as an of_platform driver, and adds localbus
> as a bus being probed by the of_platform framework.

I supposed "localbus" is what the current firmware ships with in the
device tree, right? If you still have the choice on how this is
represented it might be better not to invent another device-type
but rather make this "soc" or whatever existing type we know about.

	Arnd <><

^ permalink raw reply

* RE: [PATCH 1/2] kbuild: Add "Section mismatch" warning whitelist for powerpc
From: Li Yang-r58472 @ 2007-05-15  9:36 UTC (permalink / raw)
  To: Kumar Gala, Sam Ravnborg; +Cc: Andrew Morton, linuxppc-dev, Linus, Linux Kernel
In-Reply-To: <3DF58590-DFD9-4665-8C47-33F407AAD1E7@kernel.crashing.org>

> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Monday, May 14, 2007 9:57 PM
> To: Sam Ravnborg
> Cc: Li Yang-r58472; Linus; Andrew Morton; Linux Kernel;
linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH 1/2] kbuild: Add "Section mismatch" warning
whitelist for
> powerpc
>=20
>=20
> On May 14, 2007, at 6:06 AM, Sam Ravnborg wrote:
>=20
> > On Mon, May 14, 2007 at 06:53:32PM +0800, Li Yang wrote:
> >> This patch fixes the following "Section mismatch" warnings when
> >> build powerpc platforms.
> >>
> >> -------------
> >> WARNING: arch/powerpc/mm/built-in.o - Section mismatch: reference
to
> >> .init.text:early_get_page from .text between
> >> 'pte_alloc_one_kernel' (at
> >> offset 0xc68) and 'pte_alloc_one'
> >> WARNING: mm/built-in.o - Section mismatch: reference to
> >> .init.text:set_up_list3s from .text between
> >> 'kmem_cache_create' (at offset
> >> 0x20300) and 'cache_reap'
> >> -------------
>=20
> This warnings should be handled by __init_refok instead.

Yes.  When __init_refok gets in, we can change all Pattern 9 members in
the whitelist to use __init_refok.

- Leo

^ permalink raw reply

* RE: [PATCH 1/2] kbuild: Add "Section mismatch" warning whitelist for powerpc
From: Li Yang-r58472 @ 2007-05-15  9:22 UTC (permalink / raw)
  To: Satyam Sharma, Kumar Gala
  Cc: Andrew Morton, Linus, Sam Ravnborg, Linux Kernel, linuxppc-dev
In-Reply-To: <a781481a0705141717v2669805aoa590bfd54da7856b@mail.gmail.com>

> -----Original Message-----
> From: Satyam Sharma [mailto:satyam.sharma@gmail.com]
> Sent: Tuesday, May 15, 2007 8:18 AM
> To: Kumar Gala
> Cc: Sam Ravnborg; Li Yang-r58472; Linus; Andrew Morton; Linux Kernel;
> linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH 1/2] kbuild: Add "Section mismatch" warning
whitelist for
> powerpc
>=20
> Hi,
>=20
> On 5/14/07, Kumar Gala <galak@kernel.crashing.org> wrote:
> >
> > On May 14, 2007, at 6:06 AM, Sam Ravnborg wrote:
> >
> > > On Mon, May 14, 2007 at 06:53:32PM +0800, Li Yang wrote:
> > >> This patch fixes the following "Section mismatch" warnings when
> > >> build powerpc platforms.
> > >>
> > >> -------------
> > >> WARNING: arch/powerpc/mm/built-in.o - Section mismatch: reference
to
> > >> .init.text:early_get_page from .text between
> > >> 'pte_alloc_one_kernel' (at
> > >> offset 0xc68) and 'pte_alloc_one'
> > >> WARNING: mm/built-in.o - Section mismatch: reference to
> > >> .init.text:set_up_list3s from .text between
> > >> 'kmem_cache_create' (at offset
> > >> 0x20300) and 'cache_reap'
> > >> -------------
> >
> > This warnings should be handled by __init_refok instead.
>=20
> Actually, once __init_refok comes in, would we need any other
> whitelisting mechanism at all? I think the exception patterns in
> secref_whitelist() and those two other whitelisting functions
> (init_section_ref_ok and exit_section_ref_ok) could all be
> subsumed and made redundant if / when __init_refok is used
> in the actual sources.

I don't think so.  __init_refok can be used to mark special functions
which are legitimate to reference .init.text/.init.data but cannot be
used to mark special sections.

- Leo

^ permalink raw reply

* Re: [RFC] [patch 2/2] powerpc 2.6.21-rt1: fix kernel hang and/or panic
From: Tsutomu OWA @ 2007-05-15  8:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: mingo, tglx
In-Reply-To: <yyilkfq5vsj.wl@toshiba.co.jp>


>   It occurs on 2.6.21 + patch-2.6.21-rt1 + series of patches that I posted
> yesterday.

  I encountered the following error when doing netperf from other machine 
to Celleb running RT kernel.  PREEPT_NONE kernel works just fine as well.

Unable to handle kernel paging request for data at address 0x00000009
Faulting instruction address: 0xc000000000295434
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT SMP NR_CPUS=2 NUMA 
Modules linked in:
NIP: C000000000295434 LR: C000000000295420 CTR: 0000000000000000
REGS: c0000000095d6e30 TRAP: 0300   Not tainted  (2.6.21-rc5-rt7)
MSR: 8000000000009032 <EE,ME,IR,DR>  CR: 24000482  XER: 20000000
DAR: 0000000000000009, DSISR: 0000000040000000
TASK = c000000001e7c440[626] 'netserver' THREAD: c0000000095d4000 CPU: 0
GPR00: 0000000000000800 C0000000095D70B0 C0000000005D77B8 0000000000000001 
GPR04: 0000000000000001 0000000000000000 C0000000095D7080 0000000000000000 
GPR08: C0000000095D7030 0000000000000000 C0000000095D7040 0000000000000000 
GPR12: FC69925300080D5D C0000000004DE680 0000000000000000 0000000000422208 
GPR16: 0000000000400000 0000000000420D10 0000000000000000 C0000000095D7C88 
GPR20: C000000001E7C440 0000000000000000 0000000000000001 C000000008ACEAE0 
GPR24: 0000000000000020 C000000000E50C80 0000000081F84C5E C000000001C00BE0 
GPR28: C000000001C05430 C000000001C00B80 C000000000570F30 C000000001FD1720 
NIP [C000000000295434] .spider_net_xmit+0x1dc/0x448
LR [C000000000295420] .spider_net_xmit+0x1c8/0x448
Call Trace:
[C0000000095D70B0] [C000000000295420] .spider_net_xmit+0x1c8/0x448 (unreliable)
[C0000000095D7160] [C000000000327EE8] .dev_hard_start_xmit+0x238/0x300
[C0000000095D7200] [C00000000033A7F4] .__qdisc_run+0xdc/0x2a4
[C0000000095D72B0] [C00000000032A948] .dev_queue_xmit+0x1b0/0x2fc
[C0000000095D7350] [C00000000034B470] .ip_output+0x280/0x2d8
[C0000000095D73F0] [C00000000034C6CC] .ip_queue_xmit+0x448/0x4d8
[C0000000095D74F0] [C00000000035F6D8] .tcp_transmit_skb+0x850/0x8c0
[C0000000095D75C0] [C00000000035C394] .__tcp_ack_snd_check+0x84/0xc0
[C0000000095D7650] [C00000000035E114] .tcp_rcv_established+0x4f0/0x8ac
[C0000000095D7700] [C000000000365B24] .tcp_v4_do_rcv+0x5c/0x448
[C0000000095D77D0] [C00000000031C2C4] .release_sock+0x94/0x11c
[C0000000095D7870] [C000000000354E7C] .tcp_recvmsg+0x374/0x8d8
[C0000000095D7960] [C00000000031B8A0] .sock_common_recvmsg+0x5c/0x84
[C0000000095D79F0] [C00000000031921C] .sock_recvmsg+0x110/0x15c
[C0000000095D7C00] [C00000000031AA50] .sys_recvfrom+0xf0/0x174
[C0000000095D7D90] [C000000000339368] .compat_sys_socketcall+0x178/0x214
[C0000000095D7E30] [C000000000008634] syscall_exit+0x0/0x40
Instruction dump:
60000000 81790088 901f000c 913f0018 913f0008 917f0004 48132e8d 60000000 
a019009e 2f800800 409e0038 e9390038 <88690009> 2f830006 419e0010 2f830011 

I suspect spidernet expects spin_lock_irqsave()/restore() to disable/enable
interrupts in vain on RT kernel.

This patch works fine as far as I've tested, but I feel it's a kind of
workaround.  Any comments, suggestions, patches are welcome.

Thanks in advance

Signed-off-by: Tsutomu OWA <tsutomu.owa@toshiba.co.jp>
-- owa

diff -rup linux-2.6.21-rt1/drivers/net/spider_net.c rt/drivers/net/spider_net.c
--- linux-2.6.21-rt1/drivers/net/spider_net.c	2007-04-26 12:08:32.000000000 +0900
+++ rt/drivers/net/spider_net.c	2007-05-07 14:11:24.000000000 +0900
@@ -688,7 +688,6 @@ spider_net_prepare_tx_descr(struct spide
 	struct spider_net_descr *descr;
 	struct spider_net_hw_descr *hwdescr;
 	dma_addr_t buf;
-	unsigned long flags;
 
 	buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
 	if (pci_dma_mapping_error(buf)) {
@@ -699,10 +698,8 @@ spider_net_prepare_tx_descr(struct spide
 		return -ENOMEM;
 	}
 
-	spin_lock_irqsave(&chain->lock, flags);
 	descr = card->tx_chain.head;
 	if (descr->next == chain->tail->prev) {
-		spin_unlock_irqrestore(&chain->lock, flags);
 		pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE);
 		return -ENOMEM;
 	}
@@ -717,7 +714,6 @@ spider_net_prepare_tx_descr(struct spide
 
 	hwdescr->dmac_cmd_status =
 			SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
-	spin_unlock_irqrestore(&chain->lock, flags);
 
 	if (skb->protocol == htons(ETH_P_IP) && skb->ip_summed == CHECKSUM_PARTIAL)
 		switch (skb->nh.iph->protocol) {
@@ -742,7 +738,6 @@ spider_net_set_low_watermark(struct spid
 {
 	struct spider_net_descr *descr = card->tx_chain.tail;
 	struct spider_net_hw_descr *hwdescr;
-	unsigned long flags;
 	int status;
 	int cnt=0;
 	int i;
@@ -768,7 +763,6 @@ spider_net_set_low_watermark(struct spid
 		descr = descr->next;
 
 	/* Set the new watermark, clear the old watermark */
-	spin_lock_irqsave(&card->tx_chain.lock, flags);
 	descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
 	if (card->low_watermark && card->low_watermark != descr) {
 		hwdescr = card->low_watermark->hwdescr;
@@ -776,7 +770,7 @@ spider_net_set_low_watermark(struct spid
 		     hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
 	}
 	card->low_watermark = descr;
-	spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+
 	return cnt;
 }
 
@@ -784,6 +778,7 @@ spider_net_set_low_watermark(struct spid
  * spider_net_release_tx_chain - processes sent tx descriptors
  * @card: adapter structure
  * @brutal: if set, don't care about whether descriptor seems to be in use
+ * @locked: if set, tx_chain locked is held by caller.
  *
  * returns 0 if the tx ring is empty, otherwise 1.
  *
@@ -793,7 +788,7 @@ spider_net_set_low_watermark(struct spid
  * scheduled again (if we were scheduled) and will not loose initiative.
  */
 static int
-spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+spider_net_release_tx_chain(struct spider_net_card *card, int brutal, int locked)
 {
 	struct spider_net_descr_chain *chain = &card->tx_chain;
 	struct spider_net_descr *descr;
@@ -804,9 +799,11 @@ spider_net_release_tx_chain(struct spide
 	int status;
 
 	while (1) {
-		spin_lock_irqsave(&chain->lock, flags);
+		if (!locked)
+			spin_lock_irqsave(&chain->lock, flags);
 		if (chain->tail == chain->head) {
-			spin_unlock_irqrestore(&chain->lock, flags);
+			if (!locked)
+				spin_unlock_irqrestore(&chain->lock, flags);
 			return 0;
 		}
 		descr = chain->tail;
@@ -821,7 +818,8 @@ spider_net_release_tx_chain(struct spide
 
 		case SPIDER_NET_DESCR_CARDOWNED:
 			if (!brutal) {
-				spin_unlock_irqrestore(&chain->lock, flags);
+				if (!locked)
+					spin_unlock_irqrestore(&chain->lock, flags);
 				return 1;
 			}
 
@@ -842,7 +840,8 @@ spider_net_release_tx_chain(struct spide
 		default:
 			card->netdev_stats.tx_dropped++;
 			if (!brutal) {
-				spin_unlock_irqrestore(&chain->lock, flags);
+				if (!locked)
+					spin_unlock_irqrestore(&chain->lock, flags);
 				return 1;
 			}
 		}
@@ -852,7 +851,9 @@ spider_net_release_tx_chain(struct spide
 		skb = descr->skb;
 		descr->skb = NULL;
 		buf_addr = hwdescr->buf_addr;
-		spin_unlock_irqrestore(&chain->lock, flags);
+
+		if (!locked)
+			spin_unlock_irqrestore(&chain->lock, flags);
 
 		/* unmap the skb */
 		if (skb) {
@@ -916,18 +917,28 @@ spider_net_xmit(struct sk_buff *skb, str
 {
 	int cnt;
 	struct spider_net_card *card = netdev_priv(netdev);
+	unsigned long flags;
+
+	if (!spin_trylock_irqsave(&card->tx_chain.lock, flags))
+		return NETDEV_TX_BUSY;
+		//? collision ? return NETDEV_TX_LOCKED;
 
-	spider_net_release_tx_chain(card, 0);
+	spider_net_release_tx_chain(card, 0, 1);
 
 	if (spider_net_prepare_tx_descr(card, skb) != 0) {
+		spin_unlock_irqrestore(&card->tx_chain.lock, flags);
 		card->netdev_stats.tx_dropped++;
 		netif_stop_queue(netdev);
 		return NETDEV_TX_BUSY;
 	}
 
 	cnt = spider_net_set_low_watermark(card);
+
+	spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+
 	if (cnt < 5)
 		spider_net_kick_tx_dma(card);
+
 	return NETDEV_TX_OK;
 }
 
@@ -943,11 +954,20 @@ spider_net_xmit(struct sk_buff *skb, str
 static void
 spider_net_cleanup_tx_ring(struct spider_net_card *card)
 {
-	if ((spider_net_release_tx_chain(card, 0) != 0) &&
+	unsigned long flags;
+
+	if (!spin_trylock_irqsave(&card->tx_chain.lock, flags))
+		return;
+
+	if ((spider_net_release_tx_chain(card, 0, 1) != 0) &&
 	    (card->netdev->flags & IFF_UP)) {
+		spin_unlock_irqrestore(&card->tx_chain.lock, flags);
 		spider_net_kick_tx_dma(card);
 		netif_wake_queue(card->netdev);
-	}
+	} else
+		spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+
+
 }
 
 /**
@@ -2092,7 +2112,7 @@ spider_net_stop(struct net_device *netde
 	spider_net_disable_rxdmac(card);
 
 	/* release chains */
-	spider_net_release_tx_chain(card, 1);
+	spider_net_release_tx_chain(card, 1, 0);
 	spider_net_free_rx_chain_contents(card);
 
 	spider_net_free_chain(card, &card->tx_chain);

^ permalink raw reply

* Re: [RFC] [patch 1/2] powerpc 2.6.21-rt1: fix kernel hang and/or panic
From: Tsutomu OWA @ 2007-05-15  8:44 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: mingo, tglx
In-Reply-To: <yyilkfq5vsj.wl@toshiba.co.jp>


>   It occurs on 2.6.21 + patch-2.6.21-rt1 + series of patches that I posted
> yesterday.

When doing 'hdparm -t /dev/hda' several times, it silently hangs.
I think it freezes since It does not response to ping as well.
On the other hand, PREEMPT_NONE kernel works just fine.

After looking into the rt interrupt handling code, I noticed 
that code path differs between PREEMPT_NONE and PREEMPT_RT;
  NONE: mask() -> unmask() -> eoi() 
  RT:   mask() -> eoi() -> unmask()

The hypervisor underlying the linux on Celleb wants to be called
in this "mask() -> unmask() -> eoi()" order.  This patch mimics
the behavior of PREEPT_NONE even if PREEMPT_RT is specified.

Or, would it be better to create/add a new (threaded) irq handler?

Any comments?

Thanks in advance

Signed-off-by: Tsutomu OWA <tsutomu.owa@toshiba.co.jp>
-- owa

--- linux-2.6.21-rt1/arch/powerpc/platforms/celleb/interrupt.c	2007-05-09 17:04:41.000000000 +0900
+++ rt/arch/powerpc/platforms/celleb/interrupt.c	2007-05-09 17:05:07.000000000 +0900
@@ -29,6 +29,10 @@
 #include "interrupt.h"
 #include "beat_wrapper.h"
 
+#ifdef CONFIG_PREEMPT_HARDIRQS
+extern int hardirq_preemption;
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
 #define	MAX_IRQS	NR_IRQS
 static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);
 static uint64_t	beatic_irq_mask_enable[(MAX_IRQS+255)/64];
@@ -71,12 +75,35 @@ static void beatic_mask_irq(unsigned int
 	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
 }
 
+static void __beatic_eoi_irq(unsigned int irq_plug)
+{
+	s64 err;
+
+	if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
+		if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
+			panic("Failed to downcount IRQ! Error = %16lx", err);
+
+		printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
+	}
+}
+
 static void beatic_unmask_irq(unsigned int irq_plug)
 {
 	unsigned long flags;
 
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	if (hardirq_preemption)
+		__beatic_eoi_irq(irq_plug);
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
 	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
 	beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	if (hardirq_preemption)
+		beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
 	beatic_update_irq_mask(irq_plug);
 	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
 }
@@ -93,15 +120,15 @@ static void beatic_ack_irq(unsigned int 
 
 static void beatic_end_irq(unsigned int irq_plug)
 {
-	s64 err;
 	unsigned long flags;
 
-	if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
-		if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
-			panic("Failed to downcount IRQ! Error = %16lx", err);
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	if (hardirq_preemption)
+		return;
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
+	__beatic_eoi_irq(irq_plug);
 
-		printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
-	}
 	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
 	beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
 	beatic_update_irq_mask(irq_plug);

^ permalink raw reply

* Re: [patch 4/4] powerpc 2.6.21-rt1: reduce scheduling latency by changing tlb flush size
From: Benjamin Herrenschmidt @ 2007-05-15  8:40 UTC (permalink / raw)
  To: Tsutomu OWA
  Cc: linuxppc-dev, Thomas Gleixner, mingo, Arnd Bergmann, linux-kernel
In-Reply-To: <yyimz065x1a.wl@toshiba.co.jp>


> >                                                                Have you measured
> > the time it takes ? We might want to modulate the amount based on wether we
> > are using native hash tables or an hypervisor.
> 
>   Yes, here is the trace log.  Accordint it, flushing  9 entries takes about 50us.
> It means that flushing 192 (PPC64_TLB_BATCH_NR) entries takes 1ms.
> Please note that tracing causes *roughly* 20-30% overhead, though.
> 
>   I'm afraid I don't have numbers w/ native version, but I suppose you have :)

Actually I don't off hand but I'll try to get some.

> # cat /proc/latency_trace
> preemption latency trace v1.1.5 on 2.6.21-rt1
> --------------------------------------------------------------------
>  latency: 60 us, #53/53, CPU#0 | (M:rt VP:0, KP:0, SP:1 HP:1 #P:1)
>     -----------------
>     | task: inetd-358 (uid:0 nice:0 policy:0 rt_prio:0)
>     -----------------
>  => started at: .__switch_to+0xa8/0x178 <c00000000000feec>
>  => ended at:   .__start+0x4000000000000000/0x8 <00000000>
> 
>                  _------=> CPU#            
>                 / _-----=> irqs-off        
>                | / _----=> need-resched    
>                || / _---=> hardirq/softirq 
>                ||| / _--=> preempt-depth   
>                |||| /                      
>                |||||     delay             
>    cmd     pid ||||| time  |   caller      
>       \   /    |||||   \   |   /           
>    inetd-358   0D..2    0us : .user_trace_start (.__switch_to)
>    inetd-358   0D..2    0us : .rt_up (.user_trace_start)
>    inetd-358   0D..3    1us : .rt_mutex_unlock (.rt_up)
>    inetd-358   0D..3    2us : .__flush_tlb_pending (.__switch_to)
>    inetd-358   0D..4    3us : .flush_hash_range (.__flush_tlb_pending)
>    inetd-358   0D..4    3us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4    4us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4    5us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5    6us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   13us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   13us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   14us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   14us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   15us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   18us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   19us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   20us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   20us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   21us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   24us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   25us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   25us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   26us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   26us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   30us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   30us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   31us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   31us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   32us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   36us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   36us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   37us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   37us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   38us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   41us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   42us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   42us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   43us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   43us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   47us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   48us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   48us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   49us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   49us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   52us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..4   53us : .flush_hash_page (.flush_hash_range)
>    inetd-358   0D..4   54us : .beat_lpar_hpte_invalidate (.flush_hash_page)
>    inetd-358   0D..4   54us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   55us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..5   58us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
>    inetd-358   0D..2   59us : .user_trace_stop (.__switch_to)
>    inetd-358   0D..2   60us : .user_trace_stop (.__switch_to)
> -- owa

^ permalink raw reply

* [RFC] [patch 0/2] powerpc 2.6.21-rt1: fix kernel hang and/or  panic
From: Tsutomu OWA @ 2007-05-15  8:35 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: mingo, tglx


  Hi,

  This series of patches seems to fix kernel hang problem and
'Unable to handle kernel paging request for data at address 0x00000009'
error.

  It occurs on 2.6.21 + patch-2.6.21-rt1 + series of patches that I posted
yesterday.

  Comments and suggestions are welcome. 

thanks in advance
-- owa

^ permalink raw reply

* Re: [PATCH] powerpc: Fix warning in pci_64.c
From: Kumar Gala @ 2007-05-15  8:22 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Stephen Rothwell, Paul Mackerras, linuxppc-dev
In-Reply-To: <1179209013.32247.147.camel@localhost.localdomain>


On May 15, 2007, at 1:03 AM, Benjamin Herrenschmidt wrote:

> On Tue, 2007-05-15 at 14:30 +1000, Stephen Rothwell wrote:
>> On Tue, 15 May 2007 14:16:35 +1000 Benjamin Herrenschmidt  
>> <benh@kernel.crashing.org> wrote:
>>>
>>>  void pcibios_add_platform_entries(struct pci_dev *pdev)
>>>  {
>>> -	device_create_file(&pdev->dev, &dev_attr_devspec);
>>> +	int rc = device_create_file(&pdev->dev, &dev_attr_devspec);
>>> +	WARN_ON(rc != 0);
>>
>> If we really don't care if the file is not created, then it is  
>> probably
>> worth a comment as to why ...
>
> Well, if it's not created, then something is badly wrong thus a
> WARN_ON ... Do you think I should do more ?

Yes, fix the pci_32.c version of this as well (if it hasn't been) :)

- k

^ permalink raw reply

* Re: [patch 4/4] powerpc 2.6.21-rt1: reduce scheduling latency by changing tlb flush size
From: Tsutomu OWA @ 2007-05-15  8:08 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev, Thomas Gleixner, mingo, Arnd Bergmann, linux-kernel
In-Reply-To: <1179214707.32247.177.camel@localhost.localdomain>


At Tue, 15 May 2007 17:38:27 +1000, Benjamin Herrenschmidt wrote:

> > +#ifdef CONFIG_PREEMPT_RT
> > +	/*
> > +	 * Since flushing tlb needs expensive hypervisor call(s) on celleb,
> > +	 * always flush it on RT to reduce scheduling latency.
> > +	 */
> > +	if (machine_is(celleb)) {
> > +		flush_tlb_pending();
> > +		return;
> > +	}
> > +#endif /* CONFIG_PREEMPT_RT */

> Any reason to do that only on celleb ? :-)

  Well, at least it does not harm any other platforms :)

> Also, we might want to still batch, though in smaller amount. 

  Yeah, it's a good point.

>                                                                Have you measured
> the time it takes ? We might want to modulate the amount based on wether we
> are using native hash tables or an hypervisor.

  Yes, here is the trace log.  Accordint it, flushing  9 entries takes about 50us.
It means that flushing 192 (PPC64_TLB_BATCH_NR) entries takes 1ms.
Please note that tracing causes *roughly* 20-30% overhead, though.

  I'm afraid I don't have numbers w/ native version, but I suppose you have :)

# cat /proc/latency_trace
preemption latency trace v1.1.5 on 2.6.21-rt1
--------------------------------------------------------------------
 latency: 60 us, #53/53, CPU#0 | (M:rt VP:0, KP:0, SP:1 HP:1 #P:1)
    -----------------
    | task: inetd-358 (uid:0 nice:0 policy:0 rt_prio:0)
    -----------------
 => started at: .__switch_to+0xa8/0x178 <c00000000000feec>
 => ended at:   .__start+0x4000000000000000/0x8 <00000000>

                 _------=> CPU#            
                / _-----=> irqs-off        
               | / _----=> need-resched    
               || / _---=> hardirq/softirq 
               ||| / _--=> preempt-depth   
               |||| /                      
               |||||     delay             
   cmd     pid ||||| time  |   caller      
      \   /    |||||   \   |   /           
   inetd-358   0D..2    0us : .user_trace_start (.__switch_to)
   inetd-358   0D..2    0us : .rt_up (.user_trace_start)
   inetd-358   0D..3    1us : .rt_mutex_unlock (.rt_up)
   inetd-358   0D..3    2us : .__flush_tlb_pending (.__switch_to)
   inetd-358   0D..4    3us : .flush_hash_range (.__flush_tlb_pending)
   inetd-358   0D..4    3us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4    4us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4    5us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5    6us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   13us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   13us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   14us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   14us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   15us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   18us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   19us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   20us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   20us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   21us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   24us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   25us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   25us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   26us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   26us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   30us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   30us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   31us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   31us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   32us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   36us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   36us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   37us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   37us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   38us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   41us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   42us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   42us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   43us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   43us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   47us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   48us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   48us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   49us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   49us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   52us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..4   53us : .flush_hash_page (.flush_hash_range)
   inetd-358   0D..4   54us : .beat_lpar_hpte_invalidate (.flush_hash_page)
   inetd-358   0D..4   54us : .__spin_lock_irqsave (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   55us+: .beat_lpar_hpte_getword0 (.beat_lpar_hpte_invalidate)
   inetd-358   0D..5   58us : .__spin_unlock_irqrestore (.beat_lpar_hpte_invalidate)
   inetd-358   0D..2   59us : .user_trace_stop (.__switch_to)
   inetd-358   0D..2   60us : .user_trace_stop (.__switch_to)
-- owa

^ permalink raw reply

* Re: [patch 4/4] powerpc 2.6.21-rt1: reduce scheduling latency by changing tlb flush size
From: Benjamin Herrenschmidt @ 2007-05-15  7:38 UTC (permalink / raw)
  To: Tsutomu OWA
  Cc: linuxppc-dev, Thomas Gleixner, mingo, Arnd Bergmann, linux-kernel
In-Reply-To: <yyips5261pt.wl@toshiba.co.jp>


> +
> +#ifdef CONFIG_PREEMPT_RT
> +	/*
> +	 * Since flushing tlb needs expensive hypervisor call(s) on celleb,
> +	 * always flush it on RT to reduce scheduling latency.
> +	 */
> +	if (machine_is(celleb)) {
> +		flush_tlb_pending();
> +		return;
> +	}
> +#endif /* CONFIG_PREEMPT_RT */
> +
>  	if (i >= PPC64_TLB_BATCH_NR)
>  		flush_tlb_pending();
>  }

Any reason to do that only on celleb ? :-)

Also, we might want to still batch, though in smaller amount. Have you measured
the time it takes ? We might want to modulate the amount based on wether we
are using native hash tables or an hypervisor.

Ben.

^ permalink raw reply

* Re: [PATCH v2] pcmcia: ppc64 needs 32-bit ioaddr_t
From: Benjamin Herrenschmidt @ 2007-05-15  7:35 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pcmcia, paulus, linux-kernel
In-Reply-To: <20070515043343.GA6561@lixom.net>

On Mon, 2007-05-14 at 23:33 -0500, Olof Johansson wrote:
> ppc64 really needs ioaddr_t to be 32-bit, since I/O beyond the
> first PCI bus might be mapped at a higher range.
> 
> While the type is exported to userspace, there hasn't been any platforms
> with PCMCIA on 64-bit powerpc until now, so changing it won't regress
> any existing users. Besides, those interfaces are overdue for removal
> already.
> 
> 
> Signed-off-by: Olof Johansson <olof@lixom.net>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> Index: 2.6.21/include/pcmcia/cs_types.h
> ===================================================================
> --- 2.6.21.orig/include/pcmcia/cs_types.h
> +++ 2.6.21/include/pcmcia/cs_types.h
> @@ -21,7 +21,7 @@
>  #include <sys/types.h>
>  #endif
>  
> -#if defined(__arm__) || defined(__mips__)
> +#if defined(__arm__) || defined(__mips__) || defined(__powerpc64__)
>  /* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
>  typedef u_int   ioaddr_t;
>  #else
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply

* Re: [patch 4/4] powerpc 2.6.21-rt1: reduce scheduling latency by changing tlb flush size
From: Benjamin Herrenschmidt @ 2007-05-15  7:34 UTC (permalink / raw)
  To: Tsutomu OWA
  Cc: linuxppc-dev, Thomas Gleixner, mingo, Arnd Bergmann, linux-kernel
In-Reply-To: <yyir6pi67yd.wl@toshiba.co.jp>

On Tue, 2007-05-15 at 13:12 +0900, Tsutomu OWA wrote:

> > With this code, you get silent side-effects of enabling PPC_CELLEB
> > along with another platform.
> 
>   Yeah, thank you for pointing it out.
>   I'll send revised patch later.
> 
> > Maybe instead you should change the hpte_need_flush() to always flush
> > when running on the celleb platform and PREEMPT_RT is enabled.
> 
>   Hmm... Is it in linux-2.6.21?  grep'ing it did not help... 
> 
>   Is http://patchwork.ozlabs.org/linuxppc/patch?id=10361 is the first place
> where the hpte_need_flush() appears?

Yes, I added that when reworking the batching mecanism.

Ben.

^ permalink raw reply

* Re: [PATCH 0/3] Initial AMCC Bamboo support
From: Benjamin Herrenschmidt @ 2007-05-15  7:33 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20070515014431.GF565@localhost.localdomain>


> You may need to do both.  At least if you use the same format for the
> ebc binding as I have on Ebony: in the reg properties of the
> individual nodes I directly encode the ebc chip select value and
> offset within the peripheral bank.  The ebc node's 'ranges' gives the
> mappings into the OPB space.  So, in practice, the low 20 bits of
> address are determined by the individual peripheral's reg properties,
> and the upper 12 bits are determined by the ranges property at the EBC
> node.

In addition we might want a helper to fix the node unit address after
poking reg ...

Ben.

^ permalink raw reply

* Re: USB support for Bamboo/440EP (Yosemite/440EPx)
From: Gerhard Jaeger @ 2007-05-15  7:27 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <OFC56C5EA1.CC32B615-ON872572DB.0063BF4F-852572DB.00653577@us.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 2161 bytes --]

On Montag, 14. Mai 2007, Stephen Winiecki wrote:
> Gerhard Jaeger <g.jaeger@sysgo.com> wrote on 05/14/2007 10:31:04 AM:
> > Hi Stephen, 
> > 
> > I also played with Bamboo and Yosemite USB and found out, that the OHCI
> > ISR contains an assumption that makes the 440 OHCI implementation sometimes 
> > stop when having a timeout condition. Find the following sequence @function
> > ohci_irq() (in file ohci-hcd.c) and disable the following code:
> > 
> >         if ((ohci->hcca->done_head != 0)
> >                         && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
> >                                 & 0x01)) {
> >                 ints =  OHCI_INTR_WDH;
> >    }
> > 
> > This should make the USB host work reliably on the 440s.
> > 
> Thanks Gerhard.  This definitely makes things work better - I have had 
> 100% success in both the kernel and X recognizing the devices and having X 
> boot with this update.
> 
> However, I am occasionally still having an issue after X comes up with the 
> keyboard not working (mouse working fine).  Just to be clear - I only want 
> to comment out the code you indicated above - not also any/either of the 
> else/if clauses, correct?

Yes - the lines mentioned didn't care about irq-status register
and try to figure out from some context, how the irq-status register
should look like - but this in fact does not work correctly for the
440 OHCI implementation... 

> So has this never been formally reported/patched?  

Not that I'm aware of, I discovered that a few days ago.

> Do you know also why  
> the USB support has not been configured in the mainline kernel for these 
> platforms - is it due to known existing issues? 

I don't know why this is not part of the mainline kernel. On the PPC
side there is currently a lot of restructure work going on, so I guess
this is only a question of time, when the necessary patches will go
into the mainline.

Please find the patch for the ohc-hcd.c in the attachment.

Ciao,
Gerhard

-- 
Gerhard Jaeger <gjaeger@sysgo.com>            
SYSGO AG                      Embedded and Real-Time Software
www.sysgo.com | www.elinos.com | www.pikeos.com | www.osek.de 

[-- Attachment #2: ppc440-ohci.patch --]
[-- Type: text/x-diff, Size: 1055 bytes --]

This patch makes the OHCI code work correctly on AMCC PPC440
cpus with internal USB-host controller. It seems that the
optimization is not allowed for this OHCI implementation.

Signed-off-by: Gerhard Jaeger <gjaeger@sysgo.com>
---


--- linux/drivers/usb/host/ohci-hcd.c.orig	2007-03-09 11:33:39.000000000 +0100
+++ linux/drivers/usb/host/ohci-hcd.c	2007-05-15 09:03:50.000000000 +0200
@@ -646,13 +646,16 @@ static irqreturn_t ohci_irq (struct usb_
 
 	/* we can eliminate a (slow) ohci_readl()
 	   if _only_ WDH caused this irq */
+#if !(defined(CONFIG_USB_OHCI_HCD_PPC_SOC) && (defined(CONFIG_440EP) || defined(CONFIG_440EPX)))
 	if ((ohci->hcca->done_head != 0)
 			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
 				& 0x01)) {
 		ints =  OHCI_INTR_WDH;
 
 	/* cardbus/... hardware gone before remove() */
-	} else if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) {
+	} else 
+#endif
+	if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) {
 		disable (ohci);
 		ohci_dbg (ohci, "device removed!\n");
 		return IRQ_HANDLED;

^ permalink raw reply

* Re: [patch 4/4] powerpc 2.6.21-rt1: reduce scheduling latency by changing tlb flush size
From: Benjamin Herrenschmidt @ 2007-05-15  7:23 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, Thomas Gleixner, mingo, linux-kernel
In-Reply-To: <200705141640.02561.arnd@arndb.de>

On Mon, 2007-05-14 at 16:40 +0200, Arnd Bergmann wrote:
> On Monday 14 May 2007, Tsutomu OWA wrote:
> > --- linux-2.6.21-rt1/include/asm-powerpc/tlbflush.h     2007-04-26 12:08:32.000000000 +0900
> > +++ rt/include/asm-powerpc/tlbflush.h   2007-05-14 16:12:47.000000000 +0900
> > @@ -25,7 +25,12 @@ struct mm_struct;
> >  #include <linux/percpu.h>
> >  #include <asm/page.h>
> >  
> > +#if defined(CONFIG_PPC_CELLEB) && defined(CONFIG_PREEMPT_RT)
> > +/* Since tlb flush takes long time on Celleb, reduce it to 1 when Celleb && RT */
> > +#define PPC64_TLB_BATCH_NR 1
> > +#else
> >  #define PPC64_TLB_BATCH_NR 192
> > +#endif /* defined(CONFIG_PPC_CELLEB) && defined(CONFIG_PREEMPT_RT) */
> 
> With this code, you get silent side-effects of enabling PPC_CELLEB
> along with another platform.
> 
> Maybe instead you should change the hpte_need_flush() to always flush
> when running on the celleb platform and PREEMPT_RT is enabled.

I think it's wrong either way.... Maybe we can make it a variable and
measure how much we can reasonably do in a given time frame at
boot ? :-) Since it depends wether there's an hypervisor etc...

Ben.

^ permalink raw reply

* Re: [Fwd: [alsa-devel] embedded sound architecture question]
From: Sylvain Munaut @ 2007-05-15  7:09 UTC (permalink / raw)
  To: Lorenz Kolb; +Cc: linuxppc-embedded
In-Reply-To: <000101c795e5$0af92ce0$9602a8c0@lorenzulm>

Hi,

>> If I were you, I would chose one of sound cards which have ALSA
>> drivers implemented (the list can be found on ALSA site) and
>> mimicked their behavior in your VHDL.
>>     
>
> Actually a bunch of theses drivers rely on PCI or ISA.
> The few left do all require DMA, what is only an option, if it is some sort
> of faked DMA, so the CPU writes directly into the controller's memory as we
> intend to stay as independent as possible from Xilinx' IP Cores.
> The question was: is that a good (and practicable) idea?
>   

If you can spare the BRAM, that sounds good to me.

I'm not an alsa expert but I'm working on a driver right now. And alsa
provide you a hook so you can allocate your memory buffer your self.
So as long as your control maps it's memory somewhere in the
cpu address space you should be fine.

What you need is :
 - Be able to ask the hardware where is is "read pointer".
 - Be able to ask the hardware to generate an interrupt every 'n' samples.

And that should do it.

You also need to make the controller build the AC97 frames itself
(e.g. for the control slots, a separate set of registers), and also
preferrably
supporting multiple sample format so the CPU needs to do a minimum of
conversion.


        Sylvain

^ permalink raw reply

* Re: Small fixes for the Ebony device tree
From: Segher Boessenkool @ 2007-05-15  7:07 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev, Stefan Roese, Paul Mackerras
In-Reply-To: <20070515065826.GF6998@localhost.localdomain>

> Sod it, I think I'll just drop everything except "ibm,sdram-440gp" for
> now.

Perfect plan :-)  And then 440GX, GR, etc. can claim
compatibility to 440GP, which is the nestor of the
family.

> If some later driver has to have an extra backwards
> compatibility id_table entry for the Ebony/440GP it's no great
> disaster.

Sure, mistakes happen.  They can be fixed in the
bootwrapper, too -- or just in the DTS file if your
device tree is shipped with the kernel.


Segher

^ permalink raw reply

* Re: Small fixes for the Ebony device tree
From: Segher Boessenkool @ 2007-05-15  7:02 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linuxppc-dev, Paul Mackerras, David Gibson
In-Reply-To: <200705150846.09220.sr@denx.de>

> Why "ibm,xxx"? Is this for the CPU core? Or for the SDRAM controller 
> core?

For whatever is behind the comma.  The prefixes are
meant to give each manufacturer his own namespace,
to reduce the number of name collisions.

> Both are not IBM in this case.

Yeah.

> I forgot the new 405EX which will be equipped with a DDR2 controller 
> (not sure
> right now if it's the Denali or the other core right now). So we should
> probably drop this 40x/44x completely. Does this make sense?

Yes.  To claim compatibility to a family of devices,
specify the oldest part, or the most popular part,
or a few parts if different generations added more
features (and this part is compatible with those).


Segher

^ permalink raw reply

* [PATCH] powerpc: Rewrite IO allocation & mapping on powerpc64
From: Benjamin Herrenschmidt @ 2007-05-15  7:03 UTC (permalink / raw)
  To: linuxppc-dev

This patch rewrites pretty much from scratch the handling of
MMIO and PIO space allocations on powerpc64. The main goals
are:

 - Get rid of imalloc and use more common code where possible
 - Simplify the current mess so that PIO space is allocated and
   mapped in a single place for PCI bridges
 - Handle allocation constraints of PIO for all bridges including
   hot plugged ones within the 2GB space reserved for IO ports,
   so that devices on hotplugged busses will now work with drivers
   that assume IO ports fit in an int.
 - Cleanup and separate tracking of the ISA space in the reserved
   low 64K of IO space. No ISA -> Nothing mapped there.

The patch is mostly untested ! This is not aimed at 2.6.22 but
rather the next merge window since it's pretty big and we need to
test well the hotplug stuff among others.

I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)

With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.

This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)

A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).

imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.

I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.

This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

Applied on top of whatever else I posted today. This version fixes
things here or there and adds more debugging. I no longer tear down
the PTEs when a PCI 2 PCI bridge is unplugged as such mappings might
be smaller than 64K pages on machines with 4K IOs. I flush the hash
table instead (and introduced a new call for that).


 arch/powerpc/kernel/Makefile                 |    2 
 arch/powerpc/kernel/isa-bridge.c             |  271 ++++++++++++++++++++
 arch/powerpc/kernel/of_platform.c            |    8 
 arch/powerpc/kernel/pci_64.c                 |  354 +++++++++------------------
 arch/powerpc/kernel/rtas_pci.c               |    7 
 arch/powerpc/mm/Makefile                     |    3 
 arch/powerpc/mm/imalloc.c                    |  313 -----------------------
 arch/powerpc/mm/mmu_decl.h                   |   12 
 arch/powerpc/mm/pgtable_64.c                 |  205 +++------------
 arch/powerpc/mm/tlb_64.c                     |   56 ++++
 arch/powerpc/platforms/cell/io-workarounds.c |    2 
 arch/powerpc/platforms/iseries/pci.c         |    5 
 arch/powerpc/platforms/maple/pci.c           |   35 --
 arch/powerpc/platforms/pasemi/pci.c          |   20 -
 arch/powerpc/platforms/powermac/pci.c        |   32 --
 arch/powerpc/platforms/pseries/pci_dlpar.c   |    2 
 arch/powerpc/platforms/pseries/pseries.h     |    2 
 drivers/pci/hotplug/rpadlpar_core.c          |    6 
 include/asm-powerpc/floppy.h                 |    6 
 include/asm-powerpc/io.h                     |   19 -
 include/asm-powerpc/pci-bridge.h             |    6 
 include/asm-powerpc/pci.h                    |    4 
 include/asm-powerpc/pgtable-ppc64.h          |   23 +
 include/asm-powerpc/ppc-pci.h                |    6 
 include/asm-powerpc/tlbflush.h               |    5 
 25 files changed, 556 insertions(+), 848 deletions(-)

Index: linux-cell/include/asm-powerpc/pgtable-ppc64.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pgtable-ppc64.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/pgtable-ppc64.h	2007-05-15 16:42:37.000000000 +1000
@@ -27,7 +27,7 @@ struct mm_struct;
  */
 #define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
                 	    PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
-#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
+#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
 
 #if TASK_SIZE_USER64 > PGTABLE_RANGE
 #error TASK_SIZE_USER64 exceeds pagetable range
@@ -37,19 +37,28 @@ struct mm_struct;
 #error TASK_SIZE_USER64 exceeds user VSID range
 #endif
 
+
 /*
  * Define the address range of the vmalloc VM area.
  */
 #define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE  ASM_CONST(0x80000000000)
+#define VMALLOC_SIZE  (PGTABLE_RANGE >> 1)
 #define VMALLOC_END   (VMALLOC_START + VMALLOC_SIZE)
 
 /*
- * Define the address range of the imalloc VM area.
- */
-#define PHBS_IO_BASE	VMALLOC_END
-#define IMALLOC_BASE	(PHBS_IO_BASE + 0x80000000ul)	/* Reserve 2 gigs for PHBs */
-#define IMALLOC_END	(VMALLOC_START + PGTABLE_RANGE)
+ * Define the address ranges for MMIO and IO space :
+ *
+ *  ISA_IO_BASE = VMALLOC_END, 64K reserved area
+ *  PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
+ * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
+ */
+#define FULL_IO_SIZE	0x80000000ul
+#define  ISA_IO_BASE	(VMALLOC_END)
+#define  ISA_IO_END	(VMALLOC_END + 0x10000ul)
+#define  PHB_IO_BASE	(ISA_IO_END)
+#define  PHB_IO_END	(VMALLOC_END + FULL_IO_SIZE)
+#define IOREMAP_BASE	(PHB_IO_END)
+#define IOREMAP_END	(VMALLOC_START + PGTABLE_RANGE)
 
 /*
  * Region IDs
Index: linux-cell/arch/powerpc/kernel/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/Makefile	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/Makefile	2007-05-15 16:42:37.000000000 +1000
@@ -65,7 +65,7 @@ obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_s
 module-$(CONFIG_PPC64)		+= module_64.o
 obj-$(CONFIG_MODULES)		+= $(module-y)
 
-pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o
+pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o isa-bridge.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
 obj-$(CONFIG_PCI_MSI)		+= msi.o
Index: linux-cell/arch/powerpc/kernel/isa-bridge.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/kernel/isa-bridge.c	2007-05-15 16:42:37.000000000 +1000
@@ -0,0 +1,271 @@
+/*
+ * Routines for tracking a legacy ISA bridge
+ *
+ * Copyrigh 2007 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ *
+ * Some bits and pieces moved over from pci_64.c
+ *
+ * Copyrigh 2003 Anton Blanchard <anton@au.ibm.com>, IBM Corp.
+ *
+ *      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
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
+
+unsigned long isa_io_base;	/* NULL if no ISA bus */
+EXPORT_SYMBOL(isa_io_base);
+
+/* Cached ISA bridge dev. */
+static struct device_node *isa_bridge_devnode;
+struct pci_dev *isa_bridge_pcidev;
+EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
+
+#define ISA_SPACE_MASK 0x1
+#define ISA_SPACE_IO 0x1
+
+static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
+						unsigned long phb_io_base_phys)
+{
+	/* We should get some saner parsing here and remove these structs */
+	struct pci_address {
+		u32 a_hi;
+		u32 a_mid;
+		u32 a_lo;
+	};
+
+	struct isa_address {
+		u32 a_hi;
+		u32 a_lo;
+	};
+
+	struct isa_range {
+		struct isa_address isa_addr;
+		struct pci_address pci_addr;
+		unsigned int size;
+	};
+
+	const struct isa_range *range;
+	unsigned long pci_addr;
+	unsigned int isa_addr;
+	unsigned int size;
+	int rlen = 0;
+
+	range = of_get_property(isa_node, "ranges", &rlen);
+	if (range == NULL || (rlen < sizeof(struct isa_range)))
+		goto inval_range;
+
+	/* From "ISA Binding to 1275"
+	 * The ranges property is laid out as an array of elements,
+	 * each of which comprises:
+	 *   cells 0 - 1:	an ISA address
+	 *   cells 2 - 4:	a PCI address
+	 *			(size depending on dev->n_addr_cells)
+	 *   cell 5:		the size of the range
+	 */
+	if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) {
+		range++;
+		rlen -= sizeof(struct isa_range);
+		if (rlen < sizeof(struct isa_range))
+			goto inval_range;
+	}
+	if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO)
+		goto inval_range;
+
+	isa_addr = range->isa_addr.a_lo;
+	pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |
+		range->pci_addr.a_lo;
+
+	/* Assume these are both zero. Note: We could fix that and
+	 * do a proper parsing instead ... oh well, that will do for
+	 * now as nobody uses fancy mappings for ISA bridges
+	 */
+	if ((pci_addr != 0) || (isa_addr != 0)) {
+		printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
+		       __FUNCTION__);
+		return;
+	}
+
+	/* Align size and make sure it's cropped to 64K */
+	size = PAGE_ALIGN(range->size);
+	if (size > 0x10000)
+		size = 0x10000;
+
+	printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+	       "mapping 64k\n");
+
+	__ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
+		     size, _PAGE_NO_CACHE|_PAGE_GUARDED);
+	return;
+
+inval_range:
+	printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+	       "mapping 64k\n");
+	__ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
+		     0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED);
+}
+
+
+/**
+ * isa_bridge_find_early - Find and map the ISA IO space early before
+ *                         main PCI discovery. This is optionally called by
+ *                         the arch code when adding PCI PHBs to get early
+ *                         access to ISA IO ports
+ */
+void __init isa_bridge_find_early(struct pci_controller *hose)
+{
+	struct device_node *np, *parent = NULL, *tmp;
+
+	/* If we already have an ISA bridge, bail off */
+	if (isa_bridge_devnode != NULL)
+		return;
+
+	/* For each "isa" node in the system. Note : we do a search by
+	 * type and not by name. It might be better to do by name but that's
+	 * what the code used to do and I don't want to break too much at
+	 * once. We can look into changing that separately
+	 */
+	for_each_node_by_type(np, "isa") {
+		/* Look for our hose being a parent */
+		for (parent = of_get_parent(np); parent;) {
+			if (parent == hose->arch_data) {
+				of_node_put(parent);
+				break;
+			}
+			tmp = parent;
+			parent = of_get_parent(parent);
+			of_node_put(tmp);
+		}
+		if (parent != NULL)
+			break;
+	}
+	if (np == NULL)
+		return;
+	isa_bridge_devnode = np;
+
+	/* Now parse the "ranges" property and setup the ISA mapping */
+	pci_process_ISA_OF_ranges(np, hose->io_base_phys);
+
+	/* Set the global ISA io base to indicate we have an ISA bridge */
+	isa_io_base = ISA_IO_BASE;
+
+	pr_debug("ISA bridge (early) is %s\n", np->full_name);
+}
+
+/**
+ * isa_bridge_find_late - Find and map the ISA IO space upon discovery of
+ *                        a new ISA bridge
+ */
+static void __devinit isa_bridge_find_late(struct pci_dev *pdev,
+					   struct device_node *devnode)
+{
+	struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+
+	/* Store ISA device node and PCI device */
+	isa_bridge_devnode = of_node_get(devnode);
+	isa_bridge_pcidev = pdev;
+
+	/* Now parse the "ranges" property and setup the ISA mapping */
+	pci_process_ISA_OF_ranges(devnode, hose->io_base_phys);
+
+	/* Set the global ISA io base to indicate we have an ISA bridge */
+	isa_io_base = ISA_IO_BASE;
+
+	pr_debug("ISA bridge (late) is %s on %s\n",
+		 devnode->full_name, pci_name(pdev));
+}
+
+/**
+ * isa_bridge_remove - Remove/unmap an ISA bridge
+ */
+static void isa_bridge_remove(void)
+{
+	pr_debug("ISA bridge removed !\n");
+
+	/* Clear the global ISA io base to indicate that we have no more
+	 * ISA bridge. Note that drivers don't quite handle that, though
+	 * we should probably do something about it. But do we ever really
+	 * have ISA bridges being removed on machines using legacy devices ?
+	 */
+	isa_io_base = ISA_IO_BASE;
+
+	/* Clear references to the bridge */
+	of_node_put(isa_bridge_devnode);
+	isa_bridge_devnode = NULL;
+	isa_bridge_pcidev = NULL;
+
+	/* Unmap the ISA area */
+	__iounmap_at((void *)ISA_IO_BASE, 0x10000);
+}
+
+/**
+ * isa_bridge_notify - Get notified of PCI devices addition/removal
+ */
+static int __devinit isa_bridge_notify(struct notifier_block *nb,
+				       unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct device_node *devnode = pci_device_to_OF_node(pdev);
+
+	switch(action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		/* Check if we have an early ISA device, without PCI dev */
+		if (isa_bridge_devnode && isa_bridge_devnode == devnode &&
+		    !isa_bridge_pcidev) {
+			pr_debug("ISA bridge PCI attached: %s\n",
+				 pci_name(pdev));
+			isa_bridge_pcidev = pdev;
+		}
+
+		/* Check if we have no ISA device, and this happens to be one,
+		 * register it as such if it has an OF device
+		 */
+		if (!isa_bridge_devnode && devnode &&
+		    !strcmp(devnode->type, "isa"))
+			isa_bridge_find_late(pdev, devnode);
+
+		return 0;
+	case BUS_NOTIFY_DEL_DEVICE:
+		/* Check if this our existing ISA device */
+		if (pdev == isa_bridge_pcidev ||
+		    (devnode && devnode == isa_bridge_devnode))
+			isa_bridge_remove();
+		return 0;
+	}
+	return 0;
+}
+
+static struct notifier_block isa_bridge_notifier = {
+	.notifier_call = isa_bridge_notify
+};
+
+/**
+ * isa_bridge_init - register to be notified of ISA bridge addition/removal
+ *
+ */
+static int __init isa_bridge_init(void)
+{
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return 0;
+	bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);
+	return 0;
+}
+arch_initcall(isa_bridge_init);
Index: linux-cell/arch/powerpc/kernel/of_platform.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/of_platform.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/of_platform.c	2007-05-15 16:42:37.000000000 +1000
@@ -427,14 +427,6 @@ static int __devinit of_pci_phb_probe(st
 	/* Process "ranges" property */
 	pci_process_bridge_OF_ranges(phb, dev->node, 0);
 
-	/* Setup IO space. We use the non-dynamic version of that code here,
-	 * which doesn't quite support unplugging. Next kernel release will
-	 * have a better fix for this.
-	 * Note also that we don't do ISA, this will also be fixed with a
-	 * more massive rework.
-	 */
-	pci_setup_phb_io(phb, 0);
-
 	/* Init pci_dn data structures */
 	pci_devs_phb_init_dynamic(phb);
 
Index: linux-cell/arch/powerpc/kernel/pci_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/pci_64.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/pci_64.c	2007-05-15 16:42:37.000000000 +1000
@@ -11,7 +11,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#undef DEBUG
+#define DEBUG
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -22,6 +22,7 @@
 #include <linux/list.h>
 #include <linux/syscalls.h>
 #include <linux/irq.h>
+#include <linux/vmalloc.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -41,24 +42,19 @@
 
 unsigned long pci_probe_only = 1;
 int pci_assign_all_buses = 0;
-static int pci_initial_scan_done;
 
 static void fixup_resource(struct resource *res, struct pci_dev *dev);
 static void do_bus_setup(struct pci_bus *bus);
-static void phbs_remap_io(void);
 
 /* pci_io_base -- the base address from which io bars are offsets.
  * This is the lowest I/O base address (so bar values are always positive),
  * and it *must* be the start of ISA space if an ISA bus exists because
- * ISA drivers use hard coded offsets.  If no ISA bus exists a dummy
- * page is mapped and isa_io_limit prevents access to it.
+ * ISA drivers use hard coded offsets.  If no ISA bus exists nothing
+ * is mapped on the first 64K of IO space
  */
-unsigned long isa_io_base;	/* NULL if no ISA bus */
-EXPORT_SYMBOL(isa_io_base);
-unsigned long pci_io_base;
+unsigned long pci_io_base = ISA_IO_BASE;
 EXPORT_SYMBOL(pci_io_base);
 
-void iSeries_pcibios_init(void);
 
 LIST_HEAD(hose_list);
 
@@ -66,10 +62,6 @@ static struct dma_mapping_ops *pci_dma_o
 
 int global_phb_number;		/* Global phb counter */
 
-/* Cached ISA bridge dev. */
-struct pci_dev *ppc64_isabridge_dev = NULL;
-EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
-
 void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
 {
 	pci_dma_ops = dma_ops;
@@ -100,7 +92,7 @@ void  pcibios_resource_to_bus(struct pci
 		return;
 
 	if (res->flags & IORESOURCE_IO)
-	        offset = (unsigned long)hose->io_base_virt - pci_io_base;
+	        offset = (unsigned long)hose->io_base_virt - _IO_BASE;
 
 	if (res->flags & IORESOURCE_MEM)
 		offset = hose->pci_mem_offset;
@@ -119,7 +111,7 @@ void pcibios_bus_to_resource(struct pci_
 		return;
 
 	if (res->flags & IORESOURCE_IO)
-	        offset = (unsigned long)hose->io_base_virt - pci_io_base;
+	        offset = (unsigned long)hose->io_base_virt - _IO_BASE;
 
 	if (res->flags & IORESOURCE_MEM)
 		offset = hose->pci_mem_offset;
@@ -156,7 +148,7 @@ void pcibios_align_resource(void *data, 
 
 	if (res->flags & IORESOURCE_IO) {
 	        unsigned long offset = (unsigned long)hose->io_base_virt -
-					pci_io_base;
+					_IO_BASE;
 		/* Make sure we start at our min on all hoses */
 		if (start - offset < PCIBIOS_MIN_IO)
 			start = PCIBIOS_MIN_IO + offset;
@@ -535,10 +527,16 @@ void __devinit scan_phb(struct pci_contr
 	bus->secondary = hose->first_busno;
 	hose->bus = bus;
 
+	if (!firmware_has_feature(FW_FEATURE_ISERIES))
+		pcibios_map_io_space(bus);
+
 	bus->resource[0] = res = &hose->io_resource;
-	if (res->flags && request_resource(&ioport_resource, res))
+	if (res->flags && request_resource(&ioport_resource, res)) {
 		printk(KERN_ERR "Failed to request PCI IO region "
 		       "on PCI domain %04x\n", hose->global_number);
+		DBG("res->start = 0x%016lx, res->end = 0x%016lx\n",
+		    res->start, res->end);
+	}
 
 	for (i = 0; i < 3; ++i) {
 		res = &hose->mem_resources[i];
@@ -596,17 +594,6 @@ static int __init pcibios_init(void)
 	if (ppc_md.pcibios_fixup)
 		ppc_md.pcibios_fixup();
 
-	/* Cache the location of the ISA bridge (if we have one) */
-	ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
-	if (ppc64_isabridge_dev != NULL)
-		printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		/* map in PCI I/O space */
-		phbs_remap_io();
-
-	pci_initial_scan_done = 1;
-
 	printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
 
 	return 0;
@@ -711,7 +698,7 @@ static struct resource *__pci_mmap_make_
 #endif
 		res_bit = IORESOURCE_MEM;
 	} else {
-		io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
+		io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
 		*offset += io_offset;
 		res_bit = IORESOURCE_IO;
 	}
@@ -882,76 +869,6 @@ void pcibios_add_platform_entries(struct
 	WARN_ON(rc != 0);
 }
 
-#define ISA_SPACE_MASK 0x1
-#define ISA_SPACE_IO 0x1
-
-static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
-				      unsigned long phb_io_base_phys,
-				      void __iomem * phb_io_base_virt)
-{
-	/* Remove these asap */
-
-	struct pci_address {
-		u32 a_hi;
-		u32 a_mid;
-		u32 a_lo;
-	};
-
-	struct isa_address {
-		u32 a_hi;
-		u32 a_lo;
-	};
-
-	struct isa_range {
-		struct isa_address isa_addr;
-		struct pci_address pci_addr;
-		unsigned int size;
-	};
-
-	const struct isa_range *range;
-	unsigned long pci_addr;
-	unsigned int isa_addr;
-	unsigned int size;
-	int rlen = 0;
-
-	range = of_get_property(isa_node, "ranges", &rlen);
-	if (range == NULL || (rlen < sizeof(struct isa_range))) {
-		printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
-		       "mapping 64k\n");
-		__ioremap_explicit(phb_io_base_phys,
-				   (unsigned long)phb_io_base_virt,
-				   0x10000, _PAGE_NO_CACHE | _PAGE_GUARDED);
-		return;	
-	}
-	
-	/* From "ISA Binding to 1275"
-	 * The ranges property is laid out as an array of elements,
-	 * each of which comprises:
-	 *   cells 0 - 1:	an ISA address
-	 *   cells 2 - 4:	a PCI address 
-	 *			(size depending on dev->n_addr_cells)
-	 *   cell 5:		the size of the range
-	 */
-	if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) {
-		isa_addr = range->isa_addr.a_lo;
-		pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | 
-			range->pci_addr.a_lo;
-
-		/* Assume these are both zero */
-		if ((pci_addr != 0) || (isa_addr != 0)) {
-			printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
-					__FUNCTION__);
-			return;
-		}
-		
-		size = PAGE_ALIGN(range->size);
-
-		__ioremap_explicit(phb_io_base_phys, 
-				   (unsigned long) phb_io_base_virt, 
-				   size, _PAGE_NO_CACHE | _PAGE_GUARDED);
-	}
-}
-
 void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
 					    struct device_node *dev, int prim)
 {
@@ -1046,155 +963,122 @@ void __devinit pci_process_bridge_OF_ran
 	}
 }
 
-void __devinit pci_setup_phb_io(struct pci_controller *hose, int primary)
+#ifdef CONFIG_HOTPLUG
+
+int pcibios_unmap_io_space(struct pci_bus *bus)
 {
-	unsigned long size = hose->pci_io_size;
-	unsigned long io_virt_offset;
-	struct resource *res;
-	struct device_node *isa_dn;
+	struct pci_controller *hose;
 
-	if (size == 0)
-		return;
+	WARN_ON(bus == NULL);
 
-	hose->io_base_virt = reserve_phb_iospace(size);
-	DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
-		hose->global_number, hose->io_base_phys,
-		(unsigned long) hose->io_base_virt);
-
-	if (primary) {
-		pci_io_base = (unsigned long)hose->io_base_virt;
-		isa_dn = of_find_node_by_type(NULL, "isa");
-		if (isa_dn) {
-			isa_io_base = pci_io_base;
-			pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys,
-						hose->io_base_virt);
-			of_node_put(isa_dn);
-		}
-	}
+	/* If this is not a PHB, we only flush the hash table over
+	 * the area mapped by this bridge. We don't play with the PTE
+	 * mappings since we might have to deal with sub-page alignemnts
+	 * so flushing the hash table is the only sane way to make sure
+	 * that no hash entries are covering that removed bridge area
+	 * while still allowing other busses overlapping those pages
+	 */
+	if (bus->self) {
+		struct resource *res = bus->resource[0];
 
-	io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
-	res = &hose->io_resource;
-	res->start += io_virt_offset;
-	res->end += io_virt_offset;
+		DBG("IO unmapping for PCI-PCI bridge %s\n",
+		    pci_name(bus->self));
 
-	/* If this is called after the initial PCI scan, then we need to
-	 * proceed to IO mappings now
-	 */
-	if (pci_initial_scan_done)
-		__ioremap_explicit(hose->io_base_phys,
-				   (unsigned long)hose->io_base_virt,
-				   hose->pci_io_size,
-				   _PAGE_NO_CACHE | _PAGE_GUARDED);
-}
+		__flush_hash_table_range(&init_mm, res->start + _IO_BASE,
+					 res->end - res->start + 1);
+		return 0;
+	}
 
-void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose,
-					int primary)
-{
-	unsigned long size = hose->pci_io_size;
-	unsigned long io_virt_offset;
-	struct resource *res;
+	/* Get the host bridge */
+	hose = pci_bus_to_host(bus);
 
-	if (size == 0)
-		return;
+	/* Check if we have IOs allocated */
+	if (hose->io_base_alloc == 0)
+		return 0;
 
-	hose->io_base_virt = __ioremap(hose->io_base_phys, size,
-					_PAGE_NO_CACHE | _PAGE_GUARDED);
-	DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
-		hose->global_number, hose->io_base_phys,
-		(unsigned long) hose->io_base_virt);
+	DBG("IO unmapping for PHB %s\n",
+	    ((struct device_node *)hose->arch_data)->full_name);
+	DBG("  alloc=0x%p\n", hose->io_base_alloc);
 
-	if (primary)
-		pci_io_base = (unsigned long)hose->io_base_virt;
+	/* This is a PHB, we fully unmap the IO area */
+	vunmap(hose->io_base_alloc);
 
-	io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
-	res = &hose->io_resource;
-	res->start += io_virt_offset;
-	res->end += io_virt_offset;
+	return 0;
 }
+EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);
 
+#endif /* CONFIG_HOTPLUG */
 
-static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
-				unsigned long *start_virt, unsigned long *size)
+int __devinit pcibios_map_io_space(struct pci_bus *bus)
 {
-	struct pci_controller *hose = pci_bus_to_host(bus);
-	struct resource *res;
-
-	if (bus->self)
-		res = bus->resource[0];
-	else
-		/* Root Bus */
-		res = &hose->io_resource;
-
-	if (res->end == 0 && res->start == 0)
-		return 1;
+	struct vm_struct *area;
+	unsigned long phys_page;
+	unsigned long size_page;
+	unsigned long io_virt_offset;
+	struct pci_controller *hose;
 
-	*start_virt = pci_io_base + res->start;
-	*start_phys = *start_virt + hose->io_base_phys
-		- (unsigned long) hose->io_base_virt;
+	WARN_ON(bus == NULL);
 
-	if (res->end > res->start)
-		*size = res->end - res->start + 1;
-	else {
-		printk("%s(): unexpected region 0x%lx->0x%lx\n",
-		       __FUNCTION__, res->start, res->end);
-		return 1;
+	/* If this not a PHB, nothing to do, page tables still exist and
+	 * thus HPTEs will be faulted in when needed
+	 */
+	if (bus->self) {
+		DBG("IO mapping for PCI-PCI bridge %s\n",
+		    pci_name(bus->self));
+		DBG("  virt=0x%016lx...0x%016lx\n",
+		    bus->resource[0]->start + _IO_BASE,
+		    bus->resource[0]->end + _IO_BASE);
+		return 0;
 	}
 
-	return 0;
-}
+	/* Get the host bridge */
+	hose = pci_bus_to_host(bus);
+	phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);
+	size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);
 
-int unmap_bus_range(struct pci_bus *bus)
-{
-	unsigned long start_phys;
-	unsigned long start_virt;
-	unsigned long size;
+	/* Make sure IO area address is clear */
+	hose->io_base_alloc = NULL;
 
-	if (!bus) {
-		printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
-		return 1;
-	}
-	
-	if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
-		return 1;
-	if (__iounmap_explicit((void __iomem *) start_virt, size))
-		return 1;
-
-	return 0;
-}
-EXPORT_SYMBOL(unmap_bus_range);
+	/* If there's no IO to map on that bus, get away too */
+	if (hose->pci_io_size == 0 || hose->io_base_phys == 0)
+		return 0;
 
-int remap_bus_range(struct pci_bus *bus)
-{
-	unsigned long start_phys;
-	unsigned long start_virt;
-	unsigned long size;
+	/* Let's allocate some IO space for that guy. We don't pass
+	 * VM_IOREMAP because we don't care about alignment tricks that
+	 * the core does in that case. Maybe we should due to stupid card
+	 * with incomplete address decoding but I'd rather not deal with
+	 * those outside of the reserved 64K legacy region.
+	 */
+	area = __get_vm_area(size_page, 0, PHB_IO_BASE, PHB_IO_END);
+	if (area == NULL)
+		return -ENOMEM;
+	hose->io_base_alloc = area->addr;
+	hose->io_base_virt = (void __iomem *)(area->addr +
+					      hose->io_base_phys - phys_page);
+
+	DBG("IO mapping for PHB %s\n",
+	    ((struct device_node *)hose->arch_data)->full_name);
+	DBG("  phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",
+	    hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);
+	DBG("  size=0x%016lx (alloc=0x%016lx)\n",
+	    hose->pci_io_size, size_page);
+
+	/* Establish the mapping */
+	if (__ioremap_at(phys_page, area->addr, size_page,
+			 _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)
+		return -ENOMEM;
+
+	/* Fixup hose IO resource */
+	io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+	hose->io_resource.start += io_virt_offset;
+	hose->io_resource.end += io_virt_offset;
 
-	if (!bus) {
-		printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
-		return 1;
-	}
-	
-	
-	if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
-		return 1;
-	if (start_phys == 0)
-		return 1;
-	printk(KERN_DEBUG "mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
-	if (__ioremap_explicit(start_phys, start_virt, size,
-			       _PAGE_NO_CACHE | _PAGE_GUARDED))
-		return 1;
+	DBG("  hose->io_resource=0x%016lx...0x%016lx\n",
+	    hose->io_resource.start, hose->io_resource.end);
 
 	return 0;
 }
-EXPORT_SYMBOL(remap_bus_range);
-
-static void phbs_remap_io(void)
-{
-	struct pci_controller *hose, *tmp;
-
-	list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
-		remap_bus_range(hose->bus);
-}
+EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
 static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
 {
@@ -1202,8 +1086,7 @@ static void __devinit fixup_resource(str
 	unsigned long offset;
 
 	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
+		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
 		res->start += offset;
 		res->end += offset;
 	} else if (res->flags & IORESOURCE_MEM) {
@@ -1218,9 +1101,20 @@ void __devinit pcibios_fixup_device_reso
 	/* Update device resources.  */
 	int i;
 
-	for (i = 0; i < PCI_NUM_RESOURCES; i++)
-		if (dev->resource[i].flags)
-			fixup_resource(&dev->resource[i], dev);
+	DBG("%s: Fixup resources:\n", pci_name(dev));
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = &dev->resource[i];
+		if (!res->flags)
+			continue;
+
+		DBG("  0x%02x < %08lx:0x%016lx...0x%016lx\n",
+		    i, res->flags, res->start, res->end);
+
+		fixup_resource(res, dev);
+
+		DBG("       > %08lx:0x%016lx...0x%016lx\n",
+		    res->flags, res->start, res->end);
+	}
 }
 EXPORT_SYMBOL(pcibios_fixup_device_resources);
 
@@ -1361,7 +1255,7 @@ void pci_resource_to_user(const struct p
 		return;
 
 	if (rsrc->flags & IORESOURCE_IO)
-		offset = (unsigned long)hose->io_base_virt - pci_io_base;
+		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
 
 	/* We pass a fully fixed up address to userland for MMIO instead of
 	 * a BAR value because X is lame and expects to be able to use that
@@ -1411,7 +1305,7 @@ unsigned long pci_address_to_pio(phys_ad
 		if (address >= hose->io_base_phys &&
 		    address < (hose->io_base_phys + hose->pci_io_size)) {
 			unsigned long base =
-				(unsigned long)hose->io_base_virt - pci_io_base;
+				(unsigned long)hose->io_base_virt - _IO_BASE;
 			return base + (address - hose->io_base_phys);
 		}
 	}
Index: linux-cell/arch/powerpc/kernel/rtas_pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/rtas_pci.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/rtas_pci.c	2007-05-15 16:42:37.000000000 +1000
@@ -278,10 +278,8 @@ void __init find_and_init_phbs(void)
 {
 	struct device_node *node;
 	struct pci_controller *phb;
-	unsigned int index;
 	struct device_node *root = of_find_node_by_path("/");
 
-	index = 0;
 	for (node = of_get_next_child(root, NULL);
 	     node != NULL;
 	     node = of_get_next_child(root, node)) {
@@ -295,8 +293,7 @@ void __init find_and_init_phbs(void)
 			continue;
 		rtas_setup_phb(phb);
 		pci_process_bridge_OF_ranges(phb, node, 0);
-		pci_setup_phb_io(phb, index == 0);
-		index++;
+		isa_bridge_find_early(phb);
 	}
 
 	of_node_put(root);
@@ -335,7 +332,7 @@ int pcibios_remove_root_bus(struct pci_c
 		return 1;
 	}
 
-	rc = unmap_bus_range(b);
+	rc = pcibios_unmap_io_space(b);
 	if (rc) {
 		printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
 			__FUNCTION__, b->name);
Index: linux-cell/arch/powerpc/mm/imalloc.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/imalloc.c	2007-05-15 16:42:25.000000000 +1000
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,313 +0,0 @@
-/*
- * c 2001 PPC 64 Team, IBM Corp
- * 
- *      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
- *      2 of the License, or (at your option) any later version.
- */
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <linux/mutex.h>
-#include <asm/cacheflush.h>
-
-#include "mmu_decl.h"
-
-static DEFINE_MUTEX(imlist_mutex);
-struct vm_struct * imlist = NULL;
-
-static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
-{
-	unsigned long addr;
-	struct vm_struct **p, *tmp;
-
-	addr = ioremap_bot;
-	for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
-		if (size + addr < (unsigned long) tmp->addr)
-			break;
-		if ((unsigned long)tmp->addr >= ioremap_bot)
-			addr = tmp->size + (unsigned long) tmp->addr;
-		if (addr >= IMALLOC_END-size)
-			return 1;
-	}
-	*im_addr = addr;
-
-	return 0;
-}
-
-/* Return whether the region described by v_addr and size is a subset
- * of the region described by parent
- */
-static inline int im_region_is_subset(unsigned long v_addr, unsigned long size,
-			struct vm_struct *parent)
-{
-	return (int) (v_addr >= (unsigned long) parent->addr &&
-	              v_addr < (unsigned long) parent->addr + parent->size &&
-	    	      size < parent->size);
-}
-
-/* Return whether the region described by v_addr and size is a superset
- * of the region described by child
- */
-static int im_region_is_superset(unsigned long v_addr, unsigned long size,
-		struct vm_struct *child)
-{
-	struct vm_struct parent;
-
-	parent.addr = (void *) v_addr;
-	parent.size = size;
-
-	return im_region_is_subset((unsigned long) child->addr, child->size,
-			&parent);
-}
-
-/* Return whether the region described by v_addr and size overlaps
- * the region described by vm.  Overlapping regions meet the
- * following conditions:
- * 1) The regions share some part of the address space
- * 2) The regions aren't identical
- * 3) Neither region is a subset of the other
- */
-static int im_region_overlaps(unsigned long v_addr, unsigned long size,
-		     struct vm_struct *vm)
-{
-	if (im_region_is_superset(v_addr, size, vm))
-		return 0;
-
-	return (v_addr + size > (unsigned long) vm->addr + vm->size &&
-		v_addr < (unsigned long) vm->addr + vm->size) ||
-	       (v_addr < (unsigned long) vm->addr &&
-		v_addr + size > (unsigned long) vm->addr);
-}
-
-/* Determine imalloc status of region described by v_addr and size.
- * Can return one of the following:
- * IM_REGION_UNUSED   -  Entire region is unallocated in imalloc space.
- * IM_REGION_SUBSET -    Region is a subset of a region that is already
- * 			 allocated in imalloc space.
- * 		         vm will be assigned to a ptr to the parent region.
- * IM_REGION_EXISTS -    Exact region already allocated in imalloc space.
- *                       vm will be assigned to a ptr to the existing imlist
- *                       member.
- * IM_REGION_OVERLAPS -  Region overlaps an allocated region in imalloc space.
- * IM_REGION_SUPERSET -  Region is a superset of a region that is already
- *                       allocated in imalloc space.
- */
-static int im_region_status(unsigned long v_addr, unsigned long size,
-		    struct vm_struct **vm)
-{
-	struct vm_struct *tmp;
-
-	for (tmp = imlist; tmp; tmp = tmp->next)
-		if (v_addr < (unsigned long) tmp->addr + tmp->size)
-			break;
-
-	*vm = NULL;
-	if (tmp) {
-		if (im_region_overlaps(v_addr, size, tmp))
-			return IM_REGION_OVERLAP;
-
-		*vm = tmp;
-		if (im_region_is_subset(v_addr, size, tmp)) {
-			/* Return with tmp pointing to superset */
-			return IM_REGION_SUBSET;
-		}
-		if (im_region_is_superset(v_addr, size, tmp)) {
-			/* Return with tmp pointing to first subset */
-			return IM_REGION_SUPERSET;
-		}
-		else if (v_addr == (unsigned long) tmp->addr &&
-		 	 size == tmp->size) {
-			/* Return with tmp pointing to exact region */
-			return IM_REGION_EXISTS;
-		}
-	}
-
-	return IM_REGION_UNUSED;
-}
-
-static struct vm_struct * split_im_region(unsigned long v_addr, 
-		unsigned long size, struct vm_struct *parent)
-{
-	struct vm_struct *vm1 = NULL;
-	struct vm_struct *vm2 = NULL;
-	struct vm_struct *new_vm = NULL;
-	
-	vm1 = kmalloc(sizeof(*vm1), GFP_KERNEL);
-	if (vm1	== NULL) {
-		printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
-		return NULL;
-	}
-
-	if (v_addr == (unsigned long) parent->addr) {
-	        /* Use existing parent vm_struct to represent child, allocate
-		 * new one for the remainder of parent range
-		 */
-		vm1->size = parent->size - size;
-		vm1->addr = (void *) (v_addr + size);
-		vm1->next = parent->next;
-
-		parent->size = size;
-		parent->next = vm1;
-		new_vm = parent;
-	} else if (v_addr + size == (unsigned long) parent->addr + 
-			parent->size) {
-		/* Allocate new vm_struct to represent child, use existing
-		 * parent one for remainder of parent range
-		 */
-		vm1->size = size;
-		vm1->addr = (void *) v_addr;
-		vm1->next = parent->next;
-		new_vm = vm1;
-
-		parent->size -= size;
-		parent->next = vm1;
-	} else {
-	        /* Allocate two new vm_structs for the new child and 
-		 * uppermost remainder, and use existing parent one for the
-		 * lower remainder of parent range
-		 */
-		vm2 = kmalloc(sizeof(*vm2), GFP_KERNEL);
-		if (vm2 == NULL) {
-			printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
-			kfree(vm1);
-			return NULL;
-		}
-
-		vm1->size = size;
-		vm1->addr = (void *) v_addr;
-		vm1->next = vm2;
-		new_vm = vm1;
-
-		vm2->size = ((unsigned long) parent->addr + parent->size) - 
-				(v_addr + size);
-		vm2->addr = (void *) v_addr + size;
-		vm2->next = parent->next;
-
-		parent->size = v_addr - (unsigned long) parent->addr;
-		parent->next = vm1;
-	}
-
-	return new_vm;
-}
-
-static struct vm_struct * __add_new_im_area(unsigned long req_addr, 
-					    unsigned long size)
-{
-	struct vm_struct **p, *tmp, *area;
-		
-	for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
-		if (req_addr + size <= (unsigned long)tmp->addr)
-			break;
-	}
-	
-	area = kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area)
-		return NULL;
-	area->flags = 0;
-	area->addr = (void *)req_addr;
-	area->size = size;
-	area->next = *p;
-	*p = area;
-
-	return area;
-}
-
-static struct vm_struct * __im_get_area(unsigned long req_addr, 
-					unsigned long size,
-					int criteria)
-{
-	struct vm_struct *tmp;
-	int status;
-
-	status = im_region_status(req_addr, size, &tmp);
-	if ((criteria & status) == 0) {
-		return NULL;
-	}
-	
-	switch (status) {
-	case IM_REGION_UNUSED:
-		tmp = __add_new_im_area(req_addr, size);
-		break;
-	case IM_REGION_SUBSET:
-		tmp = split_im_region(req_addr, size, tmp);
-		break;
-	case IM_REGION_EXISTS:
-		/* Return requested region */
-		break;
-	case IM_REGION_SUPERSET:
-		/* Return first existing subset of requested region */
-		break;
-	default:
-		printk(KERN_ERR "%s() unexpected imalloc region status\n",
-				__FUNCTION__);
-		tmp = NULL;
-	}
-
-	return tmp;
-}
-
-struct vm_struct * im_get_free_area(unsigned long size)
-{
-	struct vm_struct *area;
-	unsigned long addr;
-	
-	mutex_lock(&imlist_mutex);
-	if (get_free_im_addr(size, &addr)) {
-		printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n",
-				__FUNCTION__, size);
-		area = NULL;
-		goto next_im_done;
-	}
-
-	area = __im_get_area(addr, size, IM_REGION_UNUSED);
-	if (area == NULL) {
-		printk(KERN_ERR 
-		       "%s() cannot obtain area for addr 0x%lx size 0x%lx\n",
-			__FUNCTION__, addr, size);
-	}
-next_im_done:
-	mutex_unlock(&imlist_mutex);
-	return area;
-}
-
-struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
-		int criteria)
-{
-	struct vm_struct *area;
-
-	mutex_lock(&imlist_mutex);
-	area = __im_get_area(v_addr, size, criteria);
-	mutex_unlock(&imlist_mutex);
-	return area;
-}
-
-void im_free(void * addr)
-{
-	struct vm_struct **p, *tmp;
-  
-	if (!addr)
-		return;
-	if ((unsigned long) addr & ~PAGE_MASK) {
-		printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__,			addr);
-		return;
-	}
-	mutex_lock(&imlist_mutex);
-	for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
-		if (tmp->addr == addr) {
-			*p = tmp->next;
-			unmap_vm_area(tmp);
-			kfree(tmp);
-			mutex_unlock(&imlist_mutex);
-			return;
-		}
-	}
-	mutex_unlock(&imlist_mutex);
-	printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
-			addr);
-}
Index: linux-cell/arch/powerpc/mm/mmu_decl.h
===================================================================
--- linux-cell.orig/arch/powerpc/mm/mmu_decl.h	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/mm/mmu_decl.h	2007-05-15 16:42:37.000000000 +1000
@@ -90,16 +90,4 @@ static inline void flush_HPTE(unsigned c
 	else
 		_tlbie(va);
 }
-#else /* CONFIG_PPC64 */
-/* imalloc region types */
-#define IM_REGION_UNUSED	0x1
-#define IM_REGION_SUBSET	0x2
-#define IM_REGION_EXISTS	0x4
-#define IM_REGION_OVERLAP	0x8
-#define IM_REGION_SUPERSET	0x10
-
-extern struct vm_struct * im_get_free_area(unsigned long size);
-extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
-				      int region_type);
-extern void im_free(void *addr);
 #endif
Index: linux-cell/arch/powerpc/mm/pgtable_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/pgtable_64.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/mm/pgtable_64.c	2007-05-15 16:42:37.000000000 +1000
@@ -34,41 +34,27 @@
 #include <linux/stddef.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/rtas.h>
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
-#include <asm/uaccess.h>
 #include <asm/smp.h>
 #include <asm/machdep.h>
 #include <asm/tlb.h>
-#include <asm/eeh.h>
 #include <asm/processor.h>
-#include <asm/mmzone.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
 #include <asm/system.h>
-#include <asm/iommu.h>
 #include <asm/abs_addr.h>
-#include <asm/vdso.h>
 #include <asm/firmware.h>
 
 #include "mmu_decl.h"
 
-unsigned long ioremap_bot = IMALLOC_BASE;
-static unsigned long phbs_io_bot = PHBS_IO_BASE;
+unsigned long ioremap_bot = IOREMAP_BASE;
 
 /*
  * map_io_page currently only called by __ioremap
@@ -102,8 +88,8 @@ static int map_io_page(unsigned long ea,
 		 * entry in the hardware page table.
 		 *
 		 */
-		if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags,
-				      mmu_io_psize)) {
+		if (htab_bolt_mapping(ea, (unsigned long)ea + PAGE_SIZE,
+				      pa, flags, mmu_io_psize)) {
 			printk(KERN_ERR "Failed to do bolted mapping IO "
 			       "memory at %016lx !\n", pa);
 			return -ENOMEM;
@@ -113,8 +99,11 @@ static int map_io_page(unsigned long ea,
 }
 
 
-static void __iomem * __ioremap_com(phys_addr_t addr, unsigned long pa,
-			    unsigned long ea, unsigned long size,
+/**
+ * __ioremap_at - Low level function to establish the page tables
+ *                for an IO mapping
+ */
+void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size,
 			    unsigned long flags)
 {
 	unsigned long i;
@@ -122,17 +111,40 @@ static void __iomem * __ioremap_com(phys
 	if ((flags & _PAGE_PRESENT) == 0)
 		flags |= pgprot_val(PAGE_KERNEL);
 
+	WARN_ON(pa & ~PAGE_MASK);
+	WARN_ON(size & ~PAGE_MASK);
+
 	for (i = 0; i < size; i += PAGE_SIZE)
-		if (map_io_page(ea+i, pa+i, flags))
+		if (map_io_page((unsigned long)ea+i, pa+i, flags))
 			return NULL;
 
-	return (void __iomem *) (ea + (addr & ~PAGE_MASK));
+	return (void __iomem *)ea;
+}
+
+/**
+ * __iounmap_from - Low level function to tear down the page tables
+ *                  for an IO mapping. This is used for mappings that
+ *                  are manipulated manually, like partial unmapping of
+ *                  PCI IOs or ISA space.
+ */
+void __iounmap_at(void *ea, unsigned long size)
+{
+	struct vm_struct fake_area;
+
+	/* Hack alert ! We use a fake vm_struct here in order to be able
+	 * to use unmap_vm_area(). This is a bit ugly but avoids a lot of
+	 * code duplication
+	 */
+	memset(&fake_area, 0, sizeof(struct vm_struct));
+	fake_area.addr = (void *)ea;
+	fake_area.size = size;
+	unmap_vm_area(&fake_area);
 }
 
 void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
 			 unsigned long flags)
 {
-	unsigned long pa, ea;
+	phys_addr_t paligned;
 	void __iomem *ret;
 
 	/*
@@ -144,27 +156,30 @@ void __iomem * __ioremap(phys_addr_t add
 	 * IMALLOC_END
 	 * 
 	 */
-	pa = addr & PAGE_MASK;
-	size = PAGE_ALIGN(addr + size) - pa;
+	paligned = addr & PAGE_MASK;
+	size = PAGE_ALIGN(addr + size) - paligned;
 
-	if ((size == 0) || (pa == 0))
+	if ((size == 0) || (paligned == 0))
 		return NULL;
 
 	if (mem_init_done) {
 		struct vm_struct *area;
-		area = im_get_free_area(size);
+
+		area = __get_vm_area(size, VM_IOREMAP,
+				     ioremap_bot, IOREMAP_END);
 		if (area == NULL)
 			return NULL;
-		ea = (unsigned long)(area->addr);
-		ret = __ioremap_com(addr, pa, ea, size, flags);
+		ret = __ioremap_at(paligned, area->addr, size, flags);
 		if (!ret)
-			im_free(area->addr);
+			vunmap(area->addr);
 	} else {
-		ea = ioremap_bot;
-		ret = __ioremap_com(addr, pa, ea, size, flags);
+		ret = __ioremap_at(paligned, (void *)ioremap_bot, size, flags);
 		if (ret)
 			ioremap_bot += size;
 	}
+
+	if (ret)
+		ret += addr & ~PAGE_MASK;
 	return ret;
 }
 
@@ -187,62 +202,9 @@ void __iomem * ioremap_flags(phys_addr_t
 }
 
 
-#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
-
-int __ioremap_explicit(phys_addr_t pa, unsigned long ea,
-		       unsigned long size, unsigned long flags)
-{
-	struct vm_struct *area;
-	void __iomem *ret;
-	
-	/* For now, require page-aligned values for pa, ea, and size */
-	if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) ||
-	    !IS_PAGE_ALIGNED(size)) {
-		printk(KERN_ERR	"unaligned value in %s\n", __FUNCTION__);
-		return 1;
-	}
-	
-	if (!mem_init_done) {
-		/* Two things to consider in this case:
-		 * 1) No records will be kept (imalloc, etc) that the region
-		 *    has been remapped
-		 * 2) It won't be easy to iounmap() the region later (because
-		 *    of 1)
-		 */
-		;
-	} else {
-		area = im_get_area(ea, size,
-			IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS);
-		if (area == NULL) {
-			/* Expected when PHB-dlpar is in play */
-			return 1;
-		}
-		if (ea != (unsigned long) area->addr) {
-			printk(KERN_ERR "unexpected addr return from "
-			       "im_get_area\n");
-			return 1;
-		}
-	}
-	
-	ret = __ioremap_com(pa, pa, ea, size, flags);
-	if (ret == NULL) {
-		printk(KERN_ERR "ioremap_explicit() allocation failure !\n");
-		return 1;
-	}
-	if (ret != (void *) ea) {
-		printk(KERN_ERR "__ioremap_com() returned unexpected addr\n");
-		return 1;
-	}
-
-	return 0;
-}
-
 /*  
  * Unmap an IO region and remove it from imalloc'd list.
  * Access to IO memory should be serialized by driver.
- * This code is modeled after vmalloc code - unmap_vm_area()
- *
- * XXX	what about calls before mem_init_done (ie python_countermeasures())
  */
 void __iounmap(volatile void __iomem *token)
 {
@@ -251,9 +213,9 @@ void __iounmap(volatile void __iomem *to
 	if (!mem_init_done)
 		return;
 	
-	addr = (void *) ((unsigned long __force) token & PAGE_MASK);
-
-	im_free(addr);
+	addr = (void *) ((unsigned long __force)
+			 PCI_FIX_ADDR(token) & PAGE_MASK);
+	vunmap(addr);
 }
 
 void iounmap(volatile void __iomem *token)
@@ -264,77 +226,8 @@ void iounmap(volatile void __iomem *toke
 		__iounmap(token);
 }
 
-static int iounmap_subset_regions(unsigned long addr, unsigned long size)
-{
-	struct vm_struct *area;
-
-	/* Check whether subsets of this region exist */
-	area = im_get_area(addr, size, IM_REGION_SUPERSET);
-	if (area == NULL)
-		return 1;
-
-	while (area) {
-		iounmap((void __iomem *) area->addr);
-		area = im_get_area(addr, size,
-				IM_REGION_SUPERSET);
-	}
-
-	return 0;
-}
-
-int __iounmap_explicit(volatile void __iomem *start, unsigned long size)
-{
-	struct vm_struct *area;
-	unsigned long addr;
-	int rc;
-	
-	addr = (unsigned long __force) start & PAGE_MASK;
-
-	/* Verify that the region either exists or is a subset of an existing
-	 * region.  In the latter case, split the parent region to create 
-	 * the exact region 
-	 */
-	area = im_get_area(addr, size, 
-			    IM_REGION_EXISTS | IM_REGION_SUBSET);
-	if (area == NULL) {
-		/* Determine whether subset regions exist.  If so, unmap */
-		rc = iounmap_subset_regions(addr, size);
-		if (rc) {
-			printk(KERN_ERR
-			       "%s() cannot unmap nonexistent range 0x%lx\n",
- 				__FUNCTION__, addr);
-			return 1;
-		}
-	} else {
-		iounmap((void __iomem *) area->addr);
-	}
-	/*
-	 * FIXME! This can't be right:
-	iounmap(area->addr);
-	 * Maybe it should be "iounmap(area);"
-	 */
-	return 0;
-}
-
 EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(ioremap_flags);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(__iounmap);
-
-static DEFINE_SPINLOCK(phb_io_lock);
-
-void __iomem * reserve_phb_iospace(unsigned long size)
-{
-	void __iomem *virt_addr;
-		
-	if (phbs_io_bot >= IMALLOC_BASE) 
-		panic("reserve_phb_iospace(): phb io space overflow\n");
-			
-	spin_lock(&phb_io_lock);
-	virt_addr = (void __iomem *) phbs_io_bot;
-	phbs_io_bot += size;
-	spin_unlock(&phb_io_lock);
-
-	return virt_addr;
-}
Index: linux-cell/arch/powerpc/platforms/maple/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/maple/pci.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/maple/pci.c	2007-05-15 16:42:37.000000000 +1000
@@ -519,23 +519,6 @@ void __devinit maple_pci_irq_fixup(struc
 	DBG(" <- maple_pci_irq_fixup\n");
 }
 
-static void __init maple_fixup_phb_resources(void)
-{
-	struct pci_controller *hose, *tmp;
-	
-	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-		unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
-		hose->io_resource.start += offset;
-		hose->io_resource.end += offset;
-
-		printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
-		       hose->global_number,
-		       (unsigned long long)hose->io_resource.start,
-		       (unsigned long long)hose->io_resource.end);
-	}
-}
-
 void __init maple_pci_init(void)
 {
 	struct device_node *np, *root;
@@ -573,24 +556,6 @@ void __init maple_pci_init(void)
 	if (ht && add_bridge(ht) != 0)
 		of_node_put(ht);
 
-        /*
-         * We need to call pci_setup_phb_io for the HT bridge first
-         * so it gets the I/O port numbers starting at 0, and we
-         * need to call it for the AGP bridge after that so it gets
-         * small positive I/O port numbers.
-         */
-        if (u3_ht)
-                pci_setup_phb_io(u3_ht, 1);
-        if (u3_agp)
-                pci_setup_phb_io(u3_agp, 0);
-        if (u4_pcie)
-                pci_setup_phb_io(u4_pcie, 0);
-
-	/* Fixup the IO resources on our host bridges as the common code
-	 * does it only for childs of the host bridges
-	 */
-	maple_fixup_phb_resources();
-
 	/* Setup the linkage between OF nodes and PHBs */ 
 	pci_devs_phb_init();
 
Index: linux-cell/arch/powerpc/platforms/pasemi/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pasemi/pci.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pasemi/pci.c	2007-05-15 16:42:37.000000000 +1000
@@ -150,29 +150,11 @@ static int __init add_bridge(struct devi
 	printk(KERN_INFO "Found PA-PXP PCI host bridge.\n");
 
 	/* Interpret the "ranges" property */
-	/* This also maps the I/O region and sets isa_io/mem_base */
 	pci_process_bridge_OF_ranges(hose, dev, 1);
-	pci_setup_phb_io(hose, 1);
 
 	return 0;
 }
 
-
-static void __init pas_fixup_phb_resources(void)
-{
-	struct pci_controller *hose, *tmp;
-
-	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-		unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
-		hose->io_resource.start += offset;
-		hose->io_resource.end += offset;
-		printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
-		       hose->global_number,
-		       hose->io_resource.start, hose->io_resource.end);
-	}
-}
-
-
 void __init pas_pci_init(void)
 {
 	struct device_node *np, *root;
@@ -190,8 +172,6 @@ void __init pas_pci_init(void)
 
 	of_node_put(root);
 
-	pas_fixup_phb_resources();
-
 	/* Setup the linkage between OF nodes and PHBs */
 	pci_devs_phb_init();
 
Index: linux-cell/arch/powerpc/platforms/powermac/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/powermac/pci.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/powermac/pci.c	2007-05-15 16:42:37.000000000 +1000
@@ -1006,19 +1006,6 @@ void __devinit pmac_pci_irq_fixup(struct
 #endif /* CONFIG_PPC32 */
 }
 
-#ifdef CONFIG_PPC64
-static void __init pmac_fixup_phb_resources(void)
-{
-	struct pci_controller *hose, *tmp;
-
-	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-		printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
-		       hose->global_number,
-		       hose->io_resource.start, hose->io_resource.end);
-	}
-}
-#endif
-
 void __init pmac_pci_init(void)
 {
 	struct device_node *np, *root;
@@ -1053,25 +1040,6 @@ void __init pmac_pci_init(void)
 	if (ht && add_bridge(ht) != 0)
 		of_node_put(ht);
 
-	/*
-	 * We need to call pci_setup_phb_io for the HT bridge first
-	 * so it gets the I/O port numbers starting at 0, and we
-	 * need to call it for the AGP bridge after that so it gets
-	 * small positive I/O port numbers.
-	 */
-	if (u3_ht)
-		pci_setup_phb_io(u3_ht, 1);
-	if (u3_agp)
-		pci_setup_phb_io(u3_agp, 0);
-	if (u4_pcie)
-		pci_setup_phb_io(u4_pcie, 0);
-
-	/*
-	 * On ppc64, fixup the IO resources on our host bridges as
-	 * the common code does it only for children of the host bridges
-	 */
-	pmac_fixup_phb_resources();
-
 	/* Setup the linkage between OF nodes and PHBs */
 	pci_devs_phb_init();
 
Index: linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pci_dlpar.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/pci_dlpar.c	2007-05-15 16:42:37.000000000 +1000
@@ -200,8 +200,6 @@ struct pci_controller * __devinit init_p
 	rtas_setup_phb(phb);
 	pci_process_bridge_OF_ranges(phb, dn, 0);
 
-	pci_setup_phb_io_dynamic(phb, primary);
-
 	pci_devs_phb_init_dynamic(phb);
 
 	if (dn->child)
Index: linux-cell/drivers/pci/hotplug/rpadlpar_core.c
===================================================================
--- linux-cell.orig/drivers/pci/hotplug/rpadlpar_core.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/drivers/pci/hotplug/rpadlpar_core.c	2007-05-15 16:42:37.000000000 +1000
@@ -159,8 +159,8 @@ static void dlpar_pci_add_bus(struct dev
 	/* Claim new bus resources */
 	pcibios_claim_one_bus(dev->bus);
 
-	/* ioremap() for child bus, which may or may not succeed */
-	remap_bus_range(dev->subordinate);
+	/* Map IO space for child bus, which may or may not succeed */
+	pcibios_map_io_space(dev->subordinate);
 
 	/* Add new devices to global lists.  Register in proc, sysfs. */
 	pci_bus_add_devices(phb->bus);
@@ -390,7 +390,7 @@ int dlpar_remove_pci_slot(char *drc_name
 	} else
 		pcibios_remove_pci_devices(bus);
 
-	if (unmap_bus_range(bus)) {
+	if (pcibios_unmap_io_space(bus)) {
 		printk(KERN_ERR "%s: failed to unmap bus range\n",
 			__FUNCTION__);
 		return -ERANGE;
Index: linux-cell/include/asm-powerpc/pci-bridge.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci-bridge.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci-bridge.h	2007-05-15 16:42:37.000000000 +1000
@@ -31,6 +31,7 @@ struct pci_controller {
 	int last_busno;
 
 	void __iomem *io_base_virt;
+	void *io_base_alloc;
 	resource_size_t io_base_phys;
 
 	/* Some machines have a non 1:1 mapping of
@@ -164,6 +165,11 @@ static inline unsigned long pci_address_
 }
 #endif
 
+extern void isa_bridge_find_early(struct pci_controller *hose);
+
+extern int pcibios_unmap_io_space(struct pci_bus *bus);
+extern int pcibios_map_io_space(struct pci_bus *bus);
+
 /* Return values for ppc_md.pci_probe_mode function */
 #define PCI_PROBE_NONE		-1	/* Don't look at this bus at all */
 #define PCI_PROBE_NORMAL	0	/* Do normal PCI probing */
Index: linux-cell/include/asm-powerpc/pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pci.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/pci.h	2007-05-15 16:42:37.000000000 +1000
@@ -220,10 +220,6 @@ static inline struct resource *pcibios_s
 	return root;
 }
 
-extern int unmap_bus_range(struct pci_bus *bus);
-
-extern int remap_bus_range(struct pci_bus *bus);
-
 extern void pcibios_fixup_device_resources(struct pci_dev *dev,
 			struct pci_bus *bus);
 
Index: linux-cell/include/asm-powerpc/io.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/io.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/io.h	2007-05-15 16:42:37.000000000 +1000
@@ -607,9 +607,9 @@ static inline void iosync(void)
  *
  * * iounmap undoes such a mapping and can be hooked
  *
- * * __ioremap_explicit (and the pending __iounmap_explicit) are low level
- *   functions to create hand-made mappings for use only by the PCI code
- *   and cannot currently be hooked.
+ * * __ioremap_at (and the pending __iounmap_at) are low level functions to
+ *   create hand-made mappings for use only by the PCI code and cannot
+ *   currently be hooked. Must be page aligned.
  *
  * * __ioremap is the low level implementation used by ioremap and
  *   ioremap_flags and cannot be hooked (but can be used by a hook on one
@@ -629,12 +629,9 @@ extern void __iomem *__ioremap(phys_addr
 			       unsigned long flags);
 extern void __iounmap(volatile void __iomem *addr);
 
-extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr,
-		     	      unsigned long size, unsigned long flags);
-extern int __iounmap_explicit(volatile void __iomem *start,
-			      unsigned long size);
-
-extern void __iomem * reserve_phb_iospace(unsigned long size);
+extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea,
+				   unsigned long size, unsigned long flags);
+extern void __iounmap_at(void *ea, unsigned long size);
 
 /* Those are more 32 bits only functions */
 extern unsigned long iopa(unsigned long addr);
@@ -651,8 +648,8 @@ extern void io_block_mapping(unsigned lo
  */
 #define HAVE_ARCH_PIO_SIZE		1
 #define PIO_OFFSET			0x00000000UL
-#define PIO_MASK			0x3fffffffUL
-#define PIO_RESERVED			0x40000000UL
+#define PIO_MASK			(FULL_IO_SIZE - 1)
+#define PIO_RESERVED			(FULL_IO_SIZE)
 
 #define mmio_read16be(addr)		readw_be(addr)
 #define mmio_read32be(addr)		readl_be(addr)
Index: linux-cell/arch/powerpc/mm/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/mm/Makefile	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/mm/Makefile	2007-05-15 16:42:37.000000000 +1000
@@ -11,8 +11,7 @@ obj-$(CONFIG_PPC32)		+= init_32.o pgtabl
 hash-$(CONFIG_PPC_NATIVE)	:= hash_native_64.o
 obj-$(CONFIG_PPC64)		+= init_64.o pgtable_64.o mmu_context_64.o \
 				   hash_utils_64.o hash_low_64.o tlb_64.o \
-				   slb_low.o slb.o stab.o mmap.o imalloc.o \
-				   $(hash-y)
+				   slb_low.o slb.o stab.o mmap.o $(hash-y)
 obj-$(CONFIG_PPC_STD_MMU_32)	+= ppc_mmu_32.o hash_low_32.o tlb_32.o
 obj-$(CONFIG_40x)		+= 4xx_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
Index: linux-cell/arch/powerpc/platforms/cell/io-workarounds.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/io-workarounds.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/io-workarounds.c	2007-05-15 16:42:37.000000000 +1000
@@ -102,7 +102,7 @@ static void spider_io_flush(const volati
 		vaddr = (unsigned long)PCI_FIX_ADDR(addr);
 
 		/* Check if it's in allowed range for  PIO */
-		if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE)
+		if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END)
 			return;
 
 		/* Try to find a PTE. If not, clear the paddr, we'll do
Index: linux-cell/include/asm-powerpc/floppy.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/floppy.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/floppy.h	2007-05-15 16:42:37.000000000 +1000
@@ -29,7 +29,7 @@
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
 #include <linux/pci.h>
-#include <asm/ppc-pci.h>	/* for ppc64_isabridge_dev */
+#include <asm/ppc-pci.h>	/* for isa_bridge_pcidev */
 
 #define fd_dma_setup(addr,size,mode,io) fd_ops->_dma_setup(addr,size,mode,io)
 
@@ -139,12 +139,12 @@ static int hard_dma_setup(char *addr, un
 	if (bus_addr 
 	    && (addr != prev_addr || size != prev_size || dir != prev_dir)) {
 		/* different from last time -- unmap prev */
-		pci_unmap_single(ppc64_isabridge_dev, bus_addr, prev_size, prev_dir);
+		pci_unmap_single(isa_bridge_pcidev, bus_addr, prev_size, prev_dir);
 		bus_addr = 0;
 	}
 
 	if (!bus_addr)	/* need to map it */
-		bus_addr = pci_map_single(ppc64_isabridge_dev, addr, size, dir);
+		bus_addr = pci_map_single(isa_bridge_pcidev, addr, size, dir);
 
 	/* remember this one as prev */
 	prev_addr = addr;
Index: linux-cell/include/asm-powerpc/ppc-pci.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc-pci.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/ppc-pci.h	2007-05-15 16:42:37.000000000 +1000
@@ -26,7 +26,7 @@ extern int global_phb_number;
 
 extern void find_and_init_phbs(void);
 
-extern struct pci_dev *ppc64_isabridge_dev;	/* may be NULL if no ISA bus */
+extern struct pci_dev *isa_bridge_pcidev;	/* may be NULL if no ISA bus */
 
 /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
 #define BUID_HI(buid) ((buid) >> 32)
@@ -47,8 +47,8 @@ extern void init_pci_config_tokens (void
 extern unsigned long get_phb_buid (struct device_node *);
 extern int rtas_setup_phb(struct pci_controller *phb);
 
-/* From pSeries_pci.h */
-extern void pSeries_final_fixup(void);
+/* From iSeries PCI */
+extern void iSeries_pcibios_init(void);
 
 extern unsigned long pci_probe_only;
 
Index: linux-cell/arch/powerpc/mm/tlb_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/tlb_64.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/mm/tlb_64.c	2007-05-15 17:02:25.000000000 +1000
@@ -239,3 +239,59 @@ void pte_free_finish(void)
 	pte_free_submit(*batchp);
 	*batchp = NULL;
 }
+
+/**
+ * __flush_hash_table_range - Flush all HPTEs for a given address range
+ *                            from the hash table (and the TLB). But keeps
+ *                            the linux PTEs intact.
+ *
+ * @mm		: mm_struct of the target address space (generally init_mm)
+ * @start	: starting address
+ * @end         : ending address (not included in the flush)
+ *
+ * This function is mostly to be used by some IO hotplug code in order
+ * to remove all hash entries from a given address range used to map IO
+ * space on a removed PCI-PCI bidge without tearing down the full mapping
+ * since 64K pages may overlap with other bridges when using 64K pages
+ * with 4K HW pages on IO space.
+ *
+ * Because of that usage pattern, it's only available with CONFIG_HOTPLUG
+ * and is implemented for small size rather than speed.
+ */
+#ifdef CONFIG_HOTPLUG
+
+void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
+			      unsigned long end)
+{
+	unsigned long flags;
+
+	start = _ALIGN_DOWN(start, PAGE_SIZE);
+	end = _ALIGN_UP(end, PAGE_SIZE);
+
+	BUG_ON(!mm->pgd);
+
+	/* Note: Normally, we should only ever use a batch within a
+	 * PTE locked section. This violates the rule, but will work
+	 * since we don't actually modify the PTEs, we just flush the
+	 * hash while leaving the PTEs intact (including their reference
+	 * to being hashed). This is not the most performance oriented
+	 * way to do things but is fine for our needs here.
+	 */
+	local_irq_save(flags);
+	arch_enter_lazy_mmu_mode();
+	for(;start < end; start += PAGE_SIZE) {
+		pte_t *ptep = find_linux_pte(mm->pgd, start);
+		unsigned long pte;
+
+		if (ptep == NULL)
+			continue;
+		pte = pte_val(*ptep);
+		if (!(pte & _PAGE_HASHPTE))
+			continue;
+		hpte_need_flush(mm, start, ptep, pte, 0);
+	}
+	arch_leave_lazy_mmu_mode();
+	local_irq_restore(flags);
+}
+
+#endif /* CONFIG_HOTPLUG */
Index: linux-cell/include/asm-powerpc/tlbflush.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/tlbflush.h	2007-05-15 16:42:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/tlbflush.h	2007-05-15 16:42:37.000000000 +1000
@@ -155,6 +155,11 @@ static inline void flush_tlb_kernel_rang
 {
 }
 
+/* Private function for use by PCI IO mapping code */
+extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
+				     unsigned long end);
+
+
 #endif
 
 /*
Index: linux-cell/arch/powerpc/platforms/iseries/pci.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/pci.c	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/iseries/pci.c	2007-05-15 16:42:37.000000000 +1000
@@ -742,6 +742,11 @@ void __init iSeries_pcibios_init(void)
 	/* Install IO hooks */
 	ppc_pci_io = iseries_pci_io;
 
+	/* iSeries has no IO space in the common sense, it needs to set
+	 * the IO base to 0
+	 */
+	pci_io_base = 0;
+
 	if (root == NULL) {
 		printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
 				"of device tree\n");
Index: linux-cell/arch/powerpc/platforms/pseries/pseries.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/pseries.h	2007-05-15 16:42:25.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/pseries.h	2007-05-15 16:42:37.000000000 +1000
@@ -33,6 +33,8 @@ static inline void setup_kexec_cpu_down_
 static inline void setup_kexec_cpu_down_mpic(void) { }
 #endif
 
+extern void pSeries_final_fixup(void);
+
 /* Poweron flag used for enabling auto ups restart */
 extern unsigned long rtas_poweron_auto;
 

^ permalink raw reply

* Re: Small fixes for the Ebony device tree
From: David Gibson @ 2007-05-15  6:58 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev, Stefan Roese, Paul Mackerras
In-Reply-To: <5c785f662c13fdd938d48e40d3107050@kernel.crashing.org>

On Tue, May 15, 2007 at 08:47:00AM +0200, Segher Boessenkool wrote:
> >>> finally "ibm,sdram-4xx".
> >>
> >> Is that last entry ever useful?  Do all those controllers
> >> have something in common?
> >
> > A quick glance over the descriptions in the 440GP and 405GP user
> > manuals suggests that they have most of the registers in common,
> > though I haven't checked to see if the semantics of those registers
> > are actually all the same.
> 
> Let me rephrase: can a kernel driver ever do anything
> useful with the device if it _only_ knows it is some
> 4xx memory controller?
> 
> If that isn't the case, but for example, the 440GP's
> controller can be driven by the 405GP driver, you
> can express exactly that in the "compatible" property.
> It is a bad plan in general to say "4xx", it suggests
> compatibility both ways, which almost never is true;
> so what _does_ it mean?  Lowest common denominator?
> Say exactly that, then.  "compatible" is meant for
> drivers to figure if they can drive the device (or,
> equivalently, for the kernel to figure out which driver
> can drive a given device).

Ok, I see what you mean.

Sod it, I think I'll just drop everything except "ibm,sdram-440gp" for
now.  The one place we access the SDRAM controller, it's under
platform control anyway we do it via direct DCR access anyway, so the
compatible property is pretty much irrelevant.

If a clearer pattern emerges later, we can add more compatible
strings.  If some later driver has to have an extra backwards
compatibility id_table entry for the Ebony/440GP it's no great
disaster.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: vm changes from linux-2.6.14 to linux-2.6.15
From: Benjamin Herrenschmidt @ 2007-05-15  6:56 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: mark, linuxppc-dev, wli, linux-mm, andrea, sparclinux, akpm,
	David Miller
In-Reply-To: <1179176845.32247.107.camel@localhost.localdomain>


> Ok, I'll cook a patch today.

Let's make it tomorrow :-( Got delayed by other urgent things

Cheers,
Ben.

^ permalink raw reply

* Re: Small fixes for the Ebony device tree
From: Segher Boessenkool @ 2007-05-15  6:47 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev, Stefan Roese, Paul Mackerras
In-Reply-To: <20070515063408.GE6998@localhost.localdomain>

>>> finally "ibm,sdram-4xx".
>>
>> Is that last entry ever useful?  Do all those controllers
>> have something in common?
>
> A quick glance over the descriptions in the 440GP and 405GP user
> manuals suggests that they have most of the registers in common,
> though I haven't checked to see if the semantics of those registers
> are actually all the same.

Let me rephrase: can a kernel driver ever do anything
useful with the device if it _only_ knows it is some
4xx memory controller?

If that isn't the case, but for example, the 440GP's
controller can be driven by the 405GP driver, you
can express exactly that in the "compatible" property.
It is a bad plan in general to say "4xx", it suggests
compatibility both ways, which almost never is true;
so what _does_ it mean?  Lowest common denominator?
Say exactly that, then.  "compatible" is meant for
drivers to figure if they can drive the device (or,
equivalently, for the kernel to figure out which driver
can drive a given device).


Segher

^ permalink raw reply

* Re: Small fixes for the Ebony device tree
From: Stefan Roese @ 2007-05-15  6:46 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20070515061855.GD6998@localhost.localdomain>

On Tuesday 15 May 2007, David Gibson wrote:
> Anyone have any objection to the following:  each of these controllers
> should have compatible properties listing 3 string, first, a specific
> version for the CPU in question (e.g "ibm,sdram-440gp"), then a string
> based on the type as listed below, finally "ibm,sdram-4xx".
>
> > SDRAM:		all 40x (except for 405EZ)
>
> 	ibm,sdram-40x
>
> > DDR:		440GP, 440GX, 440EP, 440GR
>
> 	ibm,sdram-44x-ddr
>
> > DDR2:		440SP, 440SPe
>
> 	ibm,sdram-44x-ddr2
>
> > DDR2 (Denali):	440EPx, 440GRx
>
> 	ibm,sdram-44x-ddr2denali

Why "ibm,xxx"? Is this for the CPU core? Or for the SDRAM controller core? 
Both are not IBM in this case.

> Seem reasonable?

I forgot the new 405EX which will be equipped with a DDR2 controller (not sure 
right now if it's the Denali or the other core right now). So we should 
probably drop this 40x/44x completely. Does this make sense?

Best regards,
Stefan

^ permalink raw reply

* Re: [PATCH] powerpc: Fix IO space on PCI busses created from of_platform
From: Michael Neuling @ 2007-05-15  6:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Olof Johansson, linuxppc-dev, Paul Mackerras, Arnd Bergmann
In-Reply-To: <20070515062007.5A4B8DDEC4@ozlabs.org>

> -	/* Setup IO space.
> -	 * This will not work properly for ISA IOs, something needs to be done
> -	 * about it if we ever generalize that way of probing PCI brigdes
> +	/* Setup IO space. We use the non-dynamic version of that code here,
> +	 * which doesn't quite support unplugging. Next kernel release will
> +	 * have a better fix for this.
> +	 * Note also that we don't do ISA, this will also be fixed with a
> +	 * more massive rework.
>  	 */

Do you want to put some absolute kernel version numbers here (rather
than "next kernel release") so that someone reading this won't have to
look through the changelog to work out if this is an old bogus comment,
or something that is actively being hacked on?

Mikey

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox