diff options
Diffstat (limited to 'drivers/parisc/dino.c')
| -rw-r--r-- | drivers/parisc/dino.c | 214 |
1 files changed, 101 insertions, 113 deletions
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 5ab75334c57..9eae9834bcc 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -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> @@ -55,7 +55,6 @@ #include <asm/pdc.h> #include <asm/page.h> -#include <asm/system.h> #include <asm/io.h> #include <asm/hardware.h> @@ -83,7 +82,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 @@ -124,6 +124,7 @@ #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 +147,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 @@ -173,12 +174,12 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge)); - u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; + u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); void __iomem *base_addr = d->hba.base_addr; unsigned long flags; - DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where, size); spin_lock_irqsave(&d->dinosaur_pen, flags); @@ -208,12 +209,12 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge)); - u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; + u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); void __iomem *base_addr = d->hba.base_addr; unsigned long flags; - DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where, size); spin_lock_irqsave(&d->dinosaur_pen, flags); @@ -285,7 +286,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, @@ -294,25 +295,25 @@ struct pci_port_ops dino_port_ops = { .outl = dino_out32 }; -static void dino_disable_irq(unsigned int irq) +static void dino_mask_irq(struct irq_data *d) { - struct dino_device *dino_dev = irq_desc[irq].handler_data; - int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq); + struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); + int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS); - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq); /* Clear the matching bit in the IMR register */ dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); __raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); } -static void dino_enable_irq(unsigned int irq) +static void dino_unmask_irq(struct irq_data *d) { - struct dino_device *dino_dev = irq_desc[irq].handler_data; - int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq); + struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); + int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS); u32 tmp; - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq); /* ** clear pending IRQ bits @@ -338,25 +339,15 @@ 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); } } -static unsigned int dino_startup_irq(unsigned int irq) -{ - dino_enable_irq(irq); - return 0; -} - -static struct hw_interrupt_type dino_interrupt_type = { - .typename = "GSC-PCI", - .startup = dino_startup_irq, - .shutdown = dino_disable_irq, - .enable = dino_enable_irq, - .disable = dino_disable_irq, - .ack = no_ack_irq, - .end = no_end_irq, +static struct irq_chip dino_interrupt_type = { + .name = "GSC-PCI", + .irq_unmask = dino_unmask_irq, + .irq_mask = dino_mask_irq, }; @@ -366,8 +357,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; @@ -387,8 +377,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); + generic_handle_irq(irq); mask &= ~(1 << local_irq); } while (mask); @@ -435,6 +425,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 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) { @@ -461,7 +466,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); @@ -472,15 +477,12 @@ dino_card_setup(struct pci_bus *bus, void __iomem *base_addr) if (ccio_allocate_resource(dino_dev->hba.dev, res, _8MB, F_EXTEND(0xf0000000UL) | _8MB, F_EXTEND(0xffffffffUL) &~ _8MB, _8MB) < 0) { - struct list_head *ln, *tmp_ln; + struct pci_dev *dev, *tmp; 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_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { list_del(&dev->bus_list); } @@ -530,7 +532,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. @@ -545,32 +547,17 @@ dino_card_fixup(struct pci_dev *dev) static void __init dino_fixup_bus(struct pci_bus *bus) { - struct list_head *ln; struct pci_dev *dev; struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge)); - 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->busn_res.start, bus->bridge->platform_data); /* Firmware doesn't set up card-mode dino, so we have to */ if (is_card_dino(&dino_dev->hba.dev->id)) { dino_card_setup(bus, dino_dev->hba.base_addr); - } else if(bus->parent == NULL) { - /* must have a dino above it, reparent the resources - * into the dino window */ - int i; - struct resource *res = &dino_dev->hba.lmmio_space; - - bus->resource[0] = &(dino_dev->hba.io_space); - for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) { - if(res[i].flags == 0) - break; - bus->resource[i+1] = &res[i]; - } - - } else if(bus->self) { + } else if (bus->parent) { int i; pci_read_bridge_bases(bus); @@ -593,23 +580,18 @@ dino_fixup_bus(struct pci_bus *bus) } - DBG("DEBUG %s assigning %d [0x%lx,0x%lx]\n", - bus->self->dev.bus_id, i, - bus->self->resource[i].start, - bus->self->resource[i].end); - pci_assign_resource(bus->self, i); - DBG("DEBUG %s after assign %d [0x%lx,0x%lx]\n", - bus->self->dev.bus_id, i, - bus->self->resource[i].start, - bus->self->resource[i].end); + DBG("DEBUG %s assigning %d [%pR]\n", + dev_name(&bus->self->dev), i, + &bus->self->resource[i]); + WARN_ON(pci_assign_resource(bus->self, i)); + DBG("DEBUG %s after assign %d [%pR]\n", + dev_name(&bus->self->dev), i, + &bus->self->resource[i]); } } - list_for_each(ln, &bus->devices) { - int i; - - dev = pci_dev_b(ln); + list_for_each_entry(dev, &bus->devices, bus_list) { if (is_card_dino(&dino_dev->hba.dev->id)) dino_card_fixup(dev); @@ -620,21 +602,6 @@ dino_fixup_bus(struct pci_bus *bus) if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) continue; - /* Adjust the I/O Port space addresses */ - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - if (res->flags & IORESOURCE_IO) { - res->start |= port_base; - res->end |= port_base; - } -#ifdef __LP64__ - /* Sign Extend MMIO addresses */ - else if (res->flags & IORESOURCE_MEM) { - res->start |= F_EXTEND(0UL); - res->end |= F_EXTEND(0UL); - } -#endif - } /* null out the ROM resource if there is one (we don't * care about an expansion rom on parisc, since it * usually contains (x86) bios code) */ @@ -655,7 +622,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, @@ -666,7 +633,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); } @@ -674,7 +640,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 }; @@ -769,7 +735,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, @@ -803,7 +769,8 @@ 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 (%pR)!\n", name, i, &res[i]); return result; } } @@ -872,7 +839,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"; @@ -883,7 +850,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; } @@ -920,14 +888,16 @@ static int __init dino_probe(struct parisc_device *dev) const char *version = "unknown"; char *name; int is_cujo = 0; + LIST_HEAD(resources); struct pci_bus *bus; unsigned long hpa = dev->hpa.start; + int max; 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]; } @@ -973,16 +943,14 @@ static int __init dino_probe(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(hpa, 4096); + 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); @@ -998,25 +966,45 @@ static int __init dino_probe(struct parisc_device *dev) dev->dev.platform_data = dino_dev; + pci_add_resource_offset(&resources, &dino_dev->hba.io_space, + HBA_PORT_BASE(dino_dev->hba.hba_num)); + if (dino_dev->hba.lmmio_space.flags) + pci_add_resource_offset(&resources, &dino_dev->hba.lmmio_space, + dino_dev->hba.lmmio_space_offset); + if (dino_dev->hba.elmmio_space.flags) + pci_add_resource_offset(&resources, &dino_dev->hba.elmmio_space, + dino_dev->hba.lmmio_space_offset); + if (dino_dev->hba.gmmio_space.flags) + pci_add_resource(&resources, &dino_dev->hba.gmmio_space); + + dino_dev->hba.bus_num.start = dino_current_bus; + dino_dev->hba.bus_num.end = 255; + dino_dev->hba.bus_num.flags = IORESOURCE_BUS; + pci_add_resource(&resources, &dino_dev->hba.bus_num); /* ** 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); - 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); - } 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); + dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev, + dino_current_bus, &dino_cfg_ops, NULL, &resources); + if (!bus) { + printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n", + dev_name(&dev->dev), dino_current_bus); + pci_free_resource_list(&resources); /* increment the bus number in case of duplicates */ dino_current_bus++; + return 0; } - dino_dev->hba.hba_bus = bus; + + max = pci_scan_child_bus(bus); + pci_bus_update_busn_res_end(bus, max); + + /* This code *depends* on scanning being single threaded + * if it isn't, this global bus number count will fail + */ + dino_current_bus = max + 1; + pci_bus_assign_resources(bus); + pci_bus_add_devices(bus); return 0; } |
