lba_pci.c
来自「linux 内核源代码」· C语言 代码 · 共 1,593 行 · 第 1/4 页
C
1,593 行
/***** PCI Lower Bus Adapter (LBA) manager**** (c) Copyright 1999,2000 Grant Grundler** (c) Copyright 1999,2000 Hewlett-Packard Company**** 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 primarily provides access to PCI bus (config/IOport** spaces) on platforms with an SBA/LBA chipset. A/B/C/J/L/N-class** with 4 digit model numbers - eg C3000 (and A400...sigh).**** LBA driver isn't as simple as the Dino driver because:** (a) this chip has substantial bug fixes between revisions** (Only one Dino bug has a software workaround :^( )** (b) has more options which we don't (yet) support (DMA hints, OLARD)** (c) IRQ support lives in the I/O SAPIC driver (not with PCI driver)** (d) play nicely with both PAT and "Legacy" PA-RISC firmware (PDC).** (dino only deals with "Legacy" PDC)**** LBA driver passes the I/O SAPIC HPA to the I/O SAPIC driver.** (I/O SAPIC is integratd in the LBA chip).**** FIXME: Add support to SBA and LBA drivers for DMA hint sets** FIXME: Add support for PCI card hot-plug (OLARD).*/#include <linux/delay.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/spinlock.h>#include <linux/init.h> /* for __init and __devinit */#include <linux/pci.h>#include <linux/ioport.h>#include <linux/slab.h>#include <asm/byteorder.h>#include <asm/pdc.h>#include <asm/pdcpat.h>#include <asm/page.h>#include <asm/system.h>#include <asm/ropes.h>#include <asm/hardware.h> /* for register_parisc_driver() stuff */#include <asm/parisc-device.h>#include <asm/io.h> /* read/write stuff */#undef DEBUG_LBA /* general stuff */#undef DEBUG_LBA_PORT /* debug I/O Port access */#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */#undef DEBUG_LBA_PAT /* debug PCI Resource Mgt code - PDC PAT only */#undef FBB_SUPPORT /* Fast Back-Back xfers - NOT READY YET */#ifdef DEBUG_LBA#define DBG(x...) printk(x)#else#define DBG(x...)#endif#ifdef DEBUG_LBA_PORT#define DBG_PORT(x...) printk(x)#else#define DBG_PORT(x...)#endif#ifdef DEBUG_LBA_CFG#define DBG_CFG(x...) printk(x)#else#define DBG_CFG(x...)#endif#ifdef DEBUG_LBA_PAT#define DBG_PAT(x...) printk(x)#else#define DBG_PAT(x...)#endif/*** Config accessor functions only pass in the 8-bit bus number and not** the 8-bit "PCI Segment" number. Each LBA will be assigned a PCI bus** number based on what firmware wrote into the scratch register.**** The "secondary" bus number is set to this before calling** pci_register_ops(). If any PPB's are present, the scan will** discover them and update the "secondary" and "subordinate"** fields in the pci_bus structure.**** Changes in the configuration *may* result in a different** bus number for each LBA depending on what firmware does.*/#define MODULE_NAME "LBA"/* non-postable I/O port space, densely packed */#define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL)static void __iomem *astro_iop_base __read_mostly;static u32 lba_t32;/* lba flags */#define LBA_FLAG_SKIP_PROBE 0x10#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE)/* Looks nice and keeps the compiler happy */#define LBA_DEV(d) ((struct lba_device *) (d))/*** Only allow 8 subsidiary busses per LBA** Problem is the PCI bus numbering is globally shared.*/#define LBA_MAX_NUM_BUSES 8/************************************ * LBA register read and write support * * BE WARNED: register writes are posted. * (ie follow writes which must reach HW with a read) */#define READ_U8(addr) __raw_readb(addr)#define READ_U16(addr) __raw_readw(addr)#define READ_U32(addr) __raw_readl(addr)#define WRITE_U8(value, addr) __raw_writeb(value, addr)#define WRITE_U16(value, addr) __raw_writew(value, addr)#define WRITE_U32(value, addr) __raw_writel(value, addr)#define READ_REG8(addr) readb(addr)#define READ_REG16(addr) readw(addr)#define READ_REG32(addr) readl(addr)#define READ_REG64(addr) readq(addr)#define WRITE_REG8(value, addr) writeb(value, addr)#define WRITE_REG16(value, addr) writew(value, addr)#define WRITE_REG32(value, addr) writel(value, addr)#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8))#define LBA_CFG_BUS(tok) ((u8) ((tok)>>16))#define LBA_CFG_DEV(tok) ((u8) ((tok)>>11) & 0x1f)#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7)/*** Extract LBA (Rope) number from HPA** REVISIT: 16 ropes for Stretch/Ike?*/#define ROPES_PER_IOC 8#define LBA_NUM(x) ((((unsigned long) x) >> 13) & (ROPES_PER_IOC-1))static voidlba_dump_res(struct resource *r, int d){ int i; if (NULL == r) return; printk(KERN_DEBUG "(%p)", r->parent); for (i = d; i ; --i) printk(" "); printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, (long)r->start, (long)r->end, r->flags); lba_dump_res(r->child, d+2); lba_dump_res(r->sibling, d);}/*** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex** workaround for cfg cycles:** -- preserve LBA state** -- prevent any DMA from occurring** -- turn on smart mode** -- probe with config writes before doing config reads** -- check ERROR_STATUS** -- clear ERROR_STATUS** -- restore LBA state**** The workaround is only used for device discovery.*/static int lba_device_present(u8 bus, u8 dfn, struct lba_device *d){ u8 first_bus = d->hba.hba_bus->secondary; u8 last_sub_bus = d->hba.hba_bus->subordinate; if ((bus < first_bus) || (bus > last_sub_bus) || ((bus - first_bus) >= LBA_MAX_NUM_BUSES)) { return 0; } return 1;}#define LBA_CFG_SETUP(d, tok) { \ /* Save contents of error config register. */ \ error_config = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); \\ /* Save contents of status control register. */ \ status_control = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); \\ /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA \ ** arbitration for full bus walks. \ */ \ /* Save contents of arb mask register. */ \ arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK); \\ /* \ * Turn off all device arbitration bits (i.e. everything \ * except arbitration enable bit). \ */ \ WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK); \\ /* \ * Set the smart mode bit so that master aborts don't cause \ * LBA to go into PCI fatal mode (required). \ */ \ WRITE_REG32(error_config | LBA_SMART_MODE, d->hba.base_addr + LBA_ERROR_CONFIG); \}#define LBA_CFG_PROBE(d, tok) { \ /* \ * Setup Vendor ID write and read back the address register \ * to make sure that LBA is the bus master. \ */ \ WRITE_REG32(tok | PCI_VENDOR_ID, (d)->hba.base_addr + LBA_PCI_CFG_ADDR);\ /* \ * Read address register to ensure that LBA is the bus master, \ * which implies that DMA traffic has stopped when DMA arb is off. \ */ \ lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ /* \ * Generate a cfg write cycle (will have no affect on \ * Vendor ID register since read-only). \ */ \ WRITE_REG32(~0, (d)->hba.base_addr + LBA_PCI_CFG_DATA); \ /* \ * Make sure write has completed before proceeding further, \ * i.e. before setting clear enable. \ */ \ lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \}/* * HPREVISIT: * -- Can't tell if config cycle got the error. * * OV bit is broken until rev 4.0, so can't use OV bit and * LBA_ERROR_LOG_ADDR to tell if error belongs to config cycle. * * As of rev 4.0, no longer need the error check. * * -- Even if we could tell, we still want to return -1 * for **ANY** error (not just master abort). * * -- Only clear non-fatal errors (we don't want to bring * LBA out of pci-fatal mode). * * Actually, there is still a race in which * we could be clearing a fatal error. We will * live with this during our initial bus walk * until rev 4.0 (no driver activity during * initial bus walk). The initial bus walk * has race conditions concerning the use of * smart mode as well. */#define LBA_MASTER_ABORT_ERROR 0xc#define LBA_FATAL_ERROR 0x10#define LBA_CFG_MASTER_ABORT_CHECK(d, base, tok, error) { \ u32 error_status = 0; \ /* \ * Set clear enable (CE) bit. Unset by HW when new \ * errors are logged -- LBA HW ERS section 14.3.3). \ */ \ WRITE_REG32(status_control | CLEAR_ERRLOG_ENABLE, base + LBA_STAT_CTL); \ error_status = READ_REG32(base + LBA_ERROR_STATUS); \ if ((error_status & 0x1f) != 0) { \ /* \ * Fail the config read request. \ */ \ error = 1; \ if ((error_status & LBA_FATAL_ERROR) == 0) { \ /* \ * Clear error status (if fatal bit not set) by setting \ * clear error log bit (CL). \ */ \ WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \ } \ } \}#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \ WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR);#define LBA_CFG_ADDR_SETUP(d, addr) { \ WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ /* \ * Read address register to ensure that LBA is the bus master, \ * which implies that DMA traffic has stopped when DMA arb is off. \ */ \ lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \}#define LBA_CFG_RESTORE(d, base) { \ /* \ * Restore status control register (turn off clear enable). \ */ \ WRITE_REG32(status_control, base + LBA_STAT_CTL); \ /* \ * Restore error config register (turn off smart mode). \ */ \ WRITE_REG32(error_config, base + LBA_ERROR_CONFIG); \ /* \ * Restore arb mask register (reenables DMA arbitration). \ */ \ WRITE_REG32(arb_mask, base + LBA_ARB_MASK); \}static unsigned intlba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size){ u32 data = ~0U; int error = 0; u32 arb_mask = 0; /* used by LBA_CFG_SETUP/RESTORE */ u32 error_config = 0; /* used by LBA_CFG_SETUP/RESTORE */ u32 status_control = 0; /* used by LBA_CFG_SETUP/RESTORE */ LBA_CFG_SETUP(d, tok); LBA_CFG_PROBE(d, tok); LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); if (!error) { void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; LBA_CFG_ADDR_SETUP(d, tok | reg); switch (size) { case 1: data = (u32) READ_REG8(data_reg + (reg & 3)); break; case 2: data = (u32) READ_REG16(data_reg+ (reg & 2)); break; case 4: data = READ_REG32(data_reg); break; } } LBA_CFG_RESTORE(d, d->hba.base_addr); return(data);}static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data){ struct lba_device *d = LBA_DEV(parisc_walk_tree(bus->bridge)); u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; u32 tok = LBA_CFG_TOK(local_bus, devfn); void __iomem *data_reg = d->hba.base_addr + LBA_PCI_CFG_DATA; if ((pos > 255) || (devfn > 255)) return -EINVAL;/* FIXME: B2K/C3600 workaround is always use old method... */ /* if (!LBA_SKIP_PROBE(d)) */ { /* original - Generate config cycle on broken elroy with risk we will miss PCI bus errors. */ *data = lba_rd_cfg(d, tok, pos, size); DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data); return 0; } if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->secondary, devfn, d)) { DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __FUNCTION__, tok, pos); /* either don't want to look or know device isn't present. */ *data = ~0U; return(0); } /* Basic Algorithm ** Should only get here on fully working LBA rev. ** This is how simple the code should have been. */ LBA_CFG_ADDR_SETUP(d, tok | pos); switch(size) { case 1: *data = READ_REG8 (data_reg + (pos & 3)); break; case 2: *data = READ_REG16(data_reg + (pos & 2)); break; case 4: *data = READ_REG32(data_reg); break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?