2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* 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 <linux/kernel.h>
|
2011-07-29 06:46:31 +08:00
|
|
|
#include <linux/export.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/pci.h>
|
2009-06-19 21:05:26 +08:00
|
|
|
#include <linux/smp.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <asm/sn/arch.h>
|
|
|
|
#include <asm/pci/bridge.h>
|
|
|
|
#include <asm/paccess.h>
|
|
|
|
#include <asm/sn/intr.h>
|
|
|
|
#include <asm/sn/sn0/hub.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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,
|
2013-01-22 19:59:30 +08:00
|
|
|
* we should try to move it later in the boot process.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
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];
|
|
|
|
|
2006-06-17 07:55:45 +08:00
|
|
|
extern struct pci_ops bridge_pci_ops;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
MIPS: Delete __cpuinit/__CPUINIT usage from MIPS code
commit 3747069b25e419f6b51395f48127e9812abc3596 upstream.
The __cpuinit type of throwaway sections might have made sense
some time ago when RAM was more constrained, but now the savings
do not offset the cost and complications. For example, the fix in
commit 5e427ec2d0 ("x86: Fix bit corruption at CPU resume time")
is a good example of the nasty type of bugs that can be created
with improper use of the various __init prefixes.
After a discussion on LKML[1] it was decided that cpuinit should go
the way of devinit and be phased out. Once all the users are gone,
we can then finally remove the macros themselves from linux/init.h.
Note that some harmless section mismatch warnings may result, since
notify_cpu_starting() and cpu_up() are arch independent (kernel/cpu.c)
and are flagged as __cpuinit -- so if we remove the __cpuinit from
the arch specific callers, we will also get section mismatch warnings.
As an intermediate step, we intend to turn the linux/init.h cpuinit
related content into no-ops as early as possible, since that will get
rid of these warnings. In any case, they are temporary and harmless.
Here, we remove all the MIPS __cpuinit from C code and __CPUINIT
from asm files. MIPS is interesting in this respect, because there
are also uasm users hiding behind their own renamed versions of the
__cpuinit macros.
[1] https://lkml.org/lkml/2013/5/20/589
[ralf@linux-mips.org: Folded in Paul's followup fix.]
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/5494/
Patchwork: https://patchwork.linux-mips.org/patch/5495/
Patchwork: https://patchwork.linux-mips.org/patch/5509/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2013-06-18 21:38:59 +08:00
|
|
|
int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
unsigned long offset = NODE_OFFSET(nasid);
|
|
|
|
struct bridge_controller *bc;
|
|
|
|
static int num_bridges = 0;
|
|
|
|
bridge_t *bridge;
|
|
|
|
int slot;
|
2008-04-18 04:07:42 +08:00
|
|
|
|
2012-02-24 11:18:57 +08:00
|
|
|
pci_set_flags(PCI_PROBE_ONLY);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2006-06-17 07:46:27 +08:00
|
|
|
bc->baddr = (u64)masterwid << 60 | PCI64_ATTR_BAR;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* point to this bridge
|
|
|
|
*/
|
|
|
|
bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id);
|
|
|
|
|
|
|
|
/*
|
2006-03-11 16:18:41 +08:00
|
|
|
* Clear all pending interrupts.
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR;
|
|
|
|
|
|
|
|
/*
|
2006-03-11 16:18:41 +08:00
|
|
|
* Until otherwise set up, assume all interrupts are from slot 0
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
bridge->b_int_device = 0x0;
|
|
|
|
|
|
|
|
/*
|
2006-03-11 16:18:41 +08:00
|
|
|
* swap pio's to pci mem and io space (big windows)
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP |
|
2013-01-22 19:59:30 +08:00
|
|
|
BRIDGE_CTRL_MEM_SWAP;
|
2008-04-18 04:07:42 +08:00
|
|
|
#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
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
2013-01-22 19:59:30 +08:00
|
|
|
bridge->b_wid_tflush; /* wait until Bridge PIO complete */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2012-12-22 06:04:39 +08:00
|
|
|
int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
2008-09-27 22:05:06 +08:00
|
|
|
{
|
|
|
|
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)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
|
2008-09-27 22:05:06 +08:00
|
|
|
struct pci_dev *rdev = bridge_root_dev(dev);
|
|
|
|
int slot = PCI_SLOT(rdev->devfn);
|
|
|
|
int irq;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-09-27 22:05:06 +08:00
|
|
|
irq = bc->pci_int[slot];
|
2005-04-17 06:20:36 +08:00
|
|
|
if (irq == -1) {
|
2008-09-27 22:05:06 +08:00
|
|
|
irq = request_bridge_irq(bc);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (irq < 0)
|
2008-09-27 22:05:06 +08:00
|
|
|
return irq;
|
|
|
|
|
|
|
|
bc->pci_int[slot] = irq;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
irq_to_bridge[irq] = bc;
|
|
|
|
irq_to_slot[irq] = slot;
|
|
|
|
|
2008-09-27 22:05:06 +08:00
|
|
|
dev->irq = irq;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-01-22 19:59:30 +08:00
|
|
|
* Device might live on a subordinate PCI bus. XXX Walk up the chain of buses
|
2005-04-17 06:20:36 +08:00
|
|
|
* 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 */
|
|
|
|
}
|
|
|
|
|
2012-12-22 06:04:39 +08:00
|
|
|
static void pci_fixup_ioc3(struct pci_dev *d)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
pci_disable_swapping(d);
|
|
|
|
}
|
|
|
|
|
2013-06-13 20:34:50 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
2005-09-15 16:52:34 +08:00
|
|
|
int pcibus_to_node(struct pci_bus *bus)
|
|
|
|
{
|
|
|
|
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
|
|
|
|
|
|
|
|
return bc->nasid;
|
|
|
|
}
|
2008-08-06 06:44:49 +08:00
|
|
|
EXPORT_SYMBOL(pcibus_to_node);
|
2013-06-13 20:34:50 +08:00
|
|
|
#endif /* CONFIG_NUMA */
|
2005-09-15 16:52:34 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
|
|
|
|
pci_fixup_ioc3);
|