Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  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 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 __devinit 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	pci_root_bus = pcibios_scan_root(0);
156	if (pci_root_bus)
157		pci_bus_add_devices(pci_root_bus);
158	if (num_online_nodes() > 1)
159		for_each_online_node(quad) {
160			if (quad == 0)
161				continue;
162			printk("Scanning PCI bus %d for quad %d\n", 
163				QUADLOCAL2BUS(quad,0), quad);
164			pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
165		}
166	return 0;
167}