* Re: [PATCH 22/27] drivers/i2c/of: don't use deprecated field in of_platform_driver
From: Sean MacLennan @ 2010-03-12 17:31 UTC (permalink / raw)
To: Grant Likely
Cc: alsa-devel, gregkh, linux-ide, James.Bottomley, linux-i2c,
sparclinux, jeremy.kerr, sfr, linux-scsi, jgarzik,
microblaze-uclinux, devicetree-discuss, ben-linux, monstr,
linuxppc-dev, netdev, broonie, linux-kernel, akpm, dwmw2, davem
In-Reply-To: <20100311182349.13103.39322.stgit@angua>
On Thu, 11 Mar 2010 11:23:49 -0700
Grant Likely <grant.likely@secretlab.ca> wrote:
> .name, .match_table and .owner are duplicated in both
> of_platform_driver and device_driver, so the of_platform_driver
> copies will be removed soon.
>
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
i2c-ibm_iic
Acked-by: Sean MacLennan <smaclennan@pikatech.com>
^ permalink raw reply
* [PATCH v4 02/11] powerpc: add min_direct_dma_addr
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
This patch adds min_direct_dma_addr to struct dev_archdata.
min_direct_dma_addr can be used to define which is the minimum address
suitable for a DMA operation.
dma_capable() is updated to use this information in the SWIOTLB case.
This will be used later to support the Nintendo Wii video game console
which has limitations performing DMA to memory below 0x10000000 (MEM1).
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/powerpc/include/asm/device.h | 1 +
arch/powerpc/include/asm/dma-mapping.h | 2 ++
2 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 6d94d27..23f0009 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -27,6 +27,7 @@ struct dev_archdata {
#ifdef CONFIG_SWIOTLB
dma_addr_t max_direct_dma_addr;
+ dma_addr_t min_direct_dma_addr;
#endif
};
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index 18ecec8..eda3ebe 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -193,6 +193,8 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
if (sd->max_direct_dma_addr && addr + size > sd->max_direct_dma_addr)
return 0;
+ if (sd->min_direct_dma_addr && addr < sd->min_direct_dma_addr)
+ return 0;
#endif
if (!dev->dma_mask)
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 01/11] powerpc: add per-device dma coherent support
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
Use the generic per-device dma coherent allocator on powerpc.
This allows a driver to declare coherent memory area from where
a device can allocate coherent memory chunks.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/powerpc/include/asm/dma-mapping.h | 1 +
arch/powerpc/kernel/dma.c | 5 +++++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index 80a973b..18ecec8 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -17,6 +17,7 @@
#include <linux/dma-debug.h>
#include <asm/io.h>
#include <asm/swiotlb.h>
+#include <asm-generic/dma-coherent.h>
#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 6215062..83d5232 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -27,6 +27,9 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
{
void *ret;
#ifdef CONFIG_NOT_COHERENT_CACHE
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
+ return ret;
+
ret = __dma_alloc_coherent(dev, size, dma_handle, flag);
if (ret == NULL)
return NULL;
@@ -54,6 +57,8 @@ void dma_direct_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
#ifdef CONFIG_NOT_COHERENT_CACHE
+ if (dma_release_from_coherent(dev, get_order(size), vaddr))
+ return;
__dma_free_coherent(size, vaddr);
#else
free_pages((unsigned long)vaddr, get_order(size));
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 00/11] wii: add usb 2.0 support
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
The following patch series adds USB 2.0 support for the Wii PowerPC
platform via the EHCI controller present in the "Hollywood" chipset
of the video game console.
The first iterations (v1 to v3) of this patchset were submitted as RFC PATCH.
The patchset is now sent as PATCH targetted for mainline inclusion.
v3 -> v4
- Set the default IO TLB size via io_tlb_nslabs.
Suggestion by Konrad Rzeszutek Wilk.
- Use kernel command line instead of device tree to tell the kernel about
the location and size of the mem2_dma region.
Suggestion by Segher Boessenkool.
- Keeps using v4 of the USB HCD_NO_COHERENT_MEM patch
Albert Herranz (11):
powerpc: add per-device dma coherent support
powerpc: add min_direct_dma_addr
swiotbl: add back swiotlb_alloc_boot()
swiotlb: support NOT_COHERENT_CACHE PowerPC platforms
swiotlb: add swiotlb_set_default_size()
USB: refactor unmap_urb_for_dma/map_urb_for_dma
USB: add HCD_NO_COHERENT_MEM host controller driver flag
wii: have generic dma coherent
wii: add mem2 dma mapping ops
wii: enable swiotlb
wii: hollywood ehci controller support
arch/ia64/include/asm/swiotlb.h | 10 +
arch/powerpc/boot/wii.c | 44 +++++
arch/powerpc/include/asm/device.h | 1 +
arch/powerpc/include/asm/dma-mapping.h | 3 +
arch/powerpc/include/asm/swiotlb.h | 3 +
arch/powerpc/include/asm/wii.h | 25 +++
arch/powerpc/kernel/dma.c | 5 +
arch/powerpc/platforms/embedded6xx/Kconfig | 3 +
arch/powerpc/platforms/embedded6xx/Makefile | 2 +-
arch/powerpc/platforms/embedded6xx/wii-dma.c | 265 ++++++++++++++++++++++++++
arch/powerpc/platforms/embedded6xx/wii.c | 2 +
arch/x86/include/asm/swiotlb.h | 10 +
drivers/usb/core/buffer.c | 29 +++-
drivers/usb/core/hcd.c | 233 ++++++++++++++++-------
drivers/usb/core/hcd.h | 13 +-
drivers/usb/host/Kconfig | 8 +
drivers/usb/host/ehci-hcd.c | 5 +
drivers/usb/host/ehci-hlwd.c | 233 ++++++++++++++++++++++
drivers/usb/host/ehci.h | 23 +++
include/linux/swiotlb.h | 4 +
include/linux/usb.h | 5 +
lib/swiotlb.c | 60 +++++-
22 files changed, 892 insertions(+), 94 deletions(-)
create mode 100644 arch/powerpc/include/asm/wii.h
create mode 100755 arch/powerpc/platforms/embedded6xx/wii-dma.c
create mode 100644 drivers/usb/host/ehci-hlwd.c
^ permalink raw reply
* [PATCH v4 03/11] swiotbl: add back swiotlb_alloc_boot()
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz, x86, linux-ia64, linux-kernel
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
This patch makes swiotlb_alloc_boot() available again.
This weak function can be overloaded to modify slightly how the SWIOTLB
and the overflow areas are allocated during boot.
This will be used later to support the Nintendo Wii video game console,
which requires placing the SWIOTLB area above 0x10000000 (MEM2).
CC: linuxppc-dev@lists.ozlabs.org
CC: linux-kernel@vger.kernel.org
CC: x86@kernel.org
CC: linux-ia64@vger.kernel.org
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
include/linux/swiotlb.h | 2 ++
lib/swiotlb.c | 10 ++++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index febedcf..3954228 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -24,6 +24,8 @@ extern int swiotlb_force;
extern void swiotlb_init(int verbose);
+extern void *swiotlb_alloc_boot(size_t bytes, unsigned long nslabs);
+
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 437eedb..94db5df 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -117,6 +117,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);
+}
+
/* Note that this doesn't work with highmem page */
static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
volatile void *address)
@@ -158,7 +163,7 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
/*
* Get IO TLB memory from the low pages
*/
- io_tlb_start = alloc_bootmem_low_pages(bytes);
+ io_tlb_start = swiotlb_alloc_boot(bytes, io_tlb_nslabs);
if (!io_tlb_start)
panic("Cannot allocate SWIOTLB buffer");
io_tlb_end = io_tlb_start + bytes;
@@ -177,7 +182,8 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
/*
* Get the overflow emergency buffer
*/
- io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
+ io_tlb_overflow_buffer = swiotlb_alloc_boot(io_tlb_overflow,
+ io_tlb_nslabs);
if (!io_tlb_overflow_buffer)
panic("Cannot allocate SWIOTLB overflow buffer!\n");
if (verbose)
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 05/11] swiotlb: add swiotlb_set_default_size()
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz, x86, linux-ia64, linux-kernel
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
The current SWIOTLB code uses a default of 64MB for the IO TLB area.
This size can be influenced using a kernel command line parameter "swiotlb".
Unfortunately, the parsing of the kernel command line is done _after_ the
swiotlb is initialized on some architectures.
This patch adds a new function swiotlb_set_default_size() which can be used
before swiotlb_init() to indicate the desired IO TLB area size in bytes.
This will be used later to implement a smaller IO TLB on the Nintendo Wii
video game console which just comes with 24MB + 64MB of RAM.
CC: linuxppc-dev@lists.ozlabs.org
CC: linux-kernel@vger.kernel.org
CC: x86@kernel.org
CC: linux-ia64@vger.kernel.org
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
include/linux/swiotlb.h | 2 ++
lib/swiotlb.c | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index 3954228..2af6a45 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -22,6 +22,8 @@ extern int swiotlb_force;
*/
#define IO_TLB_SHIFT 11
+extern size_t __init swiotlb_set_default_size(size_t size);
+
extern void swiotlb_init(int verbose);
extern void *swiotlb_alloc_boot(size_t bytes, unsigned long nslabs);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 8f2dad9..dbeca50 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -117,6 +117,26 @@ setup_io_tlb_npages(char *str)
__setup("swiotlb=", setup_io_tlb_npages);
/* make io_tlb_overflow tunable too? */
+/**
+ * swiotlb_set_default_size() - set the default size for the IO TLB
+ * @size: size in bytes of the IO TLB
+ *
+ * A platform can use this function to change the default size of the
+ * IO TLB when the default of 64MB is not suitable.
+ * This function must be called before swiotlb_init().
+ *
+ * Note that on some platforms this is the only way to influence the
+ * size of the IO TLB, as the command line may be parsed _after_ the
+ * IO TLB is initialized.
+ */
+size_t __init swiotlb_set_default_size(size_t size)
+{
+ size_t previous_size = io_tlb_nslabs << IO_TLB_SHIFT;
+
+ io_tlb_nslabs = size >> IO_TLB_SHIFT;
+ return previous_size;
+}
+
void * __weak __init swiotlb_alloc_boot(size_t size, unsigned long nslabs)
{
return alloc_bootmem_low_pages(size);
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 06/11] USB: refactor unmap_urb_for_dma/map_urb_for_dma
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
Split unmap_urb_for_dma() and map_urb_for_dma() into smaller pieces
to make the code easier to read and maintain.
This patch adds four new URB flags which are used by map_urb_for_dma()
to mark URBs with the exact method used to map the setup packet and/or the
transfer buffer.
These flags are checked too at unmap_urb_for_dma() time to determine how
to unmap the setup packet and/or the transfer buffer. The flags are cleared
when the actual unmap happens.
No functional change.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
drivers/usb/core/hcd.c | 211 +++++++++++++++++++++++++++++++-----------------
include/linux/usb.h | 5 +
2 files changed, 143 insertions(+), 73 deletions(-)
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 80995ef..44ad710 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1260,106 +1260,171 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
*dma_handle = 0;
}
-static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
- gfp_t mem_flags)
+static void unmap_urb_setup_packet(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (urb->transfer_flags & URB_SETUP_DMA_MAPPED) {
+ urb->transfer_flags &= ~URB_SETUP_DMA_MAPPED;
+ dma_unmap_single(hcd->self.controller, urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ } else if (urb->transfer_flags & URB_SETUP_BOUNCE_MAPPED) {
+ /* bounce from "local" memory */
+ urb->transfer_flags &= ~URB_SETUP_BOUNCE_MAPPED;
+ hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
+ (void **)&urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ } else {
+ /* nothing to do for PIO-based controller requests */
+ }
+}
+
+static void unmap_urb_transfer_buffer(struct usb_hcd *hcd, struct urb *urb)
{
enum dma_data_direction dir;
- int ret = 0;
- /* Map the URB's buffers for DMA access.
- * Lower level HCD code should use *_dma exclusively,
- * unless it uses pio or talks to another transport,
- * or uses the provided scatter gather list for bulk.
- */
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ if (urb->transfer_flags & URB_TRANSFER_DMA_MAPPED) {
+ urb->transfer_flags &= ~URB_TRANSFER_DMA_MAPPED;
+ dma_unmap_single(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+ } else if (urb->transfer_flags & URB_TRANSFER_BOUNCE_MAPPED) {
+ /* bounce from "local" memory */
+ urb->transfer_flags &= ~URB_TRANSFER_BOUNCE_MAPPED;
+ hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
+ &urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+ } else {
+ /* nothing to do for PIO-based controller requests */
+ }
+}
+
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
if (is_root_hub(urb->dev))
+ return;
+
+ unmap_urb_setup_packet(hcd, urb);
+ unmap_urb_transfer_buffer(hcd, urb);
+}
+
+static int urb_needs_setup_map(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* setup mappings are required only for control requests */
+ if (!usb_endpoint_xfer_control(&urb->ep->desc))
+ return 0;
+
+ /* If the caller set URB_NO_SETUP_DMA_MAP then no mapping is needed */
+ if ((urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ return 0;
+
+ return 1;
+}
+
+static int urb_needs_transfer_map(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* don't need to map anything if there's nothing to map */
+ if (urb->transfer_buffer_length == 0)
return 0;
- if (usb_endpoint_xfer_control(&urb->ep->desc)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
+ /* If the caller set URB_NO_SETUP_DMA_MAP then no mapping is needed */
+ if ((urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ return 0;
+
+ return 1;
+}
+
+static int map_urb_setup_packet(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ int ret;
+
+ if (urb_needs_setup_map(hcd, urb)) {
if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
- hcd->self.controller,
- urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
+ hcd->self.controller,
+ urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
if (dma_mapping_error(hcd->self.controller,
- urb->setup_dma))
+ urb->setup_dma))
return -EAGAIN;
- } else if (hcd->driver->flags & HCD_LOCAL_MEM)
- ret = hcd_alloc_coherent(
- urb->dev->bus, mem_flags,
- &urb->setup_dma,
- (void **)&urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
+ urb->transfer_flags |= URB_SETUP_DMA_MAPPED;
+ } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+ /* bounce to "local" memory */
+ ret = hcd_alloc_coherent(urb->dev->bus, mem_flags,
+ &urb->setup_dma,
+ (void **)&urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (ret)
+ return ret;
+ urb->transfer_flags |= URB_SETUP_BOUNCE_MAPPED;
+ } else {
+ /* nothing to do for PIO-based controller requests */
+ }
}
+ return 0;
+}
+
+static int map_urb_transfer_buffer(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ enum dma_data_direction dir;
+ int ret;
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- if (ret == 0 && urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+ if (urb_needs_transfer_map(hcd, urb)) {
if (hcd->self.uses_dma) {
urb->transfer_dma = dma_map_single (
- hcd->self.controller,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- dir);
+ hcd->self.controller,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
if (dma_mapping_error(hcd->self.controller,
- urb->transfer_dma))
+ urb->transfer_dma))
return -EAGAIN;
+ urb->transfer_flags |= URB_TRANSFER_DMA_MAPPED;
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
- ret = hcd_alloc_coherent(
- urb->dev->bus, mem_flags,
- &urb->transfer_dma,
- &urb->transfer_buffer,
- urb->transfer_buffer_length,
- dir);
-
- if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- hcd_free_coherent(urb->dev->bus,
- &urb->setup_dma,
- (void **)&urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
+ /* bounce to "local" memory */
+ ret = hcd_alloc_coherent(urb->dev->bus, mem_flags,
+ &urb->transfer_dma,
+ &urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+ if (ret)
+ return ret;
+ urb->transfer_flags |= URB_TRANSFER_BOUNCE_MAPPED;
+ } else {
+ /* nothing to do for PIO-based controller requests */
}
}
- return ret;
+ return 0;
}
-static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
{
- enum dma_data_direction dir;
+ int error;
+ /* Map the URB's buffers for DMA access.
+ * Lower level HCD code should use *_dma exclusively,
+ * unless it uses pio or talks to another transport,
+ * or uses the provided scatter gather list for bulk.
+ */
if (is_root_hub(urb->dev))
- return;
-
- if (usb_endpoint_xfer_control(&urb->ep->desc)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- if (hcd->self.uses_dma)
- dma_unmap_single(hcd->self.controller, urb->setup_dma,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- else if (hcd->driver->flags & HCD_LOCAL_MEM)
- hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
- (void **)&urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- }
+ return 0;
- dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
- if (hcd->self.uses_dma)
- dma_unmap_single(hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- dir);
- else if (hcd->driver->flags & HCD_LOCAL_MEM)
- hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
- &urb->transfer_buffer,
- urb->transfer_buffer_length,
- dir);
+ error = map_urb_setup_packet(hcd, urb, mem_flags);
+ if (!error) {
+ error = map_urb_transfer_buffer(hcd, urb, mem_flags);
+ if (error)
+ unmap_urb_setup_packet(hcd, urb);
}
+ return error;
}
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/usb.h b/include/linux/usb.h
index d7ace1b..5e99cbd 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -985,6 +985,11 @@ extern int usb_disabled(void);
#define URB_DIR_OUT 0
#define URB_DIR_MASK URB_DIR_IN
+#define URB_SETUP_DMA_MAPPED 0x1000 /* via dma_map_single */
+#define URB_SETUP_BOUNCE_MAPPED 0x2000 /* via hcd_alloc_coherent */
+#define URB_TRANSFER_DMA_MAPPED 0x4000 /* via dma_map_single */
+#define URB_TRANSFER_BOUNCE_MAPPED 0x8000 /* via hcd_alloc_coherent */
+
struct usb_iso_packet_descriptor {
unsigned int offset;
unsigned int length; /* expected length */
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 04/11] swiotlb: support NOT_COHERENT_CACHE PowerPC platforms
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz, x86, linux-ia64, linux-kernel
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
The current SWIOTLB code does not support NOT_COHERENT_CACHE platforms.
This patch adds support for NOT_COHERENT_CACHE platforms to SWIOTLB by
adding two platform specific functions swiotlb_dma_sync_page() and
swiotlb_dma_sync() which can be used to explicitly manage cache coherency.
On PowerPC these functions are mapped to their corresponding
__dma_sync_page() and __dma_sync() functions.
On other architectures using SWIOTLB these functions are optimized out.
This will be used later to support SWIOTLB on the Nintendo Wii video game
console.
CC: linuxppc-dev@lists.ozlabs.org
CC: linux-kernel@vger.kernel.org
CC: x86@kernel.org
CC: linux-ia64@vger.kernel.org
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/ia64/include/asm/swiotlb.h | 10 ++++++++++
arch/powerpc/include/asm/swiotlb.h | 3 +++
arch/x86/include/asm/swiotlb.h | 10 ++++++++++
lib/swiotlb.c | 30 ++++++++++++++++++++++++------
4 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/arch/ia64/include/asm/swiotlb.h b/arch/ia64/include/asm/swiotlb.h
index f0acde6..6722090 100644
--- a/arch/ia64/include/asm/swiotlb.h
+++ b/arch/ia64/include/asm/swiotlb.h
@@ -14,4 +14,14 @@ static inline void pci_swiotlb_init(void)
}
#endif
+static inline void swiotlb_dma_sync_page(struct page *page,
+ unsigned long offset,
+ size_t size, int direction)
+{
+}
+
+static inline void swiotlb_dma_sync(void *vaddr, size_t size, int direction)
+{
+}
+
#endif /* ASM_IA64__SWIOTLB_H */
diff --git a/arch/powerpc/include/asm/swiotlb.h b/arch/powerpc/include/asm/swiotlb.h
index 8979d4c..603b343 100644
--- a/arch/powerpc/include/asm/swiotlb.h
+++ b/arch/powerpc/include/asm/swiotlb.h
@@ -22,4 +22,7 @@ int __init swiotlb_setup_bus_notifier(void);
extern void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev);
+#define swiotlb_dma_sync_page __dma_sync_page
+#define swiotlb_dma_sync __dma_sync
+
#endif /* __ASM_SWIOTLB_H */
diff --git a/arch/x86/include/asm/swiotlb.h b/arch/x86/include/asm/swiotlb.h
index 8085277..e5f6d9c 100644
--- a/arch/x86/include/asm/swiotlb.h
+++ b/arch/x86/include/asm/swiotlb.h
@@ -20,4 +20,14 @@ static inline void pci_swiotlb_init(void)
static inline void dma_mark_clean(void *addr, size_t size) {}
+static inline void swiotlb_dma_sync_page(struct page *page,
+ unsigned long offset,
+ size_t size, int direction)
+{
+}
+
+static inline void swiotlb_dma_sync(void *vaddr, size_t size, int direction)
+{
+}
+
#endif /* _ASM_X86_SWIOTLB_H */
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 94db5df..8f2dad9 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -346,10 +346,13 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
local_irq_save(flags);
buffer = kmap_atomic(pfn_to_page(pfn),
KM_BOUNCE_READ);
- if (dir == DMA_TO_DEVICE)
+ if (dir == DMA_TO_DEVICE) {
memcpy(dma_addr, buffer + offset, sz);
- else
+ swiotlb_dma_sync(dma_addr, sz, dir);
+ } else {
+ swiotlb_dma_sync(dma_addr, sz, dir);
memcpy(buffer + offset, dma_addr, sz);
+ }
kunmap_atomic(buffer, KM_BOUNCE_READ);
local_irq_restore(flags);
@@ -359,10 +362,14 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
offset = 0;
}
} else {
- if (dir == DMA_TO_DEVICE)
+ if (dir == DMA_TO_DEVICE) {
memcpy(dma_addr, phys_to_virt(phys), size);
- else
+ swiotlb_dma_sync(dma_addr, size, dir);
+
+ } else {
+ swiotlb_dma_sync(dma_addr, size, dir);
memcpy(phys_to_virt(phys), dma_addr, size);
+ }
}
}
@@ -542,6 +549,8 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
}
}
+#ifndef CONFIG_NOT_COHERENT_CACHE
+
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags)
@@ -606,6 +615,8 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
}
EXPORT_SYMBOL(swiotlb_free_coherent);
+#endif /* !CONFIG_NOT_COHERENT_CACHE */
+
static void
swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
{
@@ -652,8 +663,10 @@ 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 (dma_capable(dev, dev_addr, size) && !swiotlb_force)
+ if (dma_capable(dev, dev_addr, size) && !swiotlb_force) {
+ swiotlb_dma_sync_page(page, offset, size, dir);
return dev_addr;
+ }
/*
* Oh well, have to allocate and map a bounce buffer.
@@ -739,6 +752,8 @@ swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
return;
}
+ swiotlb_dma_sync(phys_to_virt(paddr), size, dir);
+
if (dir != DMA_FROM_DEVICE)
return;
@@ -835,8 +850,11 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
return 0;
}
sg->dma_address = swiotlb_virt_to_bus(hwdev, map);
- } else
+ } else {
+ swiotlb_dma_sync_page(sg_page(sg), sg->offset,
+ sg->length, dir);
sg->dma_address = dev_addr;
+ }
sg->dma_length = sg->length;
}
return nelems;
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 07/11] USB: add HCD_NO_COHERENT_MEM host controller driver flag
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
The HCD_NO_COHERENT_MEM USB host controller driver flag can be enabled
to instruct the USB stack to avoid allocating coherent memory for USB
buffers.
This flag is useful to overcome some esoteric memory access restrictions
found in some platforms.
For example, the Nintendo Wii video game console is a NOT_COHERENT_CACHE
platform that is unable to safely perform non-32 bit uncached writes
to RAM because the byte enables are not connected to the bus.
Thus, in that platform, "coherent" DMA buffers cannot be directly used
by the kernel code unless it guarantees that all write accesses
to said buffers are done in 32 bit chunks (which is not the case in the
USB subsystem).
To avoid this unwanted behaviour HCD_NO_COHERENT_MEM can be enabled at
the HCD controller, causing USB buffer allocations to be satisfied from
normal kernel memory. In this case, the USB stack will make sure that
the buffers get properly mapped/unmapped for DMA transfers using the DMA
streaming mapping API.
Note that other parts of the USB stack may also use coherent memory,
like for example the hardware descriptors used in the EHCI controllers.
This needs to be checked and addressed separately. In the EHCI example,
hardware descriptors are accessed in 32-bit (or 64-bit) chunks, causing
no problems in the described scenario.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
drivers/usb/core/buffer.c | 29 +++++++++++++++++++++++------
drivers/usb/core/hcd.c | 32 +++++++++++++++++++++++++++-----
drivers/usb/core/hcd.h | 13 +++++++------
3 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 3ba2fff..10cd11d 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -36,6 +36,26 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
/* SETUP primitives */
+static inline int hcd_uses_pio(struct usb_hcd *hcd)
+{
+ if ((!hcd->self.controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM)))
+ return 1;
+ return 0;
+}
+
+static inline int hcd_needs_non_dma_mem(struct usb_hcd *hcd)
+{
+ /*
+ * PIO-based and HCD_NO_COHERENT_MEM-based controllers use
+ * normal kernel memory.
+ * The rest want DMA memory.
+ */
+ if (hcd_uses_pio(hcd) || (hcd->driver->flags & HCD_NO_COHERENT_MEM))
+ return 1;
+ return 0;
+}
+
/**
* hcd_buffer_create - initialize buffer pools
* @hcd: the bus whose buffer pools are to be initialized
@@ -53,8 +73,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
char name[16];
int i, size;
- if (!hcd->self.controller->dma_mask &&
- !(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (hcd_needs_non_dma_mem(hcd))
return 0;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -109,8 +128,7 @@ void *hcd_buffer_alloc(
int i;
/* some USB hosts just use PIO */
- if (!bus->controller->dma_mask &&
- !(hcd->driver->flags & HCD_LOCAL_MEM)) {
+ if (hcd_needs_non_dma_mem(hcd)) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
@@ -135,8 +153,7 @@ void hcd_buffer_free(
if (!addr)
return;
- if (!bus->controller->dma_mask &&
- !(hcd->driver->flags & HCD_LOCAL_MEM)) {
+ if (hcd_needs_non_dma_mem(hcd)) {
kfree(addr);
return;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 44ad710..174853a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1316,9 +1316,19 @@ static int urb_needs_setup_map(struct usb_hcd *hcd, struct urb *urb)
/* setup mappings are required only for control requests */
if (!usb_endpoint_xfer_control(&urb->ep->desc))
return 0;
-
- /* If the caller set URB_NO_SETUP_DMA_MAP then no mapping is needed */
- if ((urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ /*
+ * Setup packets are 8 bytes long and don't use scatter/gather.
+ *
+ * If the caller sets URB_NO_SETUP_DMA_MAP and urb->setup_dma
+ * contains a valid DMA handle then it is already mapped, except
+ * if the controller can't use coherent memory (HCD_NO_COHERENT_MEM).
+ *
+ * urb->setup_dma is set to ~0 when allocating USB buffers for
+ * PIO-based or HCD_NO_COHERENT_MEM-based controllers.
+ */
+ if ((urb->transfer_flags & URB_NO_SETUP_DMA_MAP) &&
+ urb->setup_dma != ~(dma_addr_t)0 &&
+ !(hcd->driver->flags & HCD_NO_COHERENT_MEM))
return 0;
return 1;
@@ -1330,8 +1340,20 @@ static int urb_needs_transfer_map(struct usb_hcd *hcd, struct urb *urb)
if (urb->transfer_buffer_length == 0)
return 0;
- /* If the caller set URB_NO_SETUP_DMA_MAP then no mapping is needed */
- if ((urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ /* if this is a scatter/gather request, it should be already mapped */
+ if (urb->num_sgs > 0)
+ return 0;
+ /*
+ * If the caller sets URB_NO_TRANSFER_DMA_MAP and urb->transfer_dma
+ * contains a valid DMA handle then it is already mapped, except
+ * if the controller can't use coherent memory (HCD_NO_COHERENT_MEM).
+ *
+ * urb->transfer_dma is set to ~0 when allocating USB buffers for
+ * PIO-based or HCD_NO_COHERENT_MEM-based controllers.
+ */
+ if ((urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) &&
+ urb->transfer_dma != ~(dma_addr_t)0 &&
+ !(hcd->driver->flags & HCD_NO_COHERENT_MEM))
return 0;
return 1;
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index bbe2b92..cde42f3 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -183,12 +183,13 @@ struct hc_driver {
irqreturn_t (*irq) (struct usb_hcd *hcd);
int flags;
-#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
-#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
-#define HCD_USB11 0x0010 /* USB 1.1 */
-#define HCD_USB2 0x0020 /* USB 2.0 */
-#define HCD_USB3 0x0040 /* USB 3.0 */
-#define HCD_MASK 0x0070
+#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
+#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
+#define HCD_NO_COHERENT_MEM 0x0004 /* HC avoids use of "coherent" mem */
+#define HCD_USB11 0x0010 /* USB 1.1 */
+#define HCD_USB2 0x0020 /* USB 2.0 */
+#define HCD_USB3 0x0040 /* USB 3.0 */
+#define HCD_MASK 0x0070
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd);
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 08/11] wii: have generic dma coherent
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
Let the Nintendo Wii gaming console use per-device dma coherent allocations.
This will be used later by some of its drivers.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/powerpc/platforms/embedded6xx/Kconfig | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 524d971..fe77ab2 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -119,6 +119,7 @@ config WII
bool "Nintendo-Wii"
depends on EMBEDDED6xx
select GAMECUBE_COMMON
+ select HAVE_GENERIC_DMA_COHERENT
help
Select WII if configuring for the Nintendo Wii.
More information at: <http://gc-linux.sourceforge.net/>
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 09/11] wii: add mem2 dma mapping ops
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
Some of the devices in the "Hollywood" chipset of the Nintendo Wii video
game console have restrictions performing DMA transfers to the first
contiguous RAM region (known as MEM1).
For example, up to 3 bytes of the last word of a DMA transfer of a
non-32 bit aligned length to MEM1 may be lost.
Such restrictions do not apply when using the second contiguous RAM
region (known as MEM2).
Add a set of DMA mapping operations which said devices can use to make
sure that DMA transfers are always performed to/from memory buffers
within MEM2.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/powerpc/boot/wii.c | 44 +++++
arch/powerpc/include/asm/wii.h | 25 +++
arch/powerpc/platforms/embedded6xx/Kconfig | 1 +
arch/powerpc/platforms/embedded6xx/Makefile | 2 +-
arch/powerpc/platforms/embedded6xx/wii-dma.c | 265 ++++++++++++++++++++++++++
5 files changed, 336 insertions(+), 1 deletions(-)
create mode 100644 arch/powerpc/include/asm/wii.h
create mode 100755 arch/powerpc/platforms/embedded6xx/wii-dma.c
diff --git a/arch/powerpc/boot/wii.c b/arch/powerpc/boot/wii.c
index 2ebaec0..84ce593 100644
--- a/arch/powerpc/boot/wii.c
+++ b/arch/powerpc/boot/wii.c
@@ -30,6 +30,7 @@ BSS_STACK(8192);
#define MEM2_TOP (0x10000000 + 64*1024*1024)
#define FIRMWARE_DEFAULT_SIZE (12*1024*1024)
+#define MEM2_DMA_DEFAULT_SIZE (512*1024)
struct mipc_infohdr {
char magic[3];
@@ -101,6 +102,42 @@ out:
}
+static char tmp_cmdline[COMMAND_LINE_SIZE];
+
+static void mem2_fixups(u32 *top, u32 *reg)
+{
+ /* ' mem2_dma=' + nnnnnnn + 'K@0x' + aaaaaaaa */
+ const int max_param_len = 10 + 7 + 4 + 8;
+ void *chosen;
+ u32 dma_base, dma_size;
+ char *p;
+
+ chosen = finddevice("/chosen");
+ if (!chosen)
+ fatal("Can't find chosen node\n");
+
+ /* the MEM2 DMA region must fit within MEM2 */
+ dma_size = MEM2_DMA_DEFAULT_SIZE;
+ if (dma_size > reg[3])
+ dma_size = reg[3];
+ /* reserve the region from the top of MEM2 */
+ *top -= dma_size;
+ dma_base = *top;
+ printf("mem2_dma: %uk@0x%08x\n", dma_size >> 10, dma_base);
+
+ /*
+ * Finally, add the MEM2 DMA region location information to the
+ * kernel command line. The wii-dma driver will pick this info up.
+ */
+ getprop(chosen, "bootargs", tmp_cmdline, COMMAND_LINE_SIZE-1);
+ p = strchr(tmp_cmdline, 0);
+ if (p - tmp_cmdline + max_param_len >= COMMAND_LINE_SIZE)
+ fatal("No space left for mem2_dma param\n");
+
+ sprintf(p, " mem2_dma=%uk@0x%08x", dma_size >> 10, dma_base);
+ setprop_str(chosen, "bootargs", tmp_cmdline);
+}
+
static void platform_fixups(void)
{
void *mem;
@@ -127,9 +164,16 @@ static void platform_fixups(void)
mem2_boundary = MEM2_TOP - FIRMWARE_DEFAULT_SIZE;
}
+ mem2_fixups(&mem2_boundary, reg);
+
if (mem2_boundary > reg[2] && mem2_boundary < reg[2] + reg[3]) {
reg[3] = mem2_boundary - reg[2];
printf("top of MEM2 @ %08X\n", reg[2] + reg[3]);
+ /*
+ * Find again the memory node as it may have changed its
+ * position after adding some non-existing properties.
+ */
+ mem = finddevice("/memory");
setprop(mem, "reg", reg, sizeof(reg));
}
diff --git a/arch/powerpc/include/asm/wii.h b/arch/powerpc/include/asm/wii.h
new file mode 100644
index 0000000..bb83c32
--- /dev/null
+++ b/arch/powerpc/include/asm/wii.h
@@ -0,0 +1,25 @@
+/*
+ * arch/powerpc/include/asm/wii.h
+ *
+ * Nintendo Wii board-specific definitions
+ * Copyright (C) 2010 The GameCube Linux Team
+ * Copyright (C) 2010 Albert Herranz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#ifndef __ASM_POWERPC_WII_H
+#define __ASM_POWERPC_WII_H
+
+/*
+ * DMA operations for the Nintendo Wii.
+ */
+extern struct dma_map_ops wii_mem2_dma_ops;
+
+extern int wii_set_mem2_dma_constraints(struct device *dev);
+extern void wii_clear_mem2_dma_constraints(struct device *dev);
+
+#endif /* __ASM_POWERPC_WII_H */
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index fe77ab2..f4fff0a 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -120,6 +120,7 @@ config WII
depends on EMBEDDED6xx
select GAMECUBE_COMMON
select HAVE_GENERIC_DMA_COHERENT
+ select SWIOTLB
help
Select WII if configuring for the Nintendo Wii.
More information at: <http://gc-linux.sourceforge.net/>
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
index 66c23e4..4d4c776 100644
--- a/arch/powerpc/platforms/embedded6xx/Makefile
+++ b/arch/powerpc/platforms/embedded6xx/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_PPC_C2K) += c2k.o
obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o
obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o
obj-$(CONFIG_GAMECUBE) += gamecube.o
-obj-$(CONFIG_WII) += wii.o hlwd-pic.o
+obj-$(CONFIG_WII) += wii.o hlwd-pic.o wii-dma.o
diff --git a/arch/powerpc/platforms/embedded6xx/wii-dma.c b/arch/powerpc/platforms/embedded6xx/wii-dma.c
new file mode 100755
index 0000000..2d3b9eb
--- /dev/null
+++ b/arch/powerpc/platforms/embedded6xx/wii-dma.c
@@ -0,0 +1,265 @@
+/*
+ * arch/powerpc/platforms/embedded6xx/wii-dma.c
+ *
+ * DMA functions for the Nintendo Wii video game console.
+ * Copyright (C) 2010 The GameCube Linux Team
+ * Copyright (C) 2010 Albert Herranz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/lmb.h>
+#include <asm/wii.h>
+
+#include "mm/mmu_decl.h"
+
+/*
+ * The Nintendo Wii video game console is a NOT_COHERENT_CACHE
+ * platform that is unable to safely perform non-32 bit uncached writes
+ * to RAM because the byte enables are not connected to the bus.
+ * Thus, in this platform, "coherent" DMA buffers cannot be directly used
+ * by the kernel code unless it guarantees that all write accesses
+ * to said buffers are done in 32 bit chunks.
+ *
+ * In addition, some of the devices in the "Hollywood" chipset have a
+ * similar restriction regarding DMA transfers: those with non-32bit
+ * aligned lengths only work when performed to/from the second contiguous
+ * region of memory (known as MEM2).
+ *
+ * To solve these issues a specific set of dma mapping operations is made
+ * available for devices requiring it. When enabled, the kernel will make
+ * sure that DMA buffers sitting in MEM1 get bounced to/from DMA buffers
+ * allocated from MEM2.
+ *
+ * Bouncing is performed with the help of the swiotlb support.
+ */
+
+/*
+ * Allocate the SWIOTLB from MEM2.
+ */
+void * __init swiotlb_alloc_boot(size_t size, unsigned long nslabs)
+{
+ return __alloc_bootmem_low(size, PAGE_SIZE,
+ wii_hole_start + wii_hole_size);
+}
+
+/*
+ * The mem2_dma "device".
+ *
+ * This device "owns" a pool of coherent MEM2 memory that can be shared among
+ * several devices requiring MEM2 DMA buffers, instead of dedicating specific
+ * pools for each device.
+ *
+ * A device can use the shared coherent MEM2 memory pool by calling
+ * wii_set_mem2_dma_constraints().
+ *
+ */
+
+struct mem2_dma {
+ struct platform_device *pdev;
+
+ dma_addr_t dma_base;
+ void *base;
+ size_t size;
+};
+
+static struct mem2_dma mem2_dma_instance;
+
+static inline struct mem2_dma *mem2_dma_get_instance(void)
+{
+ return &mem2_dma_instance;
+}
+
+static int __init mem2_dma_init(dma_addr_t dma_base, size_t size)
+{
+ struct mem2_dma *mem2_dma = mem2_dma_get_instance();
+ const int flags = DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE;
+ struct device *dev;
+ int error = 0;
+
+ mem2_dma->pdev = platform_device_register_simple("mem2_dma",
+ 0, NULL, 0);
+ if (IS_ERR(mem2_dma->pdev)) {
+ error = PTR_ERR(mem2_dma->pdev);
+ pr_err("error %d registering platform device\n", error);
+ goto err_pdev_register;
+ }
+ dev = &mem2_dma->pdev->dev;
+
+ if (!dma_declare_coherent_memory(dev, dma_base, dma_base,
+ size, flags)) {
+ dev_err(dev, "error declaring coherent memory %zu@%Lx\n",
+ size, (unsigned long long)dma_base);
+ error = -EBUSY;
+ goto err_declare_coherent;
+ }
+ mem2_dma->dma_base = dma_base;
+ mem2_dma->size = size;
+ dev_info(dev, "using %zu KiB at 0x%Lx\n", size / 1024,
+ (unsigned long long)dma_base);
+ goto out;
+
+err_declare_coherent:
+ platform_device_unregister(mem2_dma->pdev);
+err_pdev_register:
+ mem2_dma->pdev = NULL;
+out:
+ return error;
+}
+
+static __initdata dma_addr_t dma_base, dma_size;
+
+static int __init mem2_setup_parse(char *str)
+{
+ char *p, *q = str;
+
+ dma_size = memparse(q, &p);
+ if (p == q) {
+ pr_err("dma_size expected\n");
+ return -EINVAL;
+ }
+ if (*p != '@') {
+ pr_err("missing @ separator between dma_size and dma_base\n");
+ return -EINVAL;
+ }
+
+ q = p + 1;
+ dma_base = memparse(q, &p);
+ if (p == q) {
+ pr_err("dma_base expected\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+__setup("mem2_dma=", mem2_setup_parse);
+
+static int __init mem2_dma_setup(void)
+{
+ int error;
+
+ BUG_ON(dma_base < lmb_end_of_DRAM());
+ BUG_ON(dma_size == 0);
+
+ error = mem2_dma_init(dma_base, dma_size);
+ if (error)
+ pr_err("error %d during setup\n", error);
+ return error;
+}
+arch_initcall(mem2_dma_setup);
+
+/**
+ * wii_mem2_dma_dev() - returns the device "owning" the shared MEM2 DMA region
+ *
+ * Use this function to retrieve the device for which the shared pool of
+ * coherent MEM2 memory has been registered.
+ */
+static struct device *wii_mem2_dma_dev(void)
+{
+ struct mem2_dma *mem2_dma = mem2_dma_get_instance();
+ BUG_ON(!mem2_dma->pdev);
+ return &mem2_dma->pdev->dev;
+}
+
+/**
+ * wii_set_mem2_dma_constraints() - forces device to use MEM2 DMA buffers only
+ * @dev: device for which DMA constraints are defined
+ *
+ * Instructs device @dev to always use MEM2 DMA buffers for DMA transfers.
+ */
+int wii_set_mem2_dma_constraints(struct device *dev)
+{
+ struct dev_archdata *sd;
+
+ sd = &dev->archdata;
+ sd->max_direct_dma_addr = 0;
+ sd->min_direct_dma_addr = wii_hole_start + wii_hole_size;
+
+ set_dma_ops(dev, &wii_mem2_dma_ops);
+ return 0;
+}
+EXPORT_SYMBOL(wii_set_mem2_dma_constraints);
+
+/**
+ * wii_clear_mem2_dma_constraints() - clears device MEM2 DMA constraints
+ * @dev: device for which DMA constraints are cleared
+ *
+ * Instructs device @dev to stop using MEM2 DMA buffers for DMA transfers.
+ * Must be called to undo wii_set_mem2_dma_constraints().
+ */
+void wii_clear_mem2_dma_constraints(struct device *dev)
+{
+ struct dev_archdata *sd;
+
+ sd = &dev->archdata;
+ sd->max_direct_dma_addr = 0;
+ sd->min_direct_dma_addr = 0;
+
+ set_dma_ops(dev, &dma_direct_ops);
+}
+EXPORT_SYMBOL(wii_clear_mem2_dma_constraints);
+
+/*
+ * Determines if a given DMA region specified by @dma_handle
+ * requires bouncing.
+ *
+ * Bouncing is required if the DMA region falls within MEM1.
+ */
+static int mem2_needs_dmabounce(dma_addr_t dma_handle)
+{
+ return dma_handle < wii_hole_start;
+}
+
+/*
+ * Use the dma_direct_ops hooks for allocating and freeing coherent memory.
+ */
+
+static void *mem2_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ void *vaddr;
+
+ vaddr = dma_direct_ops.alloc_coherent(wii_mem2_dma_dev(), size,
+ dma_handle, gfp);
+ if (vaddr && mem2_needs_dmabounce(*dma_handle)) {
+ dma_direct_ops.free_coherent(wii_mem2_dma_dev(), size, vaddr,
+ *dma_handle);
+ dev_err(dev, "failed to allocate MEM2 coherent memory\n");
+ vaddr = NULL;
+ }
+ return vaddr;
+}
+
+static void mem2_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ dma_direct_ops.free_coherent(wii_mem2_dma_dev(), size, vaddr,
+ dma_handle);
+}
+
+/*
+ * Set of DMA operations for devices requiring MEM2 DMA buffers.
+ */
+struct dma_map_ops wii_mem2_dma_ops = {
+ .alloc_coherent = mem2_alloc_coherent,
+ .free_coherent = mem2_free_coherent,
+ .map_sg = swiotlb_map_sg_attrs,
+ .unmap_sg = swiotlb_unmap_sg_attrs,
+ .dma_supported = swiotlb_dma_supported,
+ .map_page = swiotlb_map_page,
+ .unmap_page = swiotlb_unmap_page,
+ .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,
+ .sync_sg_for_device = swiotlb_sync_sg_for_cpu,
+ .mapping_error = swiotlb_dma_mapping_error,
+};
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 10/11] wii: enable swiotlb
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
Enable the use of a software IO TLB on the Nintendo Wii video game console.
This is used by the platform DMA support code to overcome the limitations
found in some of the devices within the "Hollywood" chipset.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/powerpc/platforms/embedded6xx/wii.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c
index 57e5b60..6ad5c0a 100644
--- a/arch/powerpc/platforms/embedded6xx/wii.c
+++ b/arch/powerpc/platforms/embedded6xx/wii.c
@@ -164,6 +164,8 @@ static void __init wii_setup_arch(void)
clrbits32(hw_gpio + HW_GPIO_OUT(0),
HW_GPIO_SLOT_LED | HW_GPIO_SENSOR_BAR);
}
+ swiotlb_set_default_size(1<<20); /* 1 MB */
+ ppc_swiotlb_enable = 1;
}
static void wii_restart(char *cmd)
--
1.6.3.3
^ permalink raw reply related
* [PATCH v4 11/11] wii: hollywood ehci controller support
From: Albert Herranz @ 2010-03-12 19:12 UTC (permalink / raw)
To: linux-usb, linuxppc-dev; +Cc: Albert Herranz
In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es>
Add support for the USB Enhanced Host Controller Interface included
in the "Hollywood" chipset of the Nintendo Wii video game console.
Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
arch/powerpc/platforms/embedded6xx/Kconfig | 1 +
drivers/usb/host/Kconfig | 8 +
drivers/usb/host/ehci-hcd.c | 5 +
drivers/usb/host/ehci-hlwd.c | 233 ++++++++++++++++++++++++++++
drivers/usb/host/ehci.h | 23 +++
5 files changed, 270 insertions(+), 0 deletions(-)
create mode 100644 drivers/usb/host/ehci-hlwd.c
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index f4fff0a..63bc708 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -121,6 +121,7 @@ config WII
select GAMECUBE_COMMON
select HAVE_GENERIC_DMA_COHERENT
select SWIOTLB
+ select USB_ARCH_HAS_EHCI
help
Select WII if configuring for the Nintendo Wii.
More information at: <http://gc-linux.sourceforge.net/>
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2678a16..342954f 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -131,6 +131,14 @@ config USB_EHCI_HCD_PPC_OF
Enables support for the USB controller present on the PowerPC
OpenFirmware platform bus.
+config USB_EHCI_HCD_HLWD
+ bool "Nintendo Wii (Hollywood) EHCI USB controller support"
+ depends on USB_EHCI_HCD && WII
+ default y
+ ---help---
+ Say Y here to support the EHCI USB controller found in the
+ Hollywood chipset of the Nintendo Wii video game console.
+
config USB_W90X900_EHCI
bool "W90X900(W90P910) EHCI support"
depends on USB_EHCI_HCD && ARCH_W90X900
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1ec3857..395c6a1 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1133,6 +1133,11 @@ MODULE_LICENSE ("GPL");
#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
#endif
+#ifdef CONFIG_USB_EHCI_HCD_HLWD
+#include "ehci-hlwd.c"
+#define OF_PLATFORM_DRIVER ehci_hcd_hlwd_driver
+#endif
+
#ifdef CONFIG_XPS_USB_HCD_XILINX
#include "ehci-xilinx-of.c"
#define OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
diff --git a/drivers/usb/host/ehci-hlwd.c b/drivers/usb/host/ehci-hlwd.c
new file mode 100644
index 0000000..129e96b
--- /dev/null
+++ b/drivers/usb/host/ehci-hlwd.c
@@ -0,0 +1,233 @@
+/*
+ * drivers/usb/host/ehci-hlwd.c
+ *
+ * Nintendo Wii (Hollywood) USB Enhanced Host Controller Interface.
+ * Copyright (C) 2009-2010 The GameCube Linux Team
+ * Copyright (C) 2009,2010 Albert Herranz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Based on ehci-ppc-of.c
+ *
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus
+ * Tested on AMCC PPC 440EPx
+ *
+ * Valentine Barshak <vbarshak@ru.mvista.com>
+ *
+ * Based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
+ * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <asm/wii.h>
+
+#define DRV_MODULE_NAME "ehci-hlwd"
+#define DRV_DESCRIPTION "Nintendo Wii EHCI Host Controller"
+#define DRV_AUTHOR "Albert Herranz"
+
+/*
+ * Non-standard registers.
+ */
+#define HLWD_EHCI_CTL 0x00cc /* Controller Control */
+#define HLWD_EHCI_CTL_INTE (1<<15) /* Notify EHCI interrupts */
+
+/* called during probe() after chip reset completes */
+static int ehci_hlwd_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int error;
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ error = ehci_halt(ehci);
+ if (error)
+ goto out;
+
+ error = ehci_init(hcd);
+ if (error)
+ goto out;
+
+ /* enable notification of EHCI interrupts */
+ setbits32(hcd->regs + HLWD_EHCI_CTL, HLWD_EHCI_CTL_INTE);
+
+ ehci->sbrn = 0x20;
+ error = ehci_reset(ehci);
+ ehci_port_power(ehci, 0);
+out:
+ return error;
+}
+
+static const struct hc_driver ehci_hlwd_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Nintendo Wii EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_USB2 | HCD_NO_COHERENT_MEM,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_hlwd_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int __devinit
+ehci_hcd_hlwd_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci = NULL;
+ struct resource res;
+ int irq;
+ int error = -ENODEV;
+
+ if (usb_disabled())
+ goto out;
+
+ dev_dbg(&op->dev, "initializing " DRV_MODULE_NAME " USB Controller\n");
+
+ error = of_address_to_resource(dn, 0, &res);
+ if (error)
+ goto out;
+
+ hcd = usb_create_hcd(&ehci_hlwd_hc_driver, &op->dev, DRV_MODULE_NAME);
+ if (!hcd) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = resource_size(&res);
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ error = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ error = -EBUSY;
+ goto err_ioremap;
+ }
+
+ /* this device requires MEM2 DMA buffers */
+ error = wii_set_mem2_dma_constraints(&op->dev);
+ if (error)
+ goto err_mem2_constraints;
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ error = usb_add_hcd(hcd, irq, 0);
+ if (error == 0)
+ return 0;
+
+err_mem2_constraints:
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ usb_put_hcd(hcd);
+out:
+ return error;
+}
+
+
+static int ehci_hcd_hlwd_remove(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping " DRV_MODULE_NAME " USB Controller\n");
+
+ usb_remove_hcd(hcd);
+ wii_clear_mem2_dma_constraints(&op->dev);
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+
+static int ehci_hcd_hlwd_shutdown(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+
+ return 0;
+}
+
+
+static struct of_device_id ehci_hcd_hlwd_match[] = {
+ { .compatible = "nintendo,hollywood-usb-ehci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehci_hcd_hlwd_match);
+
+static struct of_platform_driver ehci_hcd_hlwd_driver = {
+ .name = DRV_MODULE_NAME,
+ .match_table = ehci_hcd_hlwd_match,
+ .probe = ehci_hcd_hlwd_probe,
+ .remove = ehci_hcd_hlwd_remove,
+ .shutdown = ehci_hcd_hlwd_shutdown,
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2d85e21..8fb519b 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -599,6 +599,27 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_big_endian_mmio(e) 0
#endif
+#ifdef CONFIG_USB_EHCI_HCD_HLWD
+
+/*
+ * The Nintendo Wii video game console has no PCI hardware.
+ * The USB controllers are part of the "Hollywood" chipset and are
+ * accessed via the platform internal I/O accessors.
+ */
+static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
+ __u32 __iomem *regs)
+{
+ return in_be32(regs);
+}
+
+static inline void ehci_writel(const struct ehci_hcd *ehci,
+ const unsigned int val, __u32 __iomem *regs)
+{
+ out_be32(regs, val);
+}
+
+#else
+
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
@@ -632,6 +653,8 @@ static inline void ehci_writel(const struct ehci_hcd *ehci,
#endif
}
+#endif /* CONFIG_USB_EHCI_HCD_HLWD */
+
/*
* On certain ppc-44x SoC there is a HW issue, that could only worked around with
* explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH] irq: move some interrupt arch_* functions into struct irq_chip.
From: Yinghai Lu @ 2010-03-12 19:26 UTC (permalink / raw)
To: Ian Campbell
Cc: Jeremy Fitzhardinge, x86, linux-kernel, linuxppc-dev, Ingo Molnar,
Paul Mackerras, Eric W. Biederman, H. Peter Anvin,
Thomas Gleixner
In-Reply-To: <1268387116-30522-1-git-send-email-ian.campbell@citrix.com>
On 03/12/2010 01:45 AM, Ian Campbell wrote:
> Move arch_init_copy_chip_data and arch_free_chip_data into function
> pointers in struct irq_chip since they operate on irq_desc->chip_data.
>
> arch_init_chip_data cannot be moved into struct irq_chip at this time
> because irq_desc->chip is not known at the time the irq_desc is
> setup. For now rename arch_init_chip_data to arch_init_irq_desc (for
> PowerPC, the only other user, whose usage better matches the new name)
> and on x86 convert arch_init_chip_data to x86_init_chip_data and
> call this whenever a new struct irq_desc is allocated.
>
> I've retained the chip_data behaviour for uv_irq although it isn't
> clear to me if these interrupt types support migration or how closely
> related to the APIC modes they really are. If it weren't for this the
> x86_{init,copy,free}_chip_data functions could be static to
> io_apic.c.
>
> I've tested by booting on a 64 bit system, but it's not clear to me
> what actions I need to take to actually exercise some of these code
> paths.
>
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> Acked-by: Michael Ellerman <michael@ellerman.id.au> [PowerPC rename portion]
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: H. Peter Anvin <hpa@zytor.com>
> Cc: Eric W. Biederman <ebiederm@xmission.com>
> Cc: Yinghai Lu <yinghai@kernel.org>
> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: x86@kernel.org
> Cc: linuxppc-dev@ozlabs.org
> Cc: linux-kernel@vger.kernel.org
> ---
> arch/powerpc/kernel/irq.c | 2 +-
> arch/x86/include/asm/hw_irq.h | 11 +++++++-
> arch/x86/kernel/apic/io_apic.c | 58 +++++++++++++++++++++++++++++++++++++---
> arch/x86/kernel/uv_irq.c | 5 +++
> include/linux/interrupt.h | 2 +-
> include/linux/irq.h | 12 +++++---
> kernel/irq/handle.c | 2 +-
> kernel/irq/numa_migrate.c | 12 +++++++-
> kernel/softirq.c | 3 +-
> 9 files changed, 91 insertions(+), 16 deletions(-)
>
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 64f6f20..002d87f 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -1088,7 +1088,7 @@ int arch_early_irq_init(void)
> return 0;
> }
>
> -int arch_init_chip_data(struct irq_desc *desc, int node)
> +int arch_init_irq_desc(struct irq_desc *desc, int node)
> {
> desc->status |= IRQ_NOREQUEST;
> return 0;
> diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
> index a929c9e..1bc7063 100644
> --- a/arch/x86/include/asm/hw_irq.h
> +++ b/arch/x86/include/asm/hw_irq.h
> @@ -20,9 +20,9 @@
> #include <linux/percpu.h>
> #include <linux/profile.h>
> #include <linux/smp.h>
> +#include <linux/irq.h>
>
> #include <asm/atomic.h>
> -#include <asm/irq.h>
> #include <asm/sections.h>
>
> /* Interrupt handlers registered during init_IRQ */
> @@ -61,6 +61,15 @@ extern void init_VISWS_APIC_irqs(void);
> extern void setup_IO_APIC(void);
> extern void disable_IO_APIC(void);
>
> +extern int x86_init_chip_data(struct irq_desc *desc, int node);
> +
> +#ifdef CONFIG_SPARSE_IRQ
> +extern void x86_copy_chip_data(struct irq_desc *old_desc,
> + struct irq_desc *desc, int node);
> +extern void x86_free_chip_data(struct irq_desc *old_desc,
> + struct irq_desc *desc);
> +#endif
> +
> struct io_apic_irq_attr {
> int ioapic;
> int ioapic_pin;
> diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
> index e4e0ddc..12e5cf4 100644
> --- a/arch/x86/kernel/apic/io_apic.c
> +++ b/arch/x86/kernel/apic/io_apic.c
> @@ -211,7 +211,7 @@ static struct irq_cfg *get_one_free_irq_cfg(int node)
> return cfg;
> }
>
> -int arch_init_chip_data(struct irq_desc *desc, int node)
> +int x86_init_chip_data(struct irq_desc *desc, int node)
> {
> struct irq_cfg *cfg;
>
> @@ -287,8 +287,8 @@ static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
> old_cfg->irq_2_pin = NULL;
> }
>
> -void arch_init_copy_chip_data(struct irq_desc *old_desc,
> - struct irq_desc *desc, int node)
> +void x86_copy_chip_data(struct irq_desc *old_desc,
> + struct irq_desc *desc, int node)
> {
> struct irq_cfg *cfg;
> struct irq_cfg *old_cfg;
> @@ -312,7 +312,7 @@ static void free_irq_cfg(struct irq_cfg *old_cfg)
> kfree(old_cfg);
> }
>
> -void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
> +void x86_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
> {
> struct irq_cfg *old_cfg, *cfg;
>
> @@ -336,6 +336,11 @@ struct irq_cfg *irq_cfg(unsigned int irq)
> return irq < nr_irqs ? irq_cfgx + irq : NULL;
> }
>
> +int x86_init_chip_data(struct irq_desc *desc, int node)
> +{
> + return 0;
> +}
> +
you could put one dummy x86_copy_chip_data and x86_free_chip_data here too.
> #endif
>
> struct io_apic {
> @@ -1520,6 +1525,7 @@ static void __init setup_IO_APIC_irqs(void)
> printk(KERN_INFO "can not get irq_desc for %d\n", irq);
> continue;
> }
> + x86_init_chip_data(desc, node);
> cfg = desc->chip_data;
> add_pin_to_irq_node(cfg, node, apic_id, pin);
> /*
> @@ -1570,6 +1576,7 @@ void setup_IO_APIC_irq_extra(u32 gsi)
> printk(KERN_INFO "can not get irq_desc for %d\n", irq);
> return;
> }
> + x86_init_chip_data(desc, node);
>
> cfg = desc->chip_data;
> add_pin_to_irq_node(cfg, node, apic_id, pin);
> @@ -2739,6 +2746,11 @@ static struct irq_chip ioapic_chip __read_mostly = {
> .set_affinity = set_ioapic_affinity_irq,
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> static struct irq_chip ir_ioapic_chip __read_mostly = {
> @@ -2754,6 +2766,11 @@ static struct irq_chip ir_ioapic_chip __read_mostly = {
> #endif
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> static inline void init_IO_APIC_traps(void)
> @@ -3261,6 +3278,7 @@ unsigned int create_irq_nr(unsigned int irq_want, int node)
> printk(KERN_INFO "can not get irq_desc for %d\n", new);
> continue;
> }
> + x86_init_chip_data(desc_new, node);
> cfg_new = desc_new->chip_data;
>
> if (cfg_new->vector != 0)
> @@ -3466,6 +3484,11 @@ static struct irq_chip msi_chip = {
> .set_affinity = set_msi_irq_affinity,
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> static struct irq_chip msi_ir_chip = {
> @@ -3479,6 +3502,11 @@ static struct irq_chip msi_ir_chip = {
> #endif
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> /*
> @@ -3638,6 +3666,11 @@ static struct irq_chip dmar_msi_type = {
> .set_affinity = dmar_msi_set_affinity,
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> int arch_setup_dmar_msi(unsigned int irq)
> @@ -3695,6 +3728,11 @@ static struct irq_chip ir_hpet_msi_type = {
> #endif
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> static struct irq_chip hpet_msi_type = {
> @@ -3706,6 +3744,11 @@ static struct irq_chip hpet_msi_type = {
> .set_affinity = hpet_msi_set_affinity,
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
> @@ -3792,6 +3835,11 @@ static struct irq_chip ht_irq_chip = {
> .set_affinity = set_ht_irq_affinity,
> #endif
> .retrigger = ioapic_retrigger_irq,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
> @@ -3919,6 +3967,7 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq,
> printk(KERN_INFO "can not get irq_desc %d\n", irq);
> return 0;
> }
> + x86_init_chip_data(desc, node);
>
> pin = irq_attr->ioapic_pin;
> trigger = irq_attr->trigger;
> @@ -4313,6 +4362,7 @@ void __init pre_init_apic_IRQ0(void)
> phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
> #endif
> desc = irq_to_desc_alloc_node(0, 0);
> + x86_init_chip_data(desc, 0);
>
> setup_local_APIC();
>
> diff --git a/arch/x86/kernel/uv_irq.c b/arch/x86/kernel/uv_irq.c
> index ece73d8..df2c6d6 100644
> --- a/arch/x86/kernel/uv_irq.c
> +++ b/arch/x86/kernel/uv_irq.c
> @@ -55,6 +55,11 @@ struct irq_chip uv_irq_chip = {
> .eoi = uv_ack_apic,
> .end = uv_noop,
> .set_affinity = uv_set_irq_affinity,
> +
> +#ifdef CONFIG_SPARSE_IRQ
> + .copy_chip_data = x86_copy_chip_data,
> + .free_chip_data = x86_free_chip_data,
> +#endif
> };
>
> /*
> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> index 75f3f00..cc4cd22 100644
> --- a/include/linux/interrupt.h
> +++ b/include/linux/interrupt.h
> @@ -611,6 +611,6 @@ struct irq_desc;
> extern int early_irq_init(void);
> extern int arch_probe_nr_irqs(void);
> extern int arch_early_irq_init(void);
> -extern int arch_init_chip_data(struct irq_desc *desc, int node);
> +extern int arch_init_irq_desc(struct irq_desc *desc, int node);
>
> #endif
> diff --git a/include/linux/irq.h b/include/linux/irq.h
> index 707ab12..558bd2d 100644
> --- a/include/linux/irq.h
> +++ b/include/linux/irq.h
> @@ -131,6 +131,14 @@ struct irq_chip {
> void (*bus_lock)(unsigned int irq);
> void (*bus_sync_unlock)(unsigned int irq);
>
> + /* for move_irq_desc */
> +#ifdef CONFIG_SPARSE_IRQ
> + void (*copy_chip_data)(struct irq_desc *old_desc,
> + struct irq_desc *desc, int node);
> + void (*free_chip_data)(struct irq_desc *old_desc,
> + struct irq_desc *desc);
> +#endif
> +
> /* Currently used only by UML, might disappear one day.*/
> #ifdef CONFIG_IRQ_RELEASE_METHOD
> void (*release)(unsigned int irq, void *dev_id);
> @@ -208,10 +216,6 @@ struct irq_desc {
> const char *name;
> } ____cacheline_internodealigned_in_smp;
>
> -extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
> - struct irq_desc *desc, int node);
> -extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
> -
> #ifndef CONFIG_SPARSE_IRQ
> extern struct irq_desc irq_desc[NR_IRQS];
> #endif
> diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
> index 76d5a67..168e2f8 100644
> --- a/kernel/irq/handle.c
> +++ b/kernel/irq/handle.c
> @@ -120,7 +120,6 @@ static void init_one_irq_desc(int irq, struct irq_desc *desc, int node)
> BUG_ON(1);
> }
> init_desc_masks(desc);
> - arch_init_chip_data(desc, node);
> }
>
> /*
> @@ -228,6 +227,7 @@ struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
> BUG_ON(1);
> }
> init_one_irq_desc(irq, desc, node);
> + arch_init_irq_desc(desc, node);
you move out init_chip_data for x86 out of irq_to_desc_alloc_node
current init_chip_data in irq_to_desc_alloc_node is protected by sparse_irq_lock.
wonder if you could let arch_init_irq_desc for x86 to call x86_init_chip_data?
or let add another irq_to_desc_alloc_node_f to take extra func call.
like
typedef int (*init_chip_data_f)(struct irq_desc *desc, int node);
struct irq_desc * __ref irq_to_desc_alloc_node_f(unsigned int irq, int node, init_chip_data_f *f);
struct irq_desc * __ref irq_to_desc_alloc_node_f(unsigned int irq, int node)
{
irq_to_desc_alloc_node(irq, node, NULL);
}
then for x86
int arch_init_irq_desc(struct irq_desc *desc, int node, init_chip_data_f *f)
{
if (!f)
return x86_init_chip_data(desc, node);
f(desc, node);
}
after that xen could use
irq_to_desc_alloc_node_f(irq, node, xen_init_chip_data);
as need...
at last we don't need to call x86_init_chip_data everywhere.
Thanks
Yinghai
^ permalink raw reply
* Re: [PATCH 3/4] of/gpio: Implement GPIOLIB notifier hooks
From: Andrew Morton @ 2010-03-12 21:07 UTC (permalink / raw)
To: Anton Vorontsov
Cc: David Brownell, Dmitry Eremin-Solenikov, linux-kernel,
linuxppc-dev, Bill Gatliff
In-Reply-To: <20100205203236.GC1475@oksana.dev.rtsoft.ru>
On Fri, 5 Feb 2010 23:32:36 +0300
Anton Vorontsov <avorontsov@ru.mvista.com> wrote:
> This patch implements GPIOLIB notifier hooks, and thus makes device-enabled
> GPIO chips (i.e. the ones that have gpio_chip->dev specified) automatically
> attached to the OpenFirmware subsystem. Which means that now we can handle
> I2C and SPI GPIO chips almost* transparently.
>
> ...
>
> +static int of_gpiochip_register_simple(struct gpio_chip *chip,
> + struct device_node *np)
Why is this called "register_simple" but the unregistration function
isn't called "unregister_simple"?
> +{
> + struct of_gpio_chip *of_gc;
> +
> + if (np->data) {
> + WARN_ON(1);
> + return -EBUSY;
> + }
> +
> + of_gc = kzalloc(sizeof(*of_gc), GFP_KERNEL);
> + if (!of_gc)
> + return -ENOMEM;
> +
> + of_gc->gpio_cells = 2;
> + of_gc->xlate = of_gpio_simple_xlate;
> + of_gc->chip = chip;
> + np->data = of_gc;
> + of_node_get(np);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(of_gpiochip_register_simple);
Makes no sense to export a static symbol and to provide no declaration
of it in a .h file. I assume the export was unintended.
My plot is somewhat lost. Grant, could you please summarise in
easy-for-akpm-to-understand terms what your issues are with this
patchset and how you think we should proceed?
Thanks.
^ permalink raw reply
* Re: [PATCH 3/4] of/gpio: Implement GPIOLIB notifier hooks
From: Grant Likely @ 2010-03-12 21:38 UTC (permalink / raw)
To: Andrew Morton
Cc: David Brownell, Dmitry Eremin-Solenikov, linux-kernel,
linuxppc-dev, Bill Gatliff, Anton Vorontsov
In-Reply-To: <20100312130723.43308ccd.akpm@linux-foundation.org>
On Fri, Mar 12, 2010 at 2:07 PM, Andrew Morton
<akpm@linux-foundation.org> wrote:
> On Fri, 5 Feb 2010 23:32:36 +0300
> Anton Vorontsov <avorontsov@ru.mvista.com> wrote:
>
>> This patch implements GPIOLIB notifier hooks, and thus makes device-enab=
led
>> GPIO chips (i.e. the ones that have gpio_chip->dev specified) automatica=
lly
>> attached to the OpenFirmware subsystem. Which means that now we can hand=
le
>> I2C and SPI GPIO chips almost* transparently.
>>
>> ...
>>
>> +static int of_gpiochip_register_simple(struct gpio_chip *chip,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0struct device_node *np)
>
> Why is this called "register_simple" but the unregistration function
> isn't called "unregister_simple"?
>
>> +{
>> + =A0 =A0 struct of_gpio_chip *of_gc;
>> +
>> + =A0 =A0 if (np->data) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 WARN_ON(1);
>> + =A0 =A0 =A0 =A0 =A0 =A0 return -EBUSY;
>> + =A0 =A0 }
>> +
>> + =A0 =A0 of_gc =3D kzalloc(sizeof(*of_gc), GFP_KERNEL);
>> + =A0 =A0 if (!of_gc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
>> +
>> + =A0 =A0 of_gc->gpio_cells =3D 2;
>> + =A0 =A0 of_gc->xlate =3D of_gpio_simple_xlate;
>> + =A0 =A0 of_gc->chip =3D chip;
>> + =A0 =A0 np->data =3D of_gc;
>> + =A0 =A0 of_node_get(np);
>> +
>> + =A0 =A0 return 0;
>> +}
>> +EXPORT_SYMBOL(of_gpiochip_register_simple);
>
> Makes no sense to export a static symbol and to provide no declaration
> of it in a .h file. =A0I assume the export was unintended.
>
>
> My plot is somewhat lost. =A0Grant, could you please summarise in
> easy-for-akpm-to-understand terms what your issues are with this
> patchset and how you think we should proceed?
Sure.
I suggested the notifier approach in the first place, but now that I
see what is required to implement it I don't like it. I also don't
like the potential race condition between registering GPIO devices and
registering the OF gpio notifier. It is simpler and less code to put
the of_gpio hook directly into the GPIO registration path. If
CONFIG_OF is not set, then the OF hooks can resolve to empty static
inline functions.
How to proceed: I'd like to leave this series out for the 2.6.34
cycle and I'll pick it into my OF tree before the 2.6.35 merge window,
but I'll probably modify it to call the OF hooks directly and leave
out the unnecessary notifier infrastructure.
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: Freescale MPC5554 device tree (was: cross-compiling Linux for PowerPC e200 core?)
From: David Gibson @ 2010-03-12 22:36 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, Németh Márton
In-Reply-To: <fa686aa41003120414j48825e7cr952336703fe03b04@mail.gmail.com>
On Fri, Mar 12, 2010 at 05:14:56AM -0700, Grant Likely wrote:
> 2010/3/11 Németh Márton <nm127@freemail.hu>:
[snip]
> > +
> > + cpus {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + cpu@0 {
> > + device_type = "cpu";
> > + compatible = "PowerPC,5554";
>
> I'd rather see the same convention used here as for all the other
> compatible values in this file. ie:
>
> compatible = "fsl,mpc5554-e200z6", "fsl,powerpc-e200z6";
>
> Dave, what do you think?
Well, you could add those too, but "PowerPC,5554" should probably
remain.
The historical background here is that in the original OF spec, driver
matching was done on node name, and only then on compatible.
Essentially the node name was treated as an implicit first entry in
the compatible list. The the generic names convention came along, and
instead name became a human readable generic type for the device
("ethernet", "i2c", etc..).
That convention has been widely used since long before flat trees
existed, but for some reason it was never really used for cpu nodes;
they remained as "PowerPC,XXXX" or whatever. Because the varying
names of cpu nodes was sometimes awkward to deal with in bootloaders,
we decided it would be sensible to apply the generic names convention
here too, so "cpu@X". But then, the previous node name, which was
treated as being prepended to compatible, should now explicitly be put
into compatible.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: Problem with PCI bus rescan on 460EX
From: Felix Radensky @ 2010-03-12 23:04 UTC (permalink / raw)
To: Kenji Kaneshige; +Cc: linux-pci, Alex Chiang, linuxppc-dev@ozlabs.org
In-Reply-To: <4B9A07D2.4060801@jp.fujitsu.com>
Hello Kenji-san,
Kenji Kaneshige wrote:
> I'm not sure, but I guess pci_setup_bridge() didn't update IO base/limit
> and Mem base/limit of the bridge (0000:00:02.0) because of the following
> lines.
>
> static void pci_setup_bridge(struct pci_bus *bus)
> {
> struct pci_dev *bridge = bus->self;
> struct resource *res;
> struct pci_bus_region region;
> u32 l, bu, lu, io_upper16;
>
> if (pci_is_enabled(bridge))
> <===============================
> return; <===============================
>
> dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
> bus->secondary, bus->subordinate);
> ...
>
> It seems the bridge was already enabled by
> pci_assign_unassigned_resources()
> at boot time. Does removing those lines make any change?
>
Yes, with these lines removed bridge memory window is properly allocated.
For some reason bridge memory is disabled, but if I enable it via
setpci, and
also enable device memory, then everything works fine. If the system is
booted
when device behind the bridge is plugged in, bridge memory is enabled.
Thanks a lot for your help.
Felix.
^ permalink raw reply
* Re: Freescale MPC5554 device tree (was: cross-compiling Linux for PowerPC e200 core?)
From: Grant Likely @ 2010-03-12 23:04 UTC (permalink / raw)
To: Grant Likely, Németh Márton, linuxppc-dev
In-Reply-To: <20100312223647.GM11655@yookeroo>
On Fri, Mar 12, 2010 at 3:36 PM, David Gibson
<david@gibson.dropbear.id.au> wrote:
> On Fri, Mar 12, 2010 at 05:14:56AM -0700, Grant Likely wrote:
>> 2010/3/11 N=E9meth M=E1rton <nm127@freemail.hu>:
> [snip]
>> > +
>> > + =A0 =A0 =A0 cpus {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #address-cells =3D <1>;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 #size-cells =3D <0>;
>> > +
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 cpu@0 {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 device_type =3D "cpu";
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "PowerPC,=
5554";
>>
>> I'd rather see the same convention used here as for all the other
>> compatible values in this file. =A0ie:
>>
>> compatible =3D "fsl,mpc5554-e200z6", "fsl,powerpc-e200z6";
>>
>> Dave, what do you think?
>
> Well, you could add those too, but "PowerPC,5554" should probably
> remain.
>
> The historical background here is that in the original OF spec, driver
> matching was done on node name, and only then on compatible.
> Essentially the node name was treated as an implicit first entry in
> the compatible list. =A0The the generic names convention came along, and
> instead name became a human readable generic type for the device
> ("ethernet", "i2c", etc..).
>
> That convention has been widely used since long before flat trees
> existed, but for some reason it was never really used for cpu nodes;
> they remained as "PowerPC,XXXX" or whatever. =A0Because the varying
> names of cpu nodes was sometimes awkward to deal with in bootloaders,
> we decided it would be sensible to apply the generic names convention
> here too, so "cpu@X". =A0But then, the previous node name, which was
> treated as being prepended to compatible, should now explicitly be put
> into compatible.
In this particular case, we're talking about a part that has never
previously been described in a device tree. So, since this is
something entirely new, what is the value in preserving the
PowerPC,XXXX style when there isn't any code that will be relying on
it?
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH] use correct ccr bit for syscall error status
From: Nathan Lynch @ 2010-03-12 23:16 UTC (permalink / raw)
To: linuxppc-dev
The powerpc implementations of syscall_get_error and
syscall_set_return_value should use CCR0:S0 (0x10000000) for testing
and setting syscall error status. Fortunately these APIs don't seem
to be used at the moment.
Signed-off-by: Nathan Lynch <ntl@pobox.com>
---
arch/powerpc/include/asm/syscall.h | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index efa7f0b..23913e9 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -30,7 +30,7 @@ static inline void syscall_rollback(struct task_struct *task,
static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
- return (regs->ccr & 0x1000) ? -regs->gpr[3] : 0;
+ return (regs->ccr & 0x10000000) ? -regs->gpr[3] : 0;
}
static inline long syscall_get_return_value(struct task_struct *task,
@@ -44,10 +44,10 @@ static inline void syscall_set_return_value(struct task_struct *task,
int error, long val)
{
if (error) {
- regs->ccr |= 0x1000L;
+ regs->ccr |= 0x10000000L;
regs->gpr[3] = -error;
} else {
- regs->ccr &= ~0x1000L;
+ regs->ccr &= ~0x10000000L;
regs->gpr[3] = val;
}
}
--
1.6.0.6
^ permalink raw reply related
* Re: [PATCH] irq: move some interrupt arch_* functions into struct irq_chip.
From: Eric W. Biederman @ 2010-03-13 0:29 UTC (permalink / raw)
To: Yinghai Lu
Cc: Jeremy Fitzhardinge, Ian Campbell, x86, linux-kernel,
linuxppc-dev, Ingo Molnar, Paul Mackerras, H. Peter Anvin,
Thomas Gleixner
In-Reply-To: <4B9A954A.40205@kernel.org>
Yinghai Lu <yinghai@kernel.org> writes:
> On 03/12/2010 01:45 AM, Ian Campbell wrote:
>> Move arch_init_copy_chip_data and arch_free_chip_data into function
>> pointers in struct irq_chip since they operate on irq_desc->chip_data.
>>
>> arch_init_chip_data cannot be moved into struct irq_chip at this time
>> because irq_desc->chip is not known at the time the irq_desc is
>> setup. For now rename arch_init_chip_data to arch_init_irq_desc (for
>> PowerPC, the only other user, whose usage better matches the new name)
>> and on x86 convert arch_init_chip_data to x86_init_chip_data and
>> call this whenever a new struct irq_desc is allocated.
>>
>> I've retained the chip_data behaviour for uv_irq although it isn't
>> clear to me if these interrupt types support migration or how closely
>> related to the APIC modes they really are. If it weren't for this the
>> x86_{init,copy,free}_chip_data functions could be static to
>> io_apic.c.
>>
>> I've tested by booting on a 64 bit system, but it's not clear to me
>> what actions I need to take to actually exercise some of these code
>> paths.
>>
>> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
>> Acked-by: Michael Ellerman <michael@ellerman.id.au> [PowerPC rename portion]
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> Cc: Ingo Molnar <mingo@redhat.com>
>> Cc: H. Peter Anvin <hpa@zytor.com>
>> Cc: Eric W. Biederman <ebiederm@xmission.com>
>> Cc: Yinghai Lu <yinghai@kernel.org>
>> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> Cc: Paul Mackerras <paulus@samba.org>
>> Cc: x86@kernel.org
>> Cc: linuxppc-dev@ozlabs.org
>> Cc: linux-kernel@vger.kernel.org
>> ---
>> arch/powerpc/kernel/irq.c | 2 +-
>> arch/x86/include/asm/hw_irq.h | 11 +++++++-
>> arch/x86/kernel/apic/io_apic.c | 58 +++++++++++++++++++++++++++++++++++++---
>> arch/x86/kernel/uv_irq.c | 5 +++
>> include/linux/interrupt.h | 2 +-
>> include/linux/irq.h | 12 +++++---
>> kernel/irq/handle.c | 2 +-
>> kernel/irq/numa_migrate.c | 12 +++++++-
>> kernel/softirq.c | 3 +-
>> 9 files changed, 91 insertions(+), 16 deletions(-)
>>
>> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
>> index 64f6f20..002d87f 100644
>> --- a/arch/powerpc/kernel/irq.c
>> +++ b/arch/powerpc/kernel/irq.c
>> @@ -1088,7 +1088,7 @@ int arch_early_irq_init(void)
>> return 0;
>> }
>>
>> -int arch_init_chip_data(struct irq_desc *desc, int node)
>> +int arch_init_irq_desc(struct irq_desc *desc, int node)
>> {
>> desc->status |= IRQ_NOREQUEST;
>> return 0;
>> diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
>> index a929c9e..1bc7063 100644
>> --- a/arch/x86/include/asm/hw_irq.h
>> +++ b/arch/x86/include/asm/hw_irq.h
>> @@ -20,9 +20,9 @@
>> #include <linux/percpu.h>
>> #include <linux/profile.h>
>> #include <linux/smp.h>
>> +#include <linux/irq.h>
>>
>> #include <asm/atomic.h>
>> -#include <asm/irq.h>
>> #include <asm/sections.h>
>>
>> /* Interrupt handlers registered during init_IRQ */
>> @@ -61,6 +61,15 @@ extern void init_VISWS_APIC_irqs(void);
>> extern void setup_IO_APIC(void);
>> extern void disable_IO_APIC(void);
>>
>> +extern int x86_init_chip_data(struct irq_desc *desc, int node);
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> +extern void x86_copy_chip_data(struct irq_desc *old_desc,
>> + struct irq_desc *desc, int node);
>> +extern void x86_free_chip_data(struct irq_desc *old_desc,
>> + struct irq_desc *desc);
>> +#endif
>> +
>> struct io_apic_irq_attr {
>> int ioapic;
>> int ioapic_pin;
>> diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
>> index e4e0ddc..12e5cf4 100644
>> --- a/arch/x86/kernel/apic/io_apic.c
>> +++ b/arch/x86/kernel/apic/io_apic.c
>> @@ -211,7 +211,7 @@ static struct irq_cfg *get_one_free_irq_cfg(int node)
>> return cfg;
>> }
>>
>> -int arch_init_chip_data(struct irq_desc *desc, int node)
>> +int x86_init_chip_data(struct irq_desc *desc, int node)
>> {
>> struct irq_cfg *cfg;
>>
>> @@ -287,8 +287,8 @@ static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
>> old_cfg->irq_2_pin = NULL;
>> }
>>
>> -void arch_init_copy_chip_data(struct irq_desc *old_desc,
>> - struct irq_desc *desc, int node)
>> +void x86_copy_chip_data(struct irq_desc *old_desc,
>> + struct irq_desc *desc, int node)
>> {
>> struct irq_cfg *cfg;
>> struct irq_cfg *old_cfg;
>> @@ -312,7 +312,7 @@ static void free_irq_cfg(struct irq_cfg *old_cfg)
>> kfree(old_cfg);
>> }
>>
>> -void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
>> +void x86_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
>> {
>> struct irq_cfg *old_cfg, *cfg;
>>
>> @@ -336,6 +336,11 @@ struct irq_cfg *irq_cfg(unsigned int irq)
>> return irq < nr_irqs ? irq_cfgx + irq : NULL;
>> }
>>
>> +int x86_init_chip_data(struct irq_desc *desc, int node)
>> +{
>> + return 0;
>> +}
>> +
>
> you could put one dummy x86_copy_chip_data and x86_free_chip_data here too.
>
>> #endif
>>
>> struct io_apic {
>> @@ -1520,6 +1525,7 @@ static void __init setup_IO_APIC_irqs(void)
>> printk(KERN_INFO "can not get irq_desc for %d\n", irq);
>> continue;
>> }
>> + x86_init_chip_data(desc, node);
>> cfg = desc->chip_data;
>> add_pin_to_irq_node(cfg, node, apic_id, pin);
>> /*
>> @@ -1570,6 +1576,7 @@ void setup_IO_APIC_irq_extra(u32 gsi)
>> printk(KERN_INFO "can not get irq_desc for %d\n", irq);
>> return;
>> }
>> + x86_init_chip_data(desc, node);
>>
>> cfg = desc->chip_data;
>> add_pin_to_irq_node(cfg, node, apic_id, pin);
>> @@ -2739,6 +2746,11 @@ static struct irq_chip ioapic_chip __read_mostly = {
>> .set_affinity = set_ioapic_affinity_irq,
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> static struct irq_chip ir_ioapic_chip __read_mostly = {
>> @@ -2754,6 +2766,11 @@ static struct irq_chip ir_ioapic_chip __read_mostly = {
>> #endif
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> static inline void init_IO_APIC_traps(void)
>> @@ -3261,6 +3278,7 @@ unsigned int create_irq_nr(unsigned int irq_want, int node)
>> printk(KERN_INFO "can not get irq_desc for %d\n", new);
>> continue;
>> }
>> + x86_init_chip_data(desc_new, node);
>> cfg_new = desc_new->chip_data;
>>
>> if (cfg_new->vector != 0)
>> @@ -3466,6 +3484,11 @@ static struct irq_chip msi_chip = {
>> .set_affinity = set_msi_irq_affinity,
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> static struct irq_chip msi_ir_chip = {
>> @@ -3479,6 +3502,11 @@ static struct irq_chip msi_ir_chip = {
>> #endif
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> /*
>> @@ -3638,6 +3666,11 @@ static struct irq_chip dmar_msi_type = {
>> .set_affinity = dmar_msi_set_affinity,
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> int arch_setup_dmar_msi(unsigned int irq)
>> @@ -3695,6 +3728,11 @@ static struct irq_chip ir_hpet_msi_type = {
>> #endif
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> static struct irq_chip hpet_msi_type = {
>> @@ -3706,6 +3744,11 @@ static struct irq_chip hpet_msi_type = {
>> .set_affinity = hpet_msi_set_affinity,
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
>> @@ -3792,6 +3835,11 @@ static struct irq_chip ht_irq_chip = {
>> .set_affinity = set_ht_irq_affinity,
>> #endif
>> .retrigger = ioapic_retrigger_irq,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
>> @@ -3919,6 +3967,7 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq,
>> printk(KERN_INFO "can not get irq_desc %d\n", irq);
>> return 0;
>> }
>> + x86_init_chip_data(desc, node);
>>
>> pin = irq_attr->ioapic_pin;
>> trigger = irq_attr->trigger;
>> @@ -4313,6 +4362,7 @@ void __init pre_init_apic_IRQ0(void)
>> phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
>> #endif
>> desc = irq_to_desc_alloc_node(0, 0);
>> + x86_init_chip_data(desc, 0);
>>
>> setup_local_APIC();
>>
>> diff --git a/arch/x86/kernel/uv_irq.c b/arch/x86/kernel/uv_irq.c
>> index ece73d8..df2c6d6 100644
>> --- a/arch/x86/kernel/uv_irq.c
>> +++ b/arch/x86/kernel/uv_irq.c
>> @@ -55,6 +55,11 @@ struct irq_chip uv_irq_chip = {
>> .eoi = uv_ack_apic,
>> .end = uv_noop,
>> .set_affinity = uv_set_irq_affinity,
>> +
>> +#ifdef CONFIG_SPARSE_IRQ
>> + .copy_chip_data = x86_copy_chip_data,
>> + .free_chip_data = x86_free_chip_data,
>> +#endif
>> };
>>
>> /*
>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>> index 75f3f00..cc4cd22 100644
>> --- a/include/linux/interrupt.h
>> +++ b/include/linux/interrupt.h
>> @@ -611,6 +611,6 @@ struct irq_desc;
>> extern int early_irq_init(void);
>> extern int arch_probe_nr_irqs(void);
>> extern int arch_early_irq_init(void);
>> -extern int arch_init_chip_data(struct irq_desc *desc, int node);
>> +extern int arch_init_irq_desc(struct irq_desc *desc, int node);
>>
>> #endif
>> diff --git a/include/linux/irq.h b/include/linux/irq.h
>> index 707ab12..558bd2d 100644
>> --- a/include/linux/irq.h
>> +++ b/include/linux/irq.h
>> @@ -131,6 +131,14 @@ struct irq_chip {
>> void (*bus_lock)(unsigned int irq);
>> void (*bus_sync_unlock)(unsigned int irq);
>>
>> + /* for move_irq_desc */
>> +#ifdef CONFIG_SPARSE_IRQ
>> + void (*copy_chip_data)(struct irq_desc *old_desc,
>> + struct irq_desc *desc, int node);
>> + void (*free_chip_data)(struct irq_desc *old_desc,
>> + struct irq_desc *desc);
>> +#endif
>> +
>> /* Currently used only by UML, might disappear one day.*/
>> #ifdef CONFIG_IRQ_RELEASE_METHOD
>> void (*release)(unsigned int irq, void *dev_id);
>> @@ -208,10 +216,6 @@ struct irq_desc {
>> const char *name;
>> } ____cacheline_internodealigned_in_smp;
>>
>> -extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
>> - struct irq_desc *desc, int node);
>> -extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
>> -
>> #ifndef CONFIG_SPARSE_IRQ
>> extern struct irq_desc irq_desc[NR_IRQS];
>> #endif
>> diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
>> index 76d5a67..168e2f8 100644
>> --- a/kernel/irq/handle.c
>> +++ b/kernel/irq/handle.c
>> @@ -120,7 +120,6 @@ static void init_one_irq_desc(int irq, struct irq_desc *desc, int node)
>> BUG_ON(1);
>> }
>> init_desc_masks(desc);
>> - arch_init_chip_data(desc, node);
>> }
>>
>> /*
>> @@ -228,6 +227,7 @@ struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
>> BUG_ON(1);
>> }
>> init_one_irq_desc(irq, desc, node);
>> + arch_init_irq_desc(desc, node);
>
> you move out init_chip_data for x86 out of irq_to_desc_alloc_node
> current init_chip_data in irq_to_desc_alloc_node is protected by sparse_irq_lock.
>
>
> wonder if you could let arch_init_irq_desc for x86 to call x86_init_chip_data?
>
> or let add another irq_to_desc_alloc_node_f to take extra func call.
>
> like
> typedef int (*init_chip_data_f)(struct irq_desc *desc, int node);
> struct irq_desc * __ref irq_to_desc_alloc_node_f(unsigned int irq, int node, init_chip_data_f *f);
>
> struct irq_desc * __ref irq_to_desc_alloc_node_f(unsigned int irq, int node)
> {
> irq_to_desc_alloc_node(irq, node, NULL);
> }
>
> then for x86
>
> int arch_init_irq_desc(struct irq_desc *desc, int node, init_chip_data_f *f)
> {
> if (!f)
> return x86_init_chip_data(desc, node);
> f(desc, node);
> }
>
> after that xen could use
> irq_to_desc_alloc_node_f(irq, node, xen_init_chip_data);
>
> as need...
>
> at last we don't need to call x86_init_chip_data everywhere.
Either that or we could have an arch specific wrapper say
"x86_irq_to_desc_alloc_node" that simply wraps irq_to_desc_alloc_node,
with the little extras we need. This assumes that none of the
initialization has to happen inside of the lock an arch specific
wrapper makes sense.
Let's evaluate this set of patches on it's merits. What this patchset
allows is a Xen implementation whose irq functions are fully decoupled
from the rest of x86 that supports SPARSE_IRQ. That is a huge
maintenance improvement that far outweighs the worst damage this
patch can do to maintenance.
So trying to evaluate races. The worse case for this particular piece
of code appears to be create_irq_nr. As this is the only place where
we are setting up irqs and possibly repurposing the structure. Today
we figure out if an irq has been assigned by looking at irq_cfg->vector,
and if it is non-zero the irq has been assigned.
The logic in x86_init_chip_data is correct we only assign desc->chip_data
if the generic layers are above it. However we need a lock to ensure that
two paths don't race in that comparison and that assignment. There is
no lock in x86_init_chip_data. Which unfortunately means as it stands
this patchset is buggy.
Eric
^ permalink raw reply
* [PATCH] [V2] Add non-Virtex5 support for LL TEMAC driver
From: John Linn @ 2010-03-13 1:05 UTC (permalink / raw)
To: netdev, linuxppc-dev, grant.likely, jwboyer
Cc: michal.simek, John Tyner, John Linn, john.williams
This patch adds support for using the LL TEMAC Ethernet driver on
non-Virtex 5 platforms by adding support for accessing the Soft DMA
registers as if they were memory mapped instead of solely through the
DCR's (available on the Virtex 5).
The patch also updates the driver so that it runs on the MicroBlaze.
The changes were tested on the PowerPC 440, PowerPC 405, and the
MicroBlaze platforms.
Signed-off-by: John Tyner <jtyner@cs.ucr.edu>
Signed-off-by: John Linn <john.linn@xilinx.com>
---
V2 - Incorporated comments from Grant and added more logic to allow the driver
to work on MicroBlaze.
drivers/net/Kconfig | 1 -
drivers/net/ll_temac.h | 17 +++++-
drivers/net/ll_temac_main.c | 124 ++++++++++++++++++++++++++++++++++---------
3 files changed, 113 insertions(+), 29 deletions(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9b6efe1..5402105 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2443,7 +2443,6 @@ config MV643XX_ETH
config XILINX_LL_TEMAC
tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
select PHYLIB
- depends on PPC_DCR_NATIVE
help
This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
core used in Xilinx Spartan and Virtex FPGAs
diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h
index 1af66a1..915aa34 100644
--- a/drivers/net/ll_temac.h
+++ b/drivers/net/ll_temac.h
@@ -5,8 +5,11 @@
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/spinlock.h>
+
+#ifdef CONFIG_PPC_DCR
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
+#endif
/* packet size info */
#define XTE_HDR_SIZE 14 /* size of Ethernet header */
@@ -290,8 +293,12 @@ This option defaults to enabled (set) */
#define TX_CONTROL_CALC_CSUM_MASK 1
+/* Align the IP data in the packet on word boundaries as MicroBlaze
+ * needs it.
+ */
+
#define XTE_ALIGN 32
-#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN)
+#define BUFFER_ALIGN(adr) ((34 - ((u32) adr)) % XTE_ALIGN)
#define MULTICAST_CAM_TABLE_NUM 4
@@ -335,9 +342,15 @@ struct temac_local {
struct mii_bus *mii_bus; /* MII bus reference */
int mdio_irqs[PHY_MAX_ADDR]; /* IRQs table for MDIO bus */
- /* IO registers and IRQs */
+ /* IO registers, dma functions and IRQs */
void __iomem *regs;
+ void __iomem *sdma_regs;
+#ifdef CONFIG_PPC_DCR
dcr_host_t sdma_dcrs;
+#endif
+ u32 (*dma_in)(struct temac_local *, int);
+ void (*dma_out)(struct temac_local *, int, u32);
+
int tx_irq;
int rx_irq;
int emac_num;
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index a18e348..9aedf9b 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -20,9 +20,6 @@
* or rx, so this should be okay.
*
* TODO:
- * - Fix driver to work on more than just Virtex5. Right now the driver
- * assumes that the locallink DMA registers are accessed via DCR
- * instructions.
* - Factor out locallink DMA code into separate driver
* - Fix multicast assignment.
* - Fix support for hardware checksumming.
@@ -115,17 +112,86 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
}
+/**
+ * temac_dma_in32 - Memory mapped DMA read, this function expects a
+ * register input that is based on DCR word addresses which
+ * are then converted to memory mapped byte addresses
+ */
static u32 temac_dma_in32(struct temac_local *lp, int reg)
{
- return dcr_read(lp->sdma_dcrs, reg);
+ return in_be32((u32 *)(lp->sdma_regs + (reg << 2)));
}
+/**
+ * temac_dma_out32 - Memory mapped DMA read, this function expects a
+ * register input that is based on DCR word addresses which
+ * are then converted to memory mapped byte addresses
+ */
static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
{
+ out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value);
+}
+
+/* DMA register access functions can be DCR based or memory mapped.
+ * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are both
+ * memory mapped.
+ */
+#ifdef CONFIG_PPC_DCR
+
+/**
+ * temac_dma_dcr_in32 - DCR based DMA read
+ */
+static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
+{
+ return dcr_read(lp->sdma_dcrs, reg);
+}
+
+/**
+ * temac_dma_dcr_out32 - DCR based DMA write
+ */
+static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value)
+{
dcr_write(lp->sdma_dcrs, reg, value);
}
/**
+ * temac_dcr_setup - If the DMA is DCR based, then setup the address and
+ * I/O functions
+ */
+static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
+ struct device_node *np)
+{
+ unsigned int dcrs;
+
+ /* setup the dcr address mapping if it's in the device tree */
+
+ dcrs = dcr_resource_start(np, 0);
+ if (dcrs != 0) {
+ lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
+ lp->dma_in = temac_dma_dcr_in;
+ lp->dma_out = temac_dma_dcr_out;
+ dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
+ return 0;
+ }
+ /* no DCR in the device tree, indicate a failure */
+ return -1;
+}
+
+#else
+
+/*
+ * temac_dcr_setup - This is a stub for when DCR is not supported,
+ * such as with MicroBlaze
+ */
+static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
+ struct device_node *np)
+{
+ return -1;
+}
+
+#endif
+
+/**
* temac_dma_bd_init - Setup buffer descriptor rings
*/
static int temac_dma_bd_init(struct net_device *ndev)
@@ -172,23 +238,23 @@ static int temac_dma_bd_init(struct net_device *ndev)
lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
}
- temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 |
+ lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
CHNL_CTRL_IRQ_EN |
CHNL_CTRL_IRQ_DLY_EN |
CHNL_CTRL_IRQ_COAL_EN);
/* 0x10220483 */
/* 0x00100483 */
- temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 |
+ lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
CHNL_CTRL_IRQ_EN |
CHNL_CTRL_IRQ_DLY_EN |
CHNL_CTRL_IRQ_COAL_EN |
CHNL_CTRL_IRQ_IOE);
/* 0xff010283 */
- temac_dma_out32(lp, RX_CURDESC_PTR, lp->rx_bd_p);
- temac_dma_out32(lp, RX_TAILDESC_PTR,
+ lp->dma_out(lp, RX_CURDESC_PTR, lp->rx_bd_p);
+ lp->dma_out(lp, RX_TAILDESC_PTR,
lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
- temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+ lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
return 0;
}
@@ -426,9 +492,9 @@ static void temac_device_reset(struct net_device *ndev)
temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK);
/* Reset Local Link (DMA) */
- temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
+ lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
timeout = 1000;
- while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
+ while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
udelay(1);
if (--timeout == 0) {
dev_err(&ndev->dev,
@@ -436,7 +502,7 @@ static void temac_device_reset(struct net_device *ndev)
break;
}
}
- temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
+ lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
temac_dma_bd_init(ndev);
@@ -597,7 +663,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
lp->tx_bd_tail = 0;
/* Kick off the transfer */
- temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
+ lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
return NETDEV_TX_OK;
}
@@ -663,7 +729,7 @@ static void ll_temac_recv(struct net_device *ndev)
cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
bdstat = cur_p->app0;
}
- temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p);
+ lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
spin_unlock_irqrestore(&lp->rx_lock, flags);
}
@@ -674,8 +740,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
struct temac_local *lp = netdev_priv(ndev);
unsigned int status;
- status = temac_dma_in32(lp, TX_IRQ_REG);
- temac_dma_out32(lp, TX_IRQ_REG, status);
+ status = lp->dma_in(lp, TX_IRQ_REG);
+ lp->dma_out(lp, TX_IRQ_REG, status);
if (status & (IRQ_COAL | IRQ_DLY))
temac_start_xmit_done(lp->ndev);
@@ -692,8 +758,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev)
unsigned int status;
/* Read and clear the status registers */
- status = temac_dma_in32(lp, RX_IRQ_REG);
- temac_dma_out32(lp, RX_IRQ_REG, status);
+ status = lp->dma_in(lp, RX_IRQ_REG);
+ lp->dma_out(lp, RX_IRQ_REG, status);
if (status & (IRQ_COAL | IRQ_DLY))
ll_temac_recv(lp->ndev);
@@ -794,7 +860,7 @@ static ssize_t temac_show_llink_regs(struct device *dev,
int i, len = 0;
for (i = 0; i < 0x11; i++)
- len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i),
+ len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i),
(i % 8) == 7 ? "\n" : " ");
len += sprintf(buf + len, "\n");
@@ -820,7 +886,6 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
struct net_device *ndev;
const void *addr;
int size, rc = 0;
- unsigned int dcrs;
/* Init network device structure */
ndev = alloc_etherdev(sizeof(*lp));
@@ -870,13 +935,20 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
goto nodev;
}
- dcrs = dcr_resource_start(np, 0);
- if (dcrs == 0) {
- dev_err(&op->dev, "could not get DMA register address\n");
- goto nodev;
+ /* Setup the DMA register accesses, could be DCR or memory mapped */
+ if (temac_dcr_setup(lp, op, np)) {
+
+ /* no DCR in the device tree, try non-DCR */
+ lp->sdma_regs = of_iomap(np, 0);
+ if (lp->sdma_regs) {
+ lp->dma_in = temac_dma_in32;
+ lp->dma_out = temac_dma_out32;
+ dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
+ } else {
+ dev_err(&op->dev, "unable to map DMA registers\n");
+ goto nodev;
+ }
}
- lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
- dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
lp->rx_irq = irq_of_parse_and_map(np, 0);
lp->tx_irq = irq_of_parse_and_map(np, 1);
--
1.6.2.1
This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
^ permalink raw reply related
* Re: Freescale MPC5554 device tree (was: cross-compiling Linux for PowerPC e200 core?)
From: Segher Boessenkool @ 2010-03-13 3:21 UTC (permalink / raw)
To: Grant Likely, Németh Márton, linuxppc-dev
In-Reply-To: <20100312223647.GM11655@yookeroo>
> The historical background here is that in the original OF spec, driver
> matching was done on node name, and only then on compatible.
> Essentially the node name was treated as an implicit first entry in
> the compatible list. The the generic names convention came along, and
> instead name became a human readable generic type for the device
> ("ethernet", "i2c", etc..).
Even with the generic names recommended practice, matching is _still_
done on "name" first, and only then "compatible". It isn't expected
that anything will try to match one the generic names, so for "new style"
nodes that in effect means matching on "compatible" only, but it is
important for compatibility.
> That convention has been widely used since long before flat trees
> existed, but for some reason it was never really used for cpu nodes;
> they remained as "PowerPC,XXXX" or whatever.
The PowerPC binding was not updated for generic names.
> Because the varying
> names of cpu nodes was sometimes awkward to deal with in bootloaders,
> we decided it would be sensible to apply the generic names convention
> here too, so "cpu@X". But then, the previous node name, which was
> treated as being prepended to compatible, should now explicitly be put
> into compatible.
Yes.
Segher
^ permalink raw reply
* Re: Freescale MPC5554 device tree (was: cross-compiling Linux for PowerPC e200 core?)
From: Segher Boessenkool @ 2010-03-13 3:22 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, Németh Márton
In-Reply-To: <fa686aa41003121504u7d346cf7yf1e1433019b5fd22@mail.gmail.com>
> In this particular case, we're talking about a part that has never
> previously been described in a device tree. So, since this is
> something entirely new, what is the value in preserving the
> PowerPC,XXXX style when there isn't any code that will be relying on
> it?
There could be code that matches anything starting with "PowerPC,".
Also, consistency is a good thing no matter what.
Segher
^ permalink raw reply
* Re: Freescale MPC5554 device tree (was: cross-compiling Linux for PowerPC e200 core?)
From: Németh Márton @ 2010-03-13 11:59 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev Development, David Gibson
In-Reply-To: <fa686aa41003120414j48825e7cr952336703fe03b04@mail.gmail.com>
Hi,
here is a version with modified cpu node, xbar ranges and added interrupt sources.
Please send comments.
Regards,
Márton Németh
---
From: Márton Németh <nm127@freemail.hu>
Add device tree for Freescale MPC5554.
Signed-off-by: Márton Németh <nm127@freemail.hu>
---
diff -uprN linux-2.6.33.orig/arch/powerpc/boot/dts/mpc5554.dts linux/arch/powerpc/boot/dts/mpc5554.dts
--- linux-2.6.33.orig/arch/powerpc/boot/dts/mpc5554.dts 1970-01-01 01:00:00.000000000 +0100
+++ linux/arch/powerpc/boot/dts/mpc5554.dts 2010-03-13 12:52:32.000000000 +0100
@@ -0,0 +1,473 @@
+/*
+ * Freescale MPC5554 Device Tree Source
+ *
+ * Based on MPC5553/5554 Microcontroller Reference Manual, Rev. 4.0, 04/2007
+ * http://www.freescale.com/files/32bit/doc/ref_manual/MPC5553_MPC5554_RM.pdf
+ * - Block Diagram: page 1-3, Figure 1-1
+ * - Memory Map: page 1-21, Table 1-2
+ * - Interrupt Request Sources: page 10-16, Table 10-9
+ *
+ * Copyright 2010 Márton Németh
+ * Márton Németh <nm127@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "MPC5554";
+ compatible = "fsl,MPC5554EVB"; // Freescale MPC5554 Evaluation Board
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "PowerPC,5554", "fsl,mpc5554-e200z6", "fsl,powerpc-e200z6";
+ reg = <0>;
+ d-cache-line-size = <32>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x8000>; // L1, 32KiB
+ i-cache-size = <0x8000>; // L1, 32KiB
+ timebase-frequency = <0>; // from bootloader
+ bus-frequency = <0>; // from bootloader
+ clock-frequency = <0>; // from bootloader
+ };
+ };
+
+ memory@40000000 {
+ device_type = "memory";
+ reg = <0x40000000 0x10000>; // 32KiB internal SRAM
+ };
+
+ xbar@fff04000 { // System Bus Crossbar Switch (XBAR)
+ compatible = "fsl,mpc5554-xbar";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ // The full memory range is covered by XBAR
+ ranges;
+ reg = <0xfff04000 0x4000>;
+
+ flash@0 { // read-only FLASH
+ compatible = "fsl,mpc5554-flash";
+ reg = <0x00000000 0x200000>; // 2MiB internal FLASH
+ };
+
+ bridge@c3f00000 {
+ compatible = "fsl,mpc5554-pbridge-a";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xc0000000 0x20000000>;
+ reg = <0xc3f00000 0x4000>;
+
+ fmpll@3f80000 { // Frequency Modulated PLL
+ compatible = "fsl,mpc5554-fmpll";
+ reg = <0x03f80000 0x4000>;
+ interrupts = <43 1 // Loss of Clock
+ 44 1>; // Loss of Lock
+ };
+
+ flashconfig@3f88000 { // Flash Configuration
+ compatible = "fsl,mpc5554-flashconfig";
+ reg = <0x03f88000 0x4000>;
+ };
+
+ siu@3f89000 { // System Integration Unit
+ compatible = "fsl,mpc5554-siu";
+ reg = <0x03f90000 0x4000>;
+ interrupts = <45 1 // External Interrupt Overrun 0-15
+ 46 1 // External Interrupt 0
+ 47 1 // External Interrupt 1
+ 48 1 // External Interrupt 2
+ 49 1 // External Interrupt 3
+ 50 1>; // External Interrupt 4-15
+ };
+
+ emios@3fa0000 { // Modular Timer System
+ compatible = "fsl,mpc5554-emios";
+ reg = <0x03fa0000 0x4000>;
+ interrupts = <51 1 // Channel 0
+ 52 1 // Channel 1
+ 53 1 // Channel 2
+ 54 1 // Channel 3
+ 55 1 // Channel 4
+ 56 1 // Channel 5
+ 57 1 // Channel 6
+ 58 1 // Channel 7
+ 59 1 // Channel 8
+ 60 1 // Channel 9
+ 61 1 // Channel 10
+ 62 1 // Channel 11
+ 63 1 // Channel 12
+ 64 1 // Channel 13
+ 65 1 // Channel 14
+ 66 1 // Channel 15
+ 202 1 // Channel 16
+ 203 1 // Channel 17
+ 204 1 // Channel 18
+ 205 1 // Channel 19
+ 206 1 // Channel 20
+ 207 1 // Channel 21
+ 208 1 // Channel 22
+ 209 1>; // Channel 23
+ };
+
+ etpu@3fc0000 { // Enhanced Time Processing Unit
+ compatible = "fsl,mpc5554-etpu";
+ reg = <0x03fc0000 0x4000>;
+ interrupts = <67 1 // Global Exception
+ 68 1 // A Channel 0
+ 69 1 // A Channel 1
+ 70 1 // A Channel 2
+ 71 1 // A Channel 3
+ 72 1 // A Channel 4
+ 73 1 // A Channel 5
+ 74 1 // A Channel 6
+ 75 1 // A Channel 7
+ 76 1 // A Channel 8
+ 77 1 // A Channel 9
+ 78 1 // A Channel 10
+ 79 1 // A Channel 11
+ 80 1 // A Channel 12
+ 81 1 // A Channel 13
+ 82 1 // A Channel 14
+ 83 1 // A Channel 15
+ 84 1 // A Channel 16
+ 85 1 // A Channel 17
+ 86 1 // A Channel 18
+ 87 1 // A Channel 19
+ 88 1 // A Channel 20
+ 89 1 // A Channel 21
+ 90 1 // A Channel 22
+ 91 1 // A Channel 23
+ 92 1 // A Channel 24
+ 93 1 // A Channel 25
+ 94 1 // A Channel 26
+ 95 1 // A Channel 27
+ 96 1 // A Channel 28
+ 97 1 // A Channel 29
+ 98 1 // A Channel 30
+ 99 1 // A Channel 31
+ 243 1 // B Channel 0
+ 244 1 // B Channel 1
+ 245 1 // B Channel 2
+ 246 1 // B Channel 3
+ 247 1 // B Channel 4
+ 248 1 // B Channel 5
+ 249 1 // B Channel 6
+ 250 1 // B Channel 7
+ 251 1 // B Channel 8
+ 252 1 // B Channel 9
+ 253 1 // B Channel 10
+ 254 1 // B Channel 11
+ 255 1 // B Channel 12
+ 256 1 // B Channel 13
+ 257 1 // B Channel 14
+ 258 1 // B Channel 15
+ 259 1 // B Channel 16
+ 260 1 // B Channel 17
+ 261 1 // B Channel 18
+ 262 1 // B Channel 19
+ 263 1 // B Channel 20
+ 264 1 // B Channel 21
+ 265 1 // B Channel 22
+ 266 1 // B Channel 23
+ 267 1 // B Channel 24
+ 268 1 // B Channel 25
+ 269 1 // B Channel 26
+ 270 1 // B Channel 27
+ 271 1 // B Channel 28
+ 272 1 // B Channel 29
+ 273 1 // B Channel 30
+ 274 1>; // B Channel 31
+ };
+
+ etpudata@3fc8000 { // eTPU Shared Data Memory (Parameter RAM)
+ compatible = "fsl,mpc5554-etpudata";
+ reg = <0x03fc8000 0x4000>;
+ };
+
+ etpudata@3fcc000 { // eTPU Shared Data Memory (Parameter RAM) mirror
+ compatible = "fsl,mpc5554-etpudata";
+ reg = <0x03fcc000 0x4000>;
+ };
+
+ etpucode@3fd0000 { // eTPU Shared Code RAM
+ compatible = "fsl,mpc5554-etpucode";
+ reg = <0x03fd0000 0x4000>;
+ };
+ };
+
+ bridge@fff00000 {
+ compatible = "fsl,mpc5554-pbridge-b";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xe0000000 0x20000000>;
+ reg = <0xfff00000 0x4000>;
+
+ ecsm@fff40000 { // Error Correction Status Module (ECSM)
+ compatible = "fsl,mpc5554-ecsm";
+ reg = <0xfff40000 0x4000>;
+ interrupts = <8 1 // Software Watchdog Interrupt
+ 9 1>; // Combined: Internal SRAM Non-Correctable Error, Flash Non-Correctable Error
+ };
+
+ edma@fff44000 { // Enhanced DMA Controller (eDMA)
+ compatible = "fsl,mpc5554-edma";
+ reg = <0xfff44000 0x4000>;
+ interrupts = <10 1 // Channel Error 0-31
+ 11 1 // Channel 0
+ 12 1 // Channel 1
+ 13 1 // Channel 2
+ 14 1 // Channel 3
+ 15 1 // Channel 4
+ 16 1 // Channel 5
+ 17 1 // Channel 6
+ 18 1 // Channel 7
+ 19 1 // Channel 8
+ 20 1 // Channel 9
+ 21 1 // Channel 10
+ 22 1 // Channel 11
+ 23 1 // Channel 12
+ 24 1 // Channel 13
+ 25 1 // Channel 14
+ 26 1 // Channel 15
+ 27 1 // Channel 16
+ 28 1 // Channel 17
+ 29 1 // Channel 18
+ 30 1 // Channel 19
+ 31 1 // Channel 20
+ 32 1 // Channel 21
+ 33 1 // Channel 22
+ 34 1 // Channel 23
+ 35 1 // Channel 24
+ 36 1 // Channel 25
+ 37 1 // Channel 26
+ 38 1 // Channel 27
+ 39 1 // Channel 28
+ 40 1 // Channel 29
+ 41 1 // Channel 30
+ 42 1 // Channel 31
+ 210 1 // Channel Error 32-63
+ 211 1 // Channel 32
+ 212 1 // Channel 33
+ 213 1 // Channel 34
+ 214 1 // Channel 35
+ 215 1 // Channel 36
+ 216 1 // Channel 37
+ 217 1 // Channel 38
+ 218 1 // Channel 39
+ 219 1 // Channel 40
+ 220 1 // Channel 41
+ 221 1 // Channel 42
+ 222 1 // Channel 43
+ 223 1 // Channel 44
+ 224 1 // Channel 45
+ 225 1 // Channel 46
+ 226 1 // Channel 47
+ 227 1 // Channel 48
+ 228 1 // Channel 49
+ 229 1 // Channel 50
+ 230 1 // Channel 51
+ 231 1 // Channel 52
+ 232 1 // Channel 53
+ 233 1 // Channel 54
+ 234 1 // Channel 55
+ 235 1 // Channel 56
+ 236 1 // Channel 57
+ 237 1 // Channel 58
+ 238 1 // Channel 59
+ 239 1 // Channel 60
+ 240 1 // Channel 61
+ 241 1 // Channel 62
+ 242 1>; // Channel 63
+ };
+
+ intc: intc@fff48000 { // Interrupt Controller (INTC)
+ compatible = "fsl,mpc5554-intc";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfff48000 0x4000>;
+ };
+
+ eqadc@fff80000 { // Enhanced Queued Analog-to-Digital Converter (eQADC)
+ compatible = "fsl,mpc5554-eqacd";
+ reg = <0xfff80000 0x4000>;
+ interrupts = <100 1 // Combined: Trigger Overrun, Receive FIFO Overflow, Command FIFO Underflow
+ 101 1 // Command FIFO 0 Non-Coherency
+ 102 1 // Command FIFO 0 Pause
+ 103 1 // Command FIFO 0 End of Queue
+ 104 1 // Command FIFO 0 Fill
+ 105 1 // Command FIFO 0 Drain
+ 106 1 // Command FIFO 1 Non-Coherency
+ 107 1 // Command FIFO 1 Pause
+ 108 1 // Command FIFO 1 End of Queue
+ 109 1 // Command FIFO 1 Fill
+ 111 1 // Command FIFO 1 Drain
+ 111 1 // Command FIFO 2 Non-Coherency
+ 112 1 // Command FIFO 2 Pause
+ 113 1 // Command FIFO 2 End of Queue
+ 114 1 // Command FIFO 2 Fill
+ 115 1 // Command FIFO 2 Drain
+ 116 1 // Command FIFO 3 Non-Coherency
+ 117 1 // Command FIFO 3 Pause
+ 118 1 // Command FIFO 3 End of Queue
+ 119 1 // Command FIFO 3 Fill
+ 120 1 // Command FIFO 3 Drain
+ 121 1 // Command FIFO 4 Non-Coherency
+ 122 1 // Command FIFO 4 Pause
+ 123 1 // Command FIFO 4 End of Queue
+ 124 1 // Command FIFO 4 Fill
+ 125 1 // Command FIFO 4 Drain
+ 126 1 // Command FIFO 5 Non-Coherency
+ 127 1 // Command FIFO 5 Pause
+ 128 1 // Command FIFO 5 End of Queue
+ 129 1 // Command FIFO 5 Fill
+ 130 1>; // Command FIFO 5 Drain
+ };
+
+ dspi@fff90000 { // Deserial Serial Peripheral Interface (DSPI_A)
+ compatible = "fsl,mpc5554-dspi";
+ reg = <0xfff90000 0x4000>;
+ interrupts = <275 1 // Combined: Transmit FIFO Underflow, Receive FIFO Overflow
+ 276 1 // Transmit FIFO End of Queue
+ 277 1 // Transmit FIFO Fill Flag
+ 278 1 // Transfer Complete
+ 279 1>; // Receive FIFO Drain
+ };
+
+ dspi@fff94000 { // Deserial Serial Peripheral Interface (DSPI_B)
+ compatible = "fsl,mpc5554-dspi";
+ reg = <0xfff94000 0x4000>;
+ interrupts = <131 1 // Combined: Transmit FIFO Underflow, Receive FIFO Overflow
+ 132 1 // Transmit FIFO End of Queue
+ 133 1 // Transmit FIFO Fill Flag
+ 134 1 // Transfer Complete
+ 135 1>; // Receive FIFO Drain
+ };
+
+ dspi@fff98000 { // Deserial Serial Peripheral Interface (DSPI_C)
+ compatible = "fsl,mpc5554-dspi";
+ reg = <0xfff98000 0x4000>;
+ interrupts = <136 1 // Combined: Transmit FIFO Underflow, Receive FIFO Overflow
+ 137 1 // Transmit FIFO End of Queue
+ 138 1 // Transmit FIFO Fill Flag
+ 139 1 // Transfer Complete
+ 140 1>; // Receive FIFO Drain
+ };
+
+ dspi@fff9c000 { // Deserial Serial Peripheral Interface (DSPI_D)
+ compatible = "fsl,mpc5554-dspi";
+ reg = <0xfff9c000 0x4000>;
+ interrupts = <141 1 // Combined: Transmit FIFO Underflow, Receive FIFO Overflow
+ 142 1 // Transmit FIFO End of Queue
+ 143 1 // Transmit FIFO Fill Flag
+ 144 1 // Transfer Complete
+ 145 1>; // Receive FIFO Drain
+ };
+
+ esci@fffb0000 { // Serial Communications Interface (SCI_A)
+ compatible = "fsl,mpc5554-esci";
+ reg = <0xfffb0000 0x4000>;
+ interrupts = <146 1>; // Combined request for all SCI_A interrupts
+ };
+
+ esci@fffb4000 { // Serial Communications Interface (SCI_B)
+ compatible = "fsl,mpc5554-esci";
+ reg = <0xfffb4000 0x4000>;
+ interrupts = <149 1>; // Combined request for all SCI_A interrupts
+ };
+
+ can@fffc0000 { // Controller Area Network (FlexCAN_A)
+ compatible = "fsl,mpc5554-flexcan";
+ reg = <0xfffc0000 0x4000>;
+ interrupts = <152 1 // Bus off
+ 153 1 // Error
+ 155 1 // Buffer 0
+ 156 1 // Buffer 1
+ 157 1 // Buffer 2
+ 158 1 // Buffer 3
+ 159 1 // Buffer 4
+ 160 1 // Buffer 5
+ 161 1 // Buffer 6
+ 162 1 // Buffer 7
+ 163 1 // Buffer 8
+ 164 1 // Buffer 9
+ 165 1 // Buffer 10
+ 166 1 // Buffer 11
+ 167 1 // Buffer 12
+ 168 1 // Buffer 13
+ 169 1 // Buffer 14
+ 170 1 // Buffer 15
+ 171 1 // Buffers 16-31
+ 172 1>; // Buffers 32-63
+ };
+
+ can@fffc4000 { // Controller Area Network (FlexCAN_B)
+ compatible = "fsl,mpc5554-flexcan";
+ reg = <0xfffc4000 0x4000>;
+ interrupts = <280 1 // Bus off
+ 281 1 // Error
+ 283 1 // Buffer 0
+ 284 1 // Buffer 1
+ 285 1 // Buffer 2
+ 286 1 // Buffer 3
+ 287 1 // Buffer 4
+ 288 1 // Buffer 5
+ 289 1 // Buffer 6
+ 290 1 // Buffer 7
+ 291 1 // Buffer 8
+ 292 1 // Buffer 9
+ 293 1 // Buffer 10
+ 294 1 // Buffer 11
+ 295 1 // Buffer 12
+ 296 1 // Buffer 13
+ 297 1 // Buffer 14
+ 298 1 // Buffer 15
+ 299 1 // Buffers 16-31
+ 300 1>; // Buffers 32-63
+ };
+
+ can@fffc8000 { // Controller Area Network (FlexCAN_C)
+ compatible = "fsl,mpc5554-flexcan";
+ reg = <0xfffc8000 0x4000>;
+ interrupts = <173 1 // Bus off
+ 174 1 // Error
+ 176 1 // Buffer 0
+ 177 1 // Buffer 1
+ 178 1 // Buffer 2
+ 179 1 // Buffer 3
+ 180 1 // Buffer 4
+ 181 1 // Buffer 5
+ 182 1 // Buffer 6
+ 183 1 // Buffer 7
+ 184 1 // Buffer 8
+ 185 1 // Buffer 9
+ 186 1 // Buffer 10
+ 187 1 // Buffer 11
+ 188 1 // Buffer 12
+ 189 1 // Buffer 13
+ 190 1 // Buffer 14
+ 191 1 // Buffer 15
+ 192 1 // Buffers 16-31
+ 193 1>; // Buffers 32-63
+ };
+
+ bam@ffffc000 { // Boot Assist Module (BAM)
+ compatible = "fsl,mpc5554-bam";
+ reg = <0xffffc000 0x4000>;
+ };
+
+ };
+
+ };
+
+};
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox