* [PATCH#2 2/4] [PPC] Fix cpm_dpram_addr returning phys mem instead of virt mem
From: Jochen Friedrich @ 2007-09-24 17:14 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 514 bytes --]
cpm_dpram_addr returns physical memory of the DP RAM instead of
iomapped virtual memory. As there usually is a 1:1 MMU map of
the IMMR area, this is often not noticed. However, cpm_dpram_phys
assumes this iomapped virtual memory and returns garbage on the
1:1 mapped memory causing CPM1 uart console to fail.
This patch fixes the problem (copied from the powerpc tree).
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
arch/ppc/8xx_io/commproc.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
[-- Attachment #2: e99a679ff14fb0073efd9220f5aa933e47516202.diff --]
[-- Type: text/x-patch, Size: 399 bytes --]
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index 7088428..9da880b 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -459,7 +459,7 @@ EXPORT_SYMBOL(cpm_dpdump);
void *cpm_dpram_addr(unsigned long offset)
{
- return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
+ return (void *)(dpram_vbase + offset);
}
EXPORT_SYMBOL(cpm_dpram_addr);
^ permalink raw reply related
* [PATCH#2 3/4] [PPC] Compile fix for 8xx CPM Ehernet driver
From: Jochen Friedrich @ 2007-09-24 17:15 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 492 bytes --]
Add #include <asm/cacheflush.h> for flush_dcache_range
to make the driver compile again.
CC arch/ppc/8xx_io/enet.o
arch/ppc/8xx_io/enet.c: In function 'scc_enet_start_xmit':
arch/ppc/8xx_io/enet.c:240: error: implicit declaration of function
'flush_dcache_range'
make[1]: *** [arch/ppc/8xx_io/enet.o] Error 1
make: *** [arch/ppc/8xx_io] Error 2
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
arch/ppc/8xx_io/enet.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
[-- Attachment #2: bf5c2f419c8f731109b1c39e390338dcea780e94.diff --]
[-- Type: text/x-patch, Size: 308 bytes --]
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 703d47e..eace3bc 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -44,6 +44,7 @@
#include <asm/mpc8xx.h>
#include <asm/uaccess.h>
#include <asm/commproc.h>
+#include <asm/cacheflush.h>
/*
* Theory of Operation
^ permalink raw reply related
* [PATCH#2 4/4] [POWERPC] Fix cpm_uart driver
From: Jochen Friedrich @ 2007-09-24 17:15 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 486 bytes --]
in cpm_uart_cpm1.h, DPRAM_BASE is assigned an address derived from cpmp.
On ARC=ppc, this is a physical address with 1:1 DMA mapping which can't
be used for arithmetric compare operations with virtual addresses
returned by cpm_dpram_addr. This patch changes the assignment to use
cpm_dpram_addr as well, like in cpm_uart_cpm2.h.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
drivers/serial/cpm_uart/cpm_uart_cpm1.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
[-- Attachment #2: e99364db4224fcfaf74389d1b59ec0637d899c17.diff --]
[-- Type: text/x-patch, Size: 452 bytes --]
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index a99e45e..2a64778 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -37,6 +37,6 @@ static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
up->smc_tfcr = SMC_EB;
}
-#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0])
+#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0))
#endif
^ permalink raw reply related
* Re: [apw@shadowen.org: 2.6.23-rc6-mm1 -- powerpc pSeries_log_error panic in rtas_call/early_enable_eeh]
From: Linas Vepstas @ 2007-09-24 17:21 UTC (permalink / raw)
To: Anton Blanchard, Andy Whitcroft, linuxppc-dev
In-Reply-To: <20070923161740.GA12488@kryten>
I just got back from vacation.
I'll give this a whirl shortly.
--linas
On Sun, Sep 23, 2007 at 11:17:40AM -0500, Anton Blanchard wrote:
>
> Hi Linas,
>
> Looks like EEH could be involved :)
>
> Anton
>
> ----- Forwarded message from Andy Whitcroft <apw@shadowen.org> -----
>
> From: Andy Whitcroft <apw@shadowen.org>
> To: Andrew Morton <akpm@linux-foundation.org>
> Subject: 2.6.23-rc6-mm1 -- powerpc pSeries_log_error panic in
> rtas_call/early_enable_eeh
> X-SPF-Guess: neutral
> Cc: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org
> X-BeenThere: linuxppc-dev@ozlabs.org
> X-Mailman-Version: 2.1.9
> List-Id: Linux on PowerPC Developers Mail List <linuxppc-dev.ozlabs.org>
> List-Unsubscribe: <https://ozlabs.org/mailman/listinfo/linuxppc-dev>,
> <mailto:linuxppc-dev-request@ozlabs.org?subject=unsubscribe>
> List-Archive: <http://ozlabs.org/pipermail/linuxppc-dev>
> List-Post: <mailto:linuxppc-dev@ozlabs.org>
> List-Help: <mailto:linuxppc-dev-request@ozlabs.org?subject=help>
> List-Subscribe: <https://ozlabs.org/mailman/listinfo/linuxppc-dev>,
> <mailto:linuxppc-dev-request@ozlabs.org?subject=subscribe>
>
> Seeing the following panic booting an old powerpc LPAR:
>
> Unable to handle kernel paging request for data at address 0x00000000
> Faulting instruction address: 0xc000000000047b48
> cpu 0x0: Vector: 300 (Data Access) at [c0000000006a3750]
> pc: c000000000047b48: .pSeries_log_error+0x364/0x420
> lr: c000000000047acc: .pSeries_log_error+0x2e8/0x420
> sp: c0000000006a39d0
> msr: 8000000000001032
> dar: 0
> dsisr: 42000000
> current = 0xc0000000005acab0
> paca = 0xc0000000005ad700
> pid = 0, comm = swapper
> enter ? for help
> [c0000000006a3af0] c000000000021164 .rtas_call+0x200/0x250
> [c0000000006a3ba0] c000000000049d50 .early_enable_eeh+0x168/0x360
> [c0000000006a3c70] c00000000002f674 .traverse_pci_devices+0x8c/0x138
> [c0000000006a3d10] c000000000560ce8 .eeh_init+0x1a8/0x200
> [c0000000006a3db0] c00000000055fb70 .pSeries_setup_arch+0x128/0x234
> [c0000000006a3e40] c00000000054f830 .setup_arch+0x214/0x24c
> [c0000000006a3ee0] c000000000546a38 .start_kernel+0xd4/0x3e4
> [c0000000006a3f90] c00000000045adc4 .start_here_common+0x54/0x58
> 0:mon>
>
> This machine is:
>
> # cat /proc/cpuinfo
> processor : 0
> cpu : POWER4+ (gq)
> clock : 1703.965296MHz
> revision : 19.0
>
> [...]
> machine : CHRP IBM,7040-681
>
> -apw
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
> ----- End forwarded message -----
^ permalink raw reply
* Re: [PATCH4/4] [POWERPC] Fix cpm_uart driver
From: Scott Wood @ 2007-09-24 18:22 UTC (permalink / raw)
To: Jochen Friedrich; +Cc: linux-kernel, linuxppc-embedded
In-Reply-To: <46F7EE95.1040509@scram.de>
Jochen Friedrich wrote:
> Scott Wood schrieb:
>> Jochen Friedrich wrote:
>>>
>>> In cpm_uart_core, functions cpm_uart_init_bd and cpm_uart_init_scc
>>> an offset into DP RAM is calculated by substracting a physical
>>> memory constant from an virtual address. This patch fixes the
>>> problem by converting the virtual address into a physical
>>> first.
>>
>> Huh? DPRAM_BASE is a virtual address. With this patch, you'd be
>> subtracting a virtual address from a physical address.
>
> Thanks for pointing me to it. So the bug is in cpm_uart_cpm1.h assigning
> a physical memory to DPRAM_BASE (at least on ARC=ppc). cpm_uart_cpm2.h
> seems to be correct though. I'll submit a new patch for this.
cpmp is a physical address on arch/ppc?
/me looks at arch/ppc/8xx_io/commproc.c
Yikes. Please don't change cpm_uart_cpm1.h, as it's correct for
arch/powerpc, and there are numerous other places that assume cpmp is
virtual (including in the very same function that assigns it a physical
address).
You could fix arch/ppc if you want, though it may be easier to wait for
it to die, and insist on identity maps in the meantime. :-)
-Scott
^ permalink raw reply
* [PATCH] Make instruction dumping work in real mode.
From: Scott Wood @ 2007-09-24 19:01 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev
On non-book-E, if a faulting PC is in the first few pages, and it's not an
ITLB miss, it's likely executing in real mode, probably at an exception vector.
Rather than print a useless XXXXXXXX, it is assumed that this is the case, and
the address is treated as physical. This helps when debugging corruption at
the beginning of memory.
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
arch/powerpc/kernel/process.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 57c589c..7cb94d7 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -354,6 +354,14 @@ static void show_instructions(struct pt_regs *regs)
if (!(i % 8))
printk("\n");
+#ifndef CONFIG_BOOKE
+ /* If the address is in the first couple pages, it's
+ * likely executing in real mode.
+ */
+ if (regs->nip < 0x4000)
+ pc += (unsigned long)phys_to_virt(KERNELBASE);
+#endif
+
/* We use __get_user here *only* to avoid an OOPS on a
* bad address because the pc *should* only be a
* kernel address.
--
1.5.3.1
^ permalink raw reply related
* Re: [PATCH4/4] [POWERPC] Fix cpm_uart driver
From: Dan Malek @ 2007-09-24 19:16 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-embedded, linux-kernel
In-Reply-To: <46F80049.2030509@freescale.com>
On Sep 24, 2007, at 11:22 AM, Scott Wood wrote:
> cpmp is a physical address on arch/ppc?
No, it's a well known ioremaped() address
into the IMMR space. The only physical
addresses in any of the CPM/CPM2 are
those required to by the buffer descriptors.
There are DPRAM offsets, but they should
be just that, offsets from either a virtual
or physical base address as required.
Too many people screw around in this
CPM support code without fully understanding
the original implementation or its intended
use with the peripheral drivers. A "better
idea" often breaks all drivers except the one
that is being changed.
-- Dan
^ permalink raw reply
* [PATCH 0/3] usb: ehci ppc device-tree-aware driver
From: Valentine Barshak @ 2007-09-24 19:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-usb-devel
Some PowerPC systems have a built-in EHCI controller.
This is a device tree aware version of the EHCI controller driver.
Currently it's been tested on the PowerPC 440EPx Sequoia board.
Other platforms can be added later.
The code is based on the ehci-ppc-soc driver by Stefan Roese <sr@denx.de>.
^ permalink raw reply
* [PATCH 1/3] usb: add device-tree-aware ehci driver
From: Valentine Barshak @ 2007-09-24 19:26 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-usb-devel
In-Reply-To: <20070924192519.GA4192@ru.mvista.com>
This adds device-tree-aware ehci-ppc-of driver.
The code is based on the ehci-ppc-soc driver by
Stefan Roese <sr@denx.de>.
Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
---
drivers/usb/host/Kconfig | 8 +
drivers/usb/host/ehci-hcd.c | 16 ++
drivers/usb/host/ehci-ppc-of.c | 243 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/host/ehci.h | 2
4 files changed, 267 insertions(+), 2 deletions(-)
diff -ruN linux-2.6.orig/drivers/usb/host/ehci.h linux-2.6/drivers/usb/host/ehci.h
--- linux-2.6.orig/drivers/usb/host/ehci.h 2007-09-24 14:55:44.000000000 +0400
+++ linux-2.6/drivers/usb/host/ehci.h 2007-09-24 23:07:16.000000000 +0400
@@ -725,7 +725,7 @@
* definition below can die once the 4xx support is
* finally ported over.
*/
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
#define readl_be(addr) in_be32((__force unsigned *)addr)
#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
#endif
diff -ruN linux-2.6.orig/drivers/usb/host/ehci-hcd.c linux-2.6/drivers/usb/host/ehci-hcd.c
--- linux-2.6.orig/drivers/usb/host/ehci-hcd.c 2007-09-24 14:55:44.000000000 +0400
+++ linux-2.6/drivers/usb/host/ehci-hcd.c 2007-09-24 23:07:16.000000000 +0400
@@ -944,11 +944,16 @@
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
#endif
-#ifdef CONFIG_440EPX
+#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
#include "ehci-ppc-soc.c"
#define PLATFORM_DRIVER ehci_ppc_soc_driver
#endif
+#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
+#include "ehci-ppc-of.c"
+#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ehci-hcd"
@@ -963,6 +968,12 @@
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+#ifdef OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ return retval;
+#endif
+
#ifdef PLATFORM_DRIVER
retval = platform_driver_register(&PLATFORM_DRIVER);
if (retval < 0)
@@ -998,6 +1009,9 @@
static void __exit ehci_hcd_cleanup(void)
{
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
diff -ruN linux-2.6.orig/drivers/usb/host/ehci-ppc-of.c linux-2.6/drivers/usb/host/ehci-ppc-of.c
--- linux-2.6.orig/drivers/usb/host/ehci-ppc-of.c 1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6/drivers/usb/host/ehci-ppc-of.c 2007-09-24 23:13:31.000000000 +0400
@@ -0,0 +1,243 @@
+/*
+ * 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>
+
+/* called during probe() after chip reset completes */
+static int ehci_ppc_of_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci->sbrn = 0x20;
+ return ehci_reset(ehci);
+}
+
+
+static const struct hc_driver ehci_ppc_of_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OF EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_ppc_of_setup,
+ .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,
+
+ /*
+ * 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
+ .hub_suspend = ehci_hub_suspend,
+ .hub_resume = ehci_hub_resume,
+#endif
+};
+
+
+/*
+ * 440EPx Errata USBH_3
+ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
+ */
+#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0)
+static int __devinit
+ppc44x_enable_bmt(struct device_node *dn)
+{
+ __iomem u32 *insreg_virt;
+
+ insreg_virt = of_iomap(dn, 1);
+ if (!insreg_virt)
+ return -EINVAL;
+
+ out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT);
+
+ iounmap(insreg_virt);
+ return 0;
+}
+
+
+static int __devinit
+ehci_hcd_ppc_of_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;
+ struct resource res;
+ int irq;
+ int rv;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = res.end - res.start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ rv = -EBUSY;
+ goto err_rmr;
+ }
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+
+ if (of_get_property(dn, "big-endian", NULL)) {
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+ }
+ if (of_get_property(dn, "big-endian-regs", NULL))
+ ehci->big_endian_mmio = 1;
+ if (of_get_property(dn, "big-endian-desc", NULL))
+ ehci->big_endian_desc = 1;
+
+ 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);
+
+ if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
+ rv = ppc44x_enable_bmt(dn);
+ ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
+ rv ? "NOT ": "");
+ }
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv == 0)
+ return 0;
+
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+
+static int ehci_hcd_ppc_of_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 PPC-OF USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+
+static int ehci_hcd_ppc_of_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_ppc_of_match[] = {
+ {
+ .compatible = "usb-ehci",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
+
+
+static struct of_platform_driver ehci_hcd_ppc_of_driver = {
+ .name = "ppc-of-ehci",
+ .match_table = ehci_hcd_ppc_of_match,
+ .probe = ehci_hcd_ppc_of_probe,
+ .remove = ehci_hcd_ppc_of_remove,
+ .shutdown = ehci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+ /*.suspend = ehci_hcd_ppc_of_drv_suspend,*/
+ /*.resume = ehci_hcd_ppc_of_drv_resume,*/
+#endif
+ .driver = {
+ .name = "ppc-of-ehci",
+ .owner = THIS_MODULE,
+ },
+};
+
diff -ruN linux-2.6.orig/drivers/usb/host/Kconfig linux-2.6/drivers/usb/host/Kconfig
--- linux-2.6.orig/drivers/usb/host/Kconfig 2007-09-24 14:55:44.000000000 +0400
+++ linux-2.6/drivers/usb/host/Kconfig 2007-09-24 23:07:16.000000000 +0400
@@ -84,6 +84,14 @@
---help---
Variation of ARC USB block used in some Freescale chips.
+config USB_EHCI_HCD_PPC_OF
+ bool "EHCI support for PPC USB controller on OF platform bus"
+ depends on USB_EHCI_HCD && PPC_OF
+ default y
+ ---help---
+ Enables support for the USB controller PowerPC present on the
+ OpenFirmware platform bus.
+
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
^ permalink raw reply
* [PATCH 2/3] usb: ehci-ppc-of dts bindings.
From: Valentine Barshak @ 2007-09-24 19:27 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-usb-devel
In-Reply-To: <20070924192519.GA4192@ru.mvista.com>
Adds EHCI OF bindings to documentation.
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 28 +++++++++++++++++++++++++++
1 files changed, 28 insertions(+)
diff -ruN linux-2.6.orig/Documentation/powerpc/booting-without-of.txt linux-2.6/Documentation/powerpc/booting-without-of.txt
--- linux-2.6.orig/Documentation/powerpc/booting-without-of.txt 2007-09-24 14:55:04.000000000 +0400
+++ linux-2.6/Documentation/powerpc/booting-without-of.txt 2007-09-24 22:42:35.000000000 +0400
@@ -52,6 +52,7 @@
i) Freescale QUICC Engine module (QE)
j) CFI or JEDEC memory-mapped NOR flash
k) Global Utilities Block
+ l) USB EHCI controllers
VII - Specifying interrupt information for devices
1) interrupts property
@@ -1848,6 +1849,33 @@
fsl,has-rstcr;
};
+ l) USB EHCI controllers
+
+ Required properties:
+ - compatible : should be "usb-ehci".
+ - reg : should contain at least address and length of the standard EHCI
+ register set for the device. Optional platform-dependent registers
+ (debug-port or other) can be also specified here, but only after
+ definition of standard EHCI registers.
+ - interrupts : one EHCI interrupt should be described here.
+ If device registers are implemented in big endian mode, the device
+ node should have "big-endian-regs" property.
+ If controller implementation operates with big endian descriptors,
+ "big-endian-desc" property should be specified.
+ If both big endian registers and descriptors are used by the controller
+ implementation, "big-endian" property can be specified instead of having
+ both "big-endian-regs" and "big-endian-desc".
+
+ Example (Sequoia 440EPx):
+ ehci@e0000300 {
+ compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+ interrupt-parent = <&UIC0>;
+ interrupts = <1a 4>;
+ reg = <0 e0000300 90 0 e0000390 70>;
+ big-endian;
+ };
+
+
More devices will be defined as this spec matures.
VII - Specifying interrupt information for devices
^ permalink raw reply
* Re: [PATCH4/4] [POWERPC] Fix cpm_uart driver
From: Scott Wood @ 2007-09-24 19:29 UTC (permalink / raw)
To: Dan Malek; +Cc: linuxppc-embedded, linux-kernel
In-Reply-To: <FF1A2486-BE77-49F8-99F3-B09B4EEAF50D@embeddedalley.com>
Dan Malek wrote:
>
> On Sep 24, 2007, at 11:22 AM, Scott Wood wrote:
>
>> cpmp is a physical address on arch/ppc?
>
> No, it's a well known ioremaped() address into the IMMR space.
Maybe that's how it was, but the current code initializes it (more or
less) directly with IMAP_ADDR, which also gets fed into ioremap.
One of the two has got to be wrong.
-Scott
^ permalink raw reply
* [PATCH 3/3] Add PowerPC 440EPx Sequoia ehci dts entry
From: Valentine Barshak @ 2007-09-24 19:29 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-usb-devel
In-Reply-To: <20070924192519.GA4192@ru.mvista.com>
Adds USB EHCI entry to PowerPC 440EPx Sequoia DTS.
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
---
arch/powerpc/boot/dts/sequoia.dts | 8 ++++++++
1 files changed, 8 insertions(+)
diff -ruN linux-2.6.orig/arch/powerpc/boot/dts/sequoia.dts linux-2.6/arch/powerpc/boot/dts/sequoia.dts
--- linux-2.6.orig/arch/powerpc/boot/dts/sequoia.dts 2007-09-24 14:55:15.000000000 +0400
+++ linux-2.6/arch/powerpc/boot/dts/sequoia.dts 2007-09-24 21:50:24.000000000 +0400
@@ -122,6 +122,14 @@
interrupt-map-mask = <ffffffff>;
};
+ USB0: ehci@e0000300 {
+ compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+ interrupt-parent = <&UIC0>;
+ interrupts = <1a 4>;
+ reg = <0 e0000300 90 0 e0000390 70>;
+ big-endian;
+ };
+
POB0: opb {
compatible = "ibm,opb-440epx", "ibm,opb";
#address-cells = <1>;
^ permalink raw reply
* Re: [linux-usb-devel] [PATCH 2/3] usb: ehci-ppc-of dts bindings.
From: Valentine Barshak @ 2007-09-24 19:32 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: linuxppc-dev, linux-usb-devel, David Gibson
In-Reply-To: <46F15466.6000803@ru.mvista.com>
Valentine Barshak wrote:
> Segher Boessenkool wrote:
>>>>> + Required properties:
>>>>> + - device_type : should be "usb".
>>>> No device_type please. The published USB binding doesn't define
>>>> one on purpose.
>>> Could you please, explain why?
>>> Sorry, I don't think I get the concept of device description here.
>> "device_type" is meant to be used only by OF for determining the OF
>> programming model for a device. No such thing has been defined for
>> USB busses, so the USB binding does not define a "device_type" either.
>>
>> Nothing in a flat device tree should ever define a device_type, except
>> perhaps for compatibility with legacy kernel code.
>>
>>>>> + - compatible : should be "ehci".
>>>> Just "ehci" isn't enough -- compare to OHCI, which is the name for
>>>> a kind of USB host controller as well as for a kind of Firewire
>>>> host controller.
>>> Actually, I though device type="usb" + compatible="ehci" would be enough.
>> "compatible" values are their own namespace, you should in principle
>> be able to find a driver for a device with them without having to look
>> at other properties.
>>
>>>> Maybe "usb-ehci" is best -- can anyone think of a better name?
>>> Again, why not type="usb", compatible="ehci"?
>> Because an OF client (i.e., the Linux kernel) is not supposed to use
>> "device_type" at all for its own driver matching.
>>
>>>>> + - interrupts : <a b> where a is the interrupt number and b is a
>>>>> + field that represents an encoding of the sense and level
>>>>> + information for the interrupt.
>>>> This is incorrect; not all interrupt domains use two cells, and
>>>> not all that do have this meaning for those cells.
>>> Well, this was just copied from other descriptions in
>>> Documentation/powerpc/booting-without-of.txt
>>> Do we need to fix them all?
>> Sounds like it, yes.
>>
>>>>> + If device registers are implemented in big endian mode, the device
>>>>> + node should have "big-endian" property.
>>>>> + If controller implementation operates with big endian descriptors,
>>>>> + compatible should also have "ehci-be-desc"
>>>> Ah, I understand what this is about, finally.
>>>> Don't put this in "compatible"; instead, do a "big-endian-descriptors"
>>>> property similar to the "big-endian" property. That last one should
>>>> maybe be "big-endian-registers" here then, to avoid confusion.
>>>> Or make "big-endian" mean both big-endian registers *and* big-endian
>>>> descriptors.
>>> But doesn't "big-endian" property actually mean "big-endian-registers"?
>>> Do we have to overload property meaning in this case?
>> It doesn't *have* a standard meaning, it is defined per device binding
>> that uses it. Just make it mean whatever is most logical for this
>> device.
>>
>>>> I have no opinion which is best; it depends on what configurations
>>>> actually exist, and how popular those are.
>>
>> Segher
>>
>
> OK, thanks a lot for the explanations.
> I'll modify the code.
> I think may be usb-ohci compatible values should be made properties as well,
> so that both drivers follow the same rules.
> Thanks,
> Valentine.
>
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Microsoft
> Defy all challenges. Microsoft(R) Visual Studio 2005.
> http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
> _______________________________________________
> linux-usb-devel@lists.sourceforge.net
> To unsubscribe, use the last form field at:
> https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
I've resubmitted the patches.
(http://ozlabs.org/pipermail/linuxppc-dev/2007-September/thread.html)
Please, take a look.
Thanks,
Valentine.
^ permalink raw reply
* [PATCH 6/9] fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set.
From: Scott Wood @ 2007-09-24 20:08 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
The existing OF glue code was crufty and broken. Rather than fix it, it
will be removed, and the ethernet driver now talks to the device tree
directly.
The old, non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM
platforms are dropped from arch/ppc (which will hopefully be soon), and
existing arch/powerpc boards that I wasn't able to test on for this
patchset get converted (which should be even sooner).
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Resent, with linux/of_platform.h instead of asm/of_platform.h
drivers/net/fs_enet/Kconfig | 1 +
drivers/net/fs_enet/fs_enet-main.c | 259 ++++++++++++++++++++++++++++++++---
drivers/net/fs_enet/fs_enet.h | 55 +-------
drivers/net/fs_enet/mac-fcc.c | 89 +++++++++----
drivers/net/fs_enet/mac-fec.c | 19 +++-
drivers/net/fs_enet/mac-scc.c | 53 +++++--
drivers/net/fs_enet/mii-bitbang.c | 269 +++++++++++++++++++++++++++---------
drivers/net/fs_enet/mii-fec.c | 143 +++++++++++++++++++-
include/linux/fs_enet_pd.h | 5 +
9 files changed, 714 insertions(+), 179 deletions(-)
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index e27ee21..2765e49 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -11,6 +11,7 @@ config FS_ENET_HAS_SCC
config FS_ENET_HAS_FCC
bool "Chip has an FCC usable for ethernet"
depends on FS_ENET && CPM2
+ select MDIO_BITBANG
default y
config FS_ENET_HAS_FEC
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a4b76cd..c5abdea 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -44,12 +44,18 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
+#endif
MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
MODULE_DESCRIPTION("Freescale Ethernet Driver");
@@ -953,6 +959,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
extern int fs_mii_connect(struct net_device *dev);
extern void fs_mii_disconnect(struct net_device *dev);
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static struct net_device *fs_init_instance(struct device *dev,
struct fs_platform_info *fpi)
{
@@ -1132,6 +1139,7 @@ static int fs_cleanup_instance(struct net_device *ndev)
return 0;
}
+#endif
/**************************************************************************************/
@@ -1140,35 +1148,250 @@ void *fs_enet_immap = NULL;
static int setup_immap(void)
{
- phys_addr_t paddr = 0;
- unsigned long size = 0;
-
#ifdef CONFIG_CPM1
- paddr = IMAP_ADDR;
- size = 0x10000; /* map 64K */
-#endif
-
-#ifdef CONFIG_CPM2
- paddr = CPM_MAP_ADDR;
- size = 0x40000; /* map 256 K */
+ fs_enet_immap = ioremap(IMAP_ADDR, 0x4000);
+ WARN_ON(!fs_enet_immap);
+#elif defined(CONFIG_CPM2)
+ fs_enet_immap = cpm2_immr;
#endif
- fs_enet_immap = ioremap(paddr, size);
- if (fs_enet_immap == NULL)
- return -EBADF; /* XXX ahem; maybe just BUG_ON? */
return 0;
}
static void cleanup_immap(void)
{
- if (fs_enet_immap != NULL) {
- iounmap(fs_enet_immap);
- fs_enet_immap = NULL;
- }
+#if defined(CONFIG_CPM1)
+ iounmap(fs_enet_immap);
+#endif
}
/**************************************************************************************/
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit find_phy(struct device_node *np,
+ struct fs_platform_info *fpi)
+{
+ struct device_node *phynode, *mdionode;
+ struct resource res;
+ int ret = 0, len;
+
+ const u32 *data = of_get_property(np, "phy-handle", &len);
+ if (!data || len != 4)
+ return -EINVAL;
+
+ phynode = of_find_node_by_phandle(*data);
+ if (!phynode)
+ return -EINVAL;
+
+ mdionode = of_get_parent(phynode);
+ if (!phynode)
+ goto out_put_phy;
+
+ ret = of_address_to_resource(mdionode, 0, &res);
+ if (ret)
+ goto out_put_mdio;
+
+ data = of_get_property(phynode, "reg", &len);
+ if (!data || len != 4)
+ goto out_put_mdio;
+
+ snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data);
+
+out_put_mdio:
+ of_node_put(mdionode);
+out_put_phy:
+ of_node_put(phynode);
+ return ret;
+}
+
+#ifdef CONFIG_FS_ENET_HAS_FEC
+#define IS_FEC(match) ((match)->data == &fs_fec_ops)
+#else
+#define IS_FEC(match) 0
+#endif
+
+static int __devinit fs_enet_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct net_device *ndev;
+ struct fs_enet_private *fep;
+ struct fs_platform_info *fpi;
+ const u32 *data;
+ const u8 *mac_addr;
+ int privsize, len, ret = -ENODEV;
+
+ fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
+ if (!fpi)
+ return -ENOMEM;
+
+ if (!IS_FEC(match)) {
+ data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+ if (!data || len != 4)
+ goto out_free_fpi;
+
+ fpi->cp_command = *data;
+ }
+
+ fpi->rx_ring = 32;
+ fpi->tx_ring = 32;
+ fpi->rx_copybreak = 240;
+ fpi->use_napi = 0;
+ fpi->napi_weight = 17;
+
+ ret = find_phy(ofdev->node, fpi);
+ if (ret)
+ goto out_free_fpi;
+
+ privsize = sizeof(*fep) +
+ sizeof(struct sk_buff **) *
+ (fpi->rx_ring + fpi->tx_ring);
+
+ ndev = alloc_etherdev(privsize);
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto out_free_fpi;
+ }
+
+ SET_MODULE_OWNER(ndev);
+ dev_set_drvdata(&ofdev->dev, ndev);
+
+ fep = netdev_priv(ndev);
+ fep->dev = &ofdev->dev;
+ fep->fpi = fpi;
+ fep->ops = match->data;
+
+ ret = fep->ops->setup_data(ndev);
+ if (ret)
+ goto out_free_dev;
+
+ fep->rx_skbuff = (struct sk_buff **)&fep[1];
+ fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+
+ spin_lock_init(&fep->lock);
+ spin_lock_init(&fep->tx_lock);
+
+ mac_addr = of_get_mac_address(ofdev->node);
+ if (mac_addr)
+ memcpy(ndev->dev_addr, mac_addr, 6);
+
+ ret = fep->ops->allocate_bd(ndev);
+ if (ret)
+ goto out_cleanup_data;
+
+ fep->rx_bd_base = fep->ring_base;
+ fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;
+
+ fep->tx_ring = fpi->tx_ring;
+ fep->rx_ring = fpi->rx_ring;
+
+ ndev->open = fs_enet_open;
+ ndev->hard_start_xmit = fs_enet_start_xmit;
+ ndev->tx_timeout = fs_timeout;
+ ndev->watchdog_timeo = 2 * HZ;
+ ndev->stop = fs_enet_close;
+ ndev->get_stats = fs_enet_get_stats;
+ ndev->set_multicast_list = fs_set_multicast_list;
+ if (fpi->use_napi) {
+ ndev->poll = fs_enet_rx_napi;
+ ndev->weight = fpi->napi_weight;
+ }
+ ndev->ethtool_ops = &fs_ethtool_ops;
+ ndev->do_ioctl = fs_ioctl;
+
+ init_timer(&fep->phy_timer_list);
+
+ netif_carrier_off(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto out_free_bd;
+
+ printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ return 0;
+
+out_free_bd:
+ fep->ops->free_bd(ndev);
+out_cleanup_data:
+ fep->ops->cleanup_data(ndev);
+out_free_dev:
+ free_netdev(ndev);
+ dev_set_drvdata(&ofdev->dev, NULL);
+out_free_fpi:
+ kfree(fpi);
+ return ret;
+}
+
+static int fs_enet_remove(struct of_device *ofdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct fs_enet_private *fep = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ fep->ops->free_bd(ndev);
+ fep->ops->cleanup_data(ndev);
+ dev_set_drvdata(fep->dev, NULL);
+
+ free_netdev(ndev);
+ return 0;
+}
+
+static struct of_device_id fs_enet_match[] = {
+#ifdef CONFIG_FS_ENET_HAS_SCC
+ {
+ .compatible = "fsl,cpm1-scc-enet",
+ .data = (void *)&fs_scc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FCC
+ {
+ .compatible = "fsl,cpm2-fcc-enet",
+ .data = (void *)&fs_fcc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FEC
+ {
+ .compatible = "fsl,pq1-fec-enet",
+ .data = (void *)&fs_fec_ops,
+ },
+#endif
+ {}
+};
+
+static struct of_platform_driver fs_enet_driver = {
+ .name = "fs_enet",
+ .match_table = fs_enet_match,
+ .probe = fs_enet_probe,
+ .remove = fs_enet_remove,
+};
+
+static int __init fs_init(void)
+{
+ int r = setup_immap();
+ if (r != 0)
+ return r;
+
+ r = of_register_platform_driver(&fs_enet_driver);
+ if (r != 0)
+ goto out;
+
+ return 0;
+
+out:
+ cleanup_immap();
+ return r;
+}
+
+static void __exit fs_cleanup(void)
+{
+ of_unregister_platform_driver(&fs_enet_driver);
+ cleanup_immap();
+}
+#else
static int __devinit fs_enet_probe(struct device *dev)
{
struct net_device *ndev;
@@ -1282,7 +1505,7 @@ static void __exit fs_cleanup(void)
driver_unregister(&fs_enet_scc_driver);
cleanup_immap();
}
-
+#endif
/**************************************************************************************/
module_init(fs_init);
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index f8c7ee8..14ebba8 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -24,19 +24,6 @@ struct fec_info {
#include <asm/cpm2.h>
#endif
-/* This is used to operate with pins.
- Note that the actual port size may
- be different; cpm(s) handle it OK */
-struct bb_info {
- u8 mdio_dat_msk;
- u8 mdio_dir_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dat;
- int delay;
-};
-
/* hw driver ops */
struct fs_ops {
int (*setup_data)(struct net_device *dev);
@@ -85,47 +72,11 @@ struct phy_info {
#define ENET_RX_ALIGN 16
#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)
-struct fs_enet_mii_bus {
- struct list_head list;
- spinlock_t mii_lock;
- const struct fs_mii_bus_info *bus_info;
- int refs;
- u32 usage_map;
-
- int (*mii_read)(struct fs_enet_mii_bus *bus,
- int phy_id, int location);
-
- void (*mii_write)(struct fs_enet_mii_bus *bus,
- int phy_id, int location, int value);
-
- union {
- struct {
- unsigned int mii_speed;
- void *fecp;
- } fec;
-
- struct {
- /* note that the actual port size may */
- /* be different; cpm(s) handle it OK */
- u8 mdio_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dir;
- u8 *mdc_dat;
- } bitbang;
-
- struct {
- u16 lpa;
- } fixed;
- };
-};
-
struct fs_enet_private {
struct device *dev; /* pointer back to the device (must be initialized first) */
spinlock_t lock; /* during all ops except TX pckt processing */
spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */
- const struct fs_platform_info *fpi;
+ struct fs_platform_info *fpi;
const struct fs_ops *ops;
int rx_ring, tx_ring;
dma_addr_t ring_mem_addr;
@@ -144,7 +95,6 @@ struct fs_enet_private {
u32 msg_enable;
struct mii_if_info mii_if;
unsigned int last_mii_status;
- struct fs_enet_mii_bus *mii_bus;
int interrupt;
struct phy_device *phydev;
@@ -186,9 +136,10 @@ struct fs_enet_private {
};
/***************************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
int fs_enet_mdio_bb_init(void);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
int fs_enet_mdio_fec_init(void);
+#endif
void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev);
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 8b30361..dc943fd 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -42,6 +42,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_device.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
@@ -74,33 +78,64 @@
#define MAX_CR_CMD_LOOPS 10000
-static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
const struct fs_platform_info *fpi = fep->fpi;
cpm2_map_t *immap = fs_enet_immap;
cpm_cpm2_t *cpmp = &immap->im_cpm;
- u32 v;
int i;
- /* Currently I don't know what feature call will look like. But
- I guess there'd be something like do_cpm_cmd() which will require page & sblock */
- v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);
- W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
-
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
+ return 0;
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+ struct fs_platform_info *fpi = fep->fpi;
+ int ret = -EINVAL;
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ goto out;
+
+ fep->fcc.fccp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ goto out;
+
+ fep->fcc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->fcc.ep)
+ goto out_fccp;
+
+ fep->fcc.fcccp = of_iomap(ofdev->node, 2);
+ if (!fep->fcc.fcccp)
+ goto out_ep;
+
+ fep->fcc.mem = (void *)cpm_dpalloc(128, 8);
+ fpi->dpram_offset = (u32)cpm2_immr;
+ if (IS_ERR_VALUE(fpi->dpram_offset)) {
+ ret = fpi->dpram_offset;
+ goto out_fcccp;
+ }
+
+ return 0;
+
+out_fcccp:
+ iounmap(fep->fcc.fcccp);
+out_ep:
+ iounmap(fep->fcc.ep);
+out_fccp:
+ iounmap(fep->fcc.fccp);
+out:
+ return ret;
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -138,6 +173,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
return 0;
+#endif
}
#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB)
@@ -148,11 +184,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
+
+ fpi->cp_command = (fpi->cp_page << 26) |
+ (fpi->cp_block << 21) |
+ (12 << 6);
fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
return -EINVAL;
+#endif
if (do_pd_setup(fep) != 0)
return -EINVAL;
@@ -226,7 +268,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
W16(ep, fen_taddrh, taddrh);
W16(ep, fen_taddrm, taddrm);
W16(ep, fen_taddrl, taddrl);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+ fcc_cr_cmd(fep, CPM_CR_SET_GADDR);
}
static void set_multicast_finish(struct net_device *dev)
@@ -281,7 +323,7 @@ static void restart(struct net_device *dev)
/* clear everything (slow & steady does it) */
for (i = 0; i < sizeof(*ep); i++)
- out_8((char *)ep + i, 0);
+ out_8((u8 __iomem *)ep + i, 0);
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -397,7 +439,7 @@ static void restart(struct net_device *dev)
S8(fcccp, fcc_gfemr, 0x20);
}
- fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+ fcc_cr_cmd(fep, CPM_CR_INIT_TRX);
/* clear events */
W16(fccp, fcc_fcce, 0xffff);
@@ -515,23 +557,22 @@ int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+ if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1)
return -EINVAL;
memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
p = (char *)p + sizeof(fcc_t);
- memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
- p = (char *)p + sizeof(fcc_c_t);
-
memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+ p = (char *)p + sizeof(fcc_enet_t);
+ memcpy_fromio(p, fep->fcc.fcccp, 1);
return 0;
}
int get_regs_len(struct net_device *dev)
{
- return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+ return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1;
}
/* Some transmit errors cause the transmitter to shut
@@ -551,7 +592,7 @@ void tx_restart(struct net_device *dev)
udelay(10);
S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+ fcc_cr_cmd(fep, CPM_CR_RESTART_TX);
}
/*************************************************************************/
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 04b4f80..7477da0 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_device.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -95,6 +99,19 @@ static int whack_reset(fec_t * fecp)
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->fec.fecp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ return -EINVAL;
+
+ return 0;
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
return 0;
-
+#endif
}
#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB)
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 7540966..59e0d1d 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
@@ -89,27 +93,38 @@
static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
- cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;
- u32 v, ch;
- int i = 0;
+ const struct fs_platform_info *fpi = fep->fpi;
+ int i;
- ch = fep->scc.idx << 2;
- v = mk_cr_cmd(ch, op);
- W16(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
+ return 0;
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->scc.sccp = of_iomap(ofdev->node, 0);
+ if (!fep->scc.sccp)
+ return -EINVAL;
+
+ fep->scc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->scc.ep) {
+ iounmap(fep->scc.sccp);
+ return -EINVAL;
+ }
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -129,6 +144,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
if (fep->scc.ep == NULL)
return -EINVAL;
+#endif
return 0;
}
@@ -141,12 +157,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
fep->scc.idx = fs_get_scc_index(fpi->fs_no);
- if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */
+ if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */
return -EINVAL;
+ fpi->cp_command = fep->fcc.idx << 6;
+#endif
+
do_pd_setup(fep);
fep->scc.hthi = 0;
@@ -154,7 +175,7 @@ static int setup_data(struct net_device *dev)
fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;
fep->ev_rx = SCC_RX_EVENT;
- fep->ev_tx = SCC_TX_EVENT;
+ fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE;
fep->ev_err = SCC_ERR_EVENT_MSK;
return 0;
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 8f766a5..2b9c44c 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -13,11 +13,6 @@
*/
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -25,86 +20,77 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
#include "fs_enet.h"
-static int bitbang_prep_bit(u8 **datp, u8 *mskp,
- struct fs_mii_bit *mii_bit)
-{
- void *dat;
- int adv;
- u8 msk;
-
- dat = (void*) mii_bit->offset;
-
- adv = mii_bit->bit >> 3;
- dat = (char *)dat + adv;
-
- msk = 1 << (7 - (mii_bit->bit & 7));
-
- *datp = dat;
- *mskp = msk;
-
- return 0;
-}
+struct bb_info {
+ __be32 __iomem *dir;
+ __be32 __iomem *dat;
+ u32 mdio_msk;
+ u32 mdc_msk;
+ int delay;
+};
-static inline void bb_set(u8 *p, u8 m)
+/* FIXME: If any other users of GPIO crop up, then these will have to
+ * have some sort of global synchronization to avoid races with other
+ * pins on the same port. The ideal solution would probably be to
+ * bind the ports to a GPIO driver, and have this be a client of it.
+ */
+static inline void bb_set(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) | m);
+ out_be32(p, in_be32(p) | m);
}
-static inline void bb_clr(u8 *p, u8 m)
+static inline void bb_clr(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) & ~m);
+ out_be32(p, in_be32(p) & ~m);
}
-static inline int bb_read(u8 *p, u8 m)
+static inline int bb_read(u32 __iomem *p, u32 m)
{
- return (in_8(p) & m) != 0;
+ return (in_be32(p) & m) != 0;
}
static inline void mdio_active(struct bb_info *bitbang)
{
- bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
+ bb_set(bitbang->dir, bitbang->mdio_msk);
}
-static inline void mdio_tristate(struct bb_info *bitbang )
+static inline void mdio_tristate(struct bb_info *bitbang)
{
- bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
+ bb_clr(bitbang->dir, bitbang->mdio_msk);
}
-static inline int mdio_read(struct bb_info *bitbang )
+static inline int mdio_read(struct bb_info *bitbang)
{
- return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ return bb_read(bitbang->dat, bitbang->mdio_msk);
}
-static inline void mdio(struct bb_info *bitbang , int what)
+static inline void mdio(struct bb_info *bitbang, int what)
{
if (what)
- bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_set(bitbang->dat, bitbang->mdio_msk);
else
- bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_clr(bitbang->dat, bitbang->mdio_msk);
}
-static inline void mdc(struct bb_info *bitbang , int what)
+static inline void mdc(struct bb_info *bitbang, int what)
{
if (what)
- bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_set(bitbang->dat, bitbang->mdc_msk);
else
- bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_clr(bitbang->dat, bitbang->mdc_msk);
}
-static inline void mii_delay(struct bb_info *bitbang )
+static inline void mii_delay(struct bb_info *bitbang)
{
udelay(bitbang->delay);
}
@@ -280,29 +266,178 @@ static int fs_enet_mii_bb_reset(struct mii_bus *bus)
return 0;
}
-static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
{
- int r;
+ struct resource res;
+ const u32 *data;
+ int mdio_pin, mdc_pin, len;
+ struct bb_info *bitbang = bus->priv;
- bitbang->delay = fmpi->delay;
+ int ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+
+ if (res.end - res.start < 13)
+ return -ENODEV;
+
+ /* This should really encode the pin number as well, but all
+ * we get is an int, and the odds of multiple bitbang mdio buses
+ * is low enough that it's not worth going too crazy.
+ */
+ bus->id = res.start;
+
+ data = of_get_property(np, "fsl,mdio-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdio_pin = *data;
+
+ data = of_get_property(np, "fsl,mdc-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdc_pin = *data;
+
+ bitbang->dir = ioremap(res.start, res.end - res.start + 1);
+ if (!bitbang->dir)
+ return -ENOMEM;
+
+ bitbang->dat = bitbang->dir + 4;
+ bitbang->mdio_msk = 1 << (31 - mdio_pin);
+ bitbang->mdc_msk = 1 << (31 - mdc_pin);
+ bitbang->delay = 1; /* 1 us between operations */
- r = bitbang_prep_bit(&bitbang->mdio_dir,
- &bitbang->mdio_dir_msk,
- &fmpi->mdio_dir);
- if (r != 0)
- return r;
-
- r = bitbang_prep_bit(&bitbang->mdio_dat,
- &bitbang->mdio_dat_msk,
- &fmpi->mdio_dat);
- if (r != 0)
- return r;
-
- r = bitbang_prep_bit(&bitbang->mdc_dat,
- &bitbang->mdc_msk,
- &fmpi->mdc_dat);
- if (r != 0)
- return r;
+ return 0;
+}
+
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct mii_bus *new_bus;
+ struct bb_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!new_bus)
+ goto out;
+
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ if (!bitbang)
+ goto out_free_bus;
+
+ new_bus->priv = bitbang;
+ new_bus->name = "CPM2 Bitbanged MII",
+ new_bus->read = &fs_enet_mii_bb_read,
+ new_bus->write = &fs_enet_mii_bb_write,
+ new_bus->reset = &fs_enet_mii_bb_reset,
+
+ ret = fs_mii_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bitbang;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(bitbang->dir);
+out_free_bitbang:
+ kfree(bitbang);
+out_free_bus:
+ kfree(new_bus);
+out:
+ return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct bb_info *bitbang = bus->priv;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(bitbang->dir);
+ kfree(bitbang);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id fs_enet_mdio_bb_match[] = {
+ {
+ .compatible = "fsl,cpm2-mdio-bitbang",
+ },
+ {},
+};
+
+static struct of_platform_driver fs_enet_bb_mdio_driver = {
+ .name = "fsl-bb-mdio",
+ .match_table = fs_enet_mdio_bb_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+int fs_enet_mdio_bb_init(void)
+{
+ return of_register_platform_driver(&fs_enet_bb_mdio_driver);
+}
+
+void fs_enet_mdio_bb_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
+}
+
+module_init(fs_enet_mdio_bb_init);
+module_exit(fs_enet_mdio_bb_exit);
+#else
+static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
+ struct fs_mii_bb_platform_info *fmpi)
+{
+ bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
+ bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
+ bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
+ bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
+ bitbang->delay = fmpi->delay;
return 0;
}
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 53db696..07b6f20 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -47,6 +51,7 @@
#define FEC_MII_LOOPS 10000
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static int match_has_phy (struct device *dev, void* data)
{
struct platform_device* pdev = container_of(dev, struct platform_device, dev);
@@ -90,6 +95,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info
return 0;
}
+#endif
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
@@ -145,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
return 0;
}
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct resource res;
+ struct mii_bus *new_bus;
+ struct fec_info *fec;
+ int ret = -ENOMEM, i;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!new_bus)
+ goto out;
+
+ fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+ if (!fec)
+ goto out_mii;
+
+ new_bus->priv = fec;
+ new_bus->name = "FEC MII Bus";
+ new_bus->read = &fs_enet_fec_mii_read;
+ new_bus->write = &fs_enet_fec_mii_write;
+ new_bus->reset = &fs_enet_fec_mii_reset;
+
+ ret = of_address_to_resource(ofdev->node, 0, &res);
+ if (ret)
+ return ret;
+
+ new_bus->id = res.start;
+
+ fec->fecp = ioremap(res.start, res.end - res.start + 1);
+ if (!fec->fecp)
+ goto out_fec;
+
+ fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+
+ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+ setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
+ FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
+ out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(fec->fecp);
+out_fec:
+ kfree(fec);
+out_mii:
+ kfree(new_bus);
+out:
+ return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct fec_info *fec = bus->priv;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(fec->fecp);
+ kfree(fec);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id fs_enet_mdio_fec_match[] = {
+ {
+ .compatible = "fsl,pq1-fec-mdio",
+ },
+ {},
+};
+
+static struct of_platform_driver fs_enet_fec_mdio_driver = {
+ .name = "fsl-fec-mdio",
+ .match_table = fs_enet_mdio_fec_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+static int fs_enet_mdio_fec_init(void)
+{
+ return of_register_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+static void fs_enet_mdio_fec_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+module_init(fs_enet_mdio_fec_init);
+module_exit(fs_enet_mdio_fec_exit);
+#else
static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -235,4 +376,4 @@ void fs_enet_mdio_fec_exit(void)
{
driver_unregister(&fs_enet_fec_mdio_driver);
}
-
+#endif
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 815c6f9..9bc045b 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -120,6 +120,7 @@ struct fs_platform_info {
u32 cp_page; /* CPM page */
u32 cp_block; /* CPM sblock */
+ u32 cp_command; /* CPM page/sblock/mcn */
u32 clk_trx; /* some stuff for pins & mux configuration*/
u32 clk_rx;
@@ -134,7 +135,11 @@ struct fs_platform_info {
u32 device_flags;
int phy_addr; /* the phy address (-1 no phy) */
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ char bus_id[16];
+#else
const char* bus_id;
+#endif
int phy_irq; /* the phy irq (if it exists) */
const struct fs_mii_bus_info *bus_info;
--
1.5.3.1
^ permalink raw reply related
* [PATCH 15/40] bootwrapper: Factor out dt_set_mac_address().
From: Scott Wood @ 2007-09-24 20:09 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
This allows callers to set addresses one at a time when that would be more
convenient.
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Resent, with dt_set_mac_address -> dt-fixup_mac_address.
arch/powerpc/boot/devtree.c | 31 +++++++++++++++++--------------
arch/powerpc/boot/ops.h | 1 +
2 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
index 549463b..e5dfe44 100644
--- a/arch/powerpc/boot/devtree.c
+++ b/arch/powerpc/boot/devtree.c
@@ -88,29 +88,32 @@ void dt_fixup_clock(const char *path, u32 freq)
}
}
+void dt_fixup_mac_address(u32 index, const u8 *addr)
+{
+ void *devp = find_node_by_prop_value(NULL, "linux,network-index",
+ (void*)&index, sizeof(index));
+
+ if (devp) {
+ printf("ENET%d: local-mac-address <-"
+ " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
+ addr[0], addr[1], addr[2],
+ addr[3], addr[4], addr[5]);
+
+ setprop(devp, "local-mac-address", addr, 6);
+ }
+}
+
void __dt_fixup_mac_addresses(u32 startindex, ...)
{
va_list ap;
u32 index = startindex;
- void *devp;
const u8 *addr;
va_start(ap, startindex);
- while ((addr = va_arg(ap, const u8 *))) {
- devp = find_node_by_prop_value(NULL, "linux,network-index",
- (void*)&index, sizeof(index));
- if (devp) {
- printf("ENET%d: local-mac-address <-"
- " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
- addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
+ while ((addr = va_arg(ap, const u8 *)))
+ dt_fixup_mac_address(index++, addr);
- setprop(devp, "local-mac-address", addr, 6);
- }
-
- index++;
- }
va_end(ap);
}
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 703255b..5b77fe3 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -160,6 +160,7 @@ static inline void *find_node_by_devtype(const void *prev,
void dt_fixup_memory(u64 start, u64 size);
void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq);
void dt_fixup_clock(const char *path, u32 freq);
+void dt_fixup_mac_address(u32 index, const u8 *addr);
void __dt_fixup_mac_addresses(u32 startindex, ...);
#define dt_fixup_mac_addresses(...) \
__dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
--
1.5.3.1
^ permalink raw reply related
* [PATCH 2/2] bootwrapper: Add PlanetCore firmware support.
From: Scott Wood @ 2007-09-24 20:09 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
This is a library that board code can use to extract information from the
PlanetCore configuration keys. PlanetCore is used on various boards from
Embedded Planet.
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Resent, with dt_set_mac_address -> dt_fixup_mac_address.
arch/powerpc/boot/Makefile | 2 +-
arch/powerpc/boot/planetcore.c | 166 ++++++++++++++++++++++++++++++++++++++++
arch/powerpc/boot/planetcore.h | 49 ++++++++++++
3 files changed, 216 insertions(+), 1 deletions(-)
create mode 100644 arch/powerpc/boot/planetcore.c
create mode 100644 arch/powerpc/boot/planetcore.h
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index cffef14..9ec785c 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -45,7 +45,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
- cpm-serial.c stdlib.c
+ cpm-serial.c stdlib.c planetcore.c
src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
diff --git a/arch/powerpc/boot/planetcore.c b/arch/powerpc/boot/planetcore.c
new file mode 100644
index 0000000..0d8558a
--- /dev/null
+++ b/arch/powerpc/boot/planetcore.c
@@ -0,0 +1,166 @@
+/*
+ * PlanetCore configuration data support functions
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "ops.h"
+#include "planetcore.h"
+#include "io.h"
+
+/* PlanetCore passes information to the OS in the form of
+ * a table of key=value strings, separated by newlines.
+ *
+ * The list is terminated by an empty string (i.e. two
+ * consecutive newlines).
+ *
+ * To make it easier to parse, we first convert all the
+ * newlines into null bytes.
+ */
+
+void planetcore_prepare_table(char *table)
+{
+ do {
+ if (*table == '\n')
+ *table = 0;
+
+ table++;
+ } while (*(table - 1) || *table != '\n');
+
+ *table = 0;
+}
+
+const char *planetcore_get_key(const char *table, const char *key)
+{
+ int keylen = strlen(key);
+
+ do {
+ if (!strncmp(table, key, keylen) && table[keylen] == '=')
+ return table + keylen + 1;
+
+ table += strlen(table) + 1;
+ } while (strlen(table) != 0);
+
+ return NULL;
+}
+
+int planetcore_get_decimal(const char *table, const char *key, u64 *val)
+{
+ const char *str = planetcore_get_key(table, key);
+ if (!str)
+ return 0;
+
+ *val = strtoull(str, NULL, 10);
+ return 1;
+}
+
+int planetcore_get_hex(const char *table, const char *key, u64 *val)
+{
+ const char *str = planetcore_get_key(table, key);
+ if (!str)
+ return 0;
+
+ *val = strtoull(str, NULL, 16);
+ return 1;
+}
+
+static u64 mac_table[4] = {
+ 0x000000000000,
+ 0x000000800000,
+ 0x000000400000,
+ 0x000000c00000,
+};
+
+void planetcore_set_mac_addrs(const char *table)
+{
+ u8 addr[4][6];
+ u64 int_addr;
+ u32 i;
+ int j;
+
+ if (!planetcore_get_hex(table, PLANETCORE_KEY_MAC_ADDR, &int_addr))
+ return;
+
+ for (i = 0; i < 4; i++) {
+ u64 this_dev_addr = (int_addr & ~0x000000c00000) |
+ mac_table[i];
+
+ for (j = 5; j >= 0; j--) {
+ addr[i][j] = this_dev_addr & 0xff;
+ this_dev_addr >>= 8;
+ }
+
+ dt_fixup_mac_address(i, addr[i]);
+ }
+}
+
+static char prop_buf[MAX_PROP_LEN];
+
+void planetcore_set_stdout_path(const char *table)
+{
+ char *path;
+ const char *label;
+ void *node, *chosen;
+
+ label = planetcore_get_key(table, PLANETCORE_KEY_SERIAL_PORT);
+ if (!label)
+ return;
+
+ node = find_node_by_prop_value_str(NULL, "linux,planetcore-label",
+ label);
+ if (!node)
+ return;
+
+ path = get_path(node, prop_buf, MAX_PROP_LEN);
+ if (!path)
+ return;
+
+ chosen = finddevice("/chosen");
+ if (!chosen)
+ chosen = create_node(NULL, "chosen");
+ if (!chosen)
+ return;
+
+ setprop_str(chosen, "linux,stdout-path", path);
+}
+
+void planetcore_set_serial_speed(const char *table)
+{
+ void *chosen, *stdout;
+ u64 baud;
+ u32 baud32;
+ int len;
+
+ chosen = finddevice("/chosen");
+ if (!chosen)
+ return;
+
+ len = getprop(chosen, "linux,stdout-path", prop_buf, MAX_PROP_LEN);
+ if (len <= 0)
+ return;
+
+ stdout = finddevice(prop_buf);
+ if (!stdout) {
+ printf("planetcore_set_serial_speed: "
+ "Bad /chosen/linux,stdout-path.\r\n");
+
+ return;
+ }
+
+ if (!planetcore_get_decimal(table, PLANETCORE_KEY_SERIAL_BAUD,
+ &baud)) {
+ printf("planetcore_set_serial_speed: No SB tag.\r\n");
+ return;
+ }
+
+ baud32 = baud;
+ setprop(stdout, "current-speed", &baud32, 4);
+}
diff --git a/arch/powerpc/boot/planetcore.h b/arch/powerpc/boot/planetcore.h
new file mode 100644
index 0000000..0d4094f
--- /dev/null
+++ b/arch/powerpc/boot/planetcore.h
@@ -0,0 +1,49 @@
+#ifndef _PPC_BOOT_PLANETCORE_H_
+#define _PPC_BOOT_PLANETCORE_H_
+
+#include "types.h"
+
+#define PLANETCORE_KEY_BOARD_TYPE "BO"
+#define PLANETCORE_KEY_BOARD_REV "BR"
+#define PLANETCORE_KEY_MB_RAM "D1"
+#define PLANETCORE_KEY_MAC_ADDR "EA"
+#define PLANETCORE_KEY_FLASH_SPEED "FS"
+#define PLANETCORE_KEY_IP_ADDR "IP"
+#define PLANETCORE_KEY_KB_NVRAM "NV"
+#define PLANETCORE_KEY_PROCESSOR "PR"
+#define PLANETCORE_KEY_PROC_VARIANT "PV"
+#define PLANETCORE_KEY_SERIAL_BAUD "SB"
+#define PLANETCORE_KEY_SERIAL_PORT "SP"
+#define PLANETCORE_KEY_SWITCH "SW"
+#define PLANETCORE_KEY_TEMP_OFFSET "TC"
+#define PLANETCORE_KEY_TARGET_IP "TIP"
+#define PLANETCORE_KEY_CRYSTAL_HZ "XT"
+
+/* Prepare the table for processing, by turning all newlines
+ * into NULL bytes.
+ */
+void planetcore_prepare_table(char *table);
+
+/* Return the value associated with a given key in text,
+ * decimal, or hex format.
+ *
+ * Returns zero/NULL on failure, non-zero on success.
+ */
+const char *planetcore_get_key(const char *table, const char *key);
+int planetcore_get_decimal(const char *table, const char *key, u64 *val);
+int planetcore_get_hex(const char *table, const char *key, u64 *val);
+
+/* Updates the device tree local-mac-address properties based
+ * on the EA tag.
+ */
+void planetcore_set_mac_addrs(const char *table);
+
+/* Sets the linux,stdout-path in the /chosen node. This requires the
+ * linux,planetcore-label property in each serial node.
+ */
+void planetcore_set_stdout_path(const char *table);
+
+/* Sets the current-speed property in the serial node. */
+void planetcore_set_serial_speed(const char *table);
+
+#endif
--
1.5.3.1
^ permalink raw reply related
* Re: [PATCH 15/40] bootwrapper: Factor out dt_set_mac_address().
From: Scott Wood @ 2007-09-24 20:12 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev
In-Reply-To: <20070924200911.GB21347@loki.buserror.net>
Scott Wood wrote:
> [PATCH 15/40]
Bah, that was supposed to be 1/2. Don't worry, there's no barrage of
patches coming. :-)
-Scott
^ permalink raw reply
* Re: Sequoia kernel crash workaround.
From: Benjamin Herrenschmidt @ 2007-09-24 20:55 UTC (permalink / raw)
To: Valentine Barshak
Cc: linuxppc-dev, Olof Johansson, Josh Boyer, Stefan Roese,
David Gibson
In-Reply-To: <46F79305.9050300@ru.mvista.com>
On Mon, 2007-09-24 at 14:35 +0400, Valentine Barshak wrote:
>
> From what I've seen, setup_cpu is never called for BOOKE.
> Currently It's called from cputable.c for PPC64 and from head_32.S for
> 6xx.
> Thanks,
Right. We need to fix/converge some of these but it's not totally
trivial.
Ben.
^ permalink raw reply
* Re: Sequoia kernel crash workaround.
From: Josh Boyer @ 2007-09-24 21:01 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Olof Johansson, Josh Boyer, Stefan Roese,
David Gibson
In-Reply-To: <1190667350.6886.59.camel@localhost.localdomain>
On Tue, 25 Sep 2007 06:55:50 +1000
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> On Mon, 2007-09-24 at 14:35 +0400, Valentine Barshak wrote:
> >
> > From what I've seen, setup_cpu is never called for BOOKE.
> > Currently It's called from cputable.c for PPC64 and from head_32.S for
> > 6xx.
> > Thanks,
>
> Right. We need to fix/converge some of these but it's not totally
> trivial.
Valentine has patches for adding this for BookE on the list.
josh
^ permalink raw reply
* Re: [patch 3/3] mpc8349emitx.dts: Add ds1339 RTC
From: Segher Boessenkool @ 2007-09-24 21:11 UTC (permalink / raw)
To: David Gibson; +Cc: Timur Tabi, linuxppc-dev
In-Reply-To: <20070924050709.GM8058@localhost.localdomain>
>> Scott> #size-cells is zero on i2c, so it should just be reg = <68>.
>>
>> Scott> You'll probably need to add #address-cells and #size-cells to
>> the
>> Scott> controller node, as well.
>
> Uh.. yes.. i2c interfaces should really always have #a and #s.
More generally, every node that defines a bus needs it (unless the
defaults of 2 resp. 1 are correct for this bus, but even then you
might want it because it makes things more explicit).
>> i2c@3100 {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> device_type = "i2c";
>
> Hrm... we probably want an "i2c" device_type class, but I don't think
> we've actually defined one, which is a problem
By defining new device_type's, or new semantics for device_type,
you open the door to (accidentally) becoming incompatible with
"real" OF.
And you don't need to: "real" OF has a mechanism for specifying
the "generic device class" already, if you use the "generic names"
recommended practice (and you do, for both this node and the rtc
node): it's the generic name itself!
>> + rtc@68 {
>> + device_type = "rtc";
>> + compatible = "dallas,ds1339";
>> + reg = <68>;
>> + };
>
> I think we want to think a bit more carefully about how to do bindings
> for RTC devices. No "rtc" device_type is defined, but again we might
> want to.
Actually, "device_type" = "rtc" _is_ defined (in the "device support
extensions" recommended practice), and there is no useful way a flat
device tree can implement it (it merely defines get-time and set-time
methods).
> The fact that NVRAM+RTC chips are so common is a bit of an issue from
> the point of view of defining a device class binding - a device can't
> have type "rtc" and "nvram".
You should match OS drivers on "compatible" only anyway.
Those cases where OS drivers don't nicely 1-1 match device nodes are a
bit of a headache; for RTC/NVRAM devices, these problems are nicely
side-stepped by handling this from platform code.
Segher
^ permalink raw reply
* EBC peripheral, access causing Machine Check
From: Dave Cogley @ 2007-09-24 19:19 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 916 bytes --]
Good Afternoon,
I am using an AMCC 440EPx processor with an FPGA peripheral attached to the
EBC. I am doing the entire bank configuration in the u-boot boot loader
before Linux is loaded. I can directly read and write registers using
memory read and write (md, nm) within area 0xC0000000 to 0xC000FFFF direct
memory I/O within the context of u-boot without any faults. When I attempt
to access any register in area 0xC000000 within the context of my Linux
device driver I get a Machine Check fault (attached text) which appears to
be an access permission violation. I am currently running the DENX ELDK
2.6.19.2 platform that was specific to the "Sequoia" platform.
I have configured the EBC access permissions and control resisters as
follows for bank 1:
PB1CR: 0xC003C000
PB1AP: 0x80040380
Dave Cogley
Software Engineer
Ultra Stereo Labs, Inc.
(805) 549-0161
mailto:dcogley@uslinc.com
[-- Attachment #1.2: Type: text/html, Size: 3940 bytes --]
[-- Attachment #2: mcdump.txt --]
[-- Type: text/plain, Size: 1767 bytes --]
bash-3.00#
Machine check in kernel mode.
Data Read PLB Error
OPB to PLB3: BSTAT= 0x00000000
PLB3 to PLB4: BEAR=0xffffffffffffffff BESR0=0x00000000 BESR1=0x00000000
PLB4 to PLB3: BEAR=0xfffffffffffffffd BESR0=0x00000000 BESR1=0x00000000
PLB3 to OPB: BEAR=0xffffffff BESR0=0x00000000 BESR1=0x00000000
PLB3 arbiter: BEAR=0xfffffffe ACR=0x00000000 BESR=0x00000000
PLB4 to OPB1: BEAR=0x0000000dbfffffbf BESR0=0x00000000 BESR1=0x00000000
PLB40 Arbiter: BEAR=0x00000000c0000000 ACR=0xda000000 BESR0=0x0f000000
PLB41 Arbiter: BEAR=0xfffffffffffffffc ACR=0xdb000000 BESR0=0x00000000
POB0: BEAR=0xc27e3194ffffffff BESR0=0x00000000 BESR1=0x00000000
OPB0: BEAR=0x0000000000000000 BSTAT=0x00000000
Oops: machine check, sig: 7 [#2]
NIP: D107E2D4 LR: C0069F24 CTR: 0FF40B20
REGS: c02a9f50 TRAP: 0202 Not tainted (2.6.19.2)
MSR: 00029000 <EE,ME> CR: 40000022 XER: 00000000
TASK = cf6c1030[268] 'banjocore' THREAD: cf1b8000
GPR00: 40044B01 CF1B9EB0 CF6C1030 00000000 CF0EF5C0 40044B01 7F95B928 0FF39D08
GPR08: 00000000 00000000 FFFFFFE7 D1080000 80000028 10018B10 00000000 100D8ED8
GPR16: 100C0000 00000000 100C0000 10090000 00000000 100DF660 100C7C48 00000000
GPR24: 100D9038 00000000 100D8F58 40044B01 FFFFFFF7 CF0EF5C0 0FFBB73C 7F95B928
NIP [D107E2D4] banjo_ioctl+0xc0/0x14c [banjodecoder]
LR [C0069F24] do_ioctl+0x80/0x84
Call Trace:
[CF1B9EB0] [00000001] 0x1 (unreliable)
[CF1B9ED0] [C0069F24] do_ioctl+0x80/0x84
[CF1B9EE0] [C0069FB4] vfs_ioctl+0x8c/0x418
[CF1B9F10] [C006A380] sys_ioctl+0x40/0x74
[CF1B9F40] [C0001C84] ret_from_syscall+0x0/0x3c
Instruction dump:
60004b00 7f850000 419e0044 3c004004 60004b01 7f850000 38600000 409eff74
3d60d108 812bf2a4 7c0004ac 7d204c2c <0c090000> 4c00012c 38600000 91260000
Bus error
bash-3.00#
^ permalink raw reply
* Re: [PATCH 2/3] usb: ehci-ppc-of dts bindings.
From: Segher Boessenkool @ 2007-09-24 21:40 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev, linux-usb-devel
In-Reply-To: <20070920005201.GE14404@localhost.localdomain>
>> Nothing in a flat device tree should ever define a device_type, except
>> perhaps for compatibility with legacy kernel code.
>
> This is not necessarily true. As Segher says, device_type originally
> indicated the OF programming model for a device. However, we've
> extended the notion for the flat device tree to allow device_type to
> cover "device classes" which could have certain common properties and
> semantics.
Such device classes are already handled by the "generic names"
recommended practice.
Reusing device_type for a different purpose is dangerous: before you
know it, you'll end up with a conflict, as was nicely demonstrated
today with device_type "rtc".
> However, in this case, a meaningful class binding must
> already be defined: it might make sense for usb to have a defined
> device_type, but it's not been defined so far, so for now you must
> omit device_type (if a device_type is defined in future, it's easier
> to add legacy hooks that will include devices which are missing the
> relevant device_type marker than to work around devices which *do*
> have the marker, but pre-date and don't follow the defined class
> binding).
Nothing in the kernel should assume it can find all devices of a
certain "class" any other way than by exhaustively matching on
possible "compatible" values. I'm not sure why you would want to,
anyway: you need "compatible" to select which driver to use, already.
Segher
^ permalink raw reply
* Re: EBC peripheral, access causing Machine Check
From: Josh Boyer @ 2007-09-24 23:42 UTC (permalink / raw)
To: Dave Cogley; +Cc: linuxppc-embedded
In-Reply-To: <005301c7fedf$c46f7770$9601a8c0@DCOGLEYNEW>
On Mon, 24 Sep 2007 12:19:01 -0700
"Dave Cogley" <dcogley@uslinc.com> wrote:
> Good Afternoon,
>
>
>
> I am using an AMCC 440EPx processor with an FPGA peripheral attached to the
> EBC. I am doing the entire bank configuration in the u-boot boot loader
> before Linux is loaded. I can directly read and write registers using
> memory read and write (md, nm) within area 0xC0000000 to 0xC000FFFF direct
> memory I/O within the context of u-boot without any faults. When I attempt
> to access any register in area 0xC000000 within the context of my Linux
> device driver I get a Machine Check fault (attached text) which appears to
> be an access permission violation. I am currently running the DENX ELDK
> 2.6.19.2 platform that was specific to the "Sequoia" platform.
>
>
>
> I have configured the EBC access permissions and control resisters as
> follows for bank 1:
>
>
>
> PB1CR: 0xC003C000
>
> PB1AP: 0x80040380
You need proper TLB entries set up before you can access things. Linux
discards the MMU settings that U-Boot does. So your driver needs to call
ioremap on the physical address.
Other than that, we can't help you much without your driver code.
josh
^ permalink raw reply
* [PATCH 1/2] powerpc: ptrace CHECK_FULL_REGS
From: Roland McGrath @ 2007-09-24 23:50 UTC (permalink / raw)
To: Paul Mackerras, linuxppc-dev
Cc: David Woodhouse, Andrew Morton, Linus Torvalds, linux-kernel
This restores the CHECK_FULL_REGS sanity check to every place that can
access the nonvolatile GPRs for ptrace. This is already done for
native-bitwidth PTRACE_PEEKUSR, but was omitted for many other cases
(32-bit ptrace, PTRACE_GETREGS, etc.); I think there may have been more
uniform checks before that were lost in the recent cleanup of GETREGS et al.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 4 ++++
arch/powerpc/kernel/ptrace32.c | 8 ++++++++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 8a177bd..40d34b3 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -331,6 +331,7 @@ static long arch_ptrace_old(struct task_struct *child, long request, long addr,
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;
+ CHECK_FULL_REGS(child->thread.regs);
for (i = 0; i < 32; i++) {
ret = put_user(*reg, tmp);
if (ret)
@@ -346,6 +347,7 @@ static long arch_ptrace_old(struct task_struct *child, long request, long addr,
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned long __user *tmp = (unsigned long __user *)addr;
+ CHECK_FULL_REGS(child->thread.regs);
for (i = 0; i < 32; i++) {
ret = get_user(*reg, tmp);
if (ret)
@@ -517,6 +519,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
break;
}
+ CHECK_FULL_REGS(child->thread.regs);
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
ret |= __put_user(ptrace_get_reg(child, ui),
@@ -537,6 +540,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
break;
}
+ CHECK_FULL_REGS(child->thread.regs);
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
ret = __get_user(tmp, (unsigned long __user *) data);
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 9e6baea..6b86960 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -53,6 +53,7 @@ static long compat_ptrace_old(struct task_struct *child, long request,
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned int __user *tmp = (unsigned int __user *)addr;
+ CHECK_FULL_REGS(child->thread.regs);
for (i = 0; i < 32; i++) {
ret = put_user(*reg, tmp);
if (ret)
@@ -68,6 +69,7 @@ static long compat_ptrace_old(struct task_struct *child, long request,
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
unsigned int __user *tmp = (unsigned int __user *)addr;
+ CHECK_FULL_REGS(child->thread.regs);
for (i = 0; i < 32; i++) {
ret = get_user(*reg, tmp);
if (ret)
@@ -164,6 +166,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
if ((addr & 3) || (index > PT_FPSCR32))
break;
+ CHECK_FULL_REGS(child->thread.regs);
if (index < PT_FPR0) {
tmp = ptrace_get_reg(child, index);
} else {
@@ -210,6 +213,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
if ((addr & 3) || numReg > PT_FPSCR)
break;
+ CHECK_FULL_REGS(child->thread.regs);
if (numReg >= PT_FPR0) {
flush_fp_to_thread(child);
tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
@@ -270,6 +274,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
if ((addr & 3) || (index > PT_FPSCR32))
break;
+ CHECK_FULL_REGS(child->thread.regs);
if (index < PT_FPR0) {
ret = ptrace_put_reg(child, index, data);
} else {
@@ -307,6 +312,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
*/
if ((addr & 3) || (numReg > PT_FPSCR))
break;
+ CHECK_FULL_REGS(child->thread.regs);
if (numReg < PT_FPR0) {
unsigned long freg = ptrace_get_reg(child, numReg);
if (index % 2)
@@ -342,6 +348,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
ret = -EIO;
break;
}
+ CHECK_FULL_REGS(child->thread.regs);
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
ret |= __put_user(ptrace_get_reg(child, ui),
@@ -359,6 +366,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
ret = -EIO;
break;
}
+ CHECK_FULL_REGS(child->thread.regs);
ret = 0;
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
ret = __get_user(tmp, (unsigned int __user *) data);
^ permalink raw reply related
* [PATCH 2/2] powerpc: FULL_REGS on exec
From: Roland McGrath @ 2007-09-24 23:52 UTC (permalink / raw)
To: Paul Mackerras, linuxppc-dev
Cc: David Woodhouse, Andrew Morton, Linus Torvalds, linux-kernel
When PTRACE_O_TRACEEXEC is used, a ptrace call to fetch the registers at
the PTRACE_EVENT_EXEC stop (PTRACE_PEEKUSR) will oops in CHECK_FULL_REGS.
With recent versions, "gdb --args /bin/sh -c 'exec /bin/true'" and "run" at
the (gdb) prompt is sufficient to produce this. I also have written an
isolated test case, see https://bugzilla.redhat.com/show_bug.cgi?id=301791#c15.
This change fixes the problem by clearing the low bit of pt_regs.trap in
start_thread so that FULL_REGS is true again. This is correct since all of
the GPRs that "full" refers to are cleared in start_thread.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/process.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e477c9d..fd799d2 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -605,6 +605,13 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
regs->ccr = 0;
regs->gpr[1] = sp;
+ /*
+ * We have just cleared all the nonvolatile GPRs, so make
+ * FULL_REGS(regs) return true. This is necessary to allow
+ * ptrace to examine the thread immediately after exec.
+ */
+ regs->trap &= ~1UL;
+
#ifdef CONFIG_PPC32
regs->mq = 0;
regs->nip = start;
^ permalink raw reply related
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