sysfs: In sysfs_chmod_file lazily propagate the mode change.
[safe/jmp/linux-2.6] / drivers / parisc / dino.c
index 8c61705..d69bde6 100644 (file)
@@ -5,6 +5,7 @@
 **     (c) Copyright 1999 SuSE GmbH
 **     (c) Copyright 1999,2000 Hewlett-Packard Company
 **     (c) Copyright 2000 Grant Grundler
+**     (c) Copyright 2006 Helge Deller
 **
 **     This program is free software; you can redistribute it and/or modify
 **     it under the terms of the GNU General Public License as published by
@@ -42,7 +43,6 @@
 **       for PCI drivers devices which implement/use MMIO registers.
 */
 
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -83,7 +83,8 @@
 ** bus number for each dino.
 */
 
-#define is_card_dino(id) ((id)->hw_type == HPHW_A_DMA)
+#define is_card_dino(id)       ((id)->hw_type == HPHW_A_DMA)
+#define is_cujo(id)            ((id)->hversion == 0x682)
 
 #define DINO_IAR0              0x004
 #define DINO_IODC_ADDR         0x008
 
 #define DINO_IRQS 11           /* bits 0-10 are architected */
 #define DINO_IRR_MASK  0x5ff   /* only 10 bits are implemented */
+#define DINO_LOCAL_IRQS (DINO_IRQS+1)
 
 #define DINO_MASK_IRQ(x)       (1<<(x))
 
@@ -146,7 +148,7 @@ struct dino_device
        unsigned long           txn_addr; /* EIR addr to generate interrupt */ 
        u32                     txn_data; /* EIR data assign to each dino */ 
        u32                     imr;      /* IRQ's which are enabled */ 
-       int                     global_irq[12]; /* map IMR bit to global irq */
+       int                     global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
 #ifdef DINO_DEBUG
        unsigned int            dino_irr0; /* save most recent IRQ line stat */
 #endif
@@ -178,6 +180,8 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
        void __iomem *base_addr = d->hba.base_addr;
        unsigned long flags;
 
+       DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where,
+                                                                       size);
        spin_lock_irqsave(&d->dinosaur_pen, flags);
 
        /* tell HW which CFG address */
@@ -211,6 +215,8 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where,
        void __iomem *base_addr = d->hba.base_addr;
        unsigned long flags;
 
+       DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where,
+                                                                       size);
        spin_lock_irqsave(&d->dinosaur_pen, flags);
 
        /* avoid address stepping feature */
@@ -281,7 +287,7 @@ DINO_PORT_OUT(b,  8, 3)
 DINO_PORT_OUT(w, 16, 2)
 DINO_PORT_OUT(l, 32, 0)
 
-struct pci_port_ops dino_port_ops = {
+static struct pci_port_ops dino_port_ops = {
        .inb    = dino_in8,
        .inw    = dino_in16,
        .inl    = dino_in32,
@@ -292,10 +298,11 @@ struct pci_port_ops dino_port_ops = {
 
 static void dino_disable_irq(unsigned int irq)
 {
-       struct dino_device *dino_dev = irq_desc[irq].handler_data;
-       int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct dino_device *dino_dev = desc->chip_data;
+       int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
 
-       DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq);
+       DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
 
        /* Clear the matching bit in the IMR register */
        dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq));
@@ -304,11 +311,12 @@ static void dino_disable_irq(unsigned int irq)
 
 static void dino_enable_irq(unsigned int irq)
 {
-       struct dino_device *dino_dev = irq_desc[irq].handler_data;
-       int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct dino_device *dino_dev = desc->chip_data;
+       int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
        u32 tmp;
 
-       DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq);
+       DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
 
        /*
        ** clear pending IRQ bits
@@ -334,7 +342,7 @@ static void dino_enable_irq(unsigned int irq)
        tmp = __raw_readl(dino_dev->hba.base_addr+DINO_ILR);
        if (tmp & DINO_MASK_IRQ(local_irq)) {
                DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
-                               __FUNCTION__, tmp);
+                               __func__, tmp);
                gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
        }
 }
@@ -345,7 +353,7 @@ static unsigned int dino_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type dino_interrupt_type = {
+static struct irq_chip dino_interrupt_type = {
        .typename       = "GSC-PCI",
        .startup        = dino_startup_irq,
        .shutdown       = dino_disable_irq,
@@ -362,8 +370,7 @@ static struct hw_interrupt_type dino_interrupt_type = {
  * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from
  * wedging the CPU. Could be removed or made optional at some point.
  */
-static irqreturn_t
-dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
+static irqreturn_t dino_isr(int irq, void *intr_dev)
 {
        struct dino_device *dino_dev = intr_dev;
        u32 mask;
@@ -383,8 +390,8 @@ ilr_again:
                int local_irq = __ffs(mask);
                int irq = dino_dev->global_irq[local_irq];
                DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
-                       __FUNCTION__, irq, intr_dev, mask);
-               __do_IRQ(irq, regs);
+                       __func__, irq, intr_dev, mask);
+               __do_IRQ(irq);
                mask &= ~(1 << local_irq);
        } while (mask);
 
@@ -431,6 +438,21 @@ static void dino_choose_irq(struct parisc_device *dev, void *ctrl)
        dino_assign_irq(dino, irq, &dev->irq);
 }
 
+
+/*
+ * Cirrus 6832 Cardbus reports wrong irq on RDI Tadpole PARISC Laptop (deller@gmx.de)
+ * (the irqs are off-by-one, not sure yet if this is a cirrus, dino-hardware or dino-driver problem...)
+ */
+static void __devinit quirk_cirrus_cardbus(struct pci_dev *dev)
+{
+       u8 new_irq = dev->irq - 1;
+       printk(KERN_INFO "PCI: Cirrus Cardbus IRQ fixup for %s, from %d to %d\n",
+                       pci_name(dev), dev->irq, new_irq);
+       dev->irq = new_irq;
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus );
+
+
 static void __init
 dino_bios_init(void)
 {
@@ -457,7 +479,7 @@ dino_card_setup(struct pci_bus *bus, void __iomem *base_addr)
        res = &dino_dev->hba.lmmio_space;
        res->flags = IORESOURCE_MEM;
        size = scnprintf(name, sizeof(name), "Dino LMMIO (%s)", 
-                        bus->bridge->bus_id);
+                        dev_name(bus->bridge));
        res->name = kmalloc(size+1, GFP_KERNEL);
        if(res->name)
                strcpy((char *)res->name, name);
@@ -471,12 +493,11 @@ dino_card_setup(struct pci_bus *bus, void __iomem *base_addr)
                struct list_head *ln, *tmp_ln;
 
                printk(KERN_ERR "Dino: cannot attach bus %s\n",
-                      bus->bridge->bus_id);
+                      dev_name(bus->bridge));
                /* kill the bus, we can't do anything with it */
                list_for_each_safe(ln, tmp_ln, &bus->devices) {
                        struct pci_dev *dev = pci_dev_b(ln);
 
-                       list_del(&dev->global_list);
                        list_del(&dev->bus_list);
                }
                        
@@ -490,7 +511,7 @@ dino_card_setup(struct pci_bus *bus, void __iomem *base_addr)
                if (res->start == F_EXTEND(0xf0000000UL | (i * _8MB)))
                        break;
        }
-       DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %lx\n",
+       DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %p\n",
            i, res->start, base_addr + DINO_IO_ADDR_EN);
        __raw_writel(1 << i, base_addr + DINO_IO_ADDR_EN);
 }
@@ -526,7 +547,7 @@ dino_card_fixup(struct pci_dev *dev)
        ** The additional "-1" adjusts for skewing the IRQ<->slot.
        */
        dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin); 
-       dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
+       dev->irq = pci_swizzle_interrupt_pin(dev, irq_pin) - 1;
 
        /* Shouldn't really need to do this but it's in case someone tries
        ** to bypass PCI services and look at the card themselves.
@@ -547,7 +568,7 @@ dino_fixup_bus(struct pci_bus *bus)
        int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
 
        DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
-           __FUNCTION__, bus, bus->secondary, 
+           __func__, bus, bus->secondary,
            bus->bridge->platform_data);
 
        /* Firmware doesn't set up card-mode dino, so we have to */
@@ -566,7 +587,7 @@ dino_fixup_bus(struct pci_bus *bus)
                        bus->resource[i+1] = &res[i];
                }
 
-       } else if(bus->self) {
+       } else if (bus->parent) {
                int i;
 
                pci_read_bridge_bases(bus);
@@ -590,12 +611,12 @@ dino_fixup_bus(struct pci_bus *bus)
                        }
                                        
                        DBG("DEBUG %s assigning %d [0x%lx,0x%lx]\n",
-                           bus->self->dev.bus_id, i,
+                           dev_name(&bus->self->dev), i,
                            bus->self->resource[i].start,
                            bus->self->resource[i].end);
-                       pci_assign_resource(bus->self, i);
+                       WARN_ON(pci_assign_resource(bus->self, i));
                        DBG("DEBUG %s after assign %d [0x%lx,0x%lx]\n",
-                           bus->self->dev.bus_id, i,
+                           dev_name(&bus->self->dev), i,
                            bus->self->resource[i].start,
                            bus->self->resource[i].end);
                }
@@ -651,7 +672,7 @@ dino_fixup_bus(struct pci_bus *bus)
                        
                        dino_cfg_read(dev->bus, dev->devfn, 
                                      PCI_INTERRUPT_PIN, 1, &irq_pin);
-                       irq_pin = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
+                       irq_pin = pci_swizzle_interrupt_pin(dev, irq_pin) - 1;
                        printk(KERN_WARNING "Device %s has undefined IRQ, "
                                        "setting to %d\n", pci_name(dev), irq_pin);
                        dino_cfg_write(dev->bus, dev->devfn, 
@@ -662,7 +683,6 @@ dino_fixup_bus(struct pci_bus *bus)
                        printk(KERN_WARNING "Device %s has unassigned IRQ\n", pci_name(dev));
 #endif
                } else {
-
                        /* Adjust INT_LINE for that busses region */
                        dino_assign_irq(dino_dev, dev->irq, &dev->irq);
                }
@@ -670,7 +690,7 @@ dino_fixup_bus(struct pci_bus *bus)
 }
 
 
-struct pci_bios_ops dino_bios_ops = {
+static struct pci_bios_ops dino_bios_ops = {
        .init           = dino_bios_init,
        .fixup_bus      = dino_fixup_bus
 };
@@ -683,6 +703,14 @@ static void __init
 dino_card_init(struct dino_device *dino_dev)
 {
        u32 brdg_feat = 0x00784e05;
+       unsigned long status;
+
+       status = __raw_readl(dino_dev->hba.base_addr+DINO_IO_STATUS);
+       if (status & 0x0000ff80) {
+               __raw_writel(0x00000005,
+                               dino_dev->hba.base_addr+DINO_IO_COMMAND);
+               udelay(1);
+       }
 
        __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK);
        __raw_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN);
@@ -757,7 +785,7 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name)
                if((io_addr & (1 << i)) == 0)
                        continue;
 
-               start = (unsigned long)(signed int)(0xf0000000 | (i << 23));
+               start = F_EXTEND(0xf0000000UL) | (i << 23);
                end = start + 8 * 1024 * 1024 - 1;
 
                DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count,
@@ -791,7 +819,9 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name)
 
                result = ccio_request_resource(dino_dev->hba.dev, &res[i]);
                if (result < 0) {
-                       printk(KERN_ERR "%s: failed to claim PCI Bus address space %d (0x%lx-0x%lx)!\n", name, i, res[i].start, res[i].end);
+                       printk(KERN_ERR "%s: failed to claim PCI Bus address "
+                              "space %d (0x%lx-0x%lx)!\n", name, i,
+                              (unsigned long)res[i].start, (unsigned long)res[i].end);
                        return result;
                }
        }
@@ -860,7 +890,7 @@ static int __init dino_common_init(struct parisc_device *dev,
 
        /* allocate I/O Port resource region */
        res = &dino_dev->hba.io_space;
-       if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) {
+       if (!is_cujo(&dev->id)) {
                res->name = "Dino I/O Port";
        } else {
                res->name = "Cujo I/O Port";
@@ -871,7 +901,8 @@ static int __init dino_common_init(struct parisc_device *dev,
        if (request_resource(&ioport_resource, res) < 0) {
                printk(KERN_ERR "%s: request I/O Port region failed "
                       "0x%lx/%lx (hpa 0x%p)\n",
-                      name, res->start, res->end, dino_dev->hba.base_addr);
+                      name, (unsigned long)res->start, (unsigned long)res->end,
+                      dino_dev->hba.base_addr);
                return 1;
        }
 
@@ -902,20 +933,20 @@ void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp);
 ** If so, initialize the chip appropriately (card-mode vs bridge mode).
 ** Much of the initialization is common though.
 */
-static int __init
-dino_driver_callback(struct parisc_device *dev)
+static int __init dino_probe(struct parisc_device *dev)
 {
        struct dino_device *dino_dev;   // Dino specific control struct
        const char *version = "unknown";
        char *name;
        int is_cujo = 0;
        struct pci_bus *bus;
-       
+       unsigned long hpa = dev->hpa.start;
+
        name = "Dino";
        if (is_card_dino(&dev->id)) {
                version = "3.x (card mode)";
        } else {
-               if(dev->id.hversion == 0x680) {
+               if (!is_cujo(&dev->id)) {
                        if (dev->id.hversion_rev < 4) {
                                version = dino_vers[dev->id.hversion_rev];
                        }
@@ -928,11 +959,11 @@ dino_driver_callback(struct parisc_device *dev)
                }
        }
 
-       printk("%s version %s found at 0x%lx\n", name, version, dev->hpa);
+       printk("%s version %s found at 0x%lx\n", name, version, hpa);
 
-       if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) {
+       if (!request_mem_region(hpa, PAGE_SIZE, name)) {
                printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n",
-                       dev->hpa);
+                       hpa);
                return 1;
        }
 
@@ -940,12 +971,12 @@ dino_driver_callback(struct parisc_device *dev)
        if (is_cujo && dev->id.hversion_rev == 1) {
 #ifdef CONFIG_IOMMU_CCIO
                printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n");
-               if (dev->hpa == (unsigned long)CUJO_RAVEN_ADDR) {
+               if (hpa == (unsigned long)CUJO_RAVEN_ADDR) {
                        ccio_cujo20_fixup(dev, CUJO_RAVEN_BADPAGE);
-               } else if (dev->hpa == (unsigned long)CUJO_FIREHAWK_ADDR) {
+               } else if (hpa == (unsigned long)CUJO_FIREHAWK_ADDR) {
                        ccio_cujo20_fixup(dev, CUJO_FIREHAWK_BADPAGE);
                } else {
-                       printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", dev->hpa);
+                       printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", hpa);
                }
 #endif
        } else if (!is_cujo && !is_card_dino(&dev->id) &&
@@ -961,16 +992,14 @@ dino_driver_callback(struct parisc_device *dev)
 */
        }
 
-       dino_dev = kmalloc(sizeof(struct dino_device), GFP_KERNEL);
+       dino_dev = kzalloc(sizeof(struct dino_device), GFP_KERNEL);
        if (!dino_dev) {
                printk("dino_init_chip - couldn't alloc dino_device\n");
                return 1;
        }
 
-       memset(dino_dev, 0, sizeof(struct dino_device));
-
        dino_dev->hba.dev = dev;
-       dino_dev->hba.base_addr = ioremap(dev->hpa, 4096); /* faster access */
+       dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
        dino_dev->hba.lmmio_space_offset = 0;   /* CPU addrs == bus addrs */
        spin_lock_init(&dino_dev->dinosaur_pen);
        dino_dev->hba.iommu = ccio_get_iommu(dev);
@@ -990,21 +1019,22 @@ dino_driver_callback(struct parisc_device *dev)
        ** It's not used to avoid chicken/egg problems
        ** with configuration accessor functions.
        */
-       bus = pci_scan_bus_parented(&dev->dev, dino_current_bus,
-                                   &dino_cfg_ops, NULL);
+       dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
+                        dino_current_bus, &dino_cfg_ops, NULL);
+
        if(bus) {
-               pci_bus_add_devices(bus);
                /* This code *depends* on scanning being single threaded
                 * if it isn't, this global bus number count will fail
                 */
                dino_current_bus = bus->subordinate + 1;
                pci_bus_assign_resources(bus);
+               pci_bus_add_devices(bus);
        } else {
-               printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (probably duplicate bus number %d)\n", dev->dev.bus_id, dino_current_bus);
+               printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
+                      dev_name(&dev->dev), dino_current_bus);
                /* increment the bus number in case of duplicates */
                dino_current_bus++;
        }
-       dino_dev->hba.hba_bus = bus;
        return 0;
 }