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