162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci** DINO manager 462306a36Sopenharmony_ci** 562306a36Sopenharmony_ci** (c) Copyright 1999 Red Hat Software 662306a36Sopenharmony_ci** (c) Copyright 1999 SuSE GmbH 762306a36Sopenharmony_ci** (c) Copyright 1999,2000 Hewlett-Packard Company 862306a36Sopenharmony_ci** (c) Copyright 2000 Grant Grundler 962306a36Sopenharmony_ci** (c) Copyright 2006-2019 Helge Deller 1062306a36Sopenharmony_ci** 1162306a36Sopenharmony_ci** 1262306a36Sopenharmony_ci** This module provides access to Dino PCI bus (config/IOport spaces) 1362306a36Sopenharmony_ci** and helps manage Dino IRQ lines. 1462306a36Sopenharmony_ci** 1562306a36Sopenharmony_ci** Dino interrupt handling is a bit complicated. 1662306a36Sopenharmony_ci** Dino always writes to the broadcast EIR via irr0 for now. 1762306a36Sopenharmony_ci** (BIG WARNING: using broadcast EIR is a really bad thing for SMP!) 1862306a36Sopenharmony_ci** Only one processor interrupt is used for the 11 IRQ line 1962306a36Sopenharmony_ci** inputs to dino. 2062306a36Sopenharmony_ci** 2162306a36Sopenharmony_ci** The different between Built-in Dino and Card-Mode 2262306a36Sopenharmony_ci** dino is in chip initialization and pci device initialization. 2362306a36Sopenharmony_ci** 2462306a36Sopenharmony_ci** Linux drivers can only use Card-Mode Dino if pci devices I/O port 2562306a36Sopenharmony_ci** BARs are configured and used by the driver. Programming MMIO address 2662306a36Sopenharmony_ci** requires substantial knowledge of available Host I/O address ranges 2762306a36Sopenharmony_ci** is currently not supported. Port/Config accessor functions are the 2862306a36Sopenharmony_ci** same. "BIOS" differences are handled within the existing routines. 2962306a36Sopenharmony_ci*/ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Changes : 3262306a36Sopenharmony_ci** 2001-06-14 : Clement Moyroud (moyroudc@esiee.fr) 3362306a36Sopenharmony_ci** - added support for the integrated RS232. 3462306a36Sopenharmony_ci*/ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci** TODO: create a virtual address for each Dino HPA. 3862306a36Sopenharmony_ci** GSC code might be able to do this since IODC data tells us 3962306a36Sopenharmony_ci** how many pages are used. PCI subsystem could (must?) do this 4062306a36Sopenharmony_ci** for PCI drivers devices which implement/use MMIO registers. 4162306a36Sopenharmony_ci*/ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/delay.h> 4462306a36Sopenharmony_ci#include <linux/types.h> 4562306a36Sopenharmony_ci#include <linux/kernel.h> 4662306a36Sopenharmony_ci#include <linux/pci.h> 4762306a36Sopenharmony_ci#include <linux/init.h> 4862306a36Sopenharmony_ci#include <linux/ioport.h> 4962306a36Sopenharmony_ci#include <linux/slab.h> 5062306a36Sopenharmony_ci#include <linux/interrupt.h> /* for struct irqaction */ 5162306a36Sopenharmony_ci#include <linux/spinlock.h> /* for spinlock_t and prototypes */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include <asm/pdc.h> 5462306a36Sopenharmony_ci#include <asm/page.h> 5562306a36Sopenharmony_ci#include <asm/io.h> 5662306a36Sopenharmony_ci#include <asm/hardware.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include "gsc.h" 5962306a36Sopenharmony_ci#include "iommu.h" 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#undef DINO_DEBUG 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#ifdef DINO_DEBUG 6462306a36Sopenharmony_ci#define DBG(x...) printk(x) 6562306a36Sopenharmony_ci#else 6662306a36Sopenharmony_ci#define DBG(x...) 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci** Config accessor functions only pass in the 8-bit bus number 7162306a36Sopenharmony_ci** and not the 8-bit "PCI Segment" number. Each Dino will be 7262306a36Sopenharmony_ci** assigned a PCI bus number based on "when" it's discovered. 7362306a36Sopenharmony_ci** 7462306a36Sopenharmony_ci** The "secondary" bus number is set to this before calling 7562306a36Sopenharmony_ci** pci_scan_bus(). If any PPB's are present, the scan will 7662306a36Sopenharmony_ci** discover them and update the "secondary" and "subordinate" 7762306a36Sopenharmony_ci** fields in Dino's pci_bus structure. 7862306a36Sopenharmony_ci** 7962306a36Sopenharmony_ci** Changes in the configuration *will* result in a different 8062306a36Sopenharmony_ci** bus number for each dino. 8162306a36Sopenharmony_ci*/ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define is_card_dino(id) ((id)->hw_type == HPHW_A_DMA) 8462306a36Sopenharmony_ci#define is_cujo(id) ((id)->hversion == 0x682) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define DINO_IAR0 0x004 8762306a36Sopenharmony_ci#define DINO_IODC_ADDR 0x008 8862306a36Sopenharmony_ci#define DINO_IODC_DATA_0 0x008 8962306a36Sopenharmony_ci#define DINO_IODC_DATA_1 0x008 9062306a36Sopenharmony_ci#define DINO_IRR0 0x00C 9162306a36Sopenharmony_ci#define DINO_IAR1 0x010 9262306a36Sopenharmony_ci#define DINO_IRR1 0x014 9362306a36Sopenharmony_ci#define DINO_IMR 0x018 9462306a36Sopenharmony_ci#define DINO_IPR 0x01C 9562306a36Sopenharmony_ci#define DINO_TOC_ADDR 0x020 9662306a36Sopenharmony_ci#define DINO_ICR 0x024 9762306a36Sopenharmony_ci#define DINO_ILR 0x028 9862306a36Sopenharmony_ci#define DINO_IO_COMMAND 0x030 9962306a36Sopenharmony_ci#define DINO_IO_STATUS 0x034 10062306a36Sopenharmony_ci#define DINO_IO_CONTROL 0x038 10162306a36Sopenharmony_ci#define DINO_IO_GSC_ERR_RESP 0x040 10262306a36Sopenharmony_ci#define DINO_IO_ERR_INFO 0x044 10362306a36Sopenharmony_ci#define DINO_IO_PCI_ERR_RESP 0x048 10462306a36Sopenharmony_ci#define DINO_IO_FBB_EN 0x05c 10562306a36Sopenharmony_ci#define DINO_IO_ADDR_EN 0x060 10662306a36Sopenharmony_ci#define DINO_PCI_ADDR 0x064 10762306a36Sopenharmony_ci#define DINO_CONFIG_DATA 0x068 10862306a36Sopenharmony_ci#define DINO_IO_DATA 0x06c 10962306a36Sopenharmony_ci#define DINO_MEM_DATA 0x070 /* Dino 3.x only */ 11062306a36Sopenharmony_ci#define DINO_GSC2X_CONFIG 0x7b4 11162306a36Sopenharmony_ci#define DINO_GMASK 0x800 11262306a36Sopenharmony_ci#define DINO_PAMR 0x804 11362306a36Sopenharmony_ci#define DINO_PAPR 0x808 11462306a36Sopenharmony_ci#define DINO_DAMODE 0x80c 11562306a36Sopenharmony_ci#define DINO_PCICMD 0x810 11662306a36Sopenharmony_ci#define DINO_PCISTS 0x814 11762306a36Sopenharmony_ci#define DINO_MLTIM 0x81c 11862306a36Sopenharmony_ci#define DINO_BRDG_FEAT 0x820 11962306a36Sopenharmony_ci#define DINO_PCIROR 0x824 12062306a36Sopenharmony_ci#define DINO_PCIWOR 0x828 12162306a36Sopenharmony_ci#define DINO_TLTIM 0x830 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define DINO_IRQS 11 /* bits 0-10 are architected */ 12462306a36Sopenharmony_ci#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ 12562306a36Sopenharmony_ci#define DINO_LOCAL_IRQS (DINO_IRQS+1) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define DINO_MASK_IRQ(x) (1<<(x)) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define PCIINTA 0x001 13062306a36Sopenharmony_ci#define PCIINTB 0x002 13162306a36Sopenharmony_ci#define PCIINTC 0x004 13262306a36Sopenharmony_ci#define PCIINTD 0x008 13362306a36Sopenharmony_ci#define PCIINTE 0x010 13462306a36Sopenharmony_ci#define PCIINTF 0x020 13562306a36Sopenharmony_ci#define GSCEXTINT 0x040 13662306a36Sopenharmony_ci/* #define xxx 0x080 - bit 7 is "default" */ 13762306a36Sopenharmony_ci/* #define xxx 0x100 - bit 8 not used */ 13862306a36Sopenharmony_ci/* #define xxx 0x200 - bit 9 not used */ 13962306a36Sopenharmony_ci#define RS232INT 0x400 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistruct dino_device 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct pci_hba_data hba; /* 'C' inheritance - must be first */ 14462306a36Sopenharmony_ci spinlock_t dinosaur_pen; 14562306a36Sopenharmony_ci u32 imr; /* IRQ's which are enabled */ 14662306a36Sopenharmony_ci struct gsc_irq gsc_irq; 14762306a36Sopenharmony_ci int global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */ 14862306a36Sopenharmony_ci#ifdef DINO_DEBUG 14962306a36Sopenharmony_ci unsigned int dino_irr0; /* save most recent IRQ line stat */ 15062306a36Sopenharmony_ci#endif 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline struct dino_device *DINO_DEV(struct pci_hba_data *hba) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return container_of(hba, struct dino_device, hba); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* 15962306a36Sopenharmony_ci * Dino Configuration Space Accessor Functions 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define DINO_CFG_TOK(bus,dfn,pos) ((u32) ((bus)<<16 | (dfn)<<8 | (pos))) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * keep the current highest bus count to assist in allocating busses. This 16662306a36Sopenharmony_ci * tries to keep a global bus count total so that when we discover an 16762306a36Sopenharmony_ci * entirely new bus, it can be given a unique bus number. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_cistatic int dino_current_bus = 0; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, 17262306a36Sopenharmony_ci int size, u32 *val) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge)); 17562306a36Sopenharmony_ci u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; 17662306a36Sopenharmony_ci u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); 17762306a36Sopenharmony_ci void __iomem *base_addr = d->hba.base_addr; 17862306a36Sopenharmony_ci unsigned long flags; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where, 18162306a36Sopenharmony_ci size); 18262306a36Sopenharmony_ci spin_lock_irqsave(&d->dinosaur_pen, flags); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* tell HW which CFG address */ 18562306a36Sopenharmony_ci __raw_writel(v, base_addr + DINO_PCI_ADDR); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* generate cfg read cycle */ 18862306a36Sopenharmony_ci if (size == 1) { 18962306a36Sopenharmony_ci *val = readb(base_addr + DINO_CONFIG_DATA + (where & 3)); 19062306a36Sopenharmony_ci } else if (size == 2) { 19162306a36Sopenharmony_ci *val = readw(base_addr + DINO_CONFIG_DATA + (where & 2)); 19262306a36Sopenharmony_ci } else if (size == 4) { 19362306a36Sopenharmony_ci *val = readl(base_addr + DINO_CONFIG_DATA); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dinosaur_pen, flags); 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * Dino address stepping "feature": 20262306a36Sopenharmony_ci * When address stepping, Dino attempts to drive the bus one cycle too soon 20362306a36Sopenharmony_ci * even though the type of cycle (config vs. MMIO) might be different. 20462306a36Sopenharmony_ci * The read of Ven/Prod ID is harmless and avoids Dino's address stepping. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, 20762306a36Sopenharmony_ci int size, u32 val) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct dino_device *d = DINO_DEV(parisc_walk_tree(bus->bridge)); 21062306a36Sopenharmony_ci u32 local_bus = (bus->parent == NULL) ? 0 : bus->busn_res.start; 21162306a36Sopenharmony_ci u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); 21262306a36Sopenharmony_ci void __iomem *base_addr = d->hba.base_addr; 21362306a36Sopenharmony_ci unsigned long flags; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where, 21662306a36Sopenharmony_ci size); 21762306a36Sopenharmony_ci spin_lock_irqsave(&d->dinosaur_pen, flags); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* avoid address stepping feature */ 22062306a36Sopenharmony_ci __raw_writel(v & 0xffffff00, base_addr + DINO_PCI_ADDR); 22162306a36Sopenharmony_ci __raw_readl(base_addr + DINO_CONFIG_DATA); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* tell HW which CFG address */ 22462306a36Sopenharmony_ci __raw_writel(v, base_addr + DINO_PCI_ADDR); 22562306a36Sopenharmony_ci /* generate cfg read cycle */ 22662306a36Sopenharmony_ci if (size == 1) { 22762306a36Sopenharmony_ci writeb(val, base_addr + DINO_CONFIG_DATA + (where & 3)); 22862306a36Sopenharmony_ci } else if (size == 2) { 22962306a36Sopenharmony_ci writew(val, base_addr + DINO_CONFIG_DATA + (where & 2)); 23062306a36Sopenharmony_ci } else if (size == 4) { 23162306a36Sopenharmony_ci writel(val, base_addr + DINO_CONFIG_DATA); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dinosaur_pen, flags); 23562306a36Sopenharmony_ci return 0; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic struct pci_ops dino_cfg_ops = { 23962306a36Sopenharmony_ci .read = dino_cfg_read, 24062306a36Sopenharmony_ci .write = dino_cfg_write, 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/* 24562306a36Sopenharmony_ci * Dino "I/O Port" Space Accessor Functions 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * Many PCI devices don't require use of I/O port space (eg Tulip, 24862306a36Sopenharmony_ci * NCR720) since they export the same registers to both MMIO and 24962306a36Sopenharmony_ci * I/O port space. Performance is going to stink if drivers use 25062306a36Sopenharmony_ci * I/O port instead of MMIO. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci#define DINO_PORT_IN(type, size, mask) \ 25462306a36Sopenharmony_cistatic u##size dino_in##size (struct pci_hba_data *d, u16 addr) \ 25562306a36Sopenharmony_ci{ \ 25662306a36Sopenharmony_ci u##size v; \ 25762306a36Sopenharmony_ci unsigned long flags; \ 25862306a36Sopenharmony_ci spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \ 25962306a36Sopenharmony_ci /* tell HW which IO Port address */ \ 26062306a36Sopenharmony_ci __raw_writel((u32) addr, d->base_addr + DINO_PCI_ADDR); \ 26162306a36Sopenharmony_ci /* generate I/O PORT read cycle */ \ 26262306a36Sopenharmony_ci v = read##type(d->base_addr+DINO_IO_DATA+(addr&mask)); \ 26362306a36Sopenharmony_ci spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \ 26462306a36Sopenharmony_ci return v; \ 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciDINO_PORT_IN(b, 8, 3) 26862306a36Sopenharmony_ciDINO_PORT_IN(w, 16, 2) 26962306a36Sopenharmony_ciDINO_PORT_IN(l, 32, 0) 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#define DINO_PORT_OUT(type, size, mask) \ 27262306a36Sopenharmony_cistatic void dino_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ 27362306a36Sopenharmony_ci{ \ 27462306a36Sopenharmony_ci unsigned long flags; \ 27562306a36Sopenharmony_ci spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \ 27662306a36Sopenharmony_ci /* tell HW which IO port address */ \ 27762306a36Sopenharmony_ci __raw_writel((u32) addr, d->base_addr + DINO_PCI_ADDR); \ 27862306a36Sopenharmony_ci /* generate cfg write cycle */ \ 27962306a36Sopenharmony_ci write##type(val, d->base_addr+DINO_IO_DATA+(addr&mask)); \ 28062306a36Sopenharmony_ci spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \ 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciDINO_PORT_OUT(b, 8, 3) 28462306a36Sopenharmony_ciDINO_PORT_OUT(w, 16, 2) 28562306a36Sopenharmony_ciDINO_PORT_OUT(l, 32, 0) 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic struct pci_port_ops dino_port_ops = { 28862306a36Sopenharmony_ci .inb = dino_in8, 28962306a36Sopenharmony_ci .inw = dino_in16, 29062306a36Sopenharmony_ci .inl = dino_in32, 29162306a36Sopenharmony_ci .outb = dino_out8, 29262306a36Sopenharmony_ci .outw = dino_out16, 29362306a36Sopenharmony_ci .outl = dino_out32 29462306a36Sopenharmony_ci}; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void dino_mask_irq(struct irq_data *d) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); 29962306a36Sopenharmony_ci int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci DBG(KERN_WARNING "%s(0x%px, %d)\n", __func__, dino_dev, d->irq); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Clear the matching bit in the IMR register */ 30462306a36Sopenharmony_ci dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); 30562306a36Sopenharmony_ci __raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void dino_unmask_irq(struct irq_data *d) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); 31162306a36Sopenharmony_ci int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS); 31262306a36Sopenharmony_ci u32 tmp; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci DBG(KERN_WARNING "%s(0x%px, %d)\n", __func__, dino_dev, d->irq); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci ** clear pending IRQ bits 31862306a36Sopenharmony_ci ** 31962306a36Sopenharmony_ci ** This does NOT change ILR state! 32062306a36Sopenharmony_ci ** See comment below for ILR usage. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci __raw_readl(dino_dev->hba.base_addr+DINO_IPR); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* set the matching bit in the IMR register */ 32562306a36Sopenharmony_ci dino_dev->imr |= DINO_MASK_IRQ(local_irq); /* used in dino_isr() */ 32662306a36Sopenharmony_ci __raw_writel( dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Emulate "Level Triggered" Interrupt 32962306a36Sopenharmony_ci ** Basically, a driver is blowing it if the IRQ line is asserted 33062306a36Sopenharmony_ci ** while the IRQ is disabled. But tulip.c seems to do that.... 33162306a36Sopenharmony_ci ** Give 'em a kluge award and a nice round of applause! 33262306a36Sopenharmony_ci ** 33362306a36Sopenharmony_ci ** The gsc_write will generate an interrupt which invokes dino_isr(). 33462306a36Sopenharmony_ci ** dino_isr() will read IPR and find nothing. But then catch this 33562306a36Sopenharmony_ci ** when it also checks ILR. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci tmp = __raw_readl(dino_dev->hba.base_addr+DINO_ILR); 33862306a36Sopenharmony_ci if (tmp & DINO_MASK_IRQ(local_irq)) { 33962306a36Sopenharmony_ci DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n", 34062306a36Sopenharmony_ci __func__, tmp); 34162306a36Sopenharmony_ci gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci#ifdef CONFIG_SMP 34662306a36Sopenharmony_cistatic int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest, 34762306a36Sopenharmony_ci bool force) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); 35062306a36Sopenharmony_ci struct cpumask tmask; 35162306a36Sopenharmony_ci int cpu_irq; 35262306a36Sopenharmony_ci u32 eim; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (!cpumask_and(&tmask, dest, cpu_online_mask)) 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci cpu_irq = cpu_check_affinity(d, &tmask); 35862306a36Sopenharmony_ci if (cpu_irq < 0) 35962306a36Sopenharmony_ci return cpu_irq; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq); 36262306a36Sopenharmony_ci eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data; 36362306a36Sopenharmony_ci __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci irq_data_update_effective_affinity(d, &tmask); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return IRQ_SET_MASK_OK; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci#endif 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic struct irq_chip dino_interrupt_type = { 37262306a36Sopenharmony_ci .name = "GSC-PCI", 37362306a36Sopenharmony_ci .irq_unmask = dino_unmask_irq, 37462306a36Sopenharmony_ci .irq_mask = dino_mask_irq, 37562306a36Sopenharmony_ci#ifdef CONFIG_SMP 37662306a36Sopenharmony_ci .irq_set_affinity = dino_set_affinity_irq, 37762306a36Sopenharmony_ci#endif 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* 38262306a36Sopenharmony_ci * Handle a Processor interrupt generated by Dino. 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from 38562306a36Sopenharmony_ci * wedging the CPU. Could be removed or made optional at some point. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_cistatic irqreturn_t dino_isr(int irq, void *intr_dev) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct dino_device *dino_dev = intr_dev; 39062306a36Sopenharmony_ci u32 mask; 39162306a36Sopenharmony_ci int ilr_loop = 100; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* read and acknowledge pending interrupts */ 39462306a36Sopenharmony_ci#ifdef DINO_DEBUG 39562306a36Sopenharmony_ci dino_dev->dino_irr0 = 39662306a36Sopenharmony_ci#endif 39762306a36Sopenharmony_ci mask = __raw_readl(dino_dev->hba.base_addr+DINO_IRR0) & DINO_IRR_MASK; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (mask == 0) 40062306a36Sopenharmony_ci return IRQ_NONE; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciilr_again: 40362306a36Sopenharmony_ci do { 40462306a36Sopenharmony_ci int local_irq = __ffs(mask); 40562306a36Sopenharmony_ci int irq = dino_dev->global_irq[local_irq]; 40662306a36Sopenharmony_ci DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", 40762306a36Sopenharmony_ci __func__, irq, intr_dev, mask); 40862306a36Sopenharmony_ci generic_handle_irq(irq); 40962306a36Sopenharmony_ci mask &= ~DINO_MASK_IRQ(local_irq); 41062306a36Sopenharmony_ci } while (mask); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Support for level triggered IRQ lines. 41362306a36Sopenharmony_ci ** 41462306a36Sopenharmony_ci ** Dropping this support would make this routine *much* faster. 41562306a36Sopenharmony_ci ** But since PCI requires level triggered IRQ line to share lines... 41662306a36Sopenharmony_ci ** device drivers may assume lines are level triggered (and not 41762306a36Sopenharmony_ci ** edge triggered like EISA/ISA can be). 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_ci mask = __raw_readl(dino_dev->hba.base_addr+DINO_ILR) & dino_dev->imr; 42062306a36Sopenharmony_ci if (mask) { 42162306a36Sopenharmony_ci if (--ilr_loop > 0) 42262306a36Sopenharmony_ci goto ilr_again; 42362306a36Sopenharmony_ci pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n", 42462306a36Sopenharmony_ci dino_dev->hba.base_addr, mask); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci return IRQ_HANDLED; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic void dino_assign_irq(struct dino_device *dino, int local_irq, int *irqp) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci int irq = gsc_assign_irq(&dino_interrupt_type, dino); 43262306a36Sopenharmony_ci if (irq == NO_IRQ) 43362306a36Sopenharmony_ci return; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci *irqp = irq; 43662306a36Sopenharmony_ci dino->global_irq[local_irq] = irq; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic void dino_choose_irq(struct parisc_device *dev, void *ctrl) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci int irq; 44262306a36Sopenharmony_ci struct dino_device *dino = ctrl; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci switch (dev->id.sversion) { 44562306a36Sopenharmony_ci case 0x00084: irq = 8; break; /* PS/2 */ 44662306a36Sopenharmony_ci case 0x0008c: irq = 10; break; /* RS232 */ 44762306a36Sopenharmony_ci case 0x00096: irq = 8; break; /* PS/2 */ 44862306a36Sopenharmony_ci default: return; /* Unknown */ 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci dino_assign_irq(dino, irq, &dev->irq); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/* 45662306a36Sopenharmony_ci * Cirrus 6832 Cardbus reports wrong irq on RDI Tadpole PARISC Laptop (deller@gmx.de) 45762306a36Sopenharmony_ci * (the irqs are off-by-one, not sure yet if this is a cirrus, dino-hardware or dino-driver problem...) 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_cistatic void quirk_cirrus_cardbus(struct pci_dev *dev) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci u8 new_irq = dev->irq - 1; 46262306a36Sopenharmony_ci printk(KERN_INFO "PCI: Cirrus Cardbus IRQ fixup for %s, from %d to %d\n", 46362306a36Sopenharmony_ci pci_name(dev), dev->irq, new_irq); 46462306a36Sopenharmony_ci dev->irq = new_irq; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ciDECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus ); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci#ifdef CONFIG_TULIP 46962306a36Sopenharmony_ci/* Check if PCI device is behind a Card-mode Dino. */ 47062306a36Sopenharmony_cistatic int pci_dev_is_behind_card_dino(struct pci_dev *dev) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct dino_device *dino_dev; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge)); 47562306a36Sopenharmony_ci return is_card_dino(&dino_dev->hba.dev->id); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic void pci_fixup_tulip(struct pci_dev *dev) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci if (!pci_dev_is_behind_card_dino(dev)) 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) 48362306a36Sopenharmony_ci return; 48462306a36Sopenharmony_ci pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n", 48562306a36Sopenharmony_ci pci_name(dev)); 48662306a36Sopenharmony_ci /* Disable this card by zeroing the PCI resources */ 48762306a36Sopenharmony_ci memset(&dev->resource[0], 0, sizeof(dev->resource[0])); 48862306a36Sopenharmony_ci memset(&dev->resource[1], 0, sizeof(dev->resource[1])); 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip); 49162306a36Sopenharmony_ci#endif /* CONFIG_TULIP */ 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void __init 49462306a36Sopenharmony_cidino_bios_init(void) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci DBG("dino_bios_init\n"); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci/* 50062306a36Sopenharmony_ci * dino_card_setup - Set up the memory space for a Dino in card mode. 50162306a36Sopenharmony_ci * @bus: the bus under this dino 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci * Claim an 8MB chunk of unused IO space and call the generic PCI routines 50462306a36Sopenharmony_ci * to set up the addresses of the devices on this bus. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci#define _8MB 0x00800000UL 50762306a36Sopenharmony_cistatic void __init 50862306a36Sopenharmony_cidino_card_setup(struct pci_bus *bus, void __iomem *base_addr) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci int i; 51162306a36Sopenharmony_ci struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge)); 51262306a36Sopenharmony_ci struct resource *res; 51362306a36Sopenharmony_ci char name[128]; 51462306a36Sopenharmony_ci int size; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci res = &dino_dev->hba.lmmio_space; 51762306a36Sopenharmony_ci res->flags = IORESOURCE_MEM; 51862306a36Sopenharmony_ci size = scnprintf(name, sizeof(name), "Dino LMMIO (%s)", 51962306a36Sopenharmony_ci dev_name(bus->bridge)); 52062306a36Sopenharmony_ci res->name = kmalloc(size+1, GFP_KERNEL); 52162306a36Sopenharmony_ci if(res->name) 52262306a36Sopenharmony_ci strcpy((char *)res->name, name); 52362306a36Sopenharmony_ci else 52462306a36Sopenharmony_ci res->name = dino_dev->hba.lmmio_space.name; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (ccio_allocate_resource(dino_dev->hba.dev, res, _8MB, 52862306a36Sopenharmony_ci F_EXTEND(0xf0000000UL) | _8MB, 52962306a36Sopenharmony_ci F_EXTEND(0xffffffffUL) &~ _8MB, _8MB) < 0) { 53062306a36Sopenharmony_ci struct pci_dev *dev, *tmp; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci printk(KERN_ERR "Dino: cannot attach bus %s\n", 53362306a36Sopenharmony_ci dev_name(bus->bridge)); 53462306a36Sopenharmony_ci /* kill the bus, we can't do anything with it */ 53562306a36Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { 53662306a36Sopenharmony_ci list_del(&dev->bus_list); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci bus->resource[1] = res; 54262306a36Sopenharmony_ci bus->resource[0] = &(dino_dev->hba.io_space); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Now tell dino what range it has */ 54562306a36Sopenharmony_ci for (i = 1; i < 31; i++) { 54662306a36Sopenharmony_ci if (res->start == F_EXTEND(0xf0000000UL | (i * _8MB))) 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %p\n", 55062306a36Sopenharmony_ci i, res->start, base_addr + DINO_IO_ADDR_EN); 55162306a36Sopenharmony_ci __raw_writel(1 << i, base_addr + DINO_IO_ADDR_EN); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void __init 55562306a36Sopenharmony_cidino_card_fixup(struct pci_dev *dev) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci u32 irq_pin; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci ** REVISIT: card-mode PCI-PCI expansion chassis do exist. 56162306a36Sopenharmony_ci ** Not sure they were ever productized. 56262306a36Sopenharmony_ci ** Die here since we'll die later in dino_inb() anyway. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 56562306a36Sopenharmony_ci panic("Card-Mode Dino: PCI-PCI Bridge not supported\n"); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci ** Set Latency Timer to 0xff (not a shared bus) 57062306a36Sopenharmony_ci ** Set CACHELINE_SIZE. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci dino_cfg_write(dev->bus, dev->devfn, 57362306a36Sopenharmony_ci PCI_CACHE_LINE_SIZE, 2, 0xff00 | L1_CACHE_BYTES/4); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* 57662306a36Sopenharmony_ci ** Program INT_LINE for card-mode devices. 57762306a36Sopenharmony_ci ** The cards are hardwired according to this algorithm. 57862306a36Sopenharmony_ci ** And it doesn't matter if PPB's are present or not since 57962306a36Sopenharmony_ci ** the IRQ lines bypass the PPB. 58062306a36Sopenharmony_ci ** 58162306a36Sopenharmony_ci ** "-1" converts INTA-D (1-4) to PCIINTA-D (0-3) range. 58262306a36Sopenharmony_ci ** The additional "-1" adjusts for skewing the IRQ<->slot. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin); 58562306a36Sopenharmony_ci dev->irq = pci_swizzle_interrupt_pin(dev, irq_pin) - 1; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Shouldn't really need to do this but it's in case someone tries 58862306a36Sopenharmony_ci ** to bypass PCI services and look at the card themselves. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 1, dev->irq); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/* The alignment contraints for PCI bridges under dino */ 59462306a36Sopenharmony_ci#define DINO_BRIDGE_ALIGN 0x100000 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void __init 59862306a36Sopenharmony_cidino_fixup_bus(struct pci_bus *bus) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct pci_dev *dev; 60162306a36Sopenharmony_ci struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge)); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci DBG(KERN_WARNING "%s(0x%px) bus %d platform_data 0x%px\n", 60462306a36Sopenharmony_ci __func__, bus, bus->busn_res.start, 60562306a36Sopenharmony_ci bus->bridge->platform_data); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Firmware doesn't set up card-mode dino, so we have to */ 60862306a36Sopenharmony_ci if (is_card_dino(&dino_dev->hba.dev->id)) { 60962306a36Sopenharmony_ci dino_card_setup(bus, dino_dev->hba.base_addr); 61062306a36Sopenharmony_ci } else if (bus->parent) { 61162306a36Sopenharmony_ci int i; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci pci_read_bridge_bases(bus); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci for(i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { 61762306a36Sopenharmony_ci if((bus->self->resource[i].flags & 61862306a36Sopenharmony_ci (IORESOURCE_IO | IORESOURCE_MEM)) == 0) 61962306a36Sopenharmony_ci continue; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if(bus->self->resource[i].flags & IORESOURCE_MEM) { 62262306a36Sopenharmony_ci /* There's a quirk to alignment of 62362306a36Sopenharmony_ci * bridge memory resources: the start 62462306a36Sopenharmony_ci * is the alignment and start-end is 62562306a36Sopenharmony_ci * the size. However, firmware will 62662306a36Sopenharmony_ci * have assigned start and end, so we 62762306a36Sopenharmony_ci * need to take this into account */ 62862306a36Sopenharmony_ci bus->self->resource[i].end = bus->self->resource[i].end - bus->self->resource[i].start + DINO_BRIDGE_ALIGN; 62962306a36Sopenharmony_ci bus->self->resource[i].start = DINO_BRIDGE_ALIGN; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci DBG("DEBUG %s assigning %d [%pR]\n", 63462306a36Sopenharmony_ci dev_name(&bus->self->dev), i, 63562306a36Sopenharmony_ci &bus->self->resource[i]); 63662306a36Sopenharmony_ci WARN_ON(pci_assign_resource(bus->self, i)); 63762306a36Sopenharmony_ci DBG("DEBUG %s after assign %d [%pR]\n", 63862306a36Sopenharmony_ci dev_name(&bus->self->dev), i, 63962306a36Sopenharmony_ci &bus->self->resource[i]); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci list_for_each_entry(dev, &bus->devices, bus_list) { 64562306a36Sopenharmony_ci if (is_card_dino(&dino_dev->hba.dev->id)) 64662306a36Sopenharmony_ci dino_card_fixup(dev); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci ** P2PB's only have 2 BARs, no IRQs. 65062306a36Sopenharmony_ci ** I'd like to just ignore them for now. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 65362306a36Sopenharmony_ci pcibios_init_bridge(dev); 65462306a36Sopenharmony_ci continue; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* null out the ROM resource if there is one (we don't 65862306a36Sopenharmony_ci * care about an expansion rom on parisc, since it 65962306a36Sopenharmony_ci * usually contains (x86) bios code) */ 66062306a36Sopenharmony_ci dev->resource[PCI_ROM_RESOURCE].flags = 0; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if(dev->irq == 255) { 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci#define DINO_FIX_UNASSIGNED_INTERRUPTS 66562306a36Sopenharmony_ci#ifdef DINO_FIX_UNASSIGNED_INTERRUPTS 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* This code tries to assign an unassigned 66862306a36Sopenharmony_ci * interrupt. Leave it disabled unless you 66962306a36Sopenharmony_ci * *really* know what you're doing since the 67062306a36Sopenharmony_ci * pin<->interrupt line mapping varies by bus 67162306a36Sopenharmony_ci * and machine */ 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci u32 irq_pin; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci dino_cfg_read(dev->bus, dev->devfn, 67662306a36Sopenharmony_ci PCI_INTERRUPT_PIN, 1, &irq_pin); 67762306a36Sopenharmony_ci irq_pin = pci_swizzle_interrupt_pin(dev, irq_pin) - 1; 67862306a36Sopenharmony_ci printk(KERN_WARNING "Device %s has undefined IRQ, " 67962306a36Sopenharmony_ci "setting to %d\n", pci_name(dev), irq_pin); 68062306a36Sopenharmony_ci dino_cfg_write(dev->bus, dev->devfn, 68162306a36Sopenharmony_ci PCI_INTERRUPT_LINE, 1, irq_pin); 68262306a36Sopenharmony_ci dino_assign_irq(dino_dev, irq_pin, &dev->irq); 68362306a36Sopenharmony_ci#else 68462306a36Sopenharmony_ci dev->irq = 65535; 68562306a36Sopenharmony_ci printk(KERN_WARNING "Device %s has unassigned IRQ\n", pci_name(dev)); 68662306a36Sopenharmony_ci#endif 68762306a36Sopenharmony_ci } else { 68862306a36Sopenharmony_ci /* Adjust INT_LINE for that busses region */ 68962306a36Sopenharmony_ci dino_assign_irq(dino_dev, dev->irq, &dev->irq); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic struct pci_bios_ops dino_bios_ops = { 69662306a36Sopenharmony_ci .init = dino_bios_init, 69762306a36Sopenharmony_ci .fixup_bus = dino_fixup_bus 69862306a36Sopenharmony_ci}; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci/* 70262306a36Sopenharmony_ci * Initialise a DINO controller chip 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_cistatic void __init 70562306a36Sopenharmony_cidino_card_init(struct dino_device *dino_dev) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci u32 brdg_feat = 0x00784e05; 70862306a36Sopenharmony_ci unsigned long status; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci status = __raw_readl(dino_dev->hba.base_addr+DINO_IO_STATUS); 71162306a36Sopenharmony_ci if (status & 0x0000ff80) { 71262306a36Sopenharmony_ci __raw_writel(0x00000005, 71362306a36Sopenharmony_ci dino_dev->hba.base_addr+DINO_IO_COMMAND); 71462306a36Sopenharmony_ci udelay(1); 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK); 71862306a36Sopenharmony_ci __raw_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN); 71962306a36Sopenharmony_ci __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_ICR); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci#if 1 72262306a36Sopenharmony_ci/* REVISIT - should be a runtime check (eg if (CPU_IS_PCX_L) ...) */ 72362306a36Sopenharmony_ci /* 72462306a36Sopenharmony_ci ** PCX-L processors don't support XQL like Dino wants it. 72562306a36Sopenharmony_ci ** PCX-L2 ignore XQL signal and it doesn't matter. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci brdg_feat &= ~0x4; /* UXQL */ 72862306a36Sopenharmony_ci#endif 72962306a36Sopenharmony_ci __raw_writel( brdg_feat, dino_dev->hba.base_addr+DINO_BRDG_FEAT); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* 73262306a36Sopenharmony_ci ** Don't enable address decoding until we know which I/O range 73362306a36Sopenharmony_ci ** currently is available from the host. Only affects MMIO 73462306a36Sopenharmony_ci ** and not I/O port space. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_IO_ADDR_EN); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_DAMODE); 73962306a36Sopenharmony_ci __raw_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIROR); 74062306a36Sopenharmony_ci __raw_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIWOR); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci __raw_writel(0x00000040, dino_dev->hba.base_addr+DINO_MLTIM); 74362306a36Sopenharmony_ci __raw_writel(0x00000080, dino_dev->hba.base_addr+DINO_IO_CONTROL); 74462306a36Sopenharmony_ci __raw_writel(0x0000008c, dino_dev->hba.base_addr+DINO_TLTIM); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* Disable PAMR before writing PAPR */ 74762306a36Sopenharmony_ci __raw_writel(0x0000007e, dino_dev->hba.base_addr+DINO_PAMR); 74862306a36Sopenharmony_ci __raw_writel(0x0000007f, dino_dev->hba.base_addr+DINO_PAPR); 74962306a36Sopenharmony_ci __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_PAMR); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* 75262306a36Sopenharmony_ci ** Dino ERS encourages enabling FBB (0x6f). 75362306a36Sopenharmony_ci ** We can't until we know *all* devices below us can support it. 75462306a36Sopenharmony_ci ** (Something in device configuration header tells us). 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_ci __raw_writel(0x0000004f, dino_dev->hba.base_addr+DINO_PCICMD); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Somewhere, the PCI spec says give devices 1 second 75962306a36Sopenharmony_ci ** to recover from the #RESET being de-asserted. 76062306a36Sopenharmony_ci ** Experience shows most devices only need 10ms. 76162306a36Sopenharmony_ci ** This short-cut speeds up booting significantly. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci mdelay(pci_post_reset_delay); 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic int __init 76762306a36Sopenharmony_cidino_bridge_init(struct dino_device *dino_dev, const char *name) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci unsigned long io_addr; 77062306a36Sopenharmony_ci int result, i, count=0; 77162306a36Sopenharmony_ci struct resource *res, *prevres = NULL; 77262306a36Sopenharmony_ci /* 77362306a36Sopenharmony_ci * Decoding IO_ADDR_EN only works for Built-in Dino 77462306a36Sopenharmony_ci * since PDC has already initialized this. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci io_addr = __raw_readl(dino_dev->hba.base_addr + DINO_IO_ADDR_EN); 77862306a36Sopenharmony_ci if (io_addr == 0) { 77962306a36Sopenharmony_ci printk(KERN_WARNING "%s: No PCI devices enabled.\n", name); 78062306a36Sopenharmony_ci return -ENODEV; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci res = &dino_dev->hba.lmmio_space; 78462306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 78562306a36Sopenharmony_ci unsigned long start, end; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if((io_addr & (1 << i)) == 0) 78862306a36Sopenharmony_ci continue; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci start = F_EXTEND(0xf0000000UL) | (i << 23); 79162306a36Sopenharmony_ci end = start + 8 * 1024 * 1024 - 1; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count, 79462306a36Sopenharmony_ci start, end); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if(prevres && prevres->end + 1 == start) { 79762306a36Sopenharmony_ci prevres->end = end; 79862306a36Sopenharmony_ci } else { 79962306a36Sopenharmony_ci if(count >= DINO_MAX_LMMIO_RESOURCES) { 80062306a36Sopenharmony_ci printk(KERN_ERR "%s is out of resource windows for range %d (0x%lx-0x%lx)\n", name, count, start, end); 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci prevres = res; 80462306a36Sopenharmony_ci res->start = start; 80562306a36Sopenharmony_ci res->end = end; 80662306a36Sopenharmony_ci res->flags = IORESOURCE_MEM; 80762306a36Sopenharmony_ci res->name = kmalloc(64, GFP_KERNEL); 80862306a36Sopenharmony_ci if(res->name) 80962306a36Sopenharmony_ci snprintf((char *)res->name, 64, "%s LMMIO %d", 81062306a36Sopenharmony_ci name, count); 81162306a36Sopenharmony_ci res++; 81262306a36Sopenharmony_ci count++; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci res = &dino_dev->hba.lmmio_space; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) { 81962306a36Sopenharmony_ci if(res[i].flags == 0) 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci result = ccio_request_resource(dino_dev->hba.dev, &res[i]); 82362306a36Sopenharmony_ci if (result < 0) { 82462306a36Sopenharmony_ci printk(KERN_ERR "%s: failed to claim PCI Bus address " 82562306a36Sopenharmony_ci "space %d (%pR)!\n", name, i, &res[i]); 82662306a36Sopenharmony_ci return result; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci return 0; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int __init dino_common_init(struct parisc_device *dev, 83362306a36Sopenharmony_ci struct dino_device *dino_dev, const char *name) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci int status; 83662306a36Sopenharmony_ci u32 eim; 83762306a36Sopenharmony_ci struct resource *res; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci pcibios_register_hba(&dino_dev->hba); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci pci_bios = &dino_bios_ops; /* used by pci_scan_bus() */ 84262306a36Sopenharmony_ci pci_port = &dino_port_ops; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* 84562306a36Sopenharmony_ci ** Note: SMP systems can make use of IRR1/IAR1 registers 84662306a36Sopenharmony_ci ** But it won't buy much performance except in very 84762306a36Sopenharmony_ci ** specific applications/configurations. Note Dino 84862306a36Sopenharmony_ci ** still only has 11 IRQ input lines - just map some of them 84962306a36Sopenharmony_ci ** to a different processor. 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ci dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq); 85262306a36Sopenharmony_ci eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* 85562306a36Sopenharmony_ci ** Dino needs a PA "IRQ" to get a processor's attention. 85662306a36Sopenharmony_ci ** arch/parisc/kernel/irq.c returns an EIRR bit. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_ci if (dev->irq < 0) { 85962306a36Sopenharmony_ci printk(KERN_WARNING "%s: gsc_alloc_irq() failed\n", name); 86062306a36Sopenharmony_ci return 1; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci status = request_irq(dev->irq, dino_isr, 0, name, dino_dev); 86462306a36Sopenharmony_ci if (status) { 86562306a36Sopenharmony_ci printk(KERN_WARNING "%s: request_irq() failed with %d\n", 86662306a36Sopenharmony_ci name, status); 86762306a36Sopenharmony_ci return 1; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Support the serial port which is sometimes attached on built-in 87162306a36Sopenharmony_ci * Dino / Cujo chips. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci gsc_fixup_irqs(dev, dino_dev, dino_choose_irq); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* 87762306a36Sopenharmony_ci ** This enables DINO to generate interrupts when it sees 87862306a36Sopenharmony_ci ** any of its inputs *change*. Just asserting an IRQ 87962306a36Sopenharmony_ci ** before it's enabled (ie unmasked) isn't good enough. 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* 88462306a36Sopenharmony_ci ** Some platforms don't clear Dino's IRR0 register at boot time. 88562306a36Sopenharmony_ci ** Reading will clear it now. 88662306a36Sopenharmony_ci */ 88762306a36Sopenharmony_ci __raw_readl(dino_dev->hba.base_addr+DINO_IRR0); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* allocate I/O Port resource region */ 89062306a36Sopenharmony_ci res = &dino_dev->hba.io_space; 89162306a36Sopenharmony_ci if (!is_cujo(&dev->id)) { 89262306a36Sopenharmony_ci res->name = "Dino I/O Port"; 89362306a36Sopenharmony_ci } else { 89462306a36Sopenharmony_ci res->name = "Cujo I/O Port"; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci res->start = HBA_PORT_BASE(dino_dev->hba.hba_num); 89762306a36Sopenharmony_ci res->end = res->start + (HBA_PORT_SPACE_SIZE - 1); 89862306a36Sopenharmony_ci res->flags = IORESOURCE_IO; /* do not mark it busy ! */ 89962306a36Sopenharmony_ci if (request_resource(&ioport_resource, res) < 0) { 90062306a36Sopenharmony_ci printk(KERN_ERR "%s: request I/O Port region failed " 90162306a36Sopenharmony_ci "0x%lx/%lx (hpa 0x%px)\n", 90262306a36Sopenharmony_ci name, (unsigned long)res->start, (unsigned long)res->end, 90362306a36Sopenharmony_ci dino_dev->hba.base_addr); 90462306a36Sopenharmony_ci return 1; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return 0; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci#define CUJO_RAVEN_ADDR F_EXTEND(0xf1000000UL) 91162306a36Sopenharmony_ci#define CUJO_FIREHAWK_ADDR F_EXTEND(0xf1604000UL) 91262306a36Sopenharmony_ci#define CUJO_RAVEN_BADPAGE 0x01003000UL 91362306a36Sopenharmony_ci#define CUJO_FIREHAWK_BADPAGE 0x01607000UL 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic const char dino_vers[][4] = { 91662306a36Sopenharmony_ci "2.0", 91762306a36Sopenharmony_ci "2.1", 91862306a36Sopenharmony_ci "3.0", 91962306a36Sopenharmony_ci "3.1" 92062306a36Sopenharmony_ci}; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic const char cujo_vers[][4] = { 92362306a36Sopenharmony_ci "1.0", 92462306a36Sopenharmony_ci "2.0" 92562306a36Sopenharmony_ci}; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci/* 92862306a36Sopenharmony_ci** Determine if dino should claim this chip (return 0) or not (return 1). 92962306a36Sopenharmony_ci** If so, initialize the chip appropriately (card-mode vs bridge mode). 93062306a36Sopenharmony_ci** Much of the initialization is common though. 93162306a36Sopenharmony_ci*/ 93262306a36Sopenharmony_cistatic int __init dino_probe(struct parisc_device *dev) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci struct dino_device *dino_dev; // Dino specific control struct 93562306a36Sopenharmony_ci const char *version = "unknown"; 93662306a36Sopenharmony_ci char *name; 93762306a36Sopenharmony_ci int is_cujo = 0; 93862306a36Sopenharmony_ci LIST_HEAD(resources); 93962306a36Sopenharmony_ci struct pci_bus *bus; 94062306a36Sopenharmony_ci unsigned long hpa = dev->hpa.start; 94162306a36Sopenharmony_ci int max; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci name = "Dino"; 94462306a36Sopenharmony_ci if (is_card_dino(&dev->id)) { 94562306a36Sopenharmony_ci version = "3.x (card mode)"; 94662306a36Sopenharmony_ci } else { 94762306a36Sopenharmony_ci if (!is_cujo(&dev->id)) { 94862306a36Sopenharmony_ci if (dev->id.hversion_rev < 4) { 94962306a36Sopenharmony_ci version = dino_vers[dev->id.hversion_rev]; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci } else { 95262306a36Sopenharmony_ci name = "Cujo"; 95362306a36Sopenharmony_ci is_cujo = 1; 95462306a36Sopenharmony_ci if (dev->id.hversion_rev < 2) { 95562306a36Sopenharmony_ci version = cujo_vers[dev->id.hversion_rev]; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci printk("%s version %s found at 0x%lx\n", name, version, hpa); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (!request_mem_region(hpa, PAGE_SIZE, name)) { 96362306a36Sopenharmony_ci printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%lx)!\n", 96462306a36Sopenharmony_ci hpa); 96562306a36Sopenharmony_ci return 1; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Check for bugs */ 96962306a36Sopenharmony_ci if (is_cujo && dev->id.hversion_rev == 1) { 97062306a36Sopenharmony_ci#ifdef CONFIG_IOMMU_CCIO 97162306a36Sopenharmony_ci printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n"); 97262306a36Sopenharmony_ci if (hpa == (unsigned long)CUJO_RAVEN_ADDR) { 97362306a36Sopenharmony_ci ccio_cujo20_fixup(dev, CUJO_RAVEN_BADPAGE); 97462306a36Sopenharmony_ci } else if (hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { 97562306a36Sopenharmony_ci ccio_cujo20_fixup(dev, CUJO_FIREHAWK_BADPAGE); 97662306a36Sopenharmony_ci } else { 97762306a36Sopenharmony_ci printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", hpa); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci#endif 98062306a36Sopenharmony_ci } else if (!is_cujo && !is_card_dino(&dev->id) && 98162306a36Sopenharmony_ci dev->id.hversion_rev < 3) { 98262306a36Sopenharmony_ci printk(KERN_WARNING 98362306a36Sopenharmony_ci"The GSCtoPCI (Dino hrev %d) bus converter found may exhibit\n" 98462306a36Sopenharmony_ci"data corruption. See Service Note Numbers: A4190A-01, A4191A-01.\n" 98562306a36Sopenharmony_ci"Systems shipped after Aug 20, 1997 will not exhibit this problem.\n" 98662306a36Sopenharmony_ci"Models affected: C180, C160, C160L, B160L, and B132L workstations.\n\n", 98762306a36Sopenharmony_ci dev->id.hversion_rev); 98862306a36Sopenharmony_ci/* REVISIT: why are C200/C240 listed in the README table but not 98962306a36Sopenharmony_ci** "Models affected"? Could be an omission in the original literature. 99062306a36Sopenharmony_ci*/ 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci dino_dev = kzalloc(sizeof(struct dino_device), GFP_KERNEL); 99462306a36Sopenharmony_ci if (!dino_dev) { 99562306a36Sopenharmony_ci printk("dino_init_chip - couldn't alloc dino_device\n"); 99662306a36Sopenharmony_ci return 1; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci dino_dev->hba.dev = dev; 100062306a36Sopenharmony_ci dino_dev->hba.base_addr = ioremap(hpa, 4096); 100162306a36Sopenharmony_ci dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND; 100262306a36Sopenharmony_ci spin_lock_init(&dino_dev->dinosaur_pen); 100362306a36Sopenharmony_ci dino_dev->hba.iommu = ccio_get_iommu(dev); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (is_card_dino(&dev->id)) { 100662306a36Sopenharmony_ci dino_card_init(dino_dev); 100762306a36Sopenharmony_ci } else { 100862306a36Sopenharmony_ci dino_bridge_init(dino_dev, name); 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (dino_common_init(dev, dino_dev, name)) 101262306a36Sopenharmony_ci return 1; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci dev->dev.platform_data = dino_dev; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci pci_add_resource_offset(&resources, &dino_dev->hba.io_space, 101762306a36Sopenharmony_ci HBA_PORT_BASE(dino_dev->hba.hba_num)); 101862306a36Sopenharmony_ci if (dino_dev->hba.lmmio_space.flags) 101962306a36Sopenharmony_ci pci_add_resource_offset(&resources, &dino_dev->hba.lmmio_space, 102062306a36Sopenharmony_ci dino_dev->hba.lmmio_space_offset); 102162306a36Sopenharmony_ci if (dino_dev->hba.elmmio_space.flags) 102262306a36Sopenharmony_ci pci_add_resource_offset(&resources, &dino_dev->hba.elmmio_space, 102362306a36Sopenharmony_ci dino_dev->hba.lmmio_space_offset); 102462306a36Sopenharmony_ci if (dino_dev->hba.gmmio_space.flags) 102562306a36Sopenharmony_ci pci_add_resource(&resources, &dino_dev->hba.gmmio_space); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci dino_dev->hba.bus_num.start = dino_current_bus; 102862306a36Sopenharmony_ci dino_dev->hba.bus_num.end = 255; 102962306a36Sopenharmony_ci dino_dev->hba.bus_num.flags = IORESOURCE_BUS; 103062306a36Sopenharmony_ci pci_add_resource(&resources, &dino_dev->hba.bus_num); 103162306a36Sopenharmony_ci /* 103262306a36Sopenharmony_ci ** It's not used to avoid chicken/egg problems 103362306a36Sopenharmony_ci ** with configuration accessor functions. 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_ci dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev, 103662306a36Sopenharmony_ci dino_current_bus, &dino_cfg_ops, NULL, &resources); 103762306a36Sopenharmony_ci if (!bus) { 103862306a36Sopenharmony_ci printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n", 103962306a36Sopenharmony_ci dev_name(&dev->dev), dino_current_bus); 104062306a36Sopenharmony_ci pci_free_resource_list(&resources); 104162306a36Sopenharmony_ci /* increment the bus number in case of duplicates */ 104262306a36Sopenharmony_ci dino_current_bus++; 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci max = pci_scan_child_bus(bus); 104762306a36Sopenharmony_ci pci_bus_update_busn_res_end(bus, max); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* This code *depends* on scanning being single threaded 105062306a36Sopenharmony_ci * if it isn't, this global bus number count will fail 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci dino_current_bus = max + 1; 105362306a36Sopenharmony_ci pci_bus_assign_resources(bus); 105462306a36Sopenharmony_ci pci_bus_add_devices(bus); 105562306a36Sopenharmony_ci return 0; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci/* 105962306a36Sopenharmony_ci * Normally, we would just test sversion. But the Elroy PCI adapter has 106062306a36Sopenharmony_ci * the same sversion as Dino, so we have to check hversion as well. 106162306a36Sopenharmony_ci * Unfortunately, the J2240 PDC reports the wrong hversion for the first 106262306a36Sopenharmony_ci * Dino, so we have to test for Dino, Cujo and Dino-in-a-J2240. 106362306a36Sopenharmony_ci * For card-mode Dino, most machines report an sversion of 9D. But 715 106462306a36Sopenharmony_ci * and 725 firmware misreport it as 0x08080 for no adequately explained 106562306a36Sopenharmony_ci * reason. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_cistatic const struct parisc_device_id dino_tbl[] __initconst = { 106862306a36Sopenharmony_ci { HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x004, 0x0009D },/* Card-mode Dino */ 106962306a36Sopenharmony_ci { HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x08080 }, /* XXX */ 107062306a36Sopenharmony_ci { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x680, 0xa }, /* Bridge-mode Dino */ 107162306a36Sopenharmony_ci { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x682, 0xa }, /* Bridge-mode Cujo */ 107262306a36Sopenharmony_ci { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x05d, 0xa }, /* Dino in a J2240 */ 107362306a36Sopenharmony_ci { 0, } 107462306a36Sopenharmony_ci}; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic struct parisc_driver dino_driver __refdata = { 107762306a36Sopenharmony_ci .name = "dino", 107862306a36Sopenharmony_ci .id_table = dino_tbl, 107962306a36Sopenharmony_ci .probe = dino_probe, 108062306a36Sopenharmony_ci}; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci/* 108362306a36Sopenharmony_ci * One time initialization to let the world know Dino is here. 108462306a36Sopenharmony_ci * This is the only routine which is NOT static. 108562306a36Sopenharmony_ci * Must be called exactly once before pci_init(). 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_cistatic int __init dino_init(void) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci return register_parisc_driver(&dino_driver); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ciarch_initcall(dino_init); 1092