Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
436 giacomo 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 "pci.h"
8
 
9
#define BUS2QUAD(global) (mp_bus_id_to_node[global])
10
#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
11
#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
12
 
13
#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
14
        (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
15
 
16
static int pci_conf1_mq_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
17
{
18
        unsigned long flags;
19
 
20
        if (!value || (bus > MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
21
                return -EINVAL;
22
 
23
        spin_lock_irqsave(&pci_config_lock, flags);
24
 
25
        outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
26
 
27
        switch (len) {
28
        case 1:
29
                *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
30
                break;
31
        case 2:
32
                *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
33
                break;
34
        case 4:
35
                *value = inl_quad(0xCFC, BUS2QUAD(bus));
36
                break;
37
        }
38
 
39
        spin_unlock_irqrestore(&pci_config_lock, flags);
40
 
41
        return 0;
42
}
43
 
44
static int pci_conf1_mq_write (int seg, int bus, int devfn, int reg, int len, u32 value)
45
{
46
        unsigned long flags;
47
 
48
        if ((bus > MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
49
                return -EINVAL;
50
 
51
        spin_lock_irqsave(&pci_config_lock, flags);
52
 
53
        outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
54
 
55
        switch (len) {
56
        case 1:
57
                outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
58
                break;
59
        case 2:
60
                outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
61
                break;
62
        case 4:
63
                outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
64
                break;
65
        }
66
 
67
        spin_unlock_irqrestore(&pci_config_lock, flags);
68
 
69
        return 0;
70
}
71
 
72
#undef PCI_CONF1_MQ_ADDRESS
73
 
74
static struct pci_raw_ops pci_direct_conf1_mq = {
75
        .read   = pci_conf1_mq_read,
76
        .write  = pci_conf1_mq_write
77
};
78
 
79
 
80
static void __devinit pci_fixup_i450nx(struct pci_dev *d)
81
{
82
        /*
83
         * i450NX -- Find and scan all secondary buses on all PXB's.
84
         */
85
        int pxb, reg;
86
        u8 busno, suba, subb;
87
        int quad = BUS2QUAD(d->bus->number);
88
 
89
        printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
90
        reg = 0xd0;
91
        for(pxb=0; pxb<2; pxb++) {
92
                pci_read_config_byte(d, reg++, &busno);
93
                pci_read_config_byte(d, reg++, &suba);
94
                pci_read_config_byte(d, reg++, &subb);
95
                DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
96
                if (busno)
97
                        pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL);   /* Bus A */
98
                if (suba < subb)
99
                        pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL);  /* Bus B */
100
        }
101
        pcibios_last_bus = -1;
102
}
103
 
104
struct pci_fixup pcibios_fixups[] = {
105
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82451NX,    pci_fixup_i450nx },
106
};
107
 
108
static 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 (numnodes > 1) {
119
                for (quad = 1; quad < numnodes; ++quad) {
120
                        printk("Scanning PCI bus %d for quad %d\n",
121
                                QUADLOCAL2BUS(quad,0), quad);
122
                        pci_scan_bus(QUADLOCAL2BUS(quad,0),
123
                                &pci_root_ops, NULL);
124
                }
125
        }
126
        return 0;
127
}
128
 
129
subsys_initcall(pci_numa_init);