linux/arch/i386/pci/numa.c
<<
>>
Prefs
   1/*
   2 * numa.c - Low-level PCI access for NUMA-Q machines
   3 */
   4
   5#include <linux/pci.h>
   6#include <linux/init.h>
   7#include <linux/nodemask.h>
   8#include "pci.h"
   9
  10#define BUS2QUAD(global) (mp_bus_id_to_node[global])
  11#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
  12#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
  13
  14#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
  15        (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
  16
  17static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
  18                             unsigned int devfn, int reg, int len, u32 *value)
  19{
  20        unsigned long flags;
  21
  22        if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
  23                return -EINVAL;
  24
  25        spin_lock_irqsave(&pci_config_lock, flags);
  26
  27        outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
  28
  29        switch (len) {
  30        case 1:
  31                *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
  32                break;
  33        case 2:
  34                *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
  35                break;
  36        case 4:
  37                *value = inl_quad(0xCFC, BUS2QUAD(bus));
  38                break;
  39        }
  40
  41        spin_unlock_irqrestore(&pci_config_lock, flags);
  42
  43        return 0;
  44}
  45
  46static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
  47                              unsigned int devfn, int reg, int len, u32 value)
  48{
  49        unsigned long flags;
  50
  51        if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
  52                return -EINVAL;
  53
  54        spin_lock_irqsave(&pci_config_lock, flags);
  55
  56        outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
  57
  58        switch (len) {
  59        case 1:
  60                outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
  61                break;
  62        case 2:
  63                outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
  64                break;
  65        case 4:
  66                outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
  67                break;
  68        }
  69
  70        spin_unlock_irqrestore(&pci_config_lock, flags);
  71
  72        return 0;
  73}
  74
  75#undef PCI_CONF1_MQ_ADDRESS
  76
  77static struct pci_raw_ops pci_direct_conf1_mq = {
  78        .read   = pci_conf1_mq_read,
  79        .write  = pci_conf1_mq_write
  80};
  81
  82
  83static void __devinit pci_fixup_i450nx(struct pci_dev *d)
  84{
  85        /*
  86         * i450NX -- Find and scan all secondary buses on all PXB's.
  87         */
  88        int pxb, reg;
  89        u8 busno, suba, subb;
  90        int quad = BUS2QUAD(d->bus->number);
  91
  92        printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
  93        reg = 0xd0;
  94        for(pxb=0; pxb<2; pxb++) {
  95                pci_read_config_byte(d, reg++, &busno);
  96                pci_read_config_byte(d, reg++, &suba);
  97                pci_read_config_byte(d, reg++, &subb);
  98                DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
  99                if (busno)
 100                        pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL);   /* Bus A */
 101                if (suba < subb)
 102                        pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL);  /* Bus B */
 103        }
 104        pcibios_last_bus = -1;
 105}
 106DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
 107
 108static int __init pci_numa_init(void)
 109{
 110        int quad;
 111
 112        raw_pci_ops = &pci_direct_conf1_mq;
 113
 114        if (pcibios_scanned++)
 115                return 0;
 116
 117        pci_root_bus = pcibios_scan_root(0);
 118        if (pci_root_bus)
 119                pci_bus_add_devices(pci_root_bus);
 120        if (num_online_nodes() > 1)
 121                for_each_online_node(quad) {
 122                        if (quad == 0)
 123                                continue;
 124                        printk("Scanning PCI bus %d for quad %d\n", 
 125                                QUADLOCAL2BUS(quad,0), quad);
 126                        pci_scan_bus(QUADLOCAL2BUS(quad,0), 
 127                                &pci_root_ops, NULL);
 128                }
 129        return 0;
 130}
 131
 132subsys_initcall(pci_numa_init);
 133
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.