linux/arch/x86/pci/numaq_32.c
<<
>>
Prefs
   1/*
   2 * numaq_32.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 <asm/apic.h>
   9#include <asm/mpspec.h>
  10#include <asm/pci_x86.h>
  11#include <asm/numaq.h>
  12
  13#define BUS2QUAD(global) (mp_bus_id_to_node[global])
  14
  15#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
  16
  17#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
  18
  19#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
  20        (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
  21
  22static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
  23{
  24        unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
  25        if (xquad_portio)
  26                writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
  27        else
  28                outl(val, 0xCF8);
  29}
  30
  31static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
  32                             unsigned int devfn, int reg, int len, u32 *value)
  33{
  34        unsigned long flags;
  35        void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
  36
  37        WARN_ON(seg);
  38        if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
  39                return -EINVAL;
  40
  41        raw_spin_lock_irqsave(&pci_config_lock, flags);
  42
  43        write_cf8(bus, devfn, reg);
  44
  45        switch (len) {
  46        case 1:
  47                if (xquad_portio)
  48                        *value = readb(adr + (reg & 3));
  49                else
  50                        *value = inb(0xCFC + (reg & 3));
  51                break;
  52        case 2:
  53                if (xquad_portio)
  54                        *value = readw(adr + (reg & 2));
  55                else
  56                        *value = inw(0xCFC + (reg & 2));
  57                break;
  58        case 4:
  59                if (xquad_portio)
  60                        *value = readl(adr);
  61                else
  62                        *value = inl(0xCFC);
  63                break;
  64        }
  65
  66        raw_spin_unlock_irqrestore(&pci_config_lock, flags);
  67
  68        return 0;
  69}
  70
  71static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
  72                              unsigned int devfn, int reg, int len, u32 value)
  73{
  74        unsigned long flags;
  75        void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
  76
  77        WARN_ON(seg);
  78        if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
  79                return -EINVAL;
  80
  81        raw_spin_lock_irqsave(&pci_config_lock, flags);
  82
  83        write_cf8(bus, devfn, reg);
  84
  85        switch (len) {
  86        case 1:
  87                if (xquad_portio)
  88                        writeb(value, adr + (reg & 3));
  89                else
  90                        outb((u8)value, 0xCFC + (reg & 3));
  91                break;
  92        case 2:
  93                if (xquad_portio)
  94                        writew(value, adr + (reg & 2));
  95                else
  96                        outw((u16)value, 0xCFC + (reg & 2));
  97                break;
  98        case 4:
  99                if (xquad_portio)
 100                        writel(value, adr + reg);
 101                else
 102                        outl((u32)value, 0xCFC);
 103                break;
 104        }
 105
 106        raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 107
 108        return 0;
 109}
 110
 111#undef PCI_CONF1_MQ_ADDRESS
 112
 113static const struct pci_raw_ops pci_direct_conf1_mq = {
 114        .read   = pci_conf1_mq_read,
 115        .write  = pci_conf1_mq_write
 116};
 117
 118
 119static void pci_fixup_i450nx(struct pci_dev *d)
 120{
 121        /*
 122         * i450NX -- Find and scan all secondary buses on all PXB's.
 123         */
 124        int pxb, reg;
 125        u8 busno, suba, subb;
 126        int quad = BUS2QUAD(d->bus->number);
 127
 128        dev_info(&d->dev, "searching for i450NX host bridges\n");
 129        reg = 0xd0;
 130        for(pxb=0; pxb<2; pxb++) {
 131                pci_read_config_byte(d, reg++, &busno);
 132                pci_read_config_byte(d, reg++, &suba);
 133                pci_read_config_byte(d, reg++, &subb);
 134                dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n",
 135                        pxb, busno, suba, subb);
 136                if (busno) {
 137                        /* Bus A */
 138                        pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
 139                }
 140                if (suba < subb) {
 141                        /* Bus B */
 142                        pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1));
 143                }
 144        }
 145        pcibios_last_bus = -1;
 146}
 147DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
 148
 149int __init pci_numaq_init(void)
 150{
 151        int quad;
 152
 153        raw_pci_ops = &pci_direct_conf1_mq;
 154
 155        pcibios_scan_root(0);
 156        if (num_online_nodes() > 1)
 157                for_each_online_node(quad) {
 158                        if (quad == 0)
 159                                continue;
 160                        printk("Scanning PCI bus %d for quad %d\n", 
 161                                QUADLOCAL2BUS(quad,0), quad);
 162                        pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
 163                }
 164        return 0;
 165}
 166