aperture_64.c 10.5 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2
 * Firmware replacement code.
3
 *
L
Linus Torvalds 已提交
4
 * Work around broken BIOSes that don't set an aperture or only set the
5 6 7 8 9
 * aperture in the AGP bridge.
 * If all fails map the aperture over some low memory.  This is cheaper than
 * doing bounce buffering. The memory is lost. This is done at early boot
 * because only the bootmem allocator can allocate 32+MB.
 *
L
Linus Torvalds 已提交
10 11 12 13 14 15 16 17 18 19
 * Copyright 2002 Andi Kleen, SuSE Labs.
 */
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/mmzone.h>
#include <linux/pci_ids.h>
#include <linux/pci.h>
#include <linux/bitops.h>
20
#include <linux/ioport.h>
L
Linus Torvalds 已提交
21 22
#include <asm/e820.h>
#include <asm/io.h>
J
Joerg Roedel 已提交
23
#include <asm/gart.h>
L
Linus Torvalds 已提交
24
#include <asm/pci-direct.h>
25
#include <asm/dma.h>
26
#include <asm/k8.h>
L
Linus Torvalds 已提交
27

28 29 30
int gart_iommu_aperture;
int gart_iommu_aperture_disabled __initdata = 0;
int gart_iommu_aperture_allowed __initdata = 0;
L
Linus Torvalds 已提交
31 32

int fallback_aper_order __initdata = 1; /* 64MB */
33
int fallback_aper_force __initdata = 0;
L
Linus Torvalds 已提交
34 35 36

int fix_aperture __initdata = 1;

37 38 39 40 41 42 43 44 45 46 47 48
static struct resource gart_resource = {
	.name	= "GART",
	.flags	= IORESOURCE_MEM,
};

static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
{
	gart_resource.start = aper_base;
	gart_resource.end = aper_base + aper_size - 1;
	insert_resource(&iomem_resource, &gart_resource);
}

49 50
/* This code runs before the PCI subsystem is initialized, so just
   access the northbridge directly. */
L
Linus Torvalds 已提交
51

52
static u32 __init allocate_aperture(void)
L
Linus Torvalds 已提交
53 54
{
	u32 aper_size;
55
	void *p;
L
Linus Torvalds 已提交
56

57 58 59
	if (fallback_aper_order > 7)
		fallback_aper_order = 7;
	aper_size = (32 * 1024 * 1024) << fallback_aper_order;
L
Linus Torvalds 已提交
60

61 62 63 64 65
	/*
	 * Aperture has to be naturally aligned. This means a 2GB aperture
	 * won't have much chance of finding a place in the lower 4GB of
	 * memory. Unfortunately we cannot move it up because that would
	 * make the IOMMU useless.
L
Linus Torvalds 已提交
66
	 */
67
	p = __alloc_bootmem_nopanic(aper_size, aper_size, 0);
L
Linus Torvalds 已提交
68
	if (!p || __pa(p)+aper_size > 0xffffffff) {
69 70 71
		printk(KERN_ERR
			"Cannot allocate aperture memory hole (%p,%uK)\n",
				p, aper_size>>10);
L
Linus Torvalds 已提交
72
		if (p)
73
			free_bootmem(__pa(p), aper_size);
L
Linus Torvalds 已提交
74 75
		return 0;
	}
76 77
	printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
			aper_size >> 10, __pa(p));
78
	insert_aperture_resource((u32)__pa(p), aper_size);
79 80

	return (u32)__pa(p);
L
Linus Torvalds 已提交
81 82
}

83
static int __init aperture_valid(u64 aper_base, u32 aper_size)
84 85
{
	if (!aper_base)
L
Linus Torvalds 已提交
86
		return 0;
87

88
	if (aper_size < 64*1024*1024) {
89
		printk(KERN_ERR "Aperture too small (%d MB)\n", aper_size>>20);
L
Linus Torvalds 已提交
90 91
		return 0;
	}
92
	if (aper_base + aper_size > 0x100000000UL) {
93
		printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
94
		return 0;
L
Linus Torvalds 已提交
95
	}
96
	if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
97
		printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n");
98 99
		return 0;
	}
100

L
Linus Torvalds 已提交
101
	return 1;
102
}
L
Linus Torvalds 已提交
103

104
/* Find a PCI capability */
105 106
static __u32 __init find_cap(int num, int slot, int func, int cap)
{
L
Linus Torvalds 已提交
107
	int bytes;
108 109 110 111
	u8 pos;

	if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
						PCI_STATUS_CAP_LIST))
L
Linus Torvalds 已提交
112
		return 0;
113 114 115

	pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
L
Linus Torvalds 已提交
116
		u8 id;
117 118 119

		pos &= ~3;
		id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
L
Linus Torvalds 已提交
120 121
		if (id == 0xff)
			break;
122 123 124 125 126
		if (id == cap)
			return pos;
		pos = read_pci_config_byte(num, slot, func,
						pos+PCI_CAP_LIST_NEXT);
	}
L
Linus Torvalds 已提交
127
	return 0;
128
}
L
Linus Torvalds 已提交
129 130 131

/* Read a standard AGPv3 bridge header */
static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
132
{
L
Linus Torvalds 已提交
133 134 135 136 137 138
	u32 apsize;
	u32 apsizereg;
	int nbits;
	u32 aper_low, aper_hi;
	u64 aper;

139
	printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", num, slot, func);
140
	apsizereg = read_pci_config_16(num, slot, func, cap + 0x14);
L
Linus Torvalds 已提交
141
	if (apsizereg == 0xffffffff) {
142
		printk(KERN_ERR "APSIZE in AGP bridge unreadable\n");
L
Linus Torvalds 已提交
143 144 145 146 147
		return 0;
	}

	apsize = apsizereg & 0xfff;
	/* Some BIOS use weird encodings not in the AGPv3 table. */
148 149
	if (apsize & 0xff)
		apsize |= 0xf00;
L
Linus Torvalds 已提交
150 151 152 153
	nbits = hweight16(apsize);
	*order = 7 - nbits;
	if ((int)*order < 0) /* < 32MB */
		*order = 0;
154 155 156

	aper_low = read_pci_config(num, slot, func, 0x10);
	aper_hi = read_pci_config(num, slot, func, 0x14);
L
Linus Torvalds 已提交
157 158
	aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);

159 160
	printk(KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
			aper, 32 << *order, apsizereg);
L
Linus Torvalds 已提交
161

162
	if (!aperture_valid(aper, (32*1024*1024) << *order))
163 164 165
		return 0;
	return (u32)aper;
}
L
Linus Torvalds 已提交
166

167 168 169 170 171 172 173 174 175 176 177 178 179
/*
 * Look for an AGP bridge. Windows only expects the aperture in the
 * AGP bridge and some BIOS forget to initialize the Northbridge too.
 * Work around this here.
 *
 * Do an PCI bus scan by hand because we're running before the PCI
 * subsystem.
 *
 * All K8 AGP bridges are AGPv3 compliant, so we can do this scan
 * generically. It's probably overkill to always scan all slots because
 * the AGP bridges should be always an own bus on the HT hierarchy,
 * but do it here for future safety.
 */
L
Linus Torvalds 已提交
180 181 182 183 184
static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
{
	int num, slot, func;

	/* Poor man's PCI discovery */
185 186 187
	for (num = 0; num < 256; num++) {
		for (slot = 0; slot < 32; slot++) {
			for (func = 0; func < 8; func++) {
L
Linus Torvalds 已提交
188 189
				u32 class, cap;
				u8 type;
190
				class = read_pci_config(num, slot, func,
L
Linus Torvalds 已提交
191 192
							PCI_CLASS_REVISION);
				if (class == 0xffffffff)
193 194 195
					break;

				switch (class >> 16) {
L
Linus Torvalds 已提交
196 197 198
				case PCI_CLASS_BRIDGE_HOST:
				case PCI_CLASS_BRIDGE_OTHER: /* needed? */
					/* AGP bridge? */
199 200
					cap = find_cap(num, slot, func,
							PCI_CAP_ID_AGP);
L
Linus Torvalds 已提交
201 202
					if (!cap)
						break;
203 204 205 206 207
					*valid_agp = 1;
					return read_agp(num, slot, func, cap,
							order);
				}

L
Linus Torvalds 已提交
208
				/* No multi-function device? */
209
				type = read_pci_config_byte(num, slot, func,
L
Linus Torvalds 已提交
210 211 212
							       PCI_HEADER_TYPE);
				if (!(type & 0x80))
					break;
213 214
			}
		}
L
Linus Torvalds 已提交
215
	}
216
	printk(KERN_INFO "No AGP bridge found\n");
217

L
Linus Torvalds 已提交
218 219 220
	return 0;
}

Y
Yinghai Lu 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
static int gart_fix_e820 __initdata = 1;

static int __init parse_gart_mem(char *p)
{
	if (!p)
		return -EINVAL;

	if (!strncmp(p, "off", 3))
		gart_fix_e820 = 0;
	else if (!strncmp(p, "on", 2))
		gart_fix_e820 = 1;

	return 0;
}
early_param("gart_fix_e820", parse_gart_mem);

void __init early_gart_iommu_check(void)
{
	/*
	 * in case it is enabled before, esp for kexec/kdump,
	 * previous kernel already enable that. memset called
	 * by allocate_aperture/__alloc_bootmem_nopanic cause restart.
	 * or second kernel have different position for GART hole. and new
	 * kernel could use hole as RAM that is still used by GART set by
	 * first kernel
	 * or BIOS forget to put that in reserved.
	 * try to update e820 to make that region as reserved.
	 */
	int fix, num;
	u32 ctl;
	u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
	u64 aper_base = 0, last_aper_base = 0;
	int aper_enabled = 0, last_aper_enabled = 0;

	if (!early_pci_allowed())
		return;

	fix = 0;
	for (num = 24; num < 32; num++) {
		if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
			continue;

		ctl = read_pci_config(0, num, 3, 0x90);
		aper_enabled = ctl & 1;
		aper_order = (ctl >> 1) & 7;
		aper_size = (32 * 1024 * 1024) << aper_order;
		aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
		aper_base <<= 25;

		if ((last_aper_order && aper_order != last_aper_order) ||
		    (last_aper_base && aper_base != last_aper_base) ||
		    (last_aper_enabled && aper_enabled != last_aper_enabled)) {
			fix = 1;
			break;
		}
		last_aper_order = aper_order;
		last_aper_base = aper_base;
		last_aper_enabled = aper_enabled;
	}

	if (!fix && !aper_enabled)
		return;

	if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL)
		fix = 1;

	if (gart_fix_e820 && !fix && aper_enabled) {
		if (e820_any_mapped(aper_base, aper_base + aper_size,
				    E820_RAM)) {
			/* reserved it, so we can resuse it in second kernel */
			printk(KERN_INFO "update e820 for GART\n");
			add_memory_region(aper_base, aper_size, E820_RESERVED);
			update_e820();
		}
		return;
	}

	/* different nodes have different setting, disable them all at first*/
	for (num = 24; num < 32; num++) {
		if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
			continue;

		ctl = read_pci_config(0, num, 3, 0x90);
		ctl &= ~1;
		write_pci_config(0, num, 3, 0x90, ctl);
	}

}

310
void __init gart_iommu_hole_init(void)
311
{
312
	u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
L
Linus Torvalds 已提交
313
	u64 aper_base, last_aper_base = 0;
314
	int fix, num, valid_agp = 0;
315
	int node;
L
Linus Torvalds 已提交
316

317 318
	if (gart_iommu_aperture_disabled || !fix_aperture ||
	    !early_pci_allowed())
L
Linus Torvalds 已提交
319 320
		return;

321
	printk(KERN_INFO  "Checking aperture...\n");
L
Linus Torvalds 已提交
322 323

	fix = 0;
324
	node = 0;
325
	for (num = 24; num < 32; num++) {
326 327
		if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
			continue;
L
Linus Torvalds 已提交
328

329
		iommu_detected = 1;
330
		gart_iommu_aperture = 1;
L
Linus Torvalds 已提交
331

332 333
		aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7;
		aper_size = (32 * 1024 * 1024) << aper_order;
L
Linus Torvalds 已提交
334
		aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
335
		aper_base <<= 25;
L
Linus Torvalds 已提交
336

337 338 339
		printk(KERN_INFO "Node %d: aperture @ %Lx size %u MB\n",
				node, aper_base, aper_size >> 20);
		node++;
340

341
		if (!aperture_valid(aper_base, aper_size)) {
342 343
			fix = 1;
			break;
L
Linus Torvalds 已提交
344 345 346 347 348 349 350 351 352
		}

		if ((last_aper_order && aper_order != last_aper_order) ||
		    (last_aper_base && aper_base != last_aper_base)) {
			fix = 1;
			break;
		}
		last_aper_order = aper_order;
		last_aper_base = aper_base;
353
	}
L
Linus Torvalds 已提交
354

355 356 357
	if (!fix && !fallback_aper_force) {
		if (last_aper_base) {
			unsigned long n = (32 * 1024 * 1024) << last_aper_order;
358

359 360
			insert_aperture_resource((u32)last_aper_base, n);
		}
361
		return;
362
	}
L
Linus Torvalds 已提交
363 364

	if (!fallback_aper_force)
365 366 367
		aper_alloc = search_agp_bridge(&aper_order, &valid_agp);

	if (aper_alloc) {
L
Linus Torvalds 已提交
368
		/* Got the aperture from the AGP bridge */
369 370
	} else if (swiotlb && !valid_agp) {
		/* Do nothing */
371
	} else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) ||
L
Linus Torvalds 已提交
372 373
		   force_iommu ||
		   valid_agp ||
374
		   fallback_aper_force) {
375 376 377 378 379 380 381
		printk(KERN_ERR
			"Your BIOS doesn't leave a aperture memory hole\n");
		printk(KERN_ERR
			"Please enable the IOMMU option in the BIOS setup\n");
		printk(KERN_ERR
			"This costs you %d MB of RAM\n",
				32 << fallback_aper_order);
L
Linus Torvalds 已提交
382 383 384

		aper_order = fallback_aper_order;
		aper_alloc = allocate_aperture();
385 386 387 388 389 390 391 392 393
		if (!aper_alloc) {
			/*
			 * Could disable AGP and IOMMU here, but it's
			 * probably not worth it. But the later users
			 * cannot deal with bad apertures and turning
			 * on the aperture over memory causes very
			 * strange problems, so it's better to panic
			 * early.
			 */
L
Linus Torvalds 已提交
394 395
			panic("Not enough memory for aperture");
		}
396 397 398
	} else {
		return;
	}
L
Linus Torvalds 已提交
399 400

	/* Fix up the north bridges */
401
	for (num = 24; num < 32; num++) {
402
		if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
403 404 405 406 407 408 409 410 411 412 413
			continue;

		/*
		 * Don't enable translation yet. That is done later.
		 * Assume this BIOS didn't initialise the GART so
		 * just overwrite all previous bits
		 */
		write_pci_config(0, num, 3, 0x90, aper_order<<1);
		write_pci_config(0, num, 3, 0x94, aper_alloc>>25);
	}
}