USB and PCMCIA
Matan Ziv-Av
matan@svgalib.org
Mon Jul 12 19:53:37 CEST 2004
Hi,
not willing to let a day go with nothing posted to the list, here is
what I have to say:
USB:
The attached patch is for 'almost' working usb. The problem is that when
devices are inserted they are "not accepting new address". Unlike when I
had this problem in 2.4, now both interrupts and dma appear to work OK,
so it will be harder to debug.
PCMCIA: The code in CVS now seems more buggy. About half of the times I
boot, I get the following:
sa1101 pcmcia: probe...
sa1101_pcmcia_hw_init... 0
sa1101_pcmcia_hw_init... 0
Unable to handle kernel NULL pointer dereference at virtual address 00000008
pgd = c0204000
[00000008] *pgd=00000000
Internal error: Oops: c0207005 [#1]
Modules linked in:
CPU: 0
PC is at sysfs_add_file+0xc/0xbc
LR is at class_device_create_file+0x24/0x30
pc : [<c02a3240>] lr : [<c0318bd0>] Not tainted
sp : c0fe5ebc ip : c0fe5edc fp : c0fe5ed8
r10: 00000002 r9 : 00000002 r8 : c041a338
r7 : c003fd18 r6 : c003fadc r5 : 00000000 r4 : c003fad8
r3 : ffffffea r2 : 00000000 r1 : c041a25c r0 : 00000000
Flags: NzCv IRQs on FIQs on Mode SVC_32 Segment kernel
Control: C020717F Table: C020717F DAC: 0000001D
Process swapper (pid: 1, stack limit = 0xc0fe4108)
Stack: (0xc0fe5ebc to 0xc0fe6000)
5ea0: c003fad8
5ec0: 00000000 c003fadc c003fd18 c0fe5ee8 c0fe5edc c0318bd0 c02a3240 c0fe5f28
5ee0: c0fe5eec c034f86c c0318bb8 c003fd90 c003f800 00000000 c041a39c c087fe54
5f00: c087fe54 ffffffed c041a320 c0404524 c041a338 00000000 00000000 c0fe5f3c
5f20: c0fe5f2c c0350284 c034f55c c087fe54 c0fe5f4c c0fe5f40 c0226b7c c035024c
5f40: c0fe5f68 c0fe5f50 c0318210 c0226b60 c087fe5c c041a320 c0404580 c0fe5f84
5f60: c0fe5f6c c0318314 c03181d4 c04044d8 c041a320 00000000 c0fe5fa8 c0fe5f88
5f80: c03185a8 c03182d4 c0218938 c0fe4000 00000001 c0218970 00000000 c0fe5fbc
5fa0: c0fe5fac c0318934 c0318520 c0218938 c0fe5fdc c0fe5fc0 c02086e0 c0318904
5fc0: c0fe4000 c03d5574 00000000 00000000 c0fe5ff4 c0fe5fe0 c021924c c020868c
5fe0: 00000000 00000000 00000000 c0fe5ff8 c023597c c0219200 00000000 00000000
Backtrace:
[<c02a3234>] (sysfs_add_file+0x0/0xbc) from [<c0318bd0>] (class_device_create_file+0x24/0x30)
r7 = C003FD18 r6 = C003FADC r5 = 00000000 r4 = C003FAD8
[<c0318bac>] (class_device_create_file+0x0/0x30) from [<c034f86c>] (soc_common_drv_pcmcia_probe+0x31c/0x454)
[<c034f550>] (soc_common_drv_pcmcia_probe+0x0/0x454) from [<c0350284>] (pcmcia_probe+0x44/0x58)
[<c0350240>] (pcmcia_probe+0x0/0x58) from [<c0226b7c>] (sa1101_bus_probe+0x28/0x34)
r4 = C087FE54
[<c0226b54>] (sa1101_bus_probe+0x0/0x34) from [<c0318210>] (bus_match+0x48/0x70)
[<c03181c8>] (bus_match+0x0/0x70) from [<c0318314>] (driver_attach+0x4c/0x80)
r6 = C0404580 r5 = C041A320 r4 = C087FE5C
[<c03182c8>] (driver_attach+0x0/0x80) from [<c03185a8>] (bus_add_driver+0x94/0xa8)
r6 = 00000000 r5 = C041A320 r4 = C04044D8
[<c0318514>] (bus_add_driver+0x0/0xa8) from [<c0318934>] (driver_register+0x3c/0x40)
r8 = 00000000 r7 = C0218970 r6 = 00000001 r5 = C0FE4000
r4 = C0218938
[<c03188f8>] (driver_register+0x0/0x40) from [<c02086e0>] (do_initcalls+0x60/0xd8)
[<c0208680>] (do_initcalls+0x0/0xd8) from [<c021924c>] (init+0x58/0x158)
r7 = 00000000 r6 = 00000000 r5 = C03D5574 r4 = C0FE4000
[<c02191f4>] (init+0x0/0x158) from [<c023597c>] (do_exit+0x0/0x4a0)
r5 = 00000000 r4 = 00000000
Code: e91ba830 e1a0c00d e92dd8f0 e24cb004 (e5903008)
<0>Kernel panic: Attempted to kill init!
--
Matan Ziv-Av. matan@svgalib.org
-------------- next part --------------
diff -x jornada820 -x j820_keyb.c -x CVS -urbB kernel26/arch/arm/common/sa1101.c my2/arch/arm/common/sa1101.c
--- kernel26/arch/arm/common/sa1101.c 2004-07-11 20:44:32.000000000 +0300
+++ my2/arch/arm/common/sa1101.c 2004-07-12 14:44:48.000000000 +0300
@@ -68,12 +68,12 @@
.skpcr_mask = SKPCR_UCLKEn,
.devid = SA1101_DEVID_USB,
.irq = {
- IRQ_USBPWR,
- IRQ_HCIM,
- IRQ_HCIBUFFACC,
- IRQ_HCIRMTWKP,
- IRQ_NHCIMFCIR,
- IRQ_USB_PORT_RESUME
+ IRQ_SA1101_USBERROR,
+ IRQ_SA1101_NIRQHCIM,
+ IRQ_SA1101_IRQHCIBUFFACC,
+ IRQ_SA1101_IRQHCIRMTWKP,
+ IRQ_SA1101_NHCIMFCIR,
+ IRQ_SA1101_USBRESUME
},
},
#if 0
@@ -475,13 +475,16 @@
VMCCR=0x100;
/* setup shared memory controller */
- SMCR=SMCR_ColAdrBits(10)+SMCR_RowAdrBits(12)+SMCR_ArbiterBias;
+ SMCR=SMCR_ColAdrBits(10) | SMCR_RowAdrBits(12) | SMCR_ArbiterBias;
/* reset USB */
USBReset |= USBReset_ForceIfReset;
USBReset |= USBReset_ForceHcReset;
local_irq_restore(flags);
+
+ TUCR |= TUCR_MR; /* enable master request in the sa1100. */
+
}
extern int sa1101_usb_shutdown(void)
diff -x jornada820 -x j820_keyb.c -x CVS -urbB kernel26/arch/arm/mach-sa1100/jornada820.c my2/arch/arm/mach-sa1100/jornada820.c
--- kernel26/arch/arm/mach-sa1100/jornada820.c 2004-07-11 20:44:32.000000000 +0300
+++ my2/arch/arm/mach-sa1100/jornada820.c 2004-07-12 18:20:12.000000000 +0300
@@ -83,6 +83,7 @@
static struct map_desc jornada820_io_desc[] __initdata = {
/* virtual physical length type */
+ { 0xf5000000, 0, 0x01000000, MT_DEVICE } /* Boot Rom */
{ 0xf4000000, JORNADA820_SA1101_BASE, 0x00400000, MT_DEVICE } /* SA-1101 */
};
diff -x jornada820 -x j820_keyb.c -x CVS -urbB kernel26/drivers/usb/host/ohci-hcd.c my2/drivers/usb/host/ohci-hcd.c
--- kernel26/drivers/usb/host/ohci-hcd.c 2004-07-12 17:00:38.000000000 +0300
+++ my2/drivers/usb/host/ohci-hcd.c 2004-07-12 13:23:45.000000000 +0300
@@ -106,6 +106,9 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
+#ifdef CONFIG_SA1101
+#include "ohci-sa1101.h"
+#endif
#define DRIVER_VERSION "2004 Feb 02"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
@@ -794,6 +797,10 @@
#include "ohci-sa1111.c"
#endif
+#ifdef CONFIG_SA1101
+#include "ohci-sa1101.c"
+#endif
+
#ifdef CONFIG_ARCH_ESERIES
#include "ohci-e7xx.c"
#endif
@@ -802,6 +809,6 @@
#include "ohci-omap.c"
#endif
-#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111) || defined(CONFIG_ARCH_OMAP) || defined(CONFIG_IPAQ_HANDHELD) || defined(CONFIG_ARCH_ESERIES))
+#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1101) || defined(CONFIG_SA1111) || defined(CONFIG_ARCH_OMAP) || defined(CONFIG_IPAQ_HANDHELD) || defined(CONFIG_ARCH_ESERIES))
#error "missing bus glue for ohci-hcd"
#endif
diff -x jornada820 -x j820_keyb.c -x CVS -urbB kernel26/drivers/usb/host/ohci-sa1101.c my2/drivers/usb/host/ohci-sa1101.c
--- kernel26/drivers/usb/host/ohci-sa1101.c 2004-07-12 16:39:26.000000000 +0300
+++ my2/drivers/usb/host/ohci-sa1101.c 2004-07-12 18:14:05.000000000 +0300
@@ -0,0 +1,374 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * SA1101 Bus Glue
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/sa1101.h>
+
+#ifndef CONFIG_SA1101
+#error "This file is SA-1101 bus glue. CONFIG_SA1101 must be defined."
+#endif
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void sa1101_start_hc(struct sa1101_dev *dev)
+{
+ USBReset = USBReset_ForceIfReset | USBReset_ForceHcReset;
+ /*
+ * * * Now, carefully enable the USB clock, and take
+ * * * the USB host controller out of reset.
+ * * */
+
+ SKPCR |= SKPCR_UCLKEn;
+ udelay(11);
+
+ /*
+ * * * Stop the USB clock.
+ * * */
+
+ SKPCR &= ~SKPCR_UCLKEn;
+ USBReset &= ~USBReset_ForceIfReset;
+
+ SKPCR |= SKPCR_UCLKEn;
+ USTCSR = 0x00000800;
+ USBReset &= ~USBReset_ForceHcReset;
+
+ INTPOL1 |= 0x100000;
+}
+
+static void sa1101_stop_hc(struct sa1101_dev *dev)
+{
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+#if 0
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
+{
+ unsigned long status = sa1101_readl(hcd->regs + SA1101_USB_STATUS);
+
+ dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
+ ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
+ ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
+ ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
+ ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
+ ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
+}
+#endif
+
+static irqreturn_t usb_hcd_sa1101_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+ struct usb_hcd *hcd = __hcd;
+// unsigned long status = sa1101_readl(hcd->regs + SA1101_USB_STATUS);
+
+ //dump_hci_status(hcd, "irq");
+
+#if 0
+ /* may work better this way -- need to investigate further */
+ if (status & USB_STATUS_NIRQHCIM) {
+ //dbg ("not normal HC interrupt; ignoring");
+ return;
+ }
+#endif
+
+ usb_hcd_irq(irq, hcd, r);
+
+ /*
+ * SA1101 seems to re-assert its interrupt immediately
+ * after processing an interrupt. Always return IRQ_HANDLED.
+ */
+ return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_hcd_sa1101_remove (struct usb_hcd *, struct sa1101_dev *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_sa1101_probe - initialize SA-1101-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_sa1101_probe (const struct hc_driver *driver,
+ struct usb_hcd **hcd_out,
+ struct sa1101_dev *dev)
+{
+ int retval;
+ struct usb_hcd *hcd = 0;
+
+#if 1
+ if (!request_mem_region(dev->res.start,
+ dev->res.end - dev->res.start + 1, hcd_name)) {
+ dbg("request_mem_region failed");
+ return -EBUSY;
+ }
+#endif
+
+ sa1101_start_hc(dev);
+
+ hcd = driver->hcd_alloc ();
+ if (hcd == NULL){
+ dbg ("hcd_alloc failed");
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+ hcd->driver = (struct hc_driver *) driver;
+ hcd->description = driver->description;
+ hcd->irq = dev->irq[1];
+ hcd->regs = 0; /* using special readl/writel */
+ hcd->self.controller = &dev->dev;
+
+ retval = hcd_buffer_create (hcd);
+ if (retval != 0) {
+ dbg ("pool alloc fail");
+ goto err1;
+ }
+
+ retval = request_irq (hcd->irq, usb_hcd_sa1101_hcim_irq, SA_INTERRUPT,
+ hcd->description, hcd);
+ if (retval != 0) {
+ dbg("request_irq failed");
+ retval = -EBUSY;
+ goto err2;
+ }
+
+ info ("%s (SA-1101) at 0x%p, irq %d\n",
+ hcd->description, hcd->regs, hcd->irq);
+
+ usb_bus_init (&hcd->self);
+ hcd->self.op = &usb_hcd_operations;
+ hcd->self.hcpriv = (void *) hcd;
+ hcd->self.bus_name = "sa1101";
+ hcd->product_desc = "SA-1101 OHCI";
+
+ INIT_LIST_HEAD (&hcd->dev_list);
+
+ usb_register_bus (&hcd->self);
+
+ if ((retval = driver->start (hcd)) < 0)
+ {
+ usb_hcd_sa1101_remove(hcd, dev);
+ return retval;
+ }
+
+ *hcd_out = hcd;
+ return 0;
+
+ err2:
+ hcd_buffer_destroy (hcd);
+ if (hcd)
+ driver->hcd_free(hcd);
+ err1:
+ sa1101_stop_hc(dev);
+ release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
+ return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_sa1101_remove - shutdown processing for SA-1101-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_sa1101_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_sa1101_remove (struct usb_hcd *hcd, struct sa1101_dev *dev)
+{
+ struct usb_device *hub;
+ void *base;
+
+ info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+ if (in_interrupt ())
+ BUG ();
+
+ hub = hcd->self.root_hub;
+ hcd->state = USB_STATE_QUIESCING;
+
+ dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
+ usb_disconnect (&hub);
+
+ hcd->driver->stop (hcd);
+ hcd->state = USB_STATE_HALT;
+
+ free_irq (hcd->irq, hcd);
+ hcd_buffer_destroy (hcd);
+
+ usb_deregister_bus (&hcd->self);
+
+ base = hcd->regs;
+ hcd->driver->hcd_free (hcd);
+
+ sa1101_stop_hc(dev);
+ release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_sa1101_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
+
+ ohci->hcca = dma_alloc_coherent (hcd->self.controller,
+ sizeof *ohci->hcca, &ohci->hcca_dma, 0);
+ if (!ohci->hcca)
+ return -ENOMEM;
+
+ memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+ if ((ret = ohci_mem_init (ohci)) < 0) {
+ ohci_stop (hcd);
+ return ret;
+ }
+ ohci->regs = hcd->regs;
+
+ if (hc_reset (ohci) < 0) {
+ ohci_stop (hcd);
+ return -ENODEV;
+ }
+
+ if (hc_start (ohci) < 0) {
+ err ("can't start %s", ohci->hcd.self.bus_name);
+ ohci_stop (hcd);
+ return -EBUSY;
+ }
+ create_debug_files (ohci);
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_sa1101_hc_driver = {
+ .description = hcd_name,
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_sa1101_start,
+#ifdef CONFIG_PM
+ /* suspend: ohci_sa1101_suspend, -- tbd */
+ /* resume: ohci_sa1101_resume, -- tbd */
+#endif
+ .stop = ohci_stop,
+
+ /*
+ * memory lifecycle (except per-request)
+ */
+ .hcd_alloc = ohci_hcd_alloc,
+ .hcd_free = ohci_hcd_free,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_sa1101_drv_probe(struct sa1101_dev *dev)
+{
+ struct usb_hcd *hcd = NULL;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ ret = usb_hcd_sa1101_probe(&ohci_sa1101_hc_driver, &hcd, dev);
+
+ if (ret == 0)
+ sa1101_set_drvdata(dev, hcd);
+
+ return ret;
+}
+
+static int ohci_hcd_sa1101_drv_remove(struct sa1101_dev *dev)
+{
+ struct usb_hcd *hcd = sa1101_get_drvdata(dev);
+
+ usb_hcd_sa1101_remove(hcd, dev);
+
+ sa1101_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static struct sa1101_driver ohci_hcd_sa1101_driver = {
+ .drv = {
+ .name = "sa1101-ohci",
+ },
+ .devid = SA1101_DEVID_USB,
+ .probe = ohci_hcd_sa1101_drv_probe,
+ .remove = ohci_hcd_sa1101_drv_remove,
+};
+
+static int __init ohci_hcd_sa1101_init (void)
+{
+ dbg (DRIVER_INFO " (SA-1101)");
+ dbg ("block sizes: ed %d td %d",
+ sizeof (struct ed), sizeof (struct td));
+
+ return sa1101_driver_register(&ohci_hcd_sa1101_driver);
+}
+
+static void __exit ohci_hcd_sa1101_cleanup (void)
+{
+ sa1101_driver_unregister(&ohci_hcd_sa1101_driver);
+}
+
+module_init (ohci_hcd_sa1101_init);
+module_exit (ohci_hcd_sa1101_cleanup);
diff -x jornada820 -x j820_keyb.c -x CVS -urbB kernel26/drivers/usb/host/ohci-sa1101.h my2/drivers/usb/host/ohci-sa1101.h
--- kernel26/drivers/usb/host/ohci-sa1101.h 2004-07-12 16:39:26.000000000 +0300
+++ my2/drivers/usb/host/ohci-sa1101.h 2004-07-12 13:23:03.000000000 +0300
@@ -0,0 +1,7 @@
+#include <asm/arch/hardware.h>
+
+#undef readl
+#define readl(a) (*(volatile unsigned int *)(SA1101_p2v(_Revision+0x100*(int)(a))))
+#undef writel
+#define writel(d, a) ((*(volatile unsigned int *)SA1101_p2v(_Revision+0x100*(int)(a)))=(d))
+
diff -x jornada820 -x j820_keyb.c -x CVS -urbB kernel26/include/asm-arm/arch-sa1100/SA-1101.h my2/include/asm-arm/arch-sa1100/SA-1101.h
--- kernel26/include/asm-arm/arch-sa1100/SA-1101.h 2004-07-11 20:44:32.000000000 +0300
+++ my2/include/asm-arm/arch-sa1100/SA-1101.h 2004-07-11 23:20:42.000000000 +0300
@@ -96,7 +96,7 @@
#define SMCR_DCAC Fld(2,0) /* Number of column address bits */
#define SMCR_DRAC Fld(2,2) /* Number of row address bits */
-#define SMCR_ArbiterBias 0x0008 /* favor video or USB */
+#define SMCR_ArbiterBias 0x0010 /* favor video or USB */
#define SMCR_TopVidMem Fld(4,5) /* Top 4 bits of vidmem addr. */
#define SMCR_ColAdrBits( x ) /* col. addr bits 8..11 */ \
More information about the Jornada820
mailing list