USB: isp1760: Fix probe in PCI glue code
authorKarl Bongers <kbongers@jged.com>
Mon, 1 Dec 2008 10:47:40 +0000 (11:47 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Jan 2009 18:00:04 +0000 (10:00 -0800)
Contains fixes so probe on x86 PCI runs, apparently I'm first to try
this. Several fixes to memory access to probe host scratch register.
Previously would bug check on chip_addr var used uninitialized.
Scratch reg write failed in one instance due to 16-bit initial access
mode, so added "& 0x0000ffff" to the readl as fix.
Includes some general cleanup - remove global vars, organize memory map
resource use.

Signed-off-by: Karl Bongers <kbongers@jged.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/isp1760-if.c

index a53114c367cd57b4dfdd494632433e14b0411e78..25453066fda50a105ada0ec71c1135649cfac928 100644 (file)
@@ -129,23 +129,23 @@ static struct of_platform_driver isp1760_of_driver = {
 #endif
 
 #ifdef CONFIG_PCI
-static u32 nxp_pci_io_base;
-static u32 iolength;
-static u32 pci_mem_phy0;
-static u32 length;
-static u8 __iomem *chip_addr;
-static u8 __iomem *iobase;
-
 static int __devinit isp1761_pci_probe(struct pci_dev *dev,
                const struct pci_device_id *id)
 {
        u8 latency, limit;
        __u32 reg_data;
        int retry_count;
-       int length;
-       int status = 1;
        struct usb_hcd *hcd;
        unsigned int devflags = 0;
+       int ret_status = 0;
+
+       resource_size_t pci_mem_phy0;
+       resource_size_t memlength;
+
+       u8 __iomem *chip_addr;
+       u8 __iomem *iobase;
+       resource_size_t nxp_pci_io_base;
+       resource_size_t iolength;
 
        if (usb_disabled())
                return -ENODEV;
@@ -168,26 +168,30 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
        iobase = ioremap_nocache(nxp_pci_io_base, iolength);
        if (!iobase) {
                printk(KERN_ERR "ioremap #1\n");
-               release_mem_region(nxp_pci_io_base, iolength);
-               return -ENOMEM;
+               ret_status = -ENOMEM;
+               goto cleanup1;
        }
        /* Grab the PLX PCI shared memory of the ISP 1761 we need  */
        pci_mem_phy0 = pci_resource_start(dev, 3);
-       length = pci_resource_len(dev, 3);
-
-       if (length < 0xffff) {
-               printk(KERN_ERR "memory length for this resource is less than "
-                               "required\n");
-               release_mem_region(nxp_pci_io_base, iolength);
-               iounmap(iobase);
-               return  -ENOMEM;
+       memlength = pci_resource_len(dev, 3);
+       if (memlength < 0xffff) {
+               printk(KERN_ERR "memory length for this resource is wrong\n");
+               ret_status = -ENOMEM;
+               goto cleanup2;
        }
 
-       if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+       if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
                printk(KERN_ERR "host controller already in use\n");
-               release_mem_region(nxp_pci_io_base, iolength);
-               iounmap(iobase);
-               return -EBUSY;
+               ret_status = -EBUSY;
+               goto cleanup2;
+       }
+
+       /* map available memory */
+       chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
+       if (!chip_addr) {
+               printk(KERN_ERR "Error ioremap failed\n");
+               ret_status = -ENOMEM;
+               goto cleanup3;
        }
 
        /* bad pci latencies can contribute to overruns */
@@ -210,39 +214,54 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
                 * */
                writel(0xface, chip_addr + HC_SCRATCH_REG);
                udelay(100);
-               reg_data = readl(chip_addr + HC_SCRATCH_REG);
+               reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
                retry_count--;
        }
 
+       iounmap(chip_addr);
+
        /* Host Controller presence is detected by writing to scratch register
         * and reading back and checking the contents are same or not
         */
        if (reg_data != 0xFACE) {
                dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
-               goto clean;
+               ret_status = -ENOMEM;
+               goto cleanup3;
        }
 
        pci_set_master(dev);
 
-       status = readl(iobase + 0x68);
-       status |= 0x900;
-       writel(status, iobase + 0x68);
+       /* configure PLX PCI chip to pass interrupts */
+#define PLX_INT_CSR_REG 0x68
+       reg_data = readl(iobase + PLX_INT_CSR_REG);
+       reg_data |= 0x900;
+       writel(reg_data, iobase + PLX_INT_CSR_REG);
 
        dev->dev.dma_mask = NULL;
-       hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+       hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
                IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
                devflags);
-       if (!IS_ERR(hcd)) {
-               pci_set_drvdata(dev, hcd);
-               return 0;
+       if (IS_ERR(hcd)) {
+               ret_status = -ENODEV;
+               goto cleanup3;
        }
-clean:
-       status = -ENODEV;
+
+       /* done with PLX IO access */
        iounmap(iobase);
-       release_mem_region(pci_mem_phy0, length);
        release_mem_region(nxp_pci_io_base, iolength);
-       return status;
+
+       pci_set_drvdata(dev, hcd);
+       return 0;
+
+cleanup3:
+       release_mem_region(pci_mem_phy0, memlength);
+cleanup2:
+       iounmap(iobase);
+cleanup1:
+       release_mem_region(nxp_pci_io_base, iolength);
+       return ret_status;
 }
+
 static void isp1761_pci_remove(struct pci_dev *dev)
 {
        struct usb_hcd *hcd;
@@ -255,12 +274,6 @@ static void isp1761_pci_remove(struct pci_dev *dev)
        usb_put_hcd(hcd);
 
        pci_disable_device(dev);
-
-       iounmap(iobase);
-       iounmap(chip_addr);
-
-       release_mem_region(nxp_pci_io_base, iolength);
-       release_mem_region(pci_mem_phy0, length);
 }
 
 static void isp1761_pci_shutdown(struct pci_dev *dev)