LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] powerpc: add cascade support to xilinx intc controller
From: Benjamin Herrenschmidt @ 2009-08-27  4:15 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, john.linn
In-Reply-To: <20090825060848.3913.60710.stgit@localhost.localdomain>

On Tue, 2009-08-25 at 00:08 -0600, Grant Likely wrote:
> From: Grant Likely <grant.likely@secretlab.ca>
> 
> This patch allows the Xilinx intc interrupt controller to be cascaded
> instead of being the master irqhost.  Useful when attaching an FPGA
> to an SoC that has its own interrupt controller.

Something doesn't look quite right ...

>  /*
> + * Cascaded Xilinx interrupt controller
> + */
> +static void xilinx_intc_cascade(unsigned int virq, struct irq_desc *desc)
> +{
> +	struct irq_host *cascade_irqhost = get_irq_data(virq);
> +	void *regs = cascade_irqhost->host_data;
> +	unsigned int cascade_virq;
> +
> +	pr_debug("%s(virq=%i) irq_host=%p\n", __func__, virq, cascade_irqhost);
> +	cascade_virq = irq_linear_revmap(cascade_irqhost,
> +					 in_be32(regs + XINTC_IVR));
> +	if (cascade_virq)
> +		generic_handle_irq(cascade_virq);
> +}

The cascade handler generally has to be part of the -host- controller or
the platform code (we should try maybe to invent a way to make that
more transparent but today it's not) because it may need to do special
things to ack the interrupt on the host controller.

For example, if I have an MPIC based setup with a cascaded xilinx FPGA,
I want to use something that does the EOI right on the MPIC. In fact,
it's -almost- like what we need to do for a cascade, is to find a way to
stick a get_irq() function pointer somewhere in the irq-desc for the
cascaded interrupt, and have in the -host- a generic cascade handler.

Also, you seem to be trying to do the revmap of the child interrupt
using the parent host.. .that doesn't make sense. Each PIC has it's own
revmap and the child PIC uses it's own revmap as well.

The rest of the code seems to entertain a similar confusion...

Cheers,
Ben.

> +/**
> + * xilinx_intc_cascade_setup - Add a xilinx intc device as a cascaded controller
> + * @cascade_node: device node for xilinx intc controller.
> + */
> +int xilinx_intc_cascade_setup(struct device_node *cascade_node)
> +{
> +	struct irq_host *cascade_irqhost;
> +	int cascade_virq;
> +
> +	if (!cascade_node) {
> +		pr_err("%s(): cannot find xilinx intc node\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	/* Make sure this is a xilinx intc device */
> +	if (!of_match_node(xilinx_intc_match, cascade_node)) {
> +		pr_err("%s(): %s is not compatible\n",
> +			__func__, cascade_node->name);
> +		return -EINVAL;
> +	}
> +
> +	/* Map a VIRQ for the cascaded handler */
> +	cascade_virq = irq_of_parse_and_map(cascade_node, 0);
> +	if (!cascade_virq) {
> +		pr_err("%s(): error mapping cascade interrupt\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	/* Set up the irqhost and register it */
> +	cascade_irqhost = xilinx_intc_init(cascade_node);
> +	set_irq_data(cascade_virq, cascade_irqhost);
> +	set_irq_chained_handler(cascade_virq, xilinx_intc_cascade);
> +
> +	pr_debug("%s(): cascading virq %i to irq_host %p\n",
> +		 __func__, cascade_virq, cascade_irqhost);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(xilinx_intc_cascade_setup);
> +
> +/*
>   * Initialize master Xilinx interrupt controller
>   */
>  void __init xilinx_intc_init_tree(void)

^ permalink raw reply

* Re: [PATCH] powerpc: Adjust base and index registers in Altivec macros
From: Michael Neuling @ 2009-08-27  4:36 UTC (permalink / raw)
  To: mjw; +Cc: linuxppc-dev
In-Reply-To: <1250810505.14522.3.camel@mx3>

> On POWER6 systems RA needs to be the base and RB the index.  
> If they are reversed you take a misdirect hit.  
> 
> Signed-off-by: Mike Wolf <mjwolf@us.ibm.com>

Looks good.... thanks Mike!

Acked-by: Michael Neuling <mikey@neuling.org>


> 
> ----
> --- altivec.orig/arch/powerpc/include/asm/ppc_asm.h	2009-08-17 15:39:52.000
000000 -0500
> +++ altivec/arch/powerpc/include/asm/ppc_asm.h	2009-08-20 18:08:30.000
000000 -0500
> @@ -98,13 +98,13 @@
>  #define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
>  #define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
>  
> -#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n));  stvx n,b,base
> +#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n));  stvx n,base,b
>  #define SAVE_2VRS(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base)
>  #define SAVE_4VRS(n,b,base)	SAVE_2VRS(n,b,base); SAVE_2VRS(n+2,b,base)
>  #define SAVE_8VRS(n,b,base)	SAVE_4VRS(n,b,base); SAVE_4VRS(n+4,b,base)
>  #define SAVE_16VRS(n,b,base)	SAVE_8VRS(n,b,base); SAVE_8VRS(n+8,b,base)
>  #define SAVE_32VRS(n,b,base)	SAVE_16VRS(n,b,base); SAVE_16VRS(n+16,b,base)
> -#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); lvx n,b,base
> +#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); lvx n,base,b
>  #define REST_2VRS(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base)
>  #define REST_4VRS(n,b,base)	REST_2VRS(n,b,base); REST_2VRS(n+2,b,base)
>  #define REST_8VRS(n,b,base)	REST_4VRS(n,b,base); REST_4VRS(n+4,b,base)
> @@ -112,26 +112,26 @@
>  #define REST_32VRS(n,b,base)	REST_16VRS(n,b,base); REST_16VRS(n+16,b,base)
>  
>  /* Save the lower 32 VSRs in the thread VSR region */
> -#define SAVE_VSR(n,b,base)	li b,THREAD_VSR0+(16*(n));  STXVD2X(n,b,base)
> +#define SAVE_VSR(n,b,base)	li b,THREAD_VSR0+(16*(n));  STXVD2X(n,base,b)
>  #define SAVE_2VSRS(n,b,base)	SAVE_VSR(n,b,base); SAVE_VSR(n+1,b,base)
>  #define SAVE_4VSRS(n,b,base)	SAVE_2VSRS(n,b,base); SAVE_2VSRS(n+2,b,base)
>  #define SAVE_8VSRS(n,b,base)	SAVE_4VSRS(n,b,base); SAVE_4VSRS(n+4,b,base)
>  #define SAVE_16VSRS(n,b,base)	SAVE_8VSRS(n,b,base); SAVE_8VSRS(n+8,b,
base)
>  #define SAVE_32VSRS(n,b,base)	SAVE_16VSRS(n,b,base); SAVE_16VSRS(n+16
,b,base)
> -#define REST_VSR(n,b,base)	li b,THREAD_VSR0+(16*(n)); LXVD2X(n,b,base)
> +#define REST_VSR(n,b,base)	li b,THREAD_VSR0+(16*(n)); LXVD2X(n,base,b)
>  #define REST_2VSRS(n,b,base)	REST_VSR(n,b,base); REST_VSR(n+1,b,base)
>  #define REST_4VSRS(n,b,base)	REST_2VSRS(n,b,base); REST_2VSRS(n+2,b,base)
>  #define REST_8VSRS(n,b,base)	REST_4VSRS(n,b,base); REST_4VSRS(n+4,b,base)
>  #define REST_16VSRS(n,b,base)	REST_8VSRS(n,b,base); REST_8VSRS(n+8,b,
base)
>  #define REST_32VSRS(n,b,base)	REST_16VSRS(n,b,base); REST_16VSRS(n+16
,b,base)
>  /* Save the upper 32 VSRs (32-63) in the thread VSX region (0-31) */
> -#define SAVE_VSRU(n,b,base)	li b,THREAD_VR0+(16*(n));  STXVD2X(n+32,b,base)
> +#define SAVE_VSRU(n,b,base)	li b,THREAD_VR0+(16*(n));  STXVD2X(n+32,base,b)
>  #define SAVE_2VSRSU(n,b,base)	SAVE_VSRU(n,b,base); SAVE_VSRU(n+1,b,ba
se)
>  #define SAVE_4VSRSU(n,b,base)	SAVE_2VSRSU(n,b,base); SAVE_2VSRSU(n+2,
b,base)
>  #define SAVE_8VSRSU(n,b,base)	SAVE_4VSRSU(n,b,base); SAVE_4VSRSU(n+4,
b,base)
>  #define SAVE_16VSRSU(n,b,base)	SAVE_8VSRSU(n,b,base); SAVE_8VSRSU(n+8,
b,base)
>  #define SAVE_32VSRSU(n,b,base)	SAVE_16VSRSU(n,b,base); SAVE_16VSRSU(n+
16,b,base)
> -#define REST_VSRU(n,b,base)	li b,THREAD_VR0+(16*(n)); LXVD2X(n+32,b,base)
> +#define REST_VSRU(n,b,base)	li b,THREAD_VR0+(16*(n)); LXVD2X(n+32,base,b)
>  #define REST_2VSRSU(n,b,base)	REST_VSRU(n,b,base); REST_VSRU(n+1,b,ba
se)
>  #define REST_4VSRSU(n,b,base)	REST_2VSRSU(n,b,base); REST_2VSRSU(n+2,
b,base)
>  #define REST_8VSRSU(n,b,base)	REST_4VSRSU(n,b,base); REST_4VSRSU(n+4,
b,base)
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 

^ permalink raw reply

* Question : about difference with bdnz and bdnz+
From: HongWoo Lee @ 2009-08-27  5:04 UTC (permalink / raw)
  To: linuxppc-dev

Hi ~

I found the code in the linux kernel.

static __inline__ void clear_page(void *addr)
{
    unsigned long lines, line_size;
    line_size = cpu_caches.dline_size;
    lines = cpu_caches.dlines_per_page;

    __asm__ __volatile__(
            "mtctr  %1      # clear_page\n\
            1:  dcbz    0,%0\n\
            add     %0,%0,%3\n\
            bdnz+   1b"
            : "=r" (addr)
            : "r" (lines), "0" (addr), "r" (line_size)
            : "ctr", "memory");
}

And I have a question about bdnz+ instruction.
Through googling, I learned that bdnz does decrement count register and 
branch if it is still nonzero.
But I couldn't find what "bdnz+" is.
Can anybody explain to me what it is ??

Thanks in advance.

HongWoo.

^ permalink raw reply

* Re: Extending virtio_console to support multiple ports
From: Michael Ellerman @ 2009-08-27  5:04 UTC (permalink / raw)
  To: Amit Shah
  Cc: kvm, linuxppc-dev, linux-kernel, miltonm, qemu-devel, borntraeger,
	brueckner, virtualization, alan
In-Reply-To: <20090826154552.GA31910@amit-x200.redhat.com>

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

On Wed, 2009-08-26 at 21:15 +0530, Amit Shah wrote:
> [cc'ing some people who have made some commits in hvc_console.c]
> 
> On (Wed) Aug 26 2009 [16:57:18], Amit Shah wrote:
> > On (Tue) Aug 25 2009 [11:47:20], Amit Shah wrote:
> > > 
> > > Hello all,
> > > 
> > > Here is a new iteration of the patch series that implements a
> > > transport for guest and host communications.
> > > 
> > > The code has been updated to reuse the virtio-console device instead
> > > of creating a new virtio-serial device.
> > 
> > And the problem now is that hvc calls the put_chars function with
> > spinlocks held and we now allocate pages in send_buf(), called from
> > put_chars.
> > 
> > A few solutions:
> 
> [snip]
> 
> > - Convert hvc's usage of spinlocks to mutexes. I've no idea how this
> >   will play out; I'm no expert here. But I did try doing this and so far
> >   it all looks OK. No lockups, lockdep warnings, nothing. I have full
> >   debugging enabled. But this doesn't mean it's right.
> 
> So just to test this further I added the capability to have more than
> one hvc console spawn from virtio_console, created two consoles and did
> a 'cat' of a file in each of the virtio-consoles. It's been running for
> half an hour now without any badness. No spew in debug logs too.
> 
> I also checked the code in hvc_console.c that takes the spin_locks.
> Nothing there that runs from (or needs to run from) interrupt context.
> So the change to mutexes does seem reasonable. Also, the spinlock code
> was added really long back -- git blame shows Linus' first git commit
> introduced them in the git history, so it's pure legacy baggage.

I won't tell Ryan you called his code "pure legacy baggage" if you
don't ;)

http://git.kernel.org/?p=linux/kernel/git/torvalds/old-2.6-bkcvs.git;a=commitdiff;h=d450b4ae023fb4be175389c18f4f87677da03020


cheers

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: [RFC] Clock binding
From: Grant Likely @ 2009-08-27  5:20 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, devicetree-discuss
In-Reply-To: <1251346157.20467.22.camel@pasglop>

On Wed, Aug 26, 2009 at 10:09 PM, Benjamin
Herrenschmidt<benh@kernel.crashing.org> wrote:
> On Tue, 2009-08-18 at 14:21 +1000, Benjamin Herrenschmidt wrote:
>> So here's a followup to my discussion about the clock API.
>
> Really nobody has a comment here ? :-) Not even Mitch ?

Been wanting too.. a little swamped with kids going back to school
tomorrow.  Hopefully I'll be able to dig in before the end of the
week.

g.

^ permalink raw reply

* Re: [PATCH V2 3/3] powerpc/pci: Merge ppc32 and ppc64 versions of phb_scan()
From: Benjamin Herrenschmidt @ 2009-08-27  5:46 UTC (permalink / raw)
  To: Grant Likely; +Cc: sfr, linuxppc-dev
In-Reply-To: <20090826060716.30936.40578.stgit@localhost.localdomain>

On Wed, 2009-08-26 at 00:07 -0600, Grant Likely wrote:
> From: Grant Likely <grant.likely@secretlab.ca>
> 
> The two versions are doing almost exactly the same thing.  No need to
> maintain them as separate files.  This patch also has the side effect
> of making the PCI device tree scanning code available to 32 bit powerpc
> machines, but no board ports actually make use of this feature at this
> point.

You missed various calls to scan_phb() in arch/powerpc :-)

At least pSeries with dynamic LPAR is broken, I think iSeries might
break too. Try a ppc64_defconfig.

I tentatively applied the other patches to -test

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> 
>  arch/powerpc/include/asm/pci.h   |    2 ++
>  arch/powerpc/kernel/pci-common.c |   48 ++++++++++++++++++++++++++++++++++++++
>  arch/powerpc/kernel/pci_32.c     |   25 ++------------------
>  arch/powerpc/kernel/pci_64.c     |   46 +++++-------------------------------
>  4 files changed, 58 insertions(+), 63 deletions(-)
> 
> 
> diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
> index 9ae2e3e..feebfed 100644
> --- a/arch/powerpc/include/asm/pci.h
> +++ b/arch/powerpc/include/asm/pci.h
> @@ -233,6 +233,8 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
>  
>  extern void pcibios_setup_bus_devices(struct pci_bus *bus);
>  extern void pcibios_setup_bus_self(struct pci_bus *bus);
> +extern void pcibios_setup_phb_io_space(struct pci_controller *hose);
> +extern void pcibios_scan_phb(struct pci_controller *hose, void *data);
>  
>  #endif	/* __KERNEL__ */
>  #endif /* __ASM_POWERPC_PCI_H */
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index 44497a8..8a16dbe 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -1617,3 +1617,51 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
>  		 (unsigned long)hose->io_base_virt - _IO_BASE);
>  
>  }
> +
> +/**
> + * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
> + * @hose: Pointer to the PCI host controller instance structure
> + * @data: value to use for sysdata pointer.  ppc32 and ppc64 differ here
> + *
> + * Note: the 'data' pointer is a temporary measure.  As 32 and 64 bit
> + * pci code gets merged, this parameter should become unnecessary because
> + * both will use the same value.
> + */
> +void __devinit pcibios_scan_phb(struct pci_controller *hose, void *data)
> +{
> +	struct pci_bus *bus;
> +	struct device_node *node = hose->dn;
> +	int mode;
> +
> +	pr_debug("PCI: Scanning PHB %s\n",
> +		 node ? node->full_name : "<NO NAME>");
> +
> +	/* Create an empty bus for the toplevel */
> +	bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, data);
> +	if (bus == NULL) {
> +		pr_err("Failed to create bus for PCI domain %04x\n",
> +			hose->global_number);
> +		return;
> +	}
> +	bus->secondary = hose->first_busno;
> +	hose->bus = bus;
> +
> +	/* Get some IO space for the new PHB */
> +	pcibios_setup_phb_io_space(hose);
> +
> +	/* Wire up PHB bus resources */
> +	pcibios_setup_phb_resources(hose);
> +
> +	/* Get probe mode and perform scan */
> +	mode = PCI_PROBE_NORMAL;
> +	if (node && ppc_md.pci_probe_mode)
> +		mode = ppc_md.pci_probe_mode(bus);
> +	pr_debug("    probe mode: %d\n", mode);
> +	if (mode == PCI_PROBE_DEVTREE) {
> +		bus->subordinate = hose->last_busno;
> +		of_scan_bus(node, bus);
> +	}
> +
> +	if (mode == PCI_PROBE_NORMAL)
> +		hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
> +}
> diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
> index 1e807fe..4e415e1 100644
> --- a/arch/powerpc/kernel/pci_32.c
> +++ b/arch/powerpc/kernel/pci_32.c
> @@ -354,36 +354,15 @@ pci_create_OF_bus_map(void)
>  	}
>  }
>  
> -static void __devinit pcibios_scan_phb(struct pci_controller *hose)
> +void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
>  {
> -	struct pci_bus *bus;
> -	struct device_node *node = hose->dn;
>  	unsigned long io_offset;
>  	struct resource *res = &hose->io_resource;
>  
> -	pr_debug("PCI: Scanning PHB %s\n",
> -		 node ? node->full_name : "<NO NAME>");
> -
> -	/* Create an empty bus for the toplevel */
> -	bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
> -	if (bus == NULL) {
> -		printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
> -		       hose->global_number);
> -		return;
> -	}
> -	bus->secondary = hose->first_busno;
> -	hose->bus = bus;
> -
>  	/* Fixup IO space offset */
>  	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
>  	res->start = (res->start + io_offset) & 0xffffffffu;
>  	res->end = (res->end + io_offset) & 0xffffffffu;
> -
> -	/* Wire up PHB bus resources */
> -	pcibios_setup_phb_resources(hose);
> -
> -	/* Scan children */
> -	hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
>  }
>  
>  static int __init pcibios_init(void)
> @@ -401,7 +380,7 @@ static int __init pcibios_init(void)
>  		if (pci_assign_all_buses)
>  			hose->first_busno = next_busno;
>  		hose->last_busno = 0xff;
> -		pcibios_scan_phb(hose);
> +		pcibios_scan_phb(hose, hose);
>  		pci_bus_add_devices(hose->bus);
>  		if (pci_assign_all_buses || next_busno <= hose->last_busno)
>  			next_busno = hose->last_busno + pcibios_assign_bus_offset;
> diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
> index 4d5b4ce..ba949a2 100644
> --- a/arch/powerpc/kernel/pci_64.c
> +++ b/arch/powerpc/kernel/pci_64.c
> @@ -43,45 +43,6 @@ unsigned long pci_probe_only = 1;
>  unsigned long pci_io_base = ISA_IO_BASE;
>  EXPORT_SYMBOL(pci_io_base);
>  
> -void __devinit scan_phb(struct pci_controller *hose)
> -{
> -	struct pci_bus *bus;
> -	struct device_node *node = hose->dn;
> -	int mode;
> -
> -	pr_debug("PCI: Scanning PHB %s\n",
> -		 node ? node->full_name : "<NO NAME>");
> -
> -	/* Create an empty bus for the toplevel */
> -	bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
> -	if (bus == NULL) {
> -		printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
> -		       hose->global_number);
> -		return;
> -	}
> -	bus->secondary = hose->first_busno;
> -	hose->bus = bus;
> -
> -	/* Get some IO space for the new PHB */
> -	pcibios_map_io_space(bus);
> -
> -	/* Wire up PHB bus resources */
> -	pcibios_setup_phb_resources(hose);
> -
> -	/* Get probe mode and perform scan */
> -	mode = PCI_PROBE_NORMAL;
> -	if (node && ppc_md.pci_probe_mode)
> -		mode = ppc_md.pci_probe_mode(bus);
> -	pr_debug("    probe mode: %d\n", mode);
> -	if (mode == PCI_PROBE_DEVTREE) {
> -		bus->subordinate = hose->last_busno;
> -		of_scan_bus(node, bus);
> -	}
> -
> -	if (mode == PCI_PROBE_NORMAL)
> -		hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
> -}
> -
>  static int __init pcibios_init(void)
>  {
>  	struct pci_controller *hose, *tmp;
> @@ -103,7 +64,7 @@ static int __init pcibios_init(void)
>  
>  	/* Scan all of the recorded PCI controllers.  */
>  	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
> -		scan_phb(hose);
> +		pcibios_scan_phb(hose, hose->dn);
>  		pci_bus_add_devices(hose->bus);
>  	}
>  
> @@ -237,6 +198,11 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
>  }
>  EXPORT_SYMBOL_GPL(pcibios_map_io_space);
>  
> +void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
> +{
> +	pcibios_map_io_space(hose->bus);
> +}
> +
>  #define IOBASE_BRIDGE_NUMBER	0
>  #define IOBASE_MEMORY		1
>  #define IOBASE_IO		2

^ permalink raw reply

* Re: [Qemu-devel] Re: Extending virtio_console to support multiple ports
From: Amit Shah @ 2009-08-27  6:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: kvm, borntraeger, qemu-devel, miltonm, linux-kernel, linuxppc-dev,
	brueckner, virtualization, alan
In-Reply-To: <1251346023.20467.21.camel@pasglop>

On (Thu) Aug 27 2009 [14:07:03], Benjamin Herrenschmidt wrote:
> On Wed, 2009-08-26 at 21:15 +0530, Amit Shah wrote:
> 
> > 
> > > - Convert hvc's usage of spinlocks to mutexes. I've no idea how this
> > >   will play out; I'm no expert here. But I did try doing this and so far
> > >   it all looks OK. No lockups, lockdep warnings, nothing. I have full
> > >   debugging enabled. But this doesn't mean it's right.
> > 
> > So just to test this further I added the capability to have more than
> > one hvc console spawn from virtio_console, created two consoles and did
> > a 'cat' of a file in each of the virtio-consoles. It's been running for
> > half an hour now without any badness. No spew in debug logs too.
> > 
> > I also checked the code in hvc_console.c that takes the spin_locks.
> > Nothing there that runs from (or needs to run from) interrupt context.
> > So the change to mutexes does seem reasonable. Also, the spinlock code
> > was added really long back -- git blame shows Linus' first git commit
> > introduced them in the git history, so it's pure legacy baggage.
> 
> Two things here:
> 
>  - First you seem to have completely missed the fact that hvc_poll() can
> be called from interrupt time :-) Look at hvc_irq.c which is used by

Right! That's the obvious one.

> some backends. Maybe that can be "fixed" by deferring to a work queue,
> though it's nice to have the keyboard input have somewhat of a higher
> priority than anything else here.

Hm, to maintain the current behaviour of poll() returning some
poll_mask, the poll_mask could be made into an atomic variable with
khvcd() updating it. But to have read at a higher priority than the
other stuff, I don't quite see yet how that can be done.

> So unless that's fixed, or I missed something, that's a big NACK for
> now.
> 
>  - Then, are we certain that there's no case where the tty layer will
> call us with some lock held or in an atomic context ? To be honest, I've

The other routines are open(), close(), write(), etc., and other kernel
context (hvc_instantiate() and the khvcd thread).

> totally lost track of the locking rules in tty land lately so it might
> well be ok, but something to verify.

Yes.

Thanks for the response!

		Amit

^ permalink raw reply

* Re: Extending virtio_console to support multiple ports
From: Amit Shah @ 2009-08-27  6:52 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: kvm, linuxppc-dev, linux-kernel, miltonm, qemu-devel, borntraeger,
	brueckner, virtualization, alan
In-Reply-To: <1251349485.6267.6.camel@concordia>

On (Thu) Aug 27 2009 [15:04:45], Michael Ellerman wrote:
> On Wed, 2009-08-26 at 21:15 +0530, Amit Shah wrote:
> > [cc'ing some people who have made some commits in hvc_console.c]
> > 
> > On (Wed) Aug 26 2009 [16:57:18], Amit Shah wrote:
> > > On (Tue) Aug 25 2009 [11:47:20], Amit Shah wrote:
> > > > 
> > > > Hello all,
> > > > 
> > > > Here is a new iteration of the patch series that implements a
> > > > transport for guest and host communications.
> > > > 
> > > > The code has been updated to reuse the virtio-console device instead
> > > > of creating a new virtio-serial device.
> > > 
> > > And the problem now is that hvc calls the put_chars function with
> > > spinlocks held and we now allocate pages in send_buf(), called from
> > > put_chars.
> > > 
> > > A few solutions:
> > 
> > [snip]
> > 
> > > - Convert hvc's usage of spinlocks to mutexes. I've no idea how this
> > >   will play out; I'm no expert here. But I did try doing this and so far
> > >   it all looks OK. No lockups, lockdep warnings, nothing. I have full
> > >   debugging enabled. But this doesn't mean it's right.
> > 
> > So just to test this further I added the capability to have more than
> > one hvc console spawn from virtio_console, created two consoles and did
> > a 'cat' of a file in each of the virtio-consoles. It's been running for
> > half an hour now without any badness. No spew in debug logs too.
> > 
> > I also checked the code in hvc_console.c that takes the spin_locks.
> > Nothing there that runs from (or needs to run from) interrupt context.
> > So the change to mutexes does seem reasonable. Also, the spinlock code
> > was added really long back -- git blame shows Linus' first git commit
> > introduced them in the git history, so it's pure legacy baggage.
> 
> I won't tell Ryan you called his code "pure legacy baggage" if you
> don't ;)
> 
> http://git.kernel.org/?p=linux/kernel/git/torvalds/old-2.6-bkcvs.git;a=commitdiff;h=d450b4ae023fb4be175389c18f4f87677da03020

Thanks for the link!

(and this general area might be the one that doesn't get major upheavals
in 5-yr spans :-)

		Amit

^ permalink raw reply

* [PATCH] powerpc: Properly start decrementer on BookE secondary CPUs
From: Benjamin Herrenschmidt @ 2009-08-27  7:00 UTC (permalink / raw)
  To: linuxppc-dev list; +Cc: Kumar Gala

This moves the code to start the decrementer on 40x and BookE into
a separate function which is now called from time_init() and
secondary_time_init(), before the respective clock sources are
registered. We also remove the 85xx specific code for doing it
from the platform code.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/kernel/time.c        |   30 ++++++++++++++++++++++--------
 arch/powerpc/platforms/85xx/smp.c |   12 ------------
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index edb1edb..e9404b6 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -727,6 +727,18 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
 	return found;
 }
 
+/* should become __cpuinit when start_secondary also is */
+void __devinit start_cpu_decrementer(void)
+{
+#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+	/* Clear any pending timer interrupts */
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+	/* Enable decrementer interrupt */
+	mtspr(SPRN_TCR, TCR_DIE);
+#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */
+}
+
 void __init generic_calibrate_decr(void)
 {
 	ppc_tb_freq = DEFAULT_TB_FREQ;		/* hardcoded default */
@@ -746,14 +758,6 @@ void __init generic_calibrate_decr(void)
 		printk(KERN_ERR "WARNING: Estimating processor frequency "
 				"(not found)\n");
 	}
-
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
-	/* Clear any pending timer interrupts */
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
-
-	/* Enable decrementer interrupt */
-	mtspr(SPRN_TCR, TCR_DIE);
-#endif
 }
 
 int update_persistent_clock(struct timespec now)
@@ -914,6 +918,11 @@ static void __init init_decrementer_clockevent(void)
 
 void secondary_cpu_time_init(void)
 {
+	/* Start the decrementer on CPUs that have manual control
+	 * such as BookE
+	 */
+	start_cpu_decrementer();
+
 	/* FIME: Should make unrelatred change to move snapshot_timebase
 	 * call here ! */
 	register_decrementer_clockevent(smp_processor_id());
@@ -1017,6 +1026,11 @@ void __init time_init(void)
 
 	write_sequnlock_irqrestore(&xtime_lock, flags);
 
+	/* Start the decrementer on CPUs that have manual control
+	 * such as BookE
+	 */
+	start_cpu_decrementer();
+
 	/* Register the clocksource, if we're not running on iSeries */
 	if (!firmware_has_feature(FW_FEATURE_ISERIES))
 		clocksource_init();
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 9f526ba..94f901d 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -79,21 +79,9 @@ smp_85xx_kick_cpu(int nr)
 }
 
 static void __init
-smp_85xx_basic_setup(int cpu_nr)
-{
-	/* Clear any pending timer interrupts */
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
-
-	/* Enable decrementer interrupt */
-	mtspr(SPRN_TCR, TCR_DIE);
-}
-
-static void __init
 smp_85xx_setup_cpu(int cpu_nr)
 {
 	mpic_setup_this_cpu();
-
-	smp_85xx_basic_setup(cpu_nr);
 }
 
 struct smp_ops_t smp_85xx_ops = {
-- 
1.6.1.2.14.gf26b5

^ permalink raw reply related

* ppc64 allnoconfig build warning
From: Stephen Rothwell @ 2009-08-27  7:10 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: ppc-dev

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

Hi Ben,

WARNING: vmlinux.o(.text+0x1d864): Section mismatch in reference from the function .dma_direct_dma_supported() to the function .init.text:.lmb_end_of_DRAM()
The function .dma_direct_dma_supported() references
the function __init .lmb_end_of_DRAM().
This is often because .dma_direct_dma_supported lacks a __init 
annotation or the annotation of .lmb_end_of_DRAM is wrong.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* [PATCH] lmb: Remove __init from lmb_end_of_DRAM()
From: Benjamin Herrenschmidt @ 2009-08-27  7:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev list, David Woodhouse, David S. Miller

We call lmb_end_of_DRAM() to test whether a DMA mask
is ok on a machine without IOMMU, but this function is
marked as __init.

I don't think there's a clean way to get the top of RAM
max_pfn doesn't appear to include highmem or I missed
(or we have a bug :-) so for now, let's just avoid having
a broken 2.6.31 by making this function non-__init and we
can revisit later.

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

David, you use lmb too, any objection there ?

diff --git a/lib/lmb.c b/lib/lmb.c
index e4a6482..0343c05 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -429,7 +429,7 @@ u64 __init lmb_phys_mem_size(void)
 	return lmb.memory.size;
 }
 
-u64 __init lmb_end_of_DRAM(void)
+u64 lmb_end_of_DRAM(void)
 {
 	int idx = lmb.memory.cnt - 1;
 

^ permalink raw reply related

* Re: [PATCH -v2 0/7] powerpc: use asm-generic/dma-mapping-common.h
From: Ingo Molnar @ 2009-08-27  7:22 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: FUJITA Tomonori, linuxppc-dev, linux-kernel, galak
In-Reply-To: <1251343070.20467.3.camel@pasglop>


* Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:

> On Thu, 2009-08-27 at 13:12 +1000, Benjamin Herrenschmidt wrote:
> > On Thu, 2009-08-13 at 10:55 +0200, Ingo Molnar wrote:
> > 
> > > Ok! We could also stage it a bit (one or two weeks) in a 
> > > separate branch and allow a rebase, should you find any bugs 
> > > during testing?
> > 
> > Allright so after various delays and sidetracking on my side, 
> > the patches have been in my -test branch for long enough, I'm 
> > happy for them to go in either way now.
> > 
> > I'm going to take them out of powerpc test for now and not put 
> > them in my -next right away until I'm sure I have the right 
> > source to pull, at which point I can just put from tip iommu.
> 
> IE. I think I was not clear :-)
> 
> I mean, I plan to pull tip/iommu into powerpc-next and then apply 
> the patches, but I want just your final word that this is a 
> "stable" (non-rebase) branch and from Fujita that the patches are 
> still good and haven't changed from those currently on patchwork.

ah, yes, they are stable/fine. I've put it into a separate branch 
for you.

Ben, please pull the latest iommu-for-powerpc git tree from:

   git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git iommu-for-powerpc

And i could pull back the new bits from you once you have the new 
patches added and are happy with them. [I suspect you dont want the 
diffstat below in the powerpc tree]

That was the plan, right?

 Thanks,

	Ingo

------------------>
Arnd Bergmann (1):
      dma-ops: Remove flush_write_buffers() in dma-mapping-common.h

Casey Dahlin (1):
      lib/swiotlb.c: Fix strange panic message selection logic when swiotlb fills up

FUJITA Tomonori (22):
      swiotlb: remove unused swiotlb_alloc_boot()
      swiotlb: remove unused swiotlb_alloc()
      swiotlb: remove swiotlb_arch_range_needs_mapping
      swiotlb: remove unnecessary swiotlb_bus_to_virt
      x86: add dma_capable() to replace is_buffer_dma_capable()
      x86: replace is_buffer_dma_capable() with dma_capable
      ia64: add dma_capable() to replace is_buffer_dma_capable()
      powerpc: add dma_capable() to replace is_buffer_dma_capable()
      swiotlb: use dma_capable()
      powerpc: remove unncesary swiotlb_arch_address_needs_mapping
      remove is_buffer_dma_capable()
      x86, IA64, powerpc: add phys_to_dma() and dma_to_phys()
      swiotlb: use phys_to_dma and dma_to_phys
      powerpc: remove unused swiotlb_phys_to_bus() and swiotlb_bus_to_phys()
      x86: remove unused swiotlb_phys_to_bus() and swiotlb_bus_to_phys()
      IA64: Remove NULL flush_write_buffers
      sparc: Use dma_map_ops struct
      sparc: Use asm-generic/dma-mapping-common.h
      sparc: Remove no-op dma_4v_sync_single_for_cpu and dma_4v_sync_sg_for_cpu
      sparc: Replace sbus_map_single and sbus_unmap_single with sbus_map_page and sbus_unmap_page
      sparc: Use asm-generic/pci-dma-compat
      sparc: Add CONFIG_DMA_API_DEBUG support


 arch/ia64/include/asm/dma-mapping.h      |   19 +++-
 arch/powerpc/include/asm/dma-mapping.h   |   23 ++++
 arch/powerpc/kernel/dma-swiotlb.c        |   48 +--------
 arch/sparc/Kconfig                       |    2 +
 arch/sparc/include/asm/dma-mapping.h     |  145 ++++-------------------
 arch/sparc/include/asm/pci.h             |    3 +
 arch/sparc/include/asm/pci_32.h          |  105 ----------------
 arch/sparc/include/asm/pci_64.h          |   88 --------------
 arch/sparc/kernel/Makefile               |    2 +-
 arch/sparc/kernel/dma.c                  |  175 +--------------------------
 arch/sparc/kernel/dma.h                  |   14 --
 arch/sparc/kernel/iommu.c                |   20 ++-
 arch/sparc/kernel/ioport.c               |  190 ++++++++++++++++-------------
 arch/sparc/kernel/pci.c                  |    2 +-
 arch/sparc/kernel/pci_sun4v.c            |   30 ++----
 arch/x86/include/asm/dma-mapping.h       |   18 +++
 arch/x86/kernel/pci-dma.c                |    2 +-
 arch/x86/kernel/pci-gart_64.c            |    5 +-
 arch/x86/kernel/pci-nommu.c              |   29 ++++-
 arch/x86/kernel/pci-swiotlb.c            |   25 ----
 include/asm-generic/dma-mapping-common.h |    6 -
 include/linux/dma-mapping.h              |    5 -
 include/linux/swiotlb.h                  |   11 --
 lib/swiotlb.c                            |  124 +++++++-------------
 24 files changed, 291 insertions(+), 800 deletions(-)
 delete mode 100644 arch/sparc/kernel/dma.h

diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 5a61b5c..8d3c79c 100644
--- a/arch/ia64/include/asm/dma-mapping.h
+++ b/arch/ia64/include/asm/dma-mapping.h
@@ -44,7 +44,6 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
 #define get_dma_ops(dev) platform_dma_get_ops(dev)
-#define flush_write_buffers()
 
 #include <asm-generic/dma-mapping-common.h>
 
@@ -69,6 +68,24 @@ dma_set_mask (struct device *dev, u64 mask)
 	return 0;
 }
 
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size <= *dev->dma_mask;
+}
+
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	return daddr;
+}
+
 extern int dma_get_cache_alignment(void);
 
 static inline void
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index b44aaab..0c34371 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -424,6 +424,29 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 #endif
 }
 
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	struct dma_mapping_ops *ops = get_dma_ops(dev);
+
+	if (ops->addr_needs_map && ops->addr_needs_map(dev, addr, size))
+		return 0;
+
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size <= *dev->dma_mask;
+}
+
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr + get_dma_direct_offset(dev);
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	return daddr - get_dma_direct_offset(dev);
+}
+
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 #ifdef CONFIG_NOT_COHERENT_CACHE
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 68ccf11..e8a57de 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -24,50 +24,12 @@
 int swiotlb __read_mostly;
 unsigned int ppc_swiotlb_enable;
 
-void *swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t addr)
-{
-	unsigned long pfn = PFN_DOWN(swiotlb_bus_to_phys(hwdev, addr));
-	void *pageaddr = page_address(pfn_to_page(pfn));
-
-	if (pageaddr != NULL)
-		return pageaddr + (addr % PAGE_SIZE);
-	return NULL;
-}
-
-dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
-{
-	return paddr + get_dma_direct_offset(hwdev);
-}
-
-phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
-
-{
-	return baddr - get_dma_direct_offset(hwdev);
-}
-
-/*
- * Determine if an address needs bounce buffering via swiotlb.
- * Going forward I expect the swiotlb code to generalize on using
- * a dma_ops->addr_needs_map, and this function will move from here to the
- * generic swiotlb code.
- */
-int
-swiotlb_arch_address_needs_mapping(struct device *hwdev, dma_addr_t addr,
-				   size_t size)
-{
-	struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev);
-
-	BUG_ON(!dma_ops);
-	return dma_ops->addr_needs_map(hwdev, addr, size);
-}
-
 /*
  * Determine if an address is reachable by a pci device, or if we must bounce.
  */
 static int
 swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
 {
-	u64 mask = dma_get_mask(hwdev);
 	dma_addr_t max;
 	struct pci_controller *hose;
 	struct pci_dev *pdev = to_pci_dev(hwdev);
@@ -79,16 +41,9 @@ swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
 	if ((addr + size > max) | (addr < hose->dma_window_base_cur))
 		return 1;
 
-	return !is_buffer_dma_capable(mask, addr, size);
-}
-
-static int
-swiotlb_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
-{
-	return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
+	return 0;
 }
 
-
 /*
  * At the moment, all platforms that use this code only require
  * swiotlb to be used if we're operating on HIGHMEM.  Since
@@ -104,7 +59,6 @@ struct dma_mapping_ops swiotlb_dma_ops = {
 	.dma_supported = swiotlb_dma_supported,
 	.map_page = swiotlb_map_page,
 	.unmap_page = swiotlb_unmap_page,
-	.addr_needs_map = swiotlb_addr_needs_map,
 	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
 	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
 	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 3f8b6a9..233cff5 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -25,6 +25,8 @@ config SPARC
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select RTC_CLASS
 	select RTC_DRV_M48T59
+	select HAVE_DMA_ATTRS
+	select HAVE_DMA_API_DEBUG
 
 config SPARC32
 	def_bool !64BIT
diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h
index 204e4bf..5a8c308 100644
--- a/arch/sparc/include/asm/dma-mapping.h
+++ b/arch/sparc/include/asm/dma-mapping.h
@@ -3,6 +3,7 @@
 
 #include <linux/scatterlist.h>
 #include <linux/mm.h>
+#include <linux/dma-debug.h>
 
 #define DMA_ERROR_CODE	(~(dma_addr_t)0x0)
 
@@ -13,142 +14,40 @@ extern int dma_set_mask(struct device *dev, u64 dma_mask);
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 #define dma_is_consistent(d, h)	(1)
 
-struct dma_ops {
-	void *(*alloc_coherent)(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, gfp_t flag);
-	void (*free_coherent)(struct device *dev, size_t size,
-			      void *cpu_addr, dma_addr_t dma_handle);
-	dma_addr_t (*map_page)(struct device *dev, struct page *page,
-			       unsigned long offset, size_t size,
-			       enum dma_data_direction direction);
-	void (*unmap_page)(struct device *dev, dma_addr_t dma_addr,
-			   size_t size,
-			   enum dma_data_direction direction);
-	int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents,
-		      enum dma_data_direction direction);
-	void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
-			 int nhwentries,
-			 enum dma_data_direction direction);
-	void (*sync_single_for_cpu)(struct device *dev,
-				    dma_addr_t dma_handle, size_t size,
-				    enum dma_data_direction direction);
-	void (*sync_single_for_device)(struct device *dev,
-				       dma_addr_t dma_handle, size_t size,
-				       enum dma_data_direction direction);
-	void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
-				int nelems,
-				enum dma_data_direction direction);
-	void (*sync_sg_for_device)(struct device *dev,
-				   struct scatterlist *sg, int nents,
-				   enum dma_data_direction dir);
-};
-extern const struct dma_ops *dma_ops;
+extern struct dma_map_ops *dma_ops, pci32_dma_ops;
+extern struct bus_type pci_bus_type;
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t flag)
-{
-	return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_handle)
-{
-	dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
-}
-
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-					size_t size,
-					enum dma_data_direction direction)
-{
-	return dma_ops->map_page(dev, virt_to_page(cpu_addr),
-				 (unsigned long)cpu_addr & ~PAGE_MASK, size,
-				 direction);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-				    size_t size,
-				    enum dma_data_direction direction)
-{
-	dma_ops->unmap_page(dev, dma_addr, size, direction);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
-				      unsigned long offset, size_t size,
-				      enum dma_data_direction direction)
-{
-	return dma_ops->map_page(dev, page, offset, size, direction);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-				  size_t size,
-				  enum dma_data_direction direction)
-{
-	dma_ops->unmap_page(dev, dma_address, size, direction);
-}
-
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
-			     int nents, enum dma_data_direction direction)
-{
-	return dma_ops->map_sg(dev, sg, nents, direction);
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-				int nents, enum dma_data_direction direction)
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
-	dma_ops->unmap_sg(dev, sg, nents, direction);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-					   dma_addr_t dma_handle, size_t size,
-					   enum dma_data_direction direction)
-{
-	dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction);
+#if defined(CONFIG_SPARC32) && defined(CONFIG_PCI)
+	if (dev->bus == &pci_bus_type)
+		return &pci32_dma_ops;
+#endif
+	return dma_ops;
 }
 
-static inline void dma_sync_single_for_device(struct device *dev,
-					      dma_addr_t dma_handle,
-					      size_t size,
-					      enum dma_data_direction direction)
-{
-	if (dma_ops->sync_single_for_device)
-		dma_ops->sync_single_for_device(dev, dma_handle, size,
-						direction);
-}
+#include <asm-generic/dma-mapping-common.h>
 
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-				       struct scatterlist *sg, int nelems,
-				       enum dma_data_direction direction)
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag)
 {
-	dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction);
-}
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	void *cpu_addr;
 
-static inline void dma_sync_sg_for_device(struct device *dev,
-					  struct scatterlist *sg, int nelems,
-					  enum dma_data_direction direction)
-{
-	if (dma_ops->sync_sg_for_device)
-		dma_ops->sync_sg_for_device(dev, sg, nelems, direction);
+	cpu_addr = ops->alloc_coherent(dev, size, dma_handle, flag);
+	debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+	return cpu_addr;
 }
 
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-						 dma_addr_t dma_handle,
-						 unsigned long offset,
-						 size_t size,
-						 enum dma_data_direction dir)
+static inline void dma_free_coherent(struct device *dev, size_t size,
+				     void *cpu_addr, dma_addr_t dma_handle)
 {
-	dma_sync_single_for_cpu(dev, dma_handle+offset, size, dir);
-}
+	struct dma_map_ops *ops = get_dma_ops(dev);
 
-static inline void dma_sync_single_range_for_device(struct device *dev,
-						    dma_addr_t dma_handle,
-						    unsigned long offset,
-						    size_t size,
-						    enum dma_data_direction dir)
-{
-	dma_sync_single_for_device(dev, dma_handle+offset, size, dir);
+	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+	ops->free_coherent(dev, size, cpu_addr, dma_handle);
 }
 
-
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
 	return (dma_addr == DMA_ERROR_CODE);
diff --git a/arch/sparc/include/asm/pci.h b/arch/sparc/include/asm/pci.h
index 6e14fd1..d9c031f 100644
--- a/arch/sparc/include/asm/pci.h
+++ b/arch/sparc/include/asm/pci.h
@@ -5,4 +5,7 @@
 #else
 #include <asm/pci_32.h>
 #endif
+
+#include <asm-generic/pci-dma-compat.h>
+
 #endif
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index b41c4c1..ac0e836 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -31,42 +31,8 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
  */
 #define PCI_DMA_BUS_IS_PHYS	(0)
 
-#include <asm/scatterlist.h>
-
 struct pci_dev;
 
-/* Allocate and map kernel buffer using consistent mode DMA for a device.
- * hwdev should be valid struct pci_dev pointer for PCI devices.
- */
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle);
-
-/* Free and unmap a consistent DMA buffer.
- * cpu_addr is what was returned from pci_alloc_consistent,
- * size must be the same as what as passed into pci_alloc_consistent,
- * and likewise dma_addr must be the same as what *dma_addrp was set to.
- *
- * References to the memory and mappings assosciated with cpu_addr/dma_addr
- * past this call are illegal.
- */
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle);
-
-/* Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
- */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
-
-/* Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
-
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
 	dma_addr_t ADDR_NAME;
@@ -81,69 +47,6 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
 	(((PTR)->LEN_NAME) = (VAL))
 
-/*
- * Same as above, only with pages instead of mapped addresses.
- */
-extern dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
-			unsigned long offset, size_t size, int direction);
-extern void pci_unmap_page(struct pci_dev *hwdev,
-			dma_addr_t dma_address, size_t size, int direction);
-
-/* Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction);
-
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction);
-
-/* Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
- *
- * If you perform a pci_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so.  At the
- * next point you give the PCI dma address back to the card, you
- * must first perform a pci_dma_sync_for_device, and then the device
- * again owns the buffer.
- */
-extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
-extern void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction);
-
-/* Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- *
- * The same as pci_dma_sync_single_* but for a scatter-gather list,
- * same rules and usage.
- */
-extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
-extern void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
-
-/* Return whether the given PCI device DMA address mask can
- * be supported properly.  For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
-{
-	return 1;
-}
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 					enum pci_dma_burst_strategy *strat,
@@ -154,14 +57,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 }
 #endif
 
-#define PCI_DMA_ERROR_CODE      (~(dma_addr_t)0x0)
-
-static inline int pci_dma_mapping_error(struct pci_dev *pdev,
-					dma_addr_t dma_addr)
-{
-        return (dma_addr == PCI_DMA_ERROR_CODE);
-}
-
 struct device_node;
 extern struct device_node *pci_device_to_OF_node(struct pci_dev *pdev);
 
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 7a1e356..5cc9f6a 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -35,37 +35,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
  */
 #define PCI_DMA_BUS_IS_PHYS	(0)
 
-static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size,
-					 dma_addr_t *dma_handle)
-{
-	return dma_alloc_coherent(&pdev->dev, size, dma_handle, GFP_ATOMIC);
-}
-
-static inline void pci_free_consistent(struct pci_dev *pdev, size_t size,
-				       void *vaddr, dma_addr_t dma_handle)
-{
-	return dma_free_coherent(&pdev->dev, size, vaddr, dma_handle);
-}
-
-static inline dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr,
-					size_t size, int direction)
-{
-	return dma_map_single(&pdev->dev, ptr, size,
-			      (enum dma_data_direction) direction);
-}
-
-static inline void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr,
-				    size_t size, int direction)
-{
-	dma_unmap_single(&pdev->dev, dma_addr, size,
-			 (enum dma_data_direction) direction);
-}
-
-#define pci_map_page(dev, page, off, size, dir) \
-	pci_map_single(dev, (page_address(page) + (off)), size, dir)
-#define pci_unmap_page(dev,addr,sz,dir) \
-	pci_unmap_single(dev,addr,sz,dir)
-
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
 	dma_addr_t ADDR_NAME;
@@ -80,57 +49,6 @@ static inline void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr,
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
 	(((PTR)->LEN_NAME) = (VAL))
 
-static inline int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg,
-			     int nents, int direction)
-{
-	return dma_map_sg(&pdev->dev, sg, nents,
-			  (enum dma_data_direction) direction);
-}
-
-static inline void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg,
-				int nents, int direction)
-{
-	dma_unmap_sg(&pdev->dev, sg, nents,
-		     (enum dma_data_direction) direction);
-}
-
-static inline void pci_dma_sync_single_for_cpu(struct pci_dev *pdev,
-					       dma_addr_t dma_handle,
-					       size_t size, int direction)
-{
-	dma_sync_single_for_cpu(&pdev->dev, dma_handle, size,
-				(enum dma_data_direction) direction);
-}
-
-static inline void pci_dma_sync_single_for_device(struct pci_dev *pdev,
-						  dma_addr_t dma_handle,
-						  size_t size, int direction)
-{
-	/* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev,
-					   struct scatterlist *sg,
-					   int nents, int direction)
-{
-	dma_sync_sg_for_cpu(&pdev->dev, sg, nents,
-			    (enum dma_data_direction) direction);
-}
-
-static inline void pci_dma_sync_sg_for_device(struct pci_dev *pdev,
-					      struct scatterlist *sg,
-					      int nelems, int direction)
-{
-	/* No flushing needed to sync cpu writes to the device.  */
-}
-
-/* Return whether the given PCI device DMA address mask can
- * be supported properly.  For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
-
 /* PCI IOMMU mapping bypass support. */
 
 /* PCI 64-bit addressing works for all slots on all controller
@@ -140,12 +58,6 @@ extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
 #define PCI64_REQUIRED_MASK	(~(dma64_addr_t)0)
 #define PCI64_ADDR_BASE		0xfffc000000000000UL
 
-static inline int pci_dma_mapping_error(struct pci_dev *pdev,
-					dma_addr_t dma_addr)
-{
-	return dma_mapping_error(&pdev->dev, dma_addr);
-}
-
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 					enum pci_dma_burst_strategy *strat,
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 475ce46..29b88a5 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -61,7 +61,7 @@ obj-$(CONFIG_SPARC64_SMP) += cpumap.o
 obj-$(CONFIG_SPARC32)     += devres.o
 devres-y                  := ../../../kernel/irq/devres.o
 
-obj-$(CONFIG_SPARC32)     += dma.o
+obj-y                     += dma.o
 
 obj-$(CONFIG_SPARC32_PCI) += pcic.o
 
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c
index 524c32f..e1ba8ee 100644
--- a/arch/sparc/kernel/dma.c
+++ b/arch/sparc/kernel/dma.c
@@ -1,178 +1,13 @@
-/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
- *
- * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
- */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-#include <linux/mm.h>
-
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
+#include <linux/dma-debug.h>
 
-#include "dma.h"
+#define PREALLOC_DMA_DEBUG_ENTRIES       (1 << 15)
 
-int dma_supported(struct device *dev, u64 mask)
+static int __init dma_init(void)
 {
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return pci_dma_supported(to_pci_dev(dev), mask);
-#endif
+	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
 	return 0;
 }
-EXPORT_SYMBOL(dma_supported);
-
-int dma_set_mask(struct device *dev, u64 dma_mask)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
-#endif
-	return -EOPNOTSUPP;
-}
-EXPORT_SYMBOL(dma_set_mask);
-
-static void *dma32_alloc_coherent(struct device *dev, size_t size,
-				  dma_addr_t *dma_handle, gfp_t flag)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
-#endif
-	return sbus_alloc_consistent(dev, size, dma_handle);
-}
-
-static void dma32_free_coherent(struct device *dev, size_t size,
-				void *cpu_addr, dma_addr_t dma_handle)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_free_consistent(to_pci_dev(dev), size,
-				    cpu_addr, dma_handle);
-		return;
-	}
-#endif
-	sbus_free_consistent(dev, size, cpu_addr, dma_handle);
-}
-
-static dma_addr_t dma32_map_page(struct device *dev, struct page *page,
-				 unsigned long offset, size_t size,
-				 enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return pci_map_page(to_pci_dev(dev), page, offset,
-				    size, (int)direction);
-#endif
-	return sbus_map_single(dev, page_address(page) + offset,
-			       size, (int)direction);
-}
-
-static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address,
-			     size_t size, enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_unmap_page(to_pci_dev(dev), dma_address,
-			       size, (int)direction);
-		return;
-	}
-#endif
-	sbus_unmap_single(dev, dma_address, size, (int)direction);
-}
-
-static int dma32_map_sg(struct device *dev, struct scatterlist *sg,
-			int nents, enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type)
-		return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
-#endif
-	return sbus_map_sg(dev, sg, nents, direction);
-}
-
-void dma32_unmap_sg(struct device *dev, struct scatterlist *sg,
-		    int nents, enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
-		return;
-	}
-#endif
-	sbus_unmap_sg(dev, sg, nents, (int)direction);
-}
-
-static void dma32_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-				      size_t size,
-				      enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
-					    size, (int)direction);
-		return;
-	}
-#endif
-	sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
-}
-
-static void dma32_sync_single_for_device(struct device *dev,
-					 dma_addr_t dma_handle, size_t size,
-					 enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
-					       size, (int)direction);
-		return;
-	}
-#endif
-	sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
-}
-
-static void dma32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-				  int nelems, enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
-					nelems, (int)direction);
-		return;
-	}
-#endif
-	BUG();
-}
-
-static void dma32_sync_sg_for_device(struct device *dev,
-				     struct scatterlist *sg, int nelems,
-				     enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-	if (dev->bus == &pci_bus_type) {
-		pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
-					   nelems, (int)direction);
-		return;
-	}
-#endif
-	BUG();
-}
-
-static const struct dma_ops dma32_dma_ops = {
-	.alloc_coherent		= dma32_alloc_coherent,
-	.free_coherent		= dma32_free_coherent,
-	.map_page		= dma32_map_page,
-	.unmap_page		= dma32_unmap_page,
-	.map_sg			= dma32_map_sg,
-	.unmap_sg		= dma32_unmap_sg,
-	.sync_single_for_cpu	= dma32_sync_single_for_cpu,
-	.sync_single_for_device	= dma32_sync_single_for_device,
-	.sync_sg_for_cpu	= dma32_sync_sg_for_cpu,
-	.sync_sg_for_device	= dma32_sync_sg_for_device,
-};
-
-const struct dma_ops *dma_ops = &dma32_dma_ops;
-EXPORT_SYMBOL(dma_ops);
+fs_initcall(dma_init);
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h
deleted file mode 100644
index f8d8951..0000000
--- a/arch/sparc/kernel/dma.h
+++ /dev/null
@@ -1,14 +0,0 @@
-void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
-void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
-dma_addr_t sbus_map_single(struct device *dev, void *va,
-			   size_t len, int direction);
-void sbus_unmap_single(struct device *dev, dma_addr_t ba,
-		       size_t n, int direction);
-int sbus_map_sg(struct device *dev, struct scatterlist *sg,
-		int n, int direction);
-void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
-		   int n, int direction);
-void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
-				  size_t size, int direction);
-void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
-				     size_t size, int direction);
diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c
index 0aeaefe..7690cc2 100644
--- a/arch/sparc/kernel/iommu.c
+++ b/arch/sparc/kernel/iommu.c
@@ -353,7 +353,8 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
 
 static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
 				  unsigned long offset, size_t sz,
-				  enum dma_data_direction direction)
+				  enum dma_data_direction direction,
+				  struct dma_attrs *attrs)
 {
 	struct iommu *iommu;
 	struct strbuf *strbuf;
@@ -474,7 +475,8 @@ do_flush_sync:
 }
 
 static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
-			      size_t sz, enum dma_data_direction direction)
+			      size_t sz, enum dma_data_direction direction,
+			      struct dma_attrs *attrs)
 {
 	struct iommu *iommu;
 	struct strbuf *strbuf;
@@ -520,7 +522,8 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
 }
 
 static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
-			 int nelems, enum dma_data_direction direction)
+			 int nelems, enum dma_data_direction direction,
+			 struct dma_attrs *attrs)
 {
 	struct scatterlist *s, *outs, *segstart;
 	unsigned long flags, handle, prot, ctx;
@@ -691,7 +694,8 @@ static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg)
 }
 
 static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
-			    int nelems, enum dma_data_direction direction)
+			    int nelems, enum dma_data_direction direction,
+			    struct dma_attrs *attrs)
 {
 	unsigned long flags, ctx;
 	struct scatterlist *sg;
@@ -822,7 +826,7 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev,
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static const struct dma_ops sun4u_dma_ops = {
+static struct dma_map_ops sun4u_dma_ops = {
 	.alloc_coherent		= dma_4u_alloc_coherent,
 	.free_coherent		= dma_4u_free_coherent,
 	.map_page		= dma_4u_map_page,
@@ -833,9 +837,11 @@ static const struct dma_ops sun4u_dma_ops = {
 	.sync_sg_for_cpu	= dma_4u_sync_sg_for_cpu,
 };
 
-const struct dma_ops *dma_ops = &sun4u_dma_ops;
+struct dma_map_ops *dma_ops = &sun4u_dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+extern int pci64_dma_supported(struct pci_dev *pdev, u64 device_mask);
+
 int dma_supported(struct device *dev, u64 device_mask)
 {
 	struct iommu *iommu = dev->archdata.iommu;
@@ -849,7 +855,7 @@ int dma_supported(struct device *dev, u64 device_mask)
 
 #ifdef CONFIG_PCI
 	if (dev->bus == &pci_bus_type)
-		return pci_dma_supported(to_pci_dev(dev), device_mask);
+		return pci64_dma_supported(to_pci_dev(dev), device_mask);
 #endif
 
 	return 0;
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 87ea0d0..edbea23 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -48,8 +48,6 @@
 #include <asm/iommu.h>
 #include <asm/io-unit.h>
 
-#include "dma.h"
-
 #define mmu_inval_dma_area(p, l)	/* Anton pulled it out for 2.4.0-xx */
 
 static struct resource *_sparc_find_resource(struct resource *r,
@@ -246,7 +244,8 @@ EXPORT_SYMBOL(sbus_set_sbus64);
  * Typically devices use them for control blocks.
  * CPU may access them without any explicit flushing.
  */
-void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
+static void *sbus_alloc_coherent(struct device *dev, size_t len,
+				 dma_addr_t *dma_addrp, gfp_t gfp)
 {
 	struct of_device *op = to_of_device(dev);
 	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
@@ -299,7 +298,8 @@ err_nopages:
 	return NULL;
 }
 
-void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
+static void sbus_free_coherent(struct device *dev, size_t n, void *p,
+			       dma_addr_t ba)
 {
 	struct resource *res;
 	struct page *pgv;
@@ -317,7 +317,7 @@ void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
 
 	n = (n + PAGE_SIZE-1) & PAGE_MASK;
 	if ((res->end-res->start)+1 != n) {
-		printk("sbus_free_consistent: region 0x%lx asked 0x%lx\n",
+		printk("sbus_free_consistent: region 0x%lx asked 0x%zx\n",
 		    (long)((res->end-res->start)+1), n);
 		return;
 	}
@@ -337,8 +337,13 @@ void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
  * CPU view of this memory may be inconsistent with
  * a device view and explicit flushing is necessary.
  */
-dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
+static dma_addr_t sbus_map_page(struct device *dev, struct page *page,
+				unsigned long offset, size_t len,
+				enum dma_data_direction dir,
+				struct dma_attrs *attrs)
 {
+	void *va = page_address(page) + offset;
+
 	/* XXX why are some lengths signed, others unsigned? */
 	if (len <= 0) {
 		return 0;
@@ -350,12 +355,14 @@ dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int directi
 	return mmu_get_scsi_one(dev, va, len);
 }
 
-void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
+static void sbus_unmap_page(struct device *dev, dma_addr_t ba, size_t n,
+			    enum dma_data_direction dir, struct dma_attrs *attrs)
 {
 	mmu_release_scsi_one(dev, ba, n);
 }
 
-int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
+static int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n,
+		       enum dma_data_direction dir, struct dma_attrs *attrs)
 {
 	mmu_get_scsi_sgl(dev, sg, n);
 
@@ -366,19 +373,38 @@ int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction
 	return n;
 }
 
-void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
+static void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n,
+			  enum dma_data_direction dir, struct dma_attrs *attrs)
 {
 	mmu_release_scsi_sgl(dev, sg, n);
 }
 
-void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
+static void sbus_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+				 int n,	enum dma_data_direction dir)
 {
+	BUG();
 }
 
-void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
+static void sbus_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+				    int n, enum dma_data_direction dir)
 {
+	BUG();
 }
 
+struct dma_map_ops sbus_dma_ops = {
+	.alloc_coherent		= sbus_alloc_coherent,
+	.free_coherent		= sbus_free_coherent,
+	.map_page		= sbus_map_page,
+	.unmap_page		= sbus_unmap_page,
+	.map_sg			= sbus_map_sg,
+	.unmap_sg		= sbus_unmap_sg,
+	.sync_sg_for_cpu	= sbus_sync_sg_for_cpu,
+	.sync_sg_for_device	= sbus_sync_sg_for_device,
+};
+
+struct dma_map_ops *dma_ops = &sbus_dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
 static int __init sparc_register_ioport(void)
 {
 	register_proc_sparc_ioport();
@@ -395,7 +421,8 @@ arch_initcall(sparc_register_ioport);
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices.
  */
-void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba)
+static void *pci32_alloc_coherent(struct device *dev, size_t len,
+				  dma_addr_t *pba, gfp_t gfp)
 {
 	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
 	unsigned long va;
@@ -439,7 +466,6 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba)
 	*pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */
 	return (void *) res->start;
 }
-EXPORT_SYMBOL(pci_alloc_consistent);
 
 /* Free and unmap a consistent DMA buffer.
  * cpu_addr is what was returned from pci_alloc_consistent,
@@ -449,7 +475,8 @@ EXPORT_SYMBOL(pci_alloc_consistent);
  * References to the memory and mappings associated with cpu_addr/dma_addr
  * past this call are illegal.
  */
-void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba)
+static void pci32_free_coherent(struct device *dev, size_t n, void *p,
+				dma_addr_t ba)
 {
 	struct resource *res;
 	unsigned long pgp;
@@ -481,60 +508,18 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba)
 
 	free_pages(pgp, get_order(n));
 }
-EXPORT_SYMBOL(pci_free_consistent);
-
-/* Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single_* is performed.
- */
-dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
-    int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	/* IIep is write-through, not flushing. */
-	return virt_to_phys(ptr);
-}
-EXPORT_SYMBOL(pci_map_single);
-
-/* Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size,
-    int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	if (direction != PCI_DMA_TODEVICE) {
-		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
-		    (size + PAGE_SIZE-1) & PAGE_MASK);
-	}
-}
-EXPORT_SYMBOL(pci_unmap_single);
 
 /*
  * Same as pci_map_single, but with pages.
  */
-dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
-			unsigned long offset, size_t size, int direction)
+static dma_addr_t pci32_map_page(struct device *dev, struct page *page,
+				 unsigned long offset, size_t size,
+				 enum dma_data_direction dir,
+				 struct dma_attrs *attrs)
 {
-	BUG_ON(direction == PCI_DMA_NONE);
 	/* IIep is write-through, not flushing. */
 	return page_to_phys(page) + offset;
 }
-EXPORT_SYMBOL(pci_map_page);
-
-void pci_unmap_page(struct pci_dev *hwdev,
-			dma_addr_t dma_address, size_t size, int direction)
-{
-	BUG_ON(direction == PCI_DMA_NONE);
-	/* mmu_inval_dma_area XXX */
-}
-EXPORT_SYMBOL(pci_unmap_page);
 
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
@@ -551,13 +536,13 @@ EXPORT_SYMBOL(pci_unmap_page);
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
-    int direction)
+static int pci32_map_sg(struct device *device, struct scatterlist *sgl,
+			int nents, enum dma_data_direction dir,
+			struct dma_attrs *attrs)
 {
 	struct scatterlist *sg;
 	int n;
 
-	BUG_ON(direction == PCI_DMA_NONE);
 	/* IIep is write-through, not flushing. */
 	for_each_sg(sgl, sg, nents, n) {
 		BUG_ON(page_address(sg_page(sg)) == NULL);
@@ -566,20 +551,19 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
 	}
 	return nents;
 }
-EXPORT_SYMBOL(pci_map_sg);
 
 /* Unmap a set of streaming mode DMA translations.
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
-    int direction)
+static void pci32_unmap_sg(struct device *dev, struct scatterlist *sgl,
+			   int nents, enum dma_data_direction dir,
+			   struct dma_attrs *attrs)
 {
 	struct scatterlist *sg;
 	int n;
 
-	BUG_ON(direction == PCI_DMA_NONE);
-	if (direction != PCI_DMA_TODEVICE) {
+	if (dir != PCI_DMA_TODEVICE) {
 		for_each_sg(sgl, sg, nents, n) {
 			BUG_ON(page_address(sg_page(sg)) == NULL);
 			mmu_inval_dma_area(
@@ -588,7 +572,6 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
 		}
 	}
 }
-EXPORT_SYMBOL(pci_unmap_sg);
 
 /* Make physical memory consistent for a single
  * streaming mode DMA translation before or after a transfer.
@@ -600,25 +583,23 @@ EXPORT_SYMBOL(pci_unmap_sg);
  * must first perform a pci_dma_sync_for_device, and then the
  * device again owns the buffer.
  */
-void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
+static void pci32_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
+				      size_t size, enum dma_data_direction dir)
 {
-	BUG_ON(direction == PCI_DMA_NONE);
-	if (direction != PCI_DMA_TODEVICE) {
+	if (dir != PCI_DMA_TODEVICE) {
 		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
 		    (size + PAGE_SIZE-1) & PAGE_MASK);
 	}
 }
-EXPORT_SYMBOL(pci_dma_sync_single_for_cpu);
 
-void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction)
+static void pci32_sync_single_for_device(struct device *dev, dma_addr_t ba,
+					 size_t size, enum dma_data_direction dir)
 {
-	BUG_ON(direction == PCI_DMA_NONE);
-	if (direction != PCI_DMA_TODEVICE) {
+	if (dir != PCI_DMA_TODEVICE) {
 		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
 		    (size + PAGE_SIZE-1) & PAGE_MASK);
 	}
 }
-EXPORT_SYMBOL(pci_dma_sync_single_for_device);
 
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
@@ -626,13 +607,13 @@ EXPORT_SYMBOL(pci_dma_sync_single_for_device);
  * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, int direction)
+static void pci32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
+				  int nents, enum dma_data_direction dir)
 {
 	struct scatterlist *sg;
 	int n;
 
-	BUG_ON(direction == PCI_DMA_NONE);
-	if (direction != PCI_DMA_TODEVICE) {
+	if (dir != PCI_DMA_TODEVICE) {
 		for_each_sg(sgl, sg, nents, n) {
 			BUG_ON(page_address(sg_page(sg)) == NULL);
 			mmu_inval_dma_area(
@@ -641,15 +622,14 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int
 		}
 	}
 }
-EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu);
 
-void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, int direction)
+static void pci32_sync_sg_for_device(struct device *device, struct scatterlist *sgl,
+				     int nents, enum dma_data_direction dir)
 {
 	struct scatterlist *sg;
 	int n;
 
-	BUG_ON(direction == PCI_DMA_NONE);
-	if (direction != PCI_DMA_TODEVICE) {
+	if (dir != PCI_DMA_TODEVICE) {
 		for_each_sg(sgl, sg, nents, n) {
 			BUG_ON(page_address(sg_page(sg)) == NULL);
 			mmu_inval_dma_area(
@@ -658,9 +638,49 @@ void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl,
 		}
 	}
 }
-EXPORT_SYMBOL(pci_dma_sync_sg_for_device);
+
+struct dma_map_ops pci32_dma_ops = {
+	.alloc_coherent		= pci32_alloc_coherent,
+	.free_coherent		= pci32_free_coherent,
+	.map_page		= pci32_map_page,
+	.map_sg			= pci32_map_sg,
+	.unmap_sg		= pci32_unmap_sg,
+	.sync_single_for_cpu	= pci32_sync_single_for_cpu,
+	.sync_single_for_device	= pci32_sync_single_for_device,
+	.sync_sg_for_cpu	= pci32_sync_sg_for_cpu,
+	.sync_sg_for_device	= pci32_sync_sg_for_device,
+};
+EXPORT_SYMBOL(pci32_dma_ops);
+
 #endif /* CONFIG_PCI */
 
+/*
+ * Return whether the given PCI device DMA address mask can be
+ * supported properly.  For example, if your device can only drive the
+ * low 24-bits during PCI bus mastering, then you would pass
+ * 0x00ffffff as the mask to this function.
+ */
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return 1;
+#endif
+	return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+	if (dev->bus == &pci_bus_type)
+		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+	return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+
 #ifdef CONFIG_PROC_FS
 
 static int
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 57859ad..c686486 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -1039,7 +1039,7 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
 	pci_dev_put(ali_isa_bridge);
 }
 
-int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
+int pci64_dma_supported(struct pci_dev *pdev, u64 device_mask)
 {
 	u64 dma_addr_mask;
 
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index 2485eaa..23c33ff 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -232,7 +232,8 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
 
 static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
 				  unsigned long offset, size_t sz,
-				  enum dma_data_direction direction)
+				  enum dma_data_direction direction,
+				  struct dma_attrs *attrs)
 {
 	struct iommu *iommu;
 	unsigned long flags, npages, oaddr;
@@ -296,7 +297,8 @@ iommu_map_fail:
 }
 
 static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
-			      size_t sz, enum dma_data_direction direction)
+			      size_t sz, enum dma_data_direction direction,
+			      struct dma_attrs *attrs)
 {
 	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
@@ -336,7 +338,8 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
 }
 
 static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
-			 int nelems, enum dma_data_direction direction)
+			 int nelems, enum dma_data_direction direction,
+			 struct dma_attrs *attrs)
 {
 	struct scatterlist *s, *outs, *segstart;
 	unsigned long flags, handle, prot;
@@ -478,7 +481,8 @@ iommu_map_failed:
 }
 
 static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
-			    int nelems, enum dma_data_direction direction)
+			    int nelems, enum dma_data_direction direction,
+			    struct dma_attrs *attrs)
 {
 	struct pci_pbm_info *pbm;
 	struct scatterlist *sg;
@@ -521,29 +525,13 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static void dma_4v_sync_single_for_cpu(struct device *dev,
-				       dma_addr_t bus_addr, size_t sz,
-				       enum dma_data_direction direction)
-{
-	/* Nothing to do... */
-}
-
-static void dma_4v_sync_sg_for_cpu(struct device *dev,
-				   struct scatterlist *sglist, int nelems,
-				   enum dma_data_direction direction)
-{
-	/* Nothing to do... */
-}
-
-static const struct dma_ops sun4v_dma_ops = {
+static struct dma_map_ops sun4v_dma_ops = {
 	.alloc_coherent			= dma_4v_alloc_coherent,
 	.free_coherent			= dma_4v_free_coherent,
 	.map_page			= dma_4v_map_page,
 	.unmap_page			= dma_4v_unmap_page,
 	.map_sg				= dma_4v_map_sg,
 	.unmap_sg			= dma_4v_unmap_sg,
-	.sync_single_for_cpu		= dma_4v_sync_single_for_cpu,
-	.sync_sg_for_cpu		= dma_4v_sync_sg_for_cpu,
 };
 
 static void __devinit pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 1c3f943..0ee770d 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -55,6 +55,24 @@ extern int dma_set_mask(struct device *dev, u64 mask);
 extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
 					dma_addr_t *dma_addr, gfp_t flag);
 
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size <= *dev->dma_mask;
+}
+
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	return daddr;
+}
+
 static inline void
 dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 	enum dma_data_direction dir)
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 1a041bc..3c945c0 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -147,7 +147,7 @@ again:
 		return NULL;
 
 	addr = page_to_phys(page);
-	if (!is_buffer_dma_capable(dma_mask, addr, size)) {
+	if (addr + size > dma_mask) {
 		__free_pages(page, get_order(size));
 
 		if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) {
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c
index d2e56b8..98a827e 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/pci-gart_64.c
@@ -190,14 +190,13 @@ static void iommu_full(struct device *dev, size_t size, int dir)
 static inline int
 need_iommu(struct device *dev, unsigned long addr, size_t size)
 {
-	return force_iommu ||
-		!is_buffer_dma_capable(*dev->dma_mask, addr, size);
+	return force_iommu || !dma_capable(dev, addr, size);
 }
 
 static inline int
 nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
 {
-	return !is_buffer_dma_capable(*dev->dma_mask, addr, size);
+	return !dma_capable(dev, addr, size);
 }
 
 /* Map a single continuous physical area into the IOMMU.
diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c
index 71d412a..a3933d4 100644
--- a/arch/x86/kernel/pci-nommu.c
+++ b/arch/x86/kernel/pci-nommu.c
@@ -14,7 +14,7 @@
 static int
 check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size)
 {
-	if (hwdev && !is_buffer_dma_capable(*hwdev->dma_mask, bus, size)) {
+	if (hwdev && !dma_capable(hwdev, bus, size)) {
 		if (*hwdev->dma_mask >= DMA_BIT_MASK(32))
 			printk(KERN_ERR
 			    "nommu_%s: overflow %Lx+%zu of device mask %Lx\n",
@@ -79,12 +79,29 @@ static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
 	free_pages((unsigned long)vaddr, get_order(size));
 }
 
+static void nommu_sync_single_for_device(struct device *dev,
+			dma_addr_t addr, size_t size,
+			enum dma_data_direction dir)
+{
+	flush_write_buffers();
+}
+
+
+static void nommu_sync_sg_for_device(struct device *dev,
+			struct scatterlist *sg, int nelems,
+			enum dma_data_direction dir)
+{
+	flush_write_buffers();
+}
+
 struct dma_map_ops nommu_dma_ops = {
-	.alloc_coherent	= dma_generic_alloc_coherent,
-	.free_coherent	= nommu_free_coherent,
-	.map_sg		= nommu_map_sg,
-	.map_page	= nommu_map_page,
-	.is_phys	= 1,
+	.alloc_coherent		= dma_generic_alloc_coherent,
+	.free_coherent		= nommu_free_coherent,
+	.map_sg			= nommu_map_sg,
+	.map_page		= nommu_map_page,
+	.sync_single_for_device = nommu_sync_single_for_device,
+	.sync_sg_for_device	= nommu_sync_sg_for_device,
+	.is_phys		= 1,
 };
 
 void __init no_iommu_init(void)
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c
index 6af96ee..e8a3501 100644
--- a/arch/x86/kernel/pci-swiotlb.c
+++ b/arch/x86/kernel/pci-swiotlb.c
@@ -13,31 +13,6 @@
 
 int swiotlb __read_mostly;
 
-void * __init swiotlb_alloc_boot(size_t size, unsigned long nslabs)
-{
-	return alloc_bootmem_low_pages(size);
-}
-
-void *swiotlb_alloc(unsigned order, unsigned long nslabs)
-{
-	return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
-}
-
-dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
-{
-	return paddr;
-}
-
-phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
-{
-	return baddr;
-}
-
-int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
-{
-	return 0;
-}
-
 static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 					dma_addr_t *dma_handle, gfp_t flags)
 {
diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h
index 5406a60..e694263 100644
--- a/include/asm-generic/dma-mapping-common.h
+++ b/include/asm-generic/dma-mapping-common.h
@@ -103,7 +103,6 @@ static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
 	if (ops->sync_single_for_cpu)
 		ops->sync_single_for_cpu(dev, addr, size, dir);
 	debug_dma_sync_single_for_cpu(dev, addr, size, dir);
-	flush_write_buffers();
 }
 
 static inline void dma_sync_single_for_device(struct device *dev,
@@ -116,7 +115,6 @@ static inline void dma_sync_single_for_device(struct device *dev,
 	if (ops->sync_single_for_device)
 		ops->sync_single_for_device(dev, addr, size, dir);
 	debug_dma_sync_single_for_device(dev, addr, size, dir);
-	flush_write_buffers();
 }
 
 static inline void dma_sync_single_range_for_cpu(struct device *dev,
@@ -132,7 +130,6 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
 		ops->sync_single_range_for_cpu(dev, addr, offset, size, dir);
 		debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
 
-		flush_write_buffers();
 	} else
 		dma_sync_single_for_cpu(dev, addr, size, dir);
 }
@@ -150,7 +147,6 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
 		ops->sync_single_range_for_device(dev, addr, offset, size, dir);
 		debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
 
-		flush_write_buffers();
 	} else
 		dma_sync_single_for_device(dev, addr, size, dir);
 }
@@ -165,7 +161,6 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
 	if (ops->sync_sg_for_cpu)
 		ops->sync_sg_for_cpu(dev, sg, nelems, dir);
 	debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-	flush_write_buffers();
 }
 
 static inline void
@@ -179,7 +174,6 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 		ops->sync_sg_for_device(dev, sg, nelems, dir);
 	debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
 
-	flush_write_buffers();
 }
 
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 07dfd46..c0f6c3c 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -98,11 +98,6 @@ static inline int is_device_dma_capable(struct device *dev)
 	return dev->dma_mask != NULL && *dev->dma_mask != DMA_MASK_NONE;
 }
 
-static inline int is_buffer_dma_capable(u64 mask, dma_addr_t addr, size_t size)
-{
-	return addr + size <= mask;
-}
-
 #ifdef CONFIG_HAS_DMA
 #include <asm/dma-mapping.h>
 #else
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index cb1a663..73b1f1c 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -14,7 +14,6 @@ struct scatterlist;
  */
 #define IO_TLB_SEGSIZE	128
 
-
 /*
  * log of the size of each IO TLB slab.  The number of slabs is command line
  * controllable.
@@ -24,16 +23,6 @@ struct scatterlist;
 extern void
 swiotlb_init(void);
 
-extern void *swiotlb_alloc_boot(size_t bytes, unsigned long nslabs);
-extern void *swiotlb_alloc(unsigned order, unsigned long nslabs);
-
-extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev,
-				      phys_addr_t address);
-extern phys_addr_t swiotlb_bus_to_phys(struct device *hwdev,
-				       dma_addr_t address);
-
-extern int swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size);
-
 extern void
 *swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 			dma_addr_t *dma_handle, gfp_t flags);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index bffe6d7..ac25cd2 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -114,46 +114,11 @@ setup_io_tlb_npages(char *str)
 __setup("swiotlb=", setup_io_tlb_npages);
 /* make io_tlb_overflow tunable too? */
 
-void * __weak __init swiotlb_alloc_boot(size_t size, unsigned long nslabs)
-{
-	return alloc_bootmem_low_pages(size);
-}
-
-void * __weak swiotlb_alloc(unsigned order, unsigned long nslabs)
-{
-	return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
-}
-
-dma_addr_t __weak swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
-{
-	return paddr;
-}
-
-phys_addr_t __weak swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
-{
-	return baddr;
-}
-
+/* Note that this doesn't work with highmem page */
 static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
 				      volatile void *address)
 {
-	return swiotlb_phys_to_bus(hwdev, virt_to_phys(address));
-}
-
-void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
-{
-	return phys_to_virt(swiotlb_bus_to_phys(hwdev, address));
-}
-
-int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev,
-					       dma_addr_t addr, size_t size)
-{
-	return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
-}
-
-int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
-{
-	return 0;
+	return phys_to_dma(hwdev, virt_to_phys(address));
 }
 
 static void swiotlb_print_info(unsigned long bytes)
@@ -189,7 +154,7 @@ swiotlb_init_with_default_size(size_t default_size)
 	/*
 	 * Get IO TLB memory from the low pages
 	 */
-	io_tlb_start = swiotlb_alloc_boot(bytes, io_tlb_nslabs);
+	io_tlb_start = alloc_bootmem_low_pages(bytes);
 	if (!io_tlb_start)
 		panic("Cannot allocate SWIOTLB buffer");
 	io_tlb_end = io_tlb_start + bytes;
@@ -245,7 +210,8 @@ swiotlb_late_init_with_default_size(size_t default_size)
 	bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
 	while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
-		io_tlb_start = swiotlb_alloc(order, io_tlb_nslabs);
+		io_tlb_start = (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
+							order);
 		if (io_tlb_start)
 			break;
 		order--;
@@ -315,20 +281,10 @@ cleanup1:
 	return -ENOMEM;
 }
 
-static inline int
-address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size)
+static int is_swiotlb_buffer(phys_addr_t paddr)
 {
-	return swiotlb_arch_address_needs_mapping(hwdev, addr, size);
-}
-
-static inline int range_needs_mapping(phys_addr_t paddr, size_t size)
-{
-	return swiotlb_force || swiotlb_arch_range_needs_mapping(paddr, size);
-}
-
-static int is_swiotlb_buffer(char *addr)
-{
-	return addr >= io_tlb_start && addr < io_tlb_end;
+	return paddr >= virt_to_phys(io_tlb_start) &&
+		paddr < virt_to_phys(io_tlb_end);
 }
 
 /*
@@ -561,9 +517,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		dma_mask = hwdev->coherent_dma_mask;
 
 	ret = (void *)__get_free_pages(flags, order);
-	if (ret &&
-	    !is_buffer_dma_capable(dma_mask, swiotlb_virt_to_bus(hwdev, ret),
-				   size)) {
+	if (ret && swiotlb_virt_to_bus(hwdev, ret) + size > dma_mask) {
 		/*
 		 * The allocated memory isn't reachable by the device.
 		 */
@@ -585,7 +539,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 	dev_addr = swiotlb_virt_to_bus(hwdev, ret);
 
 	/* Confirm address can be DMA'd by device */
-	if (!is_buffer_dma_capable(dma_mask, dev_addr, size)) {
+	if (dev_addr + size > dma_mask) {
 		printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
 		       (unsigned long long)dma_mask,
 		       (unsigned long long)dev_addr);
@@ -601,11 +555,13 @@ EXPORT_SYMBOL(swiotlb_alloc_coherent);
 
 void
 swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
-		      dma_addr_t dma_handle)
+		      dma_addr_t dev_addr)
 {
+	phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
+
 	WARN_ON(irqs_disabled());
-	if (!is_swiotlb_buffer(vaddr))
-		free_pages((unsigned long) vaddr, get_order(size));
+	if (!is_swiotlb_buffer(paddr))
+		free_pages((unsigned long)vaddr, get_order(size));
 	else
 		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
 		do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
@@ -625,12 +581,15 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
 	printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at "
 	       "device %s\n", size, dev ? dev_name(dev) : "?");
 
-	if (size > io_tlb_overflow && do_panic) {
-		if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
-			panic("DMA: Memory would be corrupted\n");
-		if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
-			panic("DMA: Random memory would be DMAed\n");
-	}
+	if (size <= io_tlb_overflow || !do_panic)
+		return;
+
+	if (dir == DMA_BIDIRECTIONAL)
+		panic("DMA: Random memory could be DMA accessed\n");
+	if (dir == DMA_FROM_DEVICE)
+		panic("DMA: Random memory could be DMA written\n");
+	if (dir == DMA_TO_DEVICE)
+		panic("DMA: Random memory could be DMA read\n");
 }
 
 /*
@@ -646,7 +605,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 			    struct dma_attrs *attrs)
 {
 	phys_addr_t phys = page_to_phys(page) + offset;
-	dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys);
+	dma_addr_t dev_addr = phys_to_dma(dev, phys);
 	void *map;
 
 	BUG_ON(dir == DMA_NONE);
@@ -655,8 +614,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (!address_needs_mapping(dev, dev_addr, size) &&
-	    !range_needs_mapping(phys, size))
+	if (dma_capable(dev, dev_addr, size) && !swiotlb_force)
 		return dev_addr;
 
 	/*
@@ -673,7 +631,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 	/*
 	 * Ensure that the address returned is DMA'ble
 	 */
-	if (address_needs_mapping(dev, dev_addr, size))
+	if (!dma_capable(dev, dev_addr, size))
 		panic("map_single: bounce buffer is not DMA'ble");
 
 	return dev_addr;
@@ -691,19 +649,25 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page);
 static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
 			 size_t size, int dir)
 {
-	char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr);
+	phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 
-	if (is_swiotlb_buffer(dma_addr)) {
-		do_unmap_single(hwdev, dma_addr, size, dir);
+	if (is_swiotlb_buffer(paddr)) {
+		do_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
 		return;
 	}
 
 	if (dir != DMA_FROM_DEVICE)
 		return;
 
-	dma_mark_clean(dma_addr, size);
+	/*
+	 * phys_to_virt doesn't work with hihgmem page but we could
+	 * call dma_mark_clean() with hihgmem page here. However, we
+	 * are fine since dma_mark_clean() is null on POWERPC. We can
+	 * make dma_mark_clean() take a physical address if necessary.
+	 */
+	dma_mark_clean(phys_to_virt(paddr), size);
 }
 
 void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
@@ -728,19 +692,19 @@ static void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
 		    size_t size, int dir, int target)
 {
-	char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr);
+	phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 
-	if (is_swiotlb_buffer(dma_addr)) {
-		sync_single(hwdev, dma_addr, size, dir, target);
+	if (is_swiotlb_buffer(paddr)) {
+		sync_single(hwdev, phys_to_virt(paddr), size, dir, target);
 		return;
 	}
 
 	if (dir != DMA_FROM_DEVICE)
 		return;
 
-	dma_mark_clean(dma_addr, size);
+	dma_mark_clean(phys_to_virt(paddr), size);
 }
 
 void
@@ -817,10 +781,10 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
 
 	for_each_sg(sgl, sg, nelems, i) {
 		phys_addr_t paddr = sg_phys(sg);
-		dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr);
+		dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
 
-		if (range_needs_mapping(paddr, sg->length) ||
-		    address_needs_mapping(hwdev, dev_addr, sg->length)) {
+		if (swiotlb_force ||
+		    !dma_capable(hwdev, dev_addr, sg->length)) {
 			void *map = map_single(hwdev, sg_phys(sg),
 					       sg->length, dir);
 			if (!map) {

^ permalink raw reply related

* Re: [PATCH -v2 0/7] powerpc: use asm-generic/dma-mapping-common.h
From: Benjamin Herrenschmidt @ 2009-08-27  7:36 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: FUJITA Tomonori, linuxppc-dev, linux-kernel, galak
In-Reply-To: <20090827072208.GA2131@elte.hu>

On Thu, 2009-08-27 at 09:22 +0200, Ingo Molnar wrote:
> 
> ah, yes, they are stable/fine. I've put it into a separate branch 
> for you.
> 
> Ben, please pull the latest iommu-for-powerpc git tree from:
> 
>    git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git
> iommu-for-powerpc
> 
> And i could pull back the new bits from you once you have the new 
> patches added and are happy with them. [I suspect you dont want the 
> diffstat below in the powerpc tree]
> 
> That was the plan, right?

Sure, no problem. I'll stick that in powerpc-next tomorrow hopefully.

Cheers,
Ben.

^ permalink raw reply

* LITE5200 configuration
From: FIXED-TERM Seeh Thomas (BEG/EMS1) @ 2009-08-27  8:01 UTC (permalink / raw)
  To: linuxppc-dev@lists.ozlabs.org

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

Hello everyone,

I'll try to run a 2.6.31-rc7 kernel on my Lite5200 board.
For the device tree I use lite5200.dts and compiled it simply with

        make ARCH=powerpc CROSS_COMPILE=ppc_6xx- lite5200.dtb

But I'm not sure what configuration for the kernel I should choose. There is no
lite5200_defconfig only one for the lite5200b.
I tried it with mpc5200_defconfig and lite5200b_defconfig, but I'm not sure which
is the right way.
For compiling the kernel I use:

        make ARCH=powerpc CROSS_COMPILE=ppc_6xx- "CONFIG_FILE"
        make ARCH=powerpc CROSS_COMPILE=ppc_6xx- uImage
        make ARCH=powerpc CROSS_COMPILE=ppc_6xx- modules
        make ARCH=powerpc CROSS_COMPILE=ppc_6xx- modules_install

Can anyone tell me?

I use U-Boot 2009.06, with the following settings for bootup:

=> print kernel_addr fdt_addr dtbfile bootfile bootargs
kernel_addr=900000
fdt_addr=b00000
dtbfile=/tftpboot/lite5200.dtb
bootfile=/tftpboot/uImage
bootargs=console=ttyPSC0,115200 root=/dev/nfs rw nfsroot=10.10.0.2:/opt/eldk/ppc
_82xx ip=10.10.0.99:10.10.0.2::255.255.255.0:icecube::off panic=1
=> tftp ${kernel_addr} ${boofile}; tftp ${fdt_addr} ${dtbfile}
=> bootm ${kernel_addr} - ${fdt_addr}

With lite5200b_defconfig config the last message I see is:

=> tftp ${kernel_addr} ${boofile}; tftp ${fdt_addr} ${dtbfile}
Using FEC ETHERNET device
TFTP from server 10.10.0.2; our IP address is 10.10.0.99
Filename '/tftpboot/uImage'.
Load address: 0x900000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         ###################################
done
Bytes transferred = 1507908 (170244 hex)
Using FEC ETHERNET device
TFTP from server 10.10.0.2; our IP address is 10.10.0.99
Filename '/tftpboot/lite5200.dtb'.
Load address: 0xb00000
Loading: ##
done
Bytes transferred = 5375 (14ff hex)
=> bootm ${kernel_addr} - ${fdt_addr}
## Booting kernel from Legacy Image at 00900000 ...
   Image Name:   Linux-2.6.31-rc7-01406-g83e0360-
   Created:      2009-08-27   7:58:32 UTC
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    1507844 Bytes =  1.4 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 00b00000
   Booting using the fdt blob at 0xb00000
   Uncompressing Kernel Image ... OK
   Loading Device Tree to 007fb000, end 007ff4fe ... OK
[    0.000000] Using lite5200 machine description
[    0.000000] Linux version 2.6.31-rc7-01406-g83e0360-dirty (root@user-laptop)
(gcc version 4.2.2) #6 Thu Aug 27 09:58:17 CEST 2009
[    0.000000] PCI host bridge /pci@f0000d00 (primary) ranges:
[    0.000000]  MEM 0x0000000080000000..0x000000009fffffff -> 0x0000000080000000
 Prefetch
[    0.000000]  MEM 0x00000000a0000000..0x00000000afffffff -> 0x00000000a0000000

[    0.000000]   IO 0x00000000b0000000..0x00000000b0ffffff -> 0x0000000000000000

[    0.000000] Zone PFN ranges:
[    0.000000]   DMA      0x00000000 -> 0x00004000
[    0.000000]   Normal   0x00004000 -> 0x00004000
[    0.000000] Movable zone start PFN for each node
[    0.000000] early_node_map[1] active PFN ranges
[    0.000000]     0: 0x00000000 -> 0x00004000
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pag
es: 16256
[    0.000000] Kernel command line: console=ttyPSC0,115200 root=/dev/nfs rw nfsr
oot=10.10.0.2:/opt/eldk/ppc_82xx ip=10.10.0.99:10.10.0.2::255.255.255.0:icecube:
:off panic=1
[    0.000000] PID hash table entries: 256 (order: 8, 1024 bytes)
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Memory: 61612k/65536k available (2972k kernel code, 3864k reserve
d, 144k data, 108k bss, 160k init)
[    0.000000] Kernel virtual memory layout:
[    0.000000]   * 0xffffe000..0xfffff000  : fixmap
[    0.000000]   * 0xfcffa000..0xfe000000  : early ioremap
[    0.000000]   * 0xc5000000..0xfcffa000  : vmalloc & ioremap
[    0.000000] SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, N
odes=1
[    0.000000] NR_IRQS:512
[    0.000000] MPC52xx PIC is up and running!
[    0.000000] clocksource: timebase mult[f26c9b2] shift[22] registered
[    0.000738] console [ttyPSC0] enabled
[    0.169172] Mount-cache hash table entries: 512
[    0.184911] NET: Registered protocol family 16
[    0.240784] PCI: Probing PCI hardware
[    0.248600] DMA: MPC52xx BestComm driver
[    0.253306] DMA: MPC52xx BestComm engine @f0001200 ok !
[    0.309563] bio: create slab <bio-0> at 0
[    0.320464] SCSI subsystem initialized
[    0.345661] NET: Registered protocol family 2
[    0.350793] IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.359384] TCP established hash table entries: 2048 (order: 2, 16384 bytes)
[    0.367176] TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
[    0.374059] TCP: Hash tables configured (established 2048 bind 2048)
[    0.380734] TCP reno registered
[    0.384910] NET: Registered protocol family 1
[    0.498050] msgmni has been set to 120
[    0.506553] alg: No test for stdrng (krng)
[    0.511415] io scheduler noop registered
[    0.515636] io scheduler anticipatory registered (default)
[    0.521491] io scheduler deadline registered
[    0.526513] io scheduler cfq registered
[    1.706240] Generic RTC Driver v1.07
[    1.712363] Serial: MPC52xx PSC UART driver
[    1.717645] f0002000.serial: ttyPSC0 at MMIO 0xf0002000 (irq = 129) is a MPC5
2xx PSC
[    1.779407] brd: module loaded
[    1.808029] loop: module loaded
[    1.814012] ata: MPC52xx IDE/ATA libata driver
[    1.821144] scsi0 : mpc52xx_ata
[    1.826559] ata1: PATA max PIO4 ata_regs 0xf0003a00 irq 135
[    1.838948] mpc52xx MII bus: probed
[    1.864150] i2c /dev entries driver
[    1.883715] TCP cubic registered
[    1.887261] NET: Registered protocol family 17
[    1.895154] RPC: Registered udp transport module.
[    1.900177] RPC: Registered tcp transport module.
[    3.450019] IP-Config: Complete:
[    3.453333]      device=eth0, addr=10.10.0.99, mask=255.255.255.0, gw=255.255
.255.255,
[    3.461661]      host=icecube, domain=, nis-domain=(none),
[    3.467407]      bootserver=10.10.0.2, rootserver=10.10.0.2, rootpath=
[    3.489436] Looking up port of RPC 100003/2 on 10.10.0.2
[    3.530495] Looking up port of RPC 100005/1 on 10.10.0.2
[    3.667558] VFS: Mounted root (nfs filesystem) on device 0:11.
[    3.674123] Freeing unused kernel memory: 160k init
[    4.085086] net eth0: FEC_IEVENT_RFIFO_ERROR
[    4.091135] ------------[ cut here ]------------
[    4.095874] Kernel BUG at c01b7d4c [verbose debug info unavailable]
[    4.102285] Oops: Exception in kernel mode, sig: 5 [#1]
[    4.107615] lite5200
[    4.109842] Modules linked in:
[    4.112965] NIP: c01b7d4c LR: c01b900c CTR: c0011220
[    4.118035] REGS: c030da20 TRAP: 0700   Not tainted  (2.6.31-rc7-01406-g83e03
60-dirty)
[    4.126106] MSR: 00029032 <EE,ME,CE,IR,DR>  CR: 22000024  XER: 00000000
[    4.132907] TASK = c02e93e8[0] 'swapper' THREAD: c030c000
[    4.138235] GPR00: 00010200 c030dad0 c02e93e8 c391fe00 00000001 00000000 0000
8000 00000000
[    4.146798] GPR08: 00000006 c030c000 c0335000 000734e0 22000022 ffcf5fff 03fb
8000 03fa8878
[    4.155357] GPR16: 03f81ae8 03fa8854 03f45dcc 03f45ccc 03f45bee c0328428 c386
fe00 0a0a0063
[    4.163920] GPR24: 0000106c 00008000 00000000 00000001 00000000 c391fe00 c387
7c00 c3877ec0
[    4.172666] Call Trace:
[    4.175165] [c030dad0] [c01b8ec0] 0xc01b8ec0 (unreliable)
[    4.180677] [c030db00] [c01b900c] 0xc01b900c
[    4.185034] [c030db20] [c01b9310] 0xc01b9310
[    4.189394] [c030db40] [c004fd08] 0xc004fd08
[    4.193753] [c030db60] [c0051f14] 0xc0051f14
[    4.198113] [c030db70] [c0006590] 0xc0006590
[    4.202473] [c030db90] [c0012084] 0xc0012084
[    4.206833] --- Exception: 501 at 0xc023d1a4
[    4.206846]     LR = 0xc023dcac
[    4.214387] [c030dc50] [c02395e4] 0xc02395e4 (unreliable)
[    4.219904] [c030dc80] [c023dcac] 0xc023dcac
[    4.224262] [c030dc90] [c0237e2c] 0xc0237e2c
[    4.228622] [c030dcb0] [c023c120] 0xc023c120
[    4.232982] [c030dce0] [c01c5514] 0xc01c5514
[    4.237341] [c030dd00] [c020ea08] 0xc020ea08
[    4.241701] [c030dd20] [c0210008] 0xc0210008
[    4.246059] [c030dd70] [c01eda24] 0xc01eda24
[    4.250418] [c030dd90] [c01ede54] 0xc01ede54
[    4.254775] --- Exception: c at 0xc030de50
[    4.254789]     LR = 0x00000a
[    4.261973] [c030ddc0] [c01d18ec] 0xc01d18ec (unreliable)
[    4.267490] [c030ddf0] [c01d4454] 0xc01d4454
[    4.271850] [c030de20] [c01d47fc] 0xc01d47fc
[    4.276209] [c030de50] [c0029c48] 0xc0029c48
[    4.280570] [c030de90] [c00064f4] 0xc00064f4
[    4.284929] [c030dea0] [c0029a98] 0xc0029a98
[    4.289288] [c030deb0] [c0006594] 0xc0006594
[    4.293645] [c030ded0] [c0012084] 0xc0012084
[    4.298004] --- Exception: 501 at 0xc0009398
[    4.298020]     LR = 0xc0009398
[    4.305561] [c030df90] [c0009348] 0xc0009348 (unreliable)
[    4.311077] [c030dfb0] [c0003e40] 0xc0003e40
[    4.315436] [c030dfc0] [c02bf850] 0xc02bf850
[    4.319795] [c030dff0] [00003438] 0x003438
[    4.323972] Instruction dump:
[    4.326999] 4e800020 9421ffd0 7c0802a6 bf210014 54290024 7c7d1b78 90010034 7c
9b2378
[    4.334947] 7cba2b78 7cd93378 8009000c 5400016e <0f000000> 3b830028 7f83e378
4809e8dd
[    4.343083] Kernel panic - not syncing: Fatal exception in interrupt
[    4.349564] Rebooting in 1 seconds.

And with mpc5200_defconfig config it is:

Using FEC ETHERNET device
TFTP from server 10.10.0.2; our IP address is 10.10.0.99
Filename '/tftpboot/uImage'.
Load address: 0x900000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #######################################################
done
Bytes transferred = 1945203 (1dae73 hex)
Using FEC ETHERNET device
TFTP from server 10.10.0.2; our IP address is 10.10.0.99
Filename '/tftpboot/lite5200.dtb'.
Load address: 0xb00000
Loading: ##
done
Bytes transferred = 5375 (14ff hex)
=> bootm ${kernel_addr} - ${fdt_addr}
## Booting kernel from Legacy Image at 00900000 ...
   Image Name:   Linux-2.6.31-rc7-01406-g83e0360
   Created:      2009-08-27   6:51:07 UTC
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    1945139 Bytes =  1.9 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 00b00000
   Booting using the fdt blob at 0xb00000
   Uncompressing Kernel Image ... OK
   Loading Device Tree to 007fb000, end 007ff4fe ... OK
[    0.000000] Using lite5200 machine description
[    0.000000] Linux version 2.6.31-rc7-01406-g83e0360 (root@user-laptop) (gcc v
ersion 4.2.2) #3 Thu Aug 27 08:50:54 CEST 2009
[    0.000000] PCI host bridge /pci@f0000d00 (primary) ranges:
[    0.000000]  MEM 0x0000000080000000..0x000000009fffffff -> 0x0000000080000000
 Prefetch
[    0.000000]  MEM 0x00000000a0000000..0x00000000afffffff -> 0x00000000a0000000

[    0.000000]   IO 0x00000000b0000000..0x00000000b0ffffff -> 0x0000000000000000

[    0.000000] Zone PFN ranges:
[    0.000000]   DMA      0x00000000 -> 0x00004000
[    0.000000]   Normal   0x00004000 -> 0x00004000
[    0.000000] Movable zone start PFN for each node
[    0.000000] early_node_map[1] active PFN ranges
[    0.000000]     0: 0x00000000 -> 0x00004000
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pag
es: 16256
[    0.000000] Kernel command line: console=ttyPSC0,115200 root=/dev/nfs rw nfsr
oot=10.10.0.2:/opt/eldk/ppc_82xx ip=10.10.0.99:10.10.0.2::255.255.255.0:icecube:
:off panic=1
[    0.000000] PID hash table entries: 256 (order: 8, 1024 bytes)
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Memory: 60588k/65536k available (3888k kernel code, 4884k reserve
d, 188k data, 164k bss, 188k init)
[    0.000000] Kernel virtual memory layout:
[    0.000000]   * 0xffffe000..0xfffff000  : fixmap
[    0.000000]   * 0xfcffa000..0xfe000000  : early ioremap
[    0.000000]   * 0xc5000000..0xfcffa000  : vmalloc & ioremap
[    0.000000] SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, N
odes=1
[    0.000000] NR_IRQS:512
[    0.000000] MPC52xx PIC is up and running!
[    0.000000] clocksource: timebase mult[f26c9b2] shift[22] registered
[    0.000467] Console: colour dummy device 80x25
[    0.001126] console [ttyPSC0] enabled
[    0.173540] Mount-cache hash table entries: 512
[    0.188342] NET: Registered protocol family 16
[    0.251292] PCI: Probing PCI hardware
[    0.259136] DMA: MPC52xx BestComm driver
[    0.263847] DMA: MPC52xx BestComm engine @f0001200 ok !
[    0.356705] bio: create slab <bio-0> at 0
[    0.368969] SCSI subsystem initialized
[    0.380298] usbcore: registered new interface driver usbfs
[    0.387488] usbcore: registered new interface driver hub
[    0.394699] usbcore: registered new device driver usb
[    0.420014] NET: Registered protocol family 2
[    0.425101] IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.433699] TCP established hash table entries: 2048 (order: 2, 16384 bytes)
[    0.441486] TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
[    0.448407] TCP: Hash tables configured (established 2048 bind 2048)
[    0.455022] TCP reno registered
[    0.459100] NET: Registered protocol family 1
[    0.574734] JFFS2 version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[    0.589702] msgmni has been set to 118
[    0.598135] alg: No test for stdrng (krng)
[    0.602904] io scheduler noop registered
[    0.607201] io scheduler anticipatory registered (default)
[    0.612979] io scheduler deadline registered
[    0.618008] io scheduler cfq registered
[    2.034926] [drm] Initialized drm 1.1.0 20060810
[    2.039933] Serial: MPC52xx PSC UART driver
[    2.045071] f0002000.serial: ttyPSC0 at MMIO 0xf0002000 (irq = 129) is a MPC5
2xx PSC
[    2.107178] brd: module loaded
[    2.135950] loop: module loaded
[    2.149599] ata: MPC52xx IDE/ATA libata driver
[    2.156669] scsi0 : mpc52xx_ata
[    2.162242] ata1: PATA max PIO4 ata_regs 0xf0003a00 irq 135
[    2.175746] mpc52xx MII bus: probed
[    2.203297] usbmon: debugfs is not available
[    2.207880] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    2.216515] ppc-of-ohci f0001000.usb: OF OHCI
[    2.221581] ppc-of-ohci f0001000.usb: new USB bus registered, assigned bus nu
mber 1
[    2.229777] ppc-of-ohci f0001000.usb: irq 134, io mem 0xf0001000
[    2.295284] usb usb1: configuration #1 chosen from 1 choice
[    2.303126] hub 1-0:1.0: USB hub found
[    2.307386] hub 1-0:1.0: 2 ports detected
[    2.315260] Initializing USB Mass Storage driver...
[    2.321842] usbcore: registered new interface driver usb-storage
[    2.328414] USB Mass Storage support registered.
[    2.349763] mice: PS/2 mouse device common for all mice
[    2.356703] i2c /dev entries driver
[    2.384164] usbcore: registered new interface driver usbhid
[    2.390132] usbhid: v2.6:USB HID core driver
[    2.397686] TCP cubic registered
[    2.401412] NET: Registered protocol family 17
[    2.409581] RPC: Registered udp transport module.
[    2.414646] RPC: Registered tcp transport module.
[    2.427827] drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
[    3.969764] IP-Config: Complete:
[    3.973082]      device=eth0, addr=10.10.0.99, mask=255.255.255.0, gw=255.255
.255.255,
[    3.981401]      host=icecube, domain=, nis-domain=(none),
[    3.987140]      bootserver=10.10.0.2, rootserver=10.10.0.2, rootpath=
[    4.009033] Looking up port of RPC 100003/2 on 10.10.0.2
[    4.055286] Looking up port of RPC 100005/1 on 10.10.0.2
[    4.226838] VFS: Mounted root (nfs filesystem) on device 0:12.
[    4.233384] Freeing unused kernel memory: 188k init
[    4.351275] net eth0: FEC_IEVENT_RFIFO_ERROR
[    4.357356] ------------[ cut here ]------------
[    4.362100] Kernel BUG at c0229440 [verbose debug info unavailable]
[    4.368517] Oops: Exception in kernel mode, sig: 5 [#1]
[    4.373853] lite5200
[    4.376085] Modules linked in:
[    4.379219] NIP: c0229440 LR: c022a700 CTR: c0013720
[    4.384300] REGS: c03fd980 TRAP: 0700   Not tainted  (2.6.31-rc7-01406-g83e03
60)
[    4.391848] MSR: 00029032 <EE,ME,CE,IR,DR>  CR: 22000024  XER: 00000000
[    4.398659] TASK = c03ce3e8[0] 'swapper' THREAD: c03fc000
[    4.403993] GPR00: 00010100 c03fda30 c03ce3e8 c397ec00 00000001 00000000 0000
8000 00000000
[    4.412574] GPR08: 00000021 c03fc000 c0434000 00073d80 82000022 ffcf5fff 03fb
8000 03fa8878
[    4.421148] GPR16: 03f81ae8 03fa8854 03f45dcc 03f45ccc c03f9e54 c39b2d80 0000
0000 c03c2b24
[    4.429718] GPR24: 00000064 00008000 00000000 00000001 00000000 c397ec00 c39a
2000 c39a22c0
[    4.438468] Call Trace:
[    4.440977] [c03fda30] [c022a5b4] 0xc022a5b4 (unreliable)
[    4.446497] [c03fda60] [c022a700] 0xc022a700
[    4.450863] [c03fda80] [c022aa04] 0xc022aa04
[    4.455227] [c03fdaa0] [c00528b4] 0xc00528b4
[    4.459593] [c03fdac0] [c0054ac0] 0xc0054ac0
[    4.463960] [c03fdad0] [c0006590] 0xc0006590
[    4.468326] [c03fdaf0] [c0014584] 0xc0014584
[    4.472690] --- Exception: 501 at 0xc0018b84
[    4.472708]     LR = 0xc027e5ac
[    4.480252] [c03fdbb0] [c39a2000] 0xc39a2000 (unreliable)
[    4.485772] [c03fdbf0] [c027e748] 0xc027e748
[    4.490139] [c03fdc30] [c02ef9e8] 0xc02ef9e8
[    4.494505] [c03fdc50] [c02ef620] 0xc02ef620
[    4.498871] [c03fdc90] [c02ef820] 0xc02ef820
[    4.503237] [c03fdcb0] [c02f20a8] 0xc02f20a8
[    4.507601] [c03fdce0] [c027b550] 0xc027b550
[    4.511968] [c03fdd00] [c02c4a44] 0xc02c4a44
[    4.516334] [c03fdd20] [c02c6044] 0xc02c6044
[    4.520700] [c03fdd70] [c02a3a60] 0xc02a3a60
[    4.525066] [c03fdd90] [c02a3e90] 0xc02a3e90
[    4.529433] [c03fddc0] [c0287928] 0xc0287928
[    4.533798] [c03fddf0] [c028a490] 0xc028a490
[    4.538164] [c03fde20] [c028a838] 0xc028a838
[    4.542527] [c03fde50] [c002c91c] 0xc002c91c
[    4.546894] [c03fde90] [c00064f4] 0xc00064f4
[    4.551257] [c03fdea0] [c002c76c] 0xc002c76c
[    4.555623] [c03fdeb0] [c0006594] 0xc0006594
[    4.559989] [c03fded0] [c0014584] 0xc0014584
[    4.564356] --- Exception: 501 at 0xc0009398
[    4.564375]     LR = 0xc0009398
[    4.571919] [c03fdf90] [c0009348] 0xc0009348 (unreliable)
[    4.577439] [c03fdfb0] [c0003e40] 0xc0003e40
[    4.581802] [c03fdfc0] [c039d850] 0xc039d850
[    4.586168] [c03fdff0] [00003438] 0x003438
[    4.590352] Instruction dump:
[    4.593390] 4e800020 9421ffd0 7c0802a6 bf210014 54290024 7c7d1b78 90010034 7c
9b2378
[    4.601358] 7cba2b78 7cd93378 8009000c 5400016e <0f000000> 3b830028 7f83e378
480e3221
[    4.609519] Kernel panic - not syncing: Fatal exception in interrupt
[    4.616013] Rebooting in 1 seconds..



Best regards

Thomas


[-- Attachment #2: Type: text/html, Size: 30286 bytes --]

^ permalink raw reply

* powerpc/ps3: Add missing check for PS3 to rtc-ps3 platform device registration (fwd)
From: Geert Uytterhoeven @ 2009-08-27  8:45 UTC (permalink / raw)
  To: stable; +Cc: Linux/PPC Development, Linux Kernel Development

For stable/linux-2.6.30.y

---------- Forwarded message ----------
Date: Thu, 27 Aug 2009 03:59:28 GMT
From: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
To: git-commits-head@vger.kernel.org
Subject: powerpc/ps3: Add missing check for PS3 to rtc-ps3 platform device
    registration

Gitweb:     http://git.kernel.org/linus/7b6a09f3d6aedeaac923824af2a5df30300b56e9
Commit:     7b6a09f3d6aedeaac923824af2a5df30300b56e9
Parent:     f415c413f458837bd0c27086b79aca889f9435e4
Author:     Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
AuthorDate: Sun Aug 23 22:54:32 2009 +0000
Committer:  Benjamin Herrenschmidt <benh@kernel.crashing.org>
CommitDate: Thu Aug 27 13:25:46 2009 +1000

    powerpc/ps3: Add missing check for PS3 to rtc-ps3 platform device registration
    
    On non-PS3, we get:
    
    | kernel BUG at drivers/rtc/rtc-ps3.c:36!
    
    because the rtc-ps3 platform device is registered unconditionally in a kernel
    with builtin support for PS3.
    
    Reported-by: Sachin Sant <sachinp@in.ibm.com>
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Acked-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/platforms/ps3/time.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c
index b178a1e..40b5cb4 100644
--- a/arch/powerpc/platforms/ps3/time.c
+++ b/arch/powerpc/platforms/ps3/time.c
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 
+#include <asm/firmware.h>
 #include <asm/rtc.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
@@ -84,6 +85,9 @@ static int __init ps3_rtc_init(void)
 {
 	struct platform_device *pdev;
 
+	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+		return -ENODEV;
+
 	pdev = platform_device_register_simple("rtc-ps3", -1, NULL, 0);
 	if (IS_ERR(pdev))
 		return PTR_ERR(pdev);

^ permalink raw reply related

* Re: Extending virtio_console to support multiple ports
From: Alan Cox @ 2009-08-27  9:08 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: kvm, linuxppc-dev, linux-kernel, miltonm, qemu-devel, borntraeger,
	brueckner, Amit Shah, virtualization
In-Reply-To: <1251346023.20467.21.camel@pasglop>

>  - Then, are we certain that there's no case where the tty layer will
> call us with some lock held or in an atomic context ? To be honest,
> I've totally lost track of the locking rules in tty land lately so it
> might well be ok, but something to verify.

Some of the less well behaved line disciplines do this and always have
done.

Alan
 

^ permalink raw reply

* Re: Extending virtio_console to support multiple ports
From: Benjamin Herrenschmidt @ 2009-08-27  9:27 UTC (permalink / raw)
  To: Alan Cox
  Cc: kvm, linuxppc-dev, linux-kernel, miltonm, qemu-devel, borntraeger,
	brueckner, Amit Shah, virtualization
In-Reply-To: <20090827100809.5f0aa0a7@linux.intel.com>

On Thu, 2009-08-27 at 10:08 +0100, Alan Cox wrote:
> >  - Then, are we certain that there's no case where the tty layer will
> > call us with some lock held or in an atomic context ? To be honest,
> > I've totally lost track of the locking rules in tty land lately so it
> > might well be ok, but something to verify.
> 
> Some of the less well behaved line disciplines do this and always have
> done.

That was also my understanding but heh, I though that maybe you may have
fixed all of that already :-)

So at this stage, I think the reasonably thing to do is to stick to the
spinlock, but we can try to make it a bit smarter, and we can definitely
attempt to fix the case Amit pointed out where we call resize without a
lock while it seems to expect it (though we also need to be careful
about re-entrancy I believe).

Cheers,
Ben.

^ permalink raw reply

* Re: Question : about difference with bdnz and bdnz+
From: Benjamin Herrenschmidt @ 2009-08-27  9:30 UTC (permalink / raw)
  To: HongWoo Lee; +Cc: linuxppc-dev
In-Reply-To: <4A9613E3.8020700@gmail.com>

On Thu, 2009-08-27 at 14:04 +0900, HongWoo Lee wrote:
> And I have a question about bdnz+ instruction.
> Through googling, I learned that bdnz does decrement count register
> and 
> branch if it is still nonzero.
> But I couldn't find what "bdnz+" is.
> Can anybody explain to me what it is ??

On PowerPC, branch instructions can have a "hint" (+ or - added to the
mnemonic) which indicates to the processor whether the branch is likely
to be taken or not, and overrides the dynamic branch prediction.

In most case, it's not necessary though I suppose in the case at hand,
we are pretty confident that we're going to loop a lot more times than
exit from the loop so it won't hurt to put the hint in there.

Note that there have been subtle changes in the way those hints work
between earlier and modern PowerPC processors and the way they are
encoded will be different depending on what CPU you are building for,
but that's an entirely different headache :-)

Cheers,
Ben.

^ permalink raw reply

* Re: spin_is_locked() broken for uniprocessor?
From: Benjamin Herrenschmidt @ 2009-08-27  9:32 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Linux-Kernel List, Steven Rostedt, linuxppc-dev list,
	Thomas Gleixner, Ingo Molnar
In-Reply-To: <1250674870.7583.334.camel@twins>

On Wed, 2009-08-19 at 11:41 +0200, Peter Zijlstra wrote:
> > > > which implies to me that spin_is_locked() will always return
> false.  Is this
> > > > expected behavior.
> > > 
> > > That's wrong. spin_is_locked should always return true on UP.
> > 
> > Surely it's not that simple?  Maybe spin_is_lock() should be
> undefined on UP.
> 
> #define spin_is_locked(l) panic()
> 
> should sort things out quickly ;-)

Not defining it would sort things out even faster and avoid nasty case
of system panic'ing when a module is loaded :-)

Cheers,
Ben.

^ permalink raw reply

* Re: [ewg] [PATCH] IB/ehca: Construct MAD redirect replies from request MAD
From: Joachim Fenkes @ 2009-08-27  9:44 UTC (permalink / raw)
  To: Hal Rosenstock
  Cc: Hal Rosenstock, OF-EWG, LKML, Jason Gunthorpe, LinuxPPC-Dev,
	Christoph Raisch, OF-General, Stefan Roscher
In-Reply-To: <f0e08f230908260815g70de3002pfd0b34f1b17abd6@mail.gmail.com>

Hal Rosenstock <hal.rosenstock@gmail.com> wrote on 26.08.2009 17:15:03:

> Thanks for doing this. It looks sane to me. The only issue I recall that 

> appears to be remaining is a better setting of 
ClassPortInfo:RespTimeValue 
> rather than hardcoding. Perhaps using the value from PortInfo is the way 
to go
> (ideally it would be that value from the port to which the the requester 
is 
> being redirected to but that might not be so easy to get from this port.

I don't think that effort will be necessary or even legal. The requestor 
will react to the redirection with another Get(ClassPortInfo) to the 
redirection target, which will reply with its own RespTimeValue, so our 
driver should speak for itself. Since we don't know when our MAD 
processing and sending of the response is going to be scheduled (we're not 
running on real-time constraints here), we play it safe and return 18, 
which amounts to roughly a second. 

Make sense?

Regards
  Joachim

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git merge branch
From: Josh Boyer @ 2009-08-27 11:05 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1251344028.20467.8.camel@pasglop>

On Thu, Aug 27, 2009 at 01:33:48PM +1000, Benjamin Herrenschmidt wrote:
>Hi Linus !
>
>Here are a couple of last minute patches for 2.6.31. One is a regression fix
>(afaik) where a PS3 driver gets incorrectly loaded on other platforms and
>crashes, along with a PS3 defconfig update.
>The following changes since commit f415c413f458837bd0c27086b79aca889f9435e4:
>  Linus Torvalds (1):
>        Merge git://git.kernel.org/.../davem/net-2.6
>
>are available in the git repository at:
>
>  git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge
>
>Geert Uytterhoeven (1):
>      powerpc/ps3: Add missing check for PS3 to rtc-ps3 platform device registration
>
>Geoff Levand (1):
>      powerpc/ps3: Update ps3_defconfig

Hm.  No 44x flush_icache_range patch?

josh

^ permalink raw reply

* Re: [PATCH] fix book E watchdog to take WDIOC_SETTIMEOUT arg in seconds
From: Wim Van Sebroeck @ 2009-08-27 11:14 UTC (permalink / raw)
  To: Chris Friesen; +Cc: linuxppc-dev, Linux kernel
In-Reply-To: <4A8303C6.7070705@nortel.com>

Hi Chris,

> The WDIOC_SETTIMEOUT argument is supposed to be a "seconds" value.
> However, the book E wdt currently treats it as a "period" which is
> interpreted in a board-specific way.
> 
> This patch allows the user to pass in a "seconds" value and the driver
> will set the smallest timeout that is at least as large as specified
> by the user.  It's been tested on e500 hardware and works as
> expected.
> 
> The patch only modifies the CONFIG_FSL_BOOKE case, the CONFIG_4xx case
> is left unmodified as I don't have any hardware to test it on.
> 
> Signed-off-by: Chris Friesen <cfriesen@nortel.com>

Added with some small changes to keep checkpatch happy. (removed trailing spaces + changed sizeof(struct watchdog_info) to sizeof(ident) and changed some spaces in tabs).

Now we only need someone that can look at the CONFIG_4xx cases still :-)

Kind regards,
Wim.

^ permalink raw reply

* [PATCH] hvc_console: provide (un)locked version for hvc_resize()
From: Hendrik Brueckner @ 2009-08-27 11:45 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Carsten Otte, kvm, linuxppc-dev, linux-kernel, Heiko Carstens,
	qemu-devel, miltonm, virtualization, borntraeger, brueckner,
	Amit Shah, Martin Schwidefsky, Alan Cox
In-Reply-To: <1251365243.20467.47.camel@pasglop>

On Thu, Aug 27, 2009 at 07:27:23PM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2009-08-27 at 10:08 +0100, Alan Cox wrote:
> So at this stage, I think the reasonably thing to do is to stick to the
> spinlock, but we can try to make it a bit smarter, and we can definitely
> attempt to fix the case Amit pointed out where we call resize without a
> lock while it seems to expect it (though we also need to be careful
> about re-entrancy I believe).

I have worked on a patch for providing a locked hvc_resize() function.
Since only two back-ends (virtio_console and hvc_iucv) use the function,
I decided to update my hvc_iucv back-end through renaming the function
call as follows:

Rename the locking free hvc_resize() function to __hvc_resize() and
provide an inline function that locks the hvc_struct and calls
__hvc_resize().

The rationale for this patch is that virtio_console calls the hvc_resize()
function without locking the hvc_struct.
According to naming rules, the unlocked version is renamed and
prefixed with "__".
References to unlocked function calls in hvc back-ends has been updated.

Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 drivers/char/hvc_console.c |    6 +++---
 drivers/char/hvc_console.h |   12 +++++++++++-
 drivers/char/hvc_iucv.c    |    4 +++-
 3 files changed, 17 insertions(+), 5 deletions(-)

--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -680,7 +680,7 @@ int hvc_poll(struct hvc_struct *hp)
 EXPORT_SYMBOL_GPL(hvc_poll);
 
 /**
- * hvc_resize() - Update terminal window size information.
+ * __hvc_resize() - Update terminal window size information.
  * @hp:		HVC console pointer
  * @ws:		Terminal window size structure
  *
@@ -689,12 +689,12 @@ EXPORT_SYMBOL_GPL(hvc_poll);
  *
  * Locking:	Locking free; the function MUST be called holding hp->lock
  */
-void hvc_resize(struct hvc_struct *hp, struct winsize ws)
+void __hvc_resize(struct hvc_struct *hp, struct winsize ws)
 {
 	hp->ws = ws;
 	schedule_work(&hp->tty_resize);
 }
-EXPORT_SYMBOL_GPL(hvc_resize);
+EXPORT_SYMBOL_GPL(__hvc_resize);
 
 /*
  * This kthread is either polling or interrupt driven.  This is determined by
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -28,6 +28,7 @@
 #define HVC_CONSOLE_H
 #include <linux/kref.h>
 #include <linux/tty.h>
+#include <linux/spinlock.h>
 
 /*
  * This is the max number of console adapters that can/will be found as
@@ -88,7 +89,16 @@ int hvc_poll(struct hvc_struct *hp);
 void hvc_kick(void);
 
 /* Resize hvc tty terminal window */
-extern void hvc_resize(struct hvc_struct *hp, struct winsize ws);
+extern void __hvc_resize(struct hvc_struct *hp, struct winsize ws);
+
+static inline void hvc_resize(struct hvc_struct *hp, struct winsize ws)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hp->lock, flags);
+	__hvc_resize(hp, ws);
+	spin_unlock_irqrestore(&hp->lock, flags);
+}
 
 /* default notifier for irq based notification */
 extern int notifier_add_irq(struct hvc_struct *hp, int data);
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -273,7 +273,9 @@ static int hvc_iucv_write(struct hvc_iuc
 	case MSG_TYPE_WINSIZE:
 		if (rb->mbuf->datalen != sizeof(struct winsize))
 			break;
-		hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
+		/* The caller must ensure that the hvc is locked, which
+		 * is the case when called from hvc_iucv_get_chars() */
+		__hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
 		break;
 
 	case MSG_TYPE_ERROR:	/* ignored ... */

^ permalink raw reply

* [v3 PATCH 0/4]: CPUIDLE/POWER: Introducing cpuidle infrastructure to POWER
From: Arun R Bharadwaj @ 2009-08-27 11:49 UTC (permalink / raw)
  To: oel Schopp, Benjamin Herrenschmidt, Paul Mackerras,
	Peter Zijlstra, Ingo Molnar, Vaidyanathan Srinivasan,
	Dipankar Sarma, Balbir Singh, Gautham R Shenoy,
	Pallipadi, Venkatesh, Arun R Bharadwaj
  Cc: linuxppc-dev, linux-kernel

Hi,


Changes from previous iteration:
--------------------------------

* Remove the EXPORT_SYMBOL(pm_idle) from
arch/powerpc/platform/pseries/processor_idle.c and introduce a
generic cpuidle_pm_idle in cpuidle.c which was earlier assuming pm_idle
to be the default idle routine. (As suggested by Peter and Ben).

* Move the cpu_idle_wait function from arch/powerpc/platforms/pseries/setup.c
to arch/powerpc/kernel/idle.c which would prevent breaking the build of
other platforms. (As suggested by Ben).
---------------------------------------

"Cpuidle" is a CPU Power Management infrastrusture which helps manage
idle CPUs in a clean and efficient manner. The architecture can register
its driver (in this case, pseries_idle driver) so that it subscribes for
cpuidle feature. Cpuidle has a set of governors (ladder and menu),
which will decide the best idle state to be chosen for the current situation,
based on heuristics, and calculates the expected residency time
for the current idle state. So based on this, the cpu is put into
the right idle state.

Currently, cpuidle infrasture is exploited by ACPI to choose between
the available ACPI C-states. This patch-set is aimed at enabling
cpuidle for powerpc and provides a sample implementation for pseries.

Currently, in the pseries_dedicated_idle_sleep(), the processor would
poll for a time period, which is called the snooze, and only then it
is ceded, which would put the processor in nap state. Cpuidle aims at
separating this into 2 different idle states. Based on the expected
residency time predicted by the cpuidle governor, the idle state is
chosen directly. So, choosing to enter the nap state directly based on
the decision made by cpuidle would avoid unnecessary snoozing before
entering nap.

This patch-set tries to achieve the above objective by introducing a
pseries processor idle driver called pseries_idle_driver in
arch/powerpc/platform/pseries/processor_idle.c, which implements the
idle loop which would replace the pseries_dedicated_idle_sleep()
when cpuidle is enabled.

Experiment conducted:
----------------------

The following experiment was conducted on a completely idle JS22 blade,
to prove that using cpuidle infrastructure, the amount of nap time increases.

Nap and snooze times were sampled for all the cpus.
For a window of 1000 samples, When cpuidle was enabled,
the total nap time was of the order of a few seconds (5-10s), whereas
the total snooze time was of the order of a few milliseconds(10-30 ms).

When cpuidle infrastructure was disabled and the regular
pseries_dedicated_idle_sleep() idle loop was used, the snooze time itself
was of the order of hundreds of milliseconds. (100 - 500 ms).
This is clearly due to unnecessary snoozing before napping even on a
completely idle system.


The previous post in this area can be found at
http://lkml.org/lkml/2009/8/26/233


Patches included in this set:
------------------------------

PATCH 1/4 - Enable cpuidle for pSeries.
PATCH 2/4 - Introduce architecture independent cpuidle_pm_idle in
	    drivers/cpuidle/cpuidle.c
PATCH 3/4 - Register for cpuidle_pm_idle in drivers/acpi/processor_idle.c
	    and arch/arm/mach-kirkwood/cpuidle.c
PATCH 4/4 - Implement Pseries Processor Idle idle module


--arun

^ permalink raw reply

* [PATCH 1/4]: CPUIDLE/POWER: Enable cpuidle for pSeries.
From: Arun R Bharadwaj @ 2009-08-27 11:51 UTC (permalink / raw)
  To: Joel Schopp, Benjamin Herrenschmidt, Paul Mackerras,
	Peter Zijlstra, Ingo Molnar, Vaidyanathan Srinivasan,
	Dipankar Sarma, Balbir Singh, Gautham R Shenoy,
	Pallipadi, Venkatesh, Arun Bharadwaj
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20090827114908.GA24986@linux.vnet.ibm.com>

* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-08-27 17:19:08]:

This patch enables the cpuidle option in Kconfig for pSeries.

Currently cpuidle infrastructure is enabled only for x86 and ARM.
This code is almost completely borrowed from x86 to enable
cpuidle for pSeries.

Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com>
---
 arch/powerpc/Kconfig              |   17 +++++++++++++++++
 arch/powerpc/include/asm/system.h |    2 ++
 arch/powerpc/kernel/idle.c        |   19 +++++++++++++++++++
 3 files changed, 38 insertions(+)

Index: linux.trees.git/arch/powerpc/Kconfig
===================================================================
--- linux.trees.git.orig/arch/powerpc/Kconfig
+++ linux.trees.git/arch/powerpc/Kconfig
@@ -88,6 +88,9 @@ config ARCH_HAS_ILOG2_U64
 	bool
 	default y if 64BIT
 
+config ARCH_HAS_CPU_IDLE_WAIT
+	def_bool y
+
 config GENERIC_HWEIGHT
 	bool
 	default y
@@ -243,6 +246,20 @@ source "kernel/Kconfig.freezer"
 source "arch/powerpc/sysdev/Kconfig"
 source "arch/powerpc/platforms/Kconfig"
 
+menu "Power management options"
+
+source "drivers/cpuidle/Kconfig"
+
+config PSERIES_PROCESSOR_IDLE
+	bool "Idle Power Management Support for pSeries"
+	depends on PPC_PSERIES && CPU_IDLE
+	default y
+	help
+	  Idle Power Management Support for pSeries. This hooks onto cpuidle
+	  infrastructure to help in idle cpu power management.
+
+endmenu
+
 menu "Kernel options"
 
 config HIGHMEM
Index: linux.trees.git/arch/powerpc/include/asm/system.h
===================================================================
--- linux.trees.git.orig/arch/powerpc/include/asm/system.h
+++ linux.trees.git/arch/powerpc/include/asm/system.h
@@ -546,5 +546,7 @@ extern void account_system_vtime(struct 
 
 extern struct dentry *powerpc_debugfs_root;
 
+void cpu_idle_wait(void);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SYSTEM_H */
Index: linux.trees.git/arch/powerpc/kernel/idle.c
===================================================================
--- linux.trees.git.orig/arch/powerpc/kernel/idle.c
+++ linux.trees.git/arch/powerpc/kernel/idle.c
@@ -102,6 +102,25 @@ void cpu_idle(void)
 	}
 }
 
+static void do_nothing(void *unused)
+{
+}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
+ * ppc_md.power_save and update to new value.
+ * Required while changing ppc_md.power_save handler on SMP systems.
+ * Caller must have changed ppc_md.power_save to the new value before the call.
+ */
+void cpu_idle_wait(void)
+{
+	/* Ensure that new value of ppc_md.power_save is set */
+	smp_mb();
+	/* kick all the CPUs so that they exit out of ppc_md.power_save */
+	smp_call_function(do_nothing, NULL, 1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
 int powersave_nap;
 
 #ifdef CONFIG_SYSCTL

^ 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