diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 8c16fb7..a149bfc 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -43,6 +43,9 @@ struct pci_controller { and XFree86. Eventually will be removed. */ unsigned int need_domain_info; + /* BRIDGE/XBRIDGE may need to config things before bringup */ + int (*pre_enable)(struct pci_controller *, struct pci_dev *, int); + int iommu; /* Optional access methods for reading/writing the bus number diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h index 3206245..bdab399 100644 --- a/arch/mips/include/asm/pci/bridge.h +++ b/arch/mips/include/asm/pci/bridge.h @@ -14,6 +14,8 @@ #include #include +#include + #include /* generic widget header */ #include @@ -790,10 +792,11 @@ typedef struct bridge_err_cmdword_s { /* 64-bit address attribute masks */ #define PCI64_ATTR_TARG_MASK 0xf000000000000000 #define PCI64_ATTR_TARG_SHFT 60 -#define PCI64_ATTR_PREF 0x0800000000000000 -#define PCI64_ATTR_PREC 0x0400000000000000 -#define PCI64_ATTR_VIRTUAL 0x0200000000000000 -#define PCI64_ATTR_BAR 0x0100000000000000 +#define PCI64_ATTR_PREF 0x0800000000000000 /* Prefetch */ +#define PCI64_ATTR_PREC 0x0400000000000000 /* Precise */ +#define PCI64_ATTR_VIRTUAL 0x0200000000000000 /* Virtual Request */ +#define PCI64_ATTR_BAR 0x0100000000000000 /* Barrier */ +#define PCI64_ATTR_SWAP 0x0080000000000000 /* Byte swapping (XBridge Only) */ #define PCI64_ATTR_RMF_MASK 0x00ff000000000000 #define PCI64_ATTR_RMF_SHFT 48 @@ -839,17 +842,102 @@ struct bridge_controller { bridge_t *base; nasid_t nasid; unsigned int widget_id; - unsigned int irq_cpu; u64 baddr; unsigned int pci_int[8]; + spinlock_t lock; + int (*alloc_irq)(struct pci_dev *); }; #define BRIDGE_CONTROLLER(bus) \ ((struct bridge_controller *)((bus)->sysdata)) -extern void register_bridge_irq(unsigned int irq); -extern int request_bridge_irq(struct bridge_controller *bc); - extern struct pci_ops bridge_pci_ops; +/* + * Device might live on a subordinate PCI bus. Walk up the chain of buses + * to find the slot number in sense of the bridge device register. + * XXX: This also means multiple devices might rely on conflicting bridge + * settings. + */ +static inline struct pci_dev * +bridge_root_dev(struct pci_dev *dev) +{ + /* Move up the chain of bridges. */ + while (dev->bus->parent) + dev = dev->bus->self; + + return dev; +} + +/* + * Simple macro to flush all pending BRIDGE PIO ops. + * + * XXX: IA64 actually checks the return value of the b_wid_tflush register + * and panics if it returns a non-zero status. + */ +#define BRIDGE_FLUSH(_b) \ + while((_b)->b_wid_tflush) \ + cpu_relax() + +/* + * Magic/cosmic value for BRIDGE's INT_DEV register. This sets + * bits 31:24 to all 1's. The only odd bit about this is those + * bits are marked as "reserved" in both the BRIDGE and XBRIDGE + * docs. Apparently, IRIX does this as well. + */ +#define BRIDGE_COSMIC_INT_DEV 0xff000000 + +/** + * struct bridge_platform_data - holds BRIDGE-specific data for IP27 & IP30. + * @xio_target_addr: HUB/HEART/BEDROCK address in Crosstalk space. + * @baseio_widget_id: crosstalk widget ID for the BaseIO BRIDGE. + * @iomem_swap: bool that enables mem and I/O byteswapping on BRIDGE. + * @add_512: bool that if set, adds BRIDGE_DIRMAP_ADD512 to bridge->b_dir_map. + * @setup_baseio_rrbs: platform function to config the Read Response Buffers. + * @alloc_irq: platform function used by BRIDGE to allocate an IRQ. + * @startup_resource: platform function to setup BRIDGE before enabling it. + */ +struct bridge_platform_data { + u32 xio_target_addr; + xwidgetnum_t baseio_widget_id; + bool iomem_swap; + bool add_512; + void (*setup_baseio_rrbs)(bridge_t *, const bool *); + int (*alloc_irq)(struct pci_dev *); + int (*startup_resource)(struct pci_controller *, struct pci_dev *, int); +}; + +/** + * sn_pci_set_vchan - enables the virtual channel on BRIDGE/XBRIDGE. + * @pci_dev: pointer to PCI device that will use the virtual channel. + * @addr: address of PCI device in crosstalk space. + * @vchan: flag that enables or disables the virtual channel. + * + * Returns '0' if successful, else -1. + * + * Ripped from arch/ia64/include/asm/sn/io.h. + * Needed in drivers/scsi/qla1280.c, as we're simply hijacking the existing + * IA64 #ifdefs to also work in the MIPS case. + */ +static inline int +sn_pci_set_vchan(struct pci_dev *pci_dev, unsigned long *addr, int vchan) +{ + + if (vchan > 1) + return -1; + + if (!(*addr >> 32)) /* Using a mask here would be cleaner */ + return 0; /* but this generates better code */ + + if (vchan == 1) { + /* Set Bit 57, PCI64_ATTR_VIRTUAL */ + *addr |= BIT_ULL(57); + } else { + /* Clear Bit 57, PCI64_ATTR_VIRTUAL */ + *addr &= ~BIT_ULL(57); + } + + return 0; +} + #endif /* _ASM_PCI_BRIDGE_H */ diff --git a/arch/mips/pci/ops-bridge.c b/arch/mips/pci/ops-bridge.c index 4383194..9e22fd0 100644 --- a/arch/mips/pci/ops-bridge.c +++ b/arch/mips/pci/ops-bridge.c @@ -9,6 +9,7 @@ #include #include #include + #include #include #include @@ -74,7 +75,6 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; oh_my_gawd: - /* * IOC3 is fucking fucked beyond belief ... Don't even give the * generic PCI code a chance to look at the wrong register. @@ -137,7 +137,6 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn, return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; oh_my_gawd: - /* * IOC3 is fucking fucked beyond belief ... Don't even give the * generic PCI code a chance to look at the wrong register. @@ -167,7 +166,7 @@ oh_my_gawd: static int pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * value) { - if (bus->number > 0) + if (!pci_is_root_bus(bus)) return pci_conf1_read_config(bus, devfn, where, size, value); return pci_conf0_read_config(bus, devfn, where, size, value); @@ -211,7 +210,6 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; oh_my_gawd: - /* * IOC3 is fucking fucked beyond belief ... Don't even give the * generic PCI code a chance to touch the wrong register. @@ -279,7 +277,6 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; oh_my_gawd: - /* * IOC3 is fucking fucked beyond belief ... Don't even give the * generic PCI code a chance to touch the wrong register. @@ -310,7 +307,7 @@ oh_my_gawd: static int pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - if (bus->number > 0) + if (!pci_is_root_bus(bus)) return pci_conf1_write_config(bus, devfn, where, size, value); return pci_conf0_write_config(bus, devfn, where, size, value); diff --git a/arch/mips/pci/pci-bridge.c b/arch/mips/pci/pci-bridge.c new file mode 100644 index 0000000..a497090 --- /dev/null +++ b/arch/mips/pci/pci-bridge.c @@ -0,0 +1,380 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * arch/mips/pci/pci-bridge.c + * platform_driver for SGI BRIDGE/XBRIDGE (and in the future, SGI PIC) ASICs. + * + * Originally called pci-ip27.c, which is: + * Copyright (C) 2003 Christoph Hellwig (hch@lst.de) + * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * + * Modifications sourced from pci-ip30.c in the IP30 patchset are: + * Copyright (C) 2004-2007 Stanislaw Skowronek + * Copyright (C) 2009 Johannes Dickgreber + * Copyright (C) 2016 Joshua Kinard + * + * Functions/info/insight sourced from old IA64 code are: + * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. + * All rights reserved. + */ + +#include +#include +#include + +#include +#include +#include + +#if defined(CONFIG_SGI_IP27) +#include +#include +#elif defined(CONFIG_SGI_IP30) +#include +#include +#include +#else +#error "Unknown CONFIG_SGI_IP??" +#endif + +/* Increments for each additional bridge. */ +static int num_bridges __initdata = 0; + +#define BRIDGE_MAX_RRBS 8 /* 8 RRBs max/reg */ +#define BRIDGE_PAIRS_PER_REG 4 /* 4 RRB pairs/reg */ +#define BRIDGE_DEFAULT_RRB_VALUE 0x00000000 + +/** + * bridge_alloc_rrbs - allocate specific read response buffer resources. + * @dev1: u32 num of RRBs to request for device #1. + * @dev2: ... for device #2. + * @dev3: ... for device #3. + * @dev4: ... for device #4. + * @virt1: bool to set whether virtual channel is enabled for device #1. + * @virt2: ... for device #2. + * @virt3: ... for device #3. + * @virt4: ... for device #4. + * + * returns a value to be assigned directly to a BRIDGE's even or odd + * "Read Response Buffer" register. Each register maps 4 sets of 4 bits + * for each RRB. The "even" register sets RRBs for slots 0, 2, 4, & 6 and + * the "odd" register sets RRBs for slots 1, 3, 5, & 7. + * + * This function was adapted from the original "pcibr_alloc_all_rrbs" + * function in arch/ia64/sn/io/sn1/pcibr.c in Linux-2.5.70. + */ +u32 __init +bridge_alloc_rrbs(u8 dev1, u8 dev2, u8 dev3, u8 dev4, + bool virt1, bool virt2, bool virt3, bool virt4) +{ + u8 rrb_shift = 7; + u32 rrb_value = BRIDGE_DEFAULT_RRB_VALUE; + u32 rrbs[4], virt[4]; + u32 cur_rrb; + int i, j; + + /* Copy the args to arrays for use in loops. */ + rrbs[0] = dev1; + rrbs[1] = dev2; + rrbs[2] = dev3; + rrbs[3] = dev4; + virt[0] = virt1; + virt[1] = virt2; + virt[2] = virt3; + virt[3] = virt4; + + /* Only 8 RRBs per register are available. */ + if ((dev1 + dev2 + dev3 + dev4) > BRIDGE_MAX_RRBS) + return BRIDGE_DEFAULT_RRB_VALUE; + + /* Walk through the RRBs */ + for (i = 0; i < BRIDGE_PAIRS_PER_REG; i++) { + if (virt[i]) { + cur_rrb = (i | 0xc); + cur_rrb <<= (rrb_shift * 4); + rrb_shift--; + rrb_value |= cur_rrb; + rrbs[i] -= 1; + } + for (j = 0; j < rrbs[i]; j++) { + cur_rrb = (i | 0x8); + cur_rrb <<= (rrb_shift * 4); + rrb_shift--; + rrb_value |= cur_rrb; + } + } + + return rrb_value; +} + +/** + * bridge_probe_slot - protected memory access to a bridge slot. + * @bridge: const pointer to a BRIDGE structure. + * @slot: u32 number of specific slot to probe. + * + * returns 'true' if something is in the slot, else 'false'. + */ +static bool __init +bridge_probe_slot(bridge_t *bridge, u32 slot) +{ + volatile void *addr; + u32 results; + + addr = &bridge->b_type0_cfg_dev[slot].c; + get_dbe(results, (u32 *)addr); + + return (results ? true : false); +} + +/** + * bridge_probe - probes a BRIDGE chip and configures it. + * @widget_id: xwidgetnum_t value of this BRIDGE's xtalk widget ID. + * @pdata: struct xwidget_platform_data passed by the xtalk probe. + * + * Always returns '0'. + */ +static int __init +bridge_probe(xwidgetnum_t widget_id, const struct xwidget_platform_data *pdata) +{ + u32 slot; + u32 wid_ctrl; /* BRIDGE WAR */ + nasid_t nasid = pdata->nasid; + xwidgetnum_t masterwid = pdata->masterwid; + unsigned long flags; + unsigned long offset = NODE_OFFSET(nasid); + bridge_t *bridge; + struct bridge_controller *bc; + bool slot_census[BRIDGE_DEV_CNT]; + + pci_set_flags(PCI_PROBE_ONLY); + + /* Alloc & zero some memory for the bridge_controller. */ + bc = kzalloc(sizeof(struct bridge_controller), GFP_KERNEL); + + /* Init a spinlock. */ + spin_lock_init(&bc->lock); + spin_lock_irqsave(&bc->lock, flags); + + /* Set bridge_controller parameters. */ + bc->alloc_irq = pdata->bridge_pdata->alloc_irq; + bc->pc.pre_enable = pdata->bridge_pdata->startup_resource; + bc->pc.pci_ops = &bridge_pci_ops; + bc->pc.mem_resource = &bc->mem; + bc->pc.mem_offset = offset; + bc->pc.io_resource = &bc->io; + bc->pc.io_offset = offset; + bc->pc.busn_resource = &bc->busn; + bc->pc.busn_offset = offset; + bc->pc.index = num_bridges; + bc->pc.io_map_base = NODE_SWIN_BASE(nasid, widget_id); + + bc->mem.name = "Bridge MEM"; + bc->mem.start = (NODE_SWIN_BASE(nasid, widget_id) + PCIBR_OFFSET_MEM); + bc->mem.end = (NODE_SWIN_BASE(nasid, widget_id) + PCIBR_OFFSET_IO - 1); + bc->mem.flags = IORESOURCE_MEM; + + bc->io.name = "Bridge IO"; + bc->io.start = (NODE_SWIN_BASE(nasid, widget_id) + PCIBR_OFFSET_IO); + bc->io.end = (NODE_SWIN_BASE(nasid, widget_id) + PCIBR_OFFSET_END - 1); + bc->io.flags = IORESOURCE_IO; + + bc->busn.name = "Bridge BUSN"; + bc->busn.start = num_bridges; + bc->busn.end = 255; + bc->busn.flags = IORESOURCE_BUS; + + bc->widget_id = widget_id; + bc->nasid = nasid; + bc->baddr = ((u64)masterwid << PCI64_ATTR_TARG_SHFT); + + /* + * Point to this bridge + */ + bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id); + + /* + * Clear all pending interrupts. + */ + bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR; + + /* + * Until otherwise set up, assume all interrupts are from slot 0 + */ + bridge->b_int_device = 0x0; + + /* Configure BRIDGE widget control ... */ + wid_ctrl = bridge->b_wid_control; + + /* + * IP27 & IP35 need I/O and Mem swapping enabled. + * IP30 needs it disabled. + */ + if (pdata->bridge_pdata->iomem_swap) + wid_ctrl |= (BRIDGE_CTRL_IO_SWAP | BRIDGE_CTRL_MEM_SWAP); + else + wid_ctrl &= ~(BRIDGE_CTRL_IO_SWAP | BRIDGE_CTRL_MEM_SWAP); + + /* Set the BRIDGE PAGE_SIZE */ +#ifdef CONFIG_PAGE_SIZE_4KB + wid_ctrl &= ~BRIDGE_CTRL_PAGE_SIZE; +#else /* 16kB or larger */ + wid_ctrl |= BRIDGE_CTRL_PAGE_SIZE; +#endif + + /* + * Another BRIDGE WAR, read the BRIDGE widget control register + * back after writing it to avoid an invalid address bug. + */ + bridge->b_wid_control = wid_ctrl; + wid_ctrl = bridge->b_wid_control; + + /* + * Set per-device properties. Use '|=' here, else things won't work. + * + * XXX: Setup per-slot configuration at some point. Different devices + * need different properties. + */ + for (slot = 0; slot < BRIDGE_DEV_CNT; slot++) { + bridge->b_device[slot].reg |= (BRIDGE_DEV_ERR_LOCK_EN | + BRIDGE_DEV_D64_BITS); + bc->pci_int[slot] = -1; + + /* Take a census of each slot to see if something is there. */ + slot_census[slot] = bridge_probe_slot(bridge, slot); + } + + /* Configure direct-mapped DMA */ + bridge->b_dir_map = (masterwid << BRIDGE_DIRMAP_W_ID_SHFT); + if (pdata->bridge_pdata->add_512) + bridge->b_dir_map |= BRIDGE_DIRMAP_ADD512; + + /* XXX: Assign RRBs for the BaseIO BRIDGE only (for now) */ + if (bc->widget_id == pdata->bridge_pdata->baseio_widget_id && + pdata->bridge_pdata->setup_baseio_rrbs) + pdata->bridge_pdata->setup_baseio_rrbs(bridge, slot_census); + + /* + * Route all PCI bridge interrupts to the appropriate ASIC responsible + * for handling IRQs (HUB in IP27, HEART in IP30, BEDROCK in IP35). + * The actual IRQ support and masking is done elsewhere. + */ + /* + * XXX: IRIX sets additional bits (0x8000) in the address which are + * marked as reserved in the BRIDGE docs. + */ + bridge->b_wid_int_upper = ((masterwid << WIDGET_TARGET_ID_SHFT) | + 0x8000); + bridge->b_wid_int_lower = pdata->bridge_pdata->xio_target_addr; + + bridge->b_int_device = BRIDGE_COSMIC_INT_DEV; + bridge->b_int_enable = BRIDGE_ISR_ERRORS; + bridge->b_int_mode = 0; /* 0 on rst, but better to be sure. */ + + /* Wait until Bridge PIO completes. */ + BRIDGE_FLUSH(bridge); + + bc->base = bridge; + num_bridges++; + spin_unlock_irqrestore(&bc->lock, flags); + + register_pci_controller(&bc->pc); + + return 0; +} + +/** + * bridge_alloc_irq - allocate the next available IRQ for a BRIDGE slot. + * @dev: pointer to struct pci_dev of PCI device info. + * + * Casts dev->bus->sysdata to struct bridge_controller and returns the + * outcome of the platform_data-defined 'alloc_irq' function. + */ +int inline +bridge_alloc_irq(struct pci_dev *dev) +{ + const struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); + + if (bc->alloc_irq) + return bc->alloc_irq(dev); + + return -1; +} + +/* + * All observed requests have pin == 1. We could have a global here, that + * gets incremented and returned every time - unfortunately, pci_map_irq + * may be called on the same device over and over, and need to return the + * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7]. + * + * A given PCI device, in general, should be able to interrupt any of the + * cpus on any one of the HUBs or HEART connected to its xbow. + */ +int __init +pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return 0; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int +pcibios_plat_dev_init(struct pci_dev *dev) +{ + return bridge_alloc_irq(dev); +} + +static void +bridge_disable_swapping_dma(struct pci_dev *dev) +{ + int slot = PCI_SLOT(dev->devfn); + bridge_t *bridge; + struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); + unsigned long flags; + + /* Turn off byte swapping */ + spin_lock_irqsave(&bc->lock, flags); + bridge = bc->base; + bridge->b_device[slot].reg &= ~(BRIDGE_DEV_DEV_SWAP | + BRIDGE_DEV_SWAP_PMU | + BRIDGE_DEV_SWAP_DIR); + BRIDGE_FLUSH(bridge); + spin_unlock_irqrestore(&bc->lock, flags); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, + bridge_disable_swapping_dma); +#if defined(CONFIG_SGI_IP30) +/* + * XXX: Onyx2 systems have a RAD1 on their IO6-G board, but the RAD1 driver + * and corresponding defines are part of the IP30 patchset, so we need to + * make this part conditional for now until the IP30 patches are merged + * upstream. + */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_RAD1, + bridge_disable_swapping_dma); +#endif + +static int __init +bridge_init(struct platform_device *pdev) +{ + struct xwidget_platform_data *pdata; + + /* Get the platform data. */ + pdata = (struct xwidget_platform_data *) pdev->dev.platform_data; + if (!pdata) + return -ENODEV; + + return bridge_probe(pdev->id, pdata); +} + +static struct platform_driver __refdata +bridge_driver = { + .probe = bridge_init, + /* BRIDGE cannot be dynamically removed. */ + .driver = { + .name = "bridge", + }, +}; +builtin_platform_driver(bridge_driver); diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c deleted file mode 100644 index 0f09eaf..0000000 --- a/arch/mips/pci/pci-ip27.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003 Christoph Hellwig (hch@lst.de) - * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Max #PCI busses we can handle; ie, max #PCI bridges. - */ -#define MAX_PCI_BUSSES 40 - -/* - * Max #PCI devices (like scsi controllers) we handle on a bus. - */ -#define MAX_DEVICES_PER_PCIBUS 8 - -/* - * XXX: No kmalloc available when we do our crosstalk scan, - * we should try to move it later in the boot process. - */ -static struct bridge_controller bridges[MAX_PCI_BUSSES]; - -/* - * Translate from irq to software PCI bus number and PCI slot. - */ -struct bridge_controller *irq_to_bridge[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS]; -int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS]; - -extern struct pci_ops bridge_pci_ops; - -int bridge_probe(nasid_t nasid, int widget_id, int masterwid) -{ - unsigned long offset = NODE_OFFSET(nasid); - struct bridge_controller *bc; - static int num_bridges = 0; - bridge_t *bridge; - int slot; - - pci_set_flags(PCI_PROBE_ONLY); - - printk("a bridge\n"); - - /* XXX: kludge alert.. */ - if (!num_bridges) - ioport_resource.end = ~0UL; - - bc = &bridges[num_bridges]; - - bc->pc.pci_ops = &bridge_pci_ops; - bc->pc.mem_resource = &bc->mem; - bc->pc.io_resource = &bc->io; - - bc->pc.index = num_bridges; - - bc->mem.name = "Bridge PCI MEM"; - bc->pc.mem_offset = offset; - bc->mem.start = 0; - bc->mem.end = ~0UL; - bc->mem.flags = IORESOURCE_MEM; - - bc->io.name = "Bridge IO MEM"; - bc->pc.io_offset = offset; - bc->io.start = 0UL; - bc->io.end = ~0UL; - bc->io.flags = IORESOURCE_IO; - - bc->irq_cpu = smp_processor_id(); - bc->widget_id = widget_id; - bc->nasid = nasid; - - bc->baddr = (u64)masterwid << 60 | PCI64_ATTR_BAR; - - /* - * point to this bridge - */ - bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id); - - /* - * Clear all pending interrupts. - */ - bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR; - - /* - * Until otherwise set up, assume all interrupts are from slot 0 - */ - bridge->b_int_device = 0x0; - - /* - * swap pio's to pci mem and io space (big windows) - */ - bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP | - BRIDGE_CTRL_MEM_SWAP; -#ifdef CONFIG_PAGE_SIZE_4KB - bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; -#else /* 16kB or larger */ - bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; -#endif - - /* - * Hmm... IRIX sets additional bits in the address which - * are documented as reserved in the bridge docs. - */ - bridge->b_wid_int_upper = 0x8000 | (masterwid << 16); - bridge->b_wid_int_lower = 0x01800090; /* PI_INT_PEND_MOD off*/ - bridge->b_dir_map = (masterwid << 20); /* DMA */ - bridge->b_int_enable = 0; - - for (slot = 0; slot < 8; slot ++) { - bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR; - bc->pci_int[slot] = -1; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - bc->base = bridge; - - register_pci_controller(&bc->pc); - - num_bridges++; - - return 0; -} - -/* - * All observed requests have pin == 1. We could have a global here, that - * gets incremented and returned every time - unfortunately, pci_map_irq - * may be called on the same device over and over, and need to return the - * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7]. - * - * A given PCI device, in general, should be able to intr any of the cpus - * on any one of the hubs connected to its xbow. - */ -int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - return 0; -} - -static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev) -{ - while (dev->bus->parent) { - /* Move up the chain of bridges. */ - dev = dev->bus->self; - } - - return dev; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); - struct pci_dev *rdev = bridge_root_dev(dev); - int slot = PCI_SLOT(rdev->devfn); - int irq; - - irq = bc->pci_int[slot]; - if (irq == -1) { - irq = request_bridge_irq(bc); - if (irq < 0) - return irq; - - bc->pci_int[slot] = irq; - } - - irq_to_bridge[irq] = bc; - irq_to_slot[irq] = slot; - - dev->irq = irq; - - return 0; -} - -/* - * Device might live on a subordinate PCI bus. XXX Walk up the chain of buses - * to find the slot number in sense of the bridge device register. - * XXX This also means multiple devices might rely on conflicting bridge - * settings. - */ - -static inline void pci_disable_swapping(struct pci_dev *dev) -{ - struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); - bridge_t *bridge = bc->base; - int slot = PCI_SLOT(dev->devfn); - - /* Turn off byte swapping */ - bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR; - bridge->b_widget.w_tflush; /* Flush */ -} - -static inline void pci_enable_swapping(struct pci_dev *dev) -{ - struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); - bridge_t *bridge = bc->base; - int slot = PCI_SLOT(dev->devfn); - - /* Turn on byte swapping */ - bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR; - bridge->b_widget.w_tflush; /* Flush */ -} - -static void pci_fixup_ioc3(struct pci_dev *d) -{ - pci_disable_swapping(d); -} - -#ifdef CONFIG_NUMA -int pcibus_to_node(struct pci_bus *bus) -{ - struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); - - return bc->nasid; -} -EXPORT_SYMBOL(pcibus_to_node); -#endif /* CONFIG_NUMA */ - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - pci_fixup_ioc3); diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index b8a0bf5..3b0c00f 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -261,14 +261,24 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) u16 cmd, old_cmd; int idx; struct resource *r; + struct pci_controller *hose = (struct pci_controller *)dev->sysdata; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (idx=0; idx < PCI_NUM_RESOURCES; idx++) { + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { /* Only set up the requested stuff */ - if (!(mask & (1<pre_enable) + if (hose->pre_enable(hose, dev, idx) < 0) + return -EINVAL; + r = &dev->resource[idx]; if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) continue; @@ -291,6 +301,7 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) pci_name(dev), old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); } + return 0; } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 35af362..1b7bbf5 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -545,6 +545,9 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) unsigned long base = 0; int i; + if (!pci_enable_device(pdev)) + return; + if (!pio_enabled(pdev)) return;