diff options
Diffstat (limited to 'drivers/parisc/dino.c')
| -rw-r--r-- | drivers/parisc/dino.c | 120 |
1 files changed, 83 insertions, 37 deletions
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 9eae9834bcc7..01a50a051296 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* ** DINO manager ** @@ -5,12 +6,8 @@ ** (c) Copyright 1999 SuSE GmbH ** (c) Copyright 1999,2000 Hewlett-Packard Company ** (c) Copyright 2000 Grant Grundler -** (c) Copyright 2006 Helge Deller +** (c) Copyright 2006-2019 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 -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. ** ** This module provides access to Dino PCI bus (config/IOport spaces) ** and helps manage Dino IRQ lines. @@ -59,6 +56,7 @@ #include <asm/hardware.h> #include "gsc.h" +#include "iommu.h" #undef DINO_DEBUG @@ -144,18 +142,18 @@ struct dino_device { struct pci_hba_data hba; /* 'C' inheritance - must be first */ spinlock_t dinosaur_pen; - 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 */ + struct gsc_irq gsc_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 }; -/* Looks nice and keeps the compiler happy */ -#define DINO_DEV(d) ((struct dino_device *) d) - +static inline struct dino_device *DINO_DEV(struct pci_hba_data *hba) +{ + return container_of(hba, struct dino_device, hba); +} /* * Dino Configuration Space Accessor Functions @@ -300,7 +298,7 @@ static void dino_mask_irq(struct irq_data *d) 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", __func__, dino_dev, d->irq); + DBG(KERN_WARNING "%s(0x%px, %d)\n", __func__, dino_dev, d->irq); /* Clear the matching bit in the IMR register */ dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); @@ -313,7 +311,7 @@ static void dino_unmask_irq(struct irq_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", __func__, dino_dev, d->irq); + DBG(KERN_WARNING "%s(0x%px, %d)\n", __func__, dino_dev, d->irq); /* ** clear pending IRQ bits @@ -340,14 +338,43 @@ static void dino_unmask_irq(struct irq_data *d) if (tmp & DINO_MASK_IRQ(local_irq)) { DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n", __func__, tmp); - gsc_writel(dino_dev->txn_data, dino_dev->txn_addr); + gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr); } } +#ifdef CONFIG_SMP +static int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest, + bool force) +{ + struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); + struct cpumask tmask; + int cpu_irq; + u32 eim; + + if (!cpumask_and(&tmask, dest, cpu_online_mask)) + return -EINVAL; + + cpu_irq = cpu_check_affinity(d, &tmask); + if (cpu_irq < 0) + return cpu_irq; + + dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq); + eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data; + __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); + + irq_data_update_effective_affinity(d, &tmask); + + return IRQ_SET_MASK_OK; +} +#endif + static struct irq_chip dino_interrupt_type = { .name = "GSC-PCI", .irq_unmask = dino_unmask_irq, .irq_mask = dino_mask_irq, +#ifdef CONFIG_SMP + .irq_set_affinity = dino_set_affinity_irq, +#endif }; @@ -379,7 +406,7 @@ ilr_again: DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", __func__, irq, intr_dev, mask); generic_handle_irq(irq); - mask &= ~(1 << local_irq); + mask &= ~DINO_MASK_IRQ(local_irq); } while (mask); /* Support for level triggered IRQ lines. @@ -393,9 +420,8 @@ ilr_again: if (mask) { if (--ilr_loop > 0) goto ilr_again; - printk(KERN_ERR "Dino 0x%p: stuck interrupt %d\n", + pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n", dino_dev->hba.base_addr, mask); - return IRQ_NONE; } return IRQ_HANDLED; } @@ -439,6 +465,30 @@ static void quirk_cirrus_cardbus(struct pci_dev *dev) } DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus ); +#ifdef CONFIG_TULIP +/* Check if PCI device is behind a Card-mode Dino. */ +static int pci_dev_is_behind_card_dino(struct pci_dev *dev) +{ + struct dino_device *dino_dev; + + dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge)); + return is_card_dino(&dino_dev->hba.dev->id); +} + +static void pci_fixup_tulip(struct pci_dev *dev) +{ + if (!pci_dev_is_behind_card_dino(dev)) + return; + if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) + return; + pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n", + pci_name(dev)); + /* Disable this card by zeroing the PCI resources */ + memset(&dev->resource[0], 0, sizeof(dev->resource[0])); + memset(&dev->resource[1], 0, sizeof(dev->resource[1])); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip); +#endif /* CONFIG_TULIP */ static void __init dino_bios_init(void) @@ -550,7 +600,7 @@ dino_fixup_bus(struct pci_bus *bus) struct pci_dev *dev; struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge)); - DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n", + DBG(KERN_WARNING "%s(0x%px) bus %d platform_data 0x%px\n", __func__, bus, bus->busn_res.start, bus->bridge->platform_data); @@ -599,8 +649,10 @@ dino_fixup_bus(struct pci_bus *bus) ** P2PB's only have 2 BARs, no IRQs. ** I'd like to just ignore them for now. */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pcibios_init_bridge(dev); continue; + } /* null out the ROM resource if there is one (we don't * care about an expansion rom on parisc, since it @@ -782,7 +834,6 @@ static int __init dino_common_init(struct parisc_device *dev, { int status; u32 eim; - struct gsc_irq gsc_irq; struct resource *res; pcibios_register_hba(&dino_dev->hba); @@ -797,10 +848,8 @@ static int __init dino_common_init(struct parisc_device *dev, ** still only has 11 IRQ input lines - just map some of them ** to a different processor. */ - dev->irq = gsc_alloc_irq(&gsc_irq); - dino_dev->txn_addr = gsc_irq.txn_addr; - dino_dev->txn_data = gsc_irq.txn_data; - eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq); + eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data; /* ** Dino needs a PA "IRQ" to get a processor's attention. @@ -849,7 +898,7 @@ static int __init dino_common_init(struct parisc_device *dev, res->flags = IORESOURCE_IO; /* do not mark it busy ! */ if (request_resource(&ioport_resource, res) < 0) { printk(KERN_ERR "%s: request I/O Port region failed " - "0x%lx/%lx (hpa 0x%p)\n", + "0x%lx/%lx (hpa 0x%px)\n", name, (unsigned long)res->start, (unsigned long)res->end, dino_dev->hba.base_addr); return 1; @@ -863,20 +912,18 @@ static int __init dino_common_init(struct parisc_device *dev, #define CUJO_RAVEN_BADPAGE 0x01003000UL #define CUJO_FIREHAWK_BADPAGE 0x01607000UL -static const char *dino_vers[] = { +static const char dino_vers[][4] = { "2.0", "2.1", "3.0", "3.1" }; -static const char *cujo_vers[] = { +static const char cujo_vers[][4] = { "1.0", "2.0" }; -void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp); - /* ** Determine if dino should claim this chip (return 0) or not (return 1). ** If so, initialize the chip appropriately (card-mode vs bridge mode). @@ -913,7 +960,7 @@ static int __init dino_probe(struct parisc_device *dev) printk("%s version %s found at 0x%lx\n", name, version, hpa); if (!request_mem_region(hpa, PAGE_SIZE, name)) { - printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n", + printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%lx)!\n", hpa); return 1; } @@ -950,8 +997,8 @@ static int __init dino_probe(struct parisc_device *dev) } dino_dev->hba.dev = dev; - dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096); - dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */ + dino_dev->hba.base_addr = ioremap(hpa, 4096); + dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND; spin_lock_init(&dino_dev->dinosaur_pen); dino_dev->hba.iommu = ccio_get_iommu(dev); @@ -1017,7 +1064,7 @@ static int __init dino_probe(struct parisc_device *dev) * and 725 firmware misreport it as 0x08080 for no adequately explained * reason. */ -static struct parisc_device_id dino_tbl[] = { +static const struct parisc_device_id dino_tbl[] __initconst = { { HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x004, 0x0009D },/* Card-mode Dino */ { HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x08080 }, /* XXX */ { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x680, 0xa }, /* Bridge-mode Dino */ @@ -1026,7 +1073,7 @@ static struct parisc_device_id dino_tbl[] = { { 0, } }; -static struct parisc_driver dino_driver = { +static struct parisc_driver dino_driver __refdata = { .name = "dino", .id_table = dino_tbl, .probe = dino_probe, @@ -1037,9 +1084,8 @@ static struct parisc_driver dino_driver = { * This is the only routine which is NOT static. * Must be called exactly once before pci_init(). */ -int __init dino_init(void) +static int __init dino_init(void) { - register_parisc_driver(&dino_driver); - return 0; + return register_parisc_driver(&dino_driver); } - +arch_initcall(dino_init); |
