ia64/linux-2.6.18-xen.hg

annotate arch/alpha/kernel/core_marvel.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 * linux/arch/alpha/kernel/core_marvel.c
ian@0 3 *
ian@0 4 * Code common to all Marvel based systems.
ian@0 5 */
ian@0 6
ian@0 7 #define __EXTERN_INLINE inline
ian@0 8 #include <asm/io.h>
ian@0 9 #include <asm/core_marvel.h>
ian@0 10 #undef __EXTERN_INLINE
ian@0 11
ian@0 12 #include <linux/types.h>
ian@0 13 #include <linux/pci.h>
ian@0 14 #include <linux/sched.h>
ian@0 15 #include <linux/init.h>
ian@0 16 #include <linux/vmalloc.h>
ian@0 17 #include <linux/mc146818rtc.h>
ian@0 18 #include <linux/rtc.h>
ian@0 19 #include <linux/module.h>
ian@0 20 #include <linux/bootmem.h>
ian@0 21
ian@0 22 #include <asm/ptrace.h>
ian@0 23 #include <asm/smp.h>
ian@0 24 #include <asm/gct.h>
ian@0 25 #include <asm/pgalloc.h>
ian@0 26 #include <asm/tlbflush.h>
ian@0 27 #include <asm/rtc.h>
ian@0 28
ian@0 29 #include "proto.h"
ian@0 30 #include "pci_impl.h"
ian@0 31
ian@0 32
ian@0 33 /*
ian@0 34 * Debug helpers
ian@0 35 */
ian@0 36 #define DEBUG_CONFIG 0
ian@0 37
ian@0 38 #if DEBUG_CONFIG
ian@0 39 # define DBG_CFG(args) printk args
ian@0 40 #else
ian@0 41 # define DBG_CFG(args)
ian@0 42 #endif
ian@0 43
ian@0 44
ian@0 45 /*
ian@0 46 * Private data
ian@0 47 */
ian@0 48 static struct io7 *io7_head = NULL;
ian@0 49
ian@0 50
ian@0 51 /*
ian@0 52 * Helper functions
ian@0 53 */
ian@0 54 static unsigned long __attribute__ ((unused))
ian@0 55 read_ev7_csr(int pe, unsigned long offset)
ian@0 56 {
ian@0 57 ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
ian@0 58 unsigned long q;
ian@0 59
ian@0 60 mb();
ian@0 61 q = ev7csr->csr;
ian@0 62 mb();
ian@0 63
ian@0 64 return q;
ian@0 65 }
ian@0 66
ian@0 67 static void __attribute__ ((unused))
ian@0 68 write_ev7_csr(int pe, unsigned long offset, unsigned long q)
ian@0 69 {
ian@0 70 ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
ian@0 71
ian@0 72 mb();
ian@0 73 ev7csr->csr = q;
ian@0 74 mb();
ian@0 75 }
ian@0 76
ian@0 77 static char * __init
ian@0 78 mk_resource_name(int pe, int port, char *str)
ian@0 79 {
ian@0 80 char tmp[80];
ian@0 81 char *name;
ian@0 82
ian@0 83 sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
ian@0 84 name = alloc_bootmem(strlen(tmp) + 1);
ian@0 85 strcpy(name, tmp);
ian@0 86
ian@0 87 return name;
ian@0 88 }
ian@0 89
ian@0 90 inline struct io7 *
ian@0 91 marvel_next_io7(struct io7 *prev)
ian@0 92 {
ian@0 93 return (prev ? prev->next : io7_head);
ian@0 94 }
ian@0 95
ian@0 96 struct io7 *
ian@0 97 marvel_find_io7(int pe)
ian@0 98 {
ian@0 99 struct io7 *io7;
ian@0 100
ian@0 101 for (io7 = io7_head; io7 && io7->pe != pe; io7 = io7->next)
ian@0 102 continue;
ian@0 103
ian@0 104 return io7;
ian@0 105 }
ian@0 106
ian@0 107 static struct io7 * __init
ian@0 108 alloc_io7(unsigned int pe)
ian@0 109 {
ian@0 110 struct io7 *io7;
ian@0 111 struct io7 *insp;
ian@0 112 int h;
ian@0 113
ian@0 114 if (marvel_find_io7(pe)) {
ian@0 115 printk(KERN_WARNING "IO7 at PE %d already allocated!\n", pe);
ian@0 116 return NULL;
ian@0 117 }
ian@0 118
ian@0 119 io7 = alloc_bootmem(sizeof(*io7));
ian@0 120 io7->pe = pe;
ian@0 121 spin_lock_init(&io7->irq_lock);
ian@0 122
ian@0 123 for (h = 0; h < 4; h++) {
ian@0 124 io7->ports[h].io7 = io7;
ian@0 125 io7->ports[h].port = h;
ian@0 126 io7->ports[h].enabled = 0; /* default to disabled */
ian@0 127 }
ian@0 128
ian@0 129 /*
ian@0 130 * Insert in pe sorted order.
ian@0 131 */
ian@0 132 if (NULL == io7_head) /* empty list */
ian@0 133 io7_head = io7;
ian@0 134 else if (io7_head->pe > io7->pe) { /* insert at head */
ian@0 135 io7->next = io7_head;
ian@0 136 io7_head = io7;
ian@0 137 } else { /* insert at position */
ian@0 138 for (insp = io7_head; insp; insp = insp->next) {
ian@0 139 if (insp->pe == io7->pe) {
ian@0 140 printk(KERN_ERR "Too many IO7s at PE %d\n",
ian@0 141 io7->pe);
ian@0 142 return NULL;
ian@0 143 }
ian@0 144
ian@0 145 if (NULL == insp->next ||
ian@0 146 insp->next->pe > io7->pe) { /* insert here */
ian@0 147 io7->next = insp->next;
ian@0 148 insp->next = io7;
ian@0 149 break;
ian@0 150 }
ian@0 151 }
ian@0 152
ian@0 153 if (NULL == insp) { /* couldn't insert ?!? */
ian@0 154 printk(KERN_WARNING "Failed to insert IO7 at PE %d "
ian@0 155 " - adding at head of list\n", io7->pe);
ian@0 156 io7->next = io7_head;
ian@0 157 io7_head = io7;
ian@0 158 }
ian@0 159 }
ian@0 160
ian@0 161 return io7;
ian@0 162 }
ian@0 163
ian@0 164 void
ian@0 165 io7_clear_errors(struct io7 *io7)
ian@0 166 {
ian@0 167 io7_port7_csrs *p7csrs;
ian@0 168 io7_ioport_csrs *csrs;
ian@0 169 int port;
ian@0 170
ian@0 171
ian@0 172 /*
ian@0 173 * First the IO ports.
ian@0 174 */
ian@0 175 for (port = 0; port < 4; port++) {
ian@0 176 csrs = IO7_CSRS_KERN(io7->pe, port);
ian@0 177
ian@0 178 csrs->POx_ERR_SUM.csr = -1UL;
ian@0 179 csrs->POx_TLB_ERR.csr = -1UL;
ian@0 180 csrs->POx_SPL_COMPLT.csr = -1UL;
ian@0 181 csrs->POx_TRANS_SUM.csr = -1UL;
ian@0 182 }
ian@0 183
ian@0 184 /*
ian@0 185 * Then the common ones.
ian@0 186 */
ian@0 187 p7csrs = IO7_PORT7_CSRS_KERN(io7->pe);
ian@0 188
ian@0 189 p7csrs->PO7_ERROR_SUM.csr = -1UL;
ian@0 190 p7csrs->PO7_UNCRR_SYM.csr = -1UL;
ian@0 191 p7csrs->PO7_CRRCT_SYM.csr = -1UL;
ian@0 192 }
ian@0 193
ian@0 194
ian@0 195 /*
ian@0 196 * IO7 PCI, PCI/X, AGP configuration.
ian@0 197 */
ian@0 198 static void __init
ian@0 199 io7_init_hose(struct io7 *io7, int port)
ian@0 200 {
ian@0 201 static int hose_index = 0;
ian@0 202
ian@0 203 struct pci_controller *hose = alloc_pci_controller();
ian@0 204 struct io7_port *io7_port = &io7->ports[port];
ian@0 205 io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, port);
ian@0 206 int i;
ian@0 207
ian@0 208 hose->index = hose_index++; /* arbitrary */
ian@0 209
ian@0 210 /*
ian@0 211 * We don't have an isa or legacy hose, but glibc expects to be
ian@0 212 * able to use the bus == 0 / dev == 0 form of the iobase syscall
ian@0 213 * to determine information about the i/o system. Since XFree86
ian@0 214 * relies on glibc's determination to tell whether or not to use
ian@0 215 * sparse access, we need to point the pci_isa_hose at a real hose
ian@0 216 * so at least that determination is correct.
ian@0 217 */
ian@0 218 if (hose->index == 0)
ian@0 219 pci_isa_hose = hose;
ian@0 220
ian@0 221 io7_port->csrs = csrs;
ian@0 222 io7_port->hose = hose;
ian@0 223 hose->sysdata = io7_port;
ian@0 224
ian@0 225 hose->io_space = alloc_resource();
ian@0 226 hose->mem_space = alloc_resource();
ian@0 227
ian@0 228 /*
ian@0 229 * Base addresses for userland consumption. Since these are going
ian@0 230 * to be mapped, they are pure physical addresses.
ian@0 231 */
ian@0 232 hose->sparse_mem_base = hose->sparse_io_base = 0;
ian@0 233 hose->dense_mem_base = IO7_MEM_PHYS(io7->pe, port);
ian@0 234 hose->dense_io_base = IO7_IO_PHYS(io7->pe, port);
ian@0 235
ian@0 236 /*
ian@0 237 * Base addresses and resource ranges for kernel consumption.
ian@0 238 */
ian@0 239 hose->config_space_base = (unsigned long)IO7_CONF_KERN(io7->pe, port);
ian@0 240
ian@0 241 hose->io_space->start = (unsigned long)IO7_IO_KERN(io7->pe, port);
ian@0 242 hose->io_space->end = hose->io_space->start + IO7_IO_SPACE - 1;
ian@0 243 hose->io_space->name = mk_resource_name(io7->pe, port, "IO");
ian@0 244 hose->io_space->flags = IORESOURCE_IO;
ian@0 245
ian@0 246 hose->mem_space->start = (unsigned long)IO7_MEM_KERN(io7->pe, port);
ian@0 247 hose->mem_space->end = hose->mem_space->start + IO7_MEM_SPACE - 1;
ian@0 248 hose->mem_space->name = mk_resource_name(io7->pe, port, "MEM");
ian@0 249 hose->mem_space->flags = IORESOURCE_MEM;
ian@0 250
ian@0 251 if (request_resource(&ioport_resource, hose->io_space) < 0)
ian@0 252 printk(KERN_ERR "Failed to request IO on hose %d\n",
ian@0 253 hose->index);
ian@0 254 if (request_resource(&iomem_resource, hose->mem_space) < 0)
ian@0 255 printk(KERN_ERR "Failed to request MEM on hose %d\n",
ian@0 256 hose->index);
ian@0 257
ian@0 258 /*
ian@0 259 * Save the existing DMA window settings for later restoration.
ian@0 260 */
ian@0 261 for (i = 0; i < 4; i++) {
ian@0 262 io7_port->saved_wbase[i] = csrs->POx_WBASE[i].csr;
ian@0 263 io7_port->saved_wmask[i] = csrs->POx_WMASK[i].csr;
ian@0 264 io7_port->saved_tbase[i] = csrs->POx_TBASE[i].csr;
ian@0 265 }
ian@0 266
ian@0 267 /*
ian@0 268 * Set up the PCI to main memory translation windows.
ian@0 269 *
ian@0 270 * Window 0 is scatter-gather 8MB at 8MB
ian@0 271 * Window 1 is direct access 1GB at 2GB
ian@0 272 * Window 2 is scatter-gather (up-to) 1GB at 3GB
ian@0 273 * Window 3 is disabled
ian@0 274 */
ian@0 275
ian@0 276 /*
ian@0 277 * TBIA before modifying windows.
ian@0 278 */
ian@0 279 marvel_pci_tbi(hose, 0, -1);
ian@0 280
ian@0 281 /*
ian@0 282 * Set up window 0 for scatter-gather 8MB at 8MB.
ian@0 283 */
ian@0 284 hose->sg_isa = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
ian@0 285 hose, 0x00800000, 0x00800000, 0);
ian@0 286 hose->sg_isa->align_entry = 8; /* cache line boundary */
ian@0 287 csrs->POx_WBASE[0].csr =
ian@0 288 hose->sg_isa->dma_base | wbase_m_ena | wbase_m_sg;
ian@0 289 csrs->POx_WMASK[0].csr = (hose->sg_isa->size - 1) & wbase_m_addr;
ian@0 290 csrs->POx_TBASE[0].csr = virt_to_phys(hose->sg_isa->ptes);
ian@0 291
ian@0 292 /*
ian@0 293 * Set up window 1 for direct-mapped 1GB at 2GB.
ian@0 294 */
ian@0 295 csrs->POx_WBASE[1].csr = __direct_map_base | wbase_m_ena;
ian@0 296 csrs->POx_WMASK[1].csr = (__direct_map_size - 1) & wbase_m_addr;
ian@0 297 csrs->POx_TBASE[1].csr = 0;
ian@0 298
ian@0 299 /*
ian@0 300 * Set up window 2 for scatter-gather (up-to) 1GB at 3GB.
ian@0 301 */
ian@0 302 hose->sg_pci = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
ian@0 303 hose, 0xc0000000, 0x40000000, 0);
ian@0 304 hose->sg_pci->align_entry = 8; /* cache line boundary */
ian@0 305 csrs->POx_WBASE[2].csr =
ian@0 306 hose->sg_pci->dma_base | wbase_m_ena | wbase_m_sg;
ian@0 307 csrs->POx_WMASK[2].csr = (hose->sg_pci->size - 1) & wbase_m_addr;
ian@0 308 csrs->POx_TBASE[2].csr = virt_to_phys(hose->sg_pci->ptes);
ian@0 309
ian@0 310 /*
ian@0 311 * Disable window 3.
ian@0 312 */
ian@0 313 csrs->POx_WBASE[3].csr = 0;
ian@0 314
ian@0 315 /*
ian@0 316 * Make sure that the AGP Monster Window is disabled.
ian@0 317 */
ian@0 318 csrs->POx_CTRL.csr &= ~(1UL << 61);
ian@0 319
ian@0 320 #if 1
ian@0 321 printk("FIXME: disabling master aborts\n");
ian@0 322 csrs->POx_MSK_HEI.csr &= ~(3UL << 14);
ian@0 323 #endif
ian@0 324 /*
ian@0 325 * TBIA after modifying windows.
ian@0 326 */
ian@0 327 marvel_pci_tbi(hose, 0, -1);
ian@0 328 }
ian@0 329
ian@0 330 static void __init
ian@0 331 marvel_init_io7(struct io7 *io7)
ian@0 332 {
ian@0 333 int i;
ian@0 334
ian@0 335 printk("Initializing IO7 at PID %d\n", io7->pe);
ian@0 336
ian@0 337 /*
ian@0 338 * Get the Port 7 CSR pointer.
ian@0 339 */
ian@0 340 io7->csrs = IO7_PORT7_CSRS_KERN(io7->pe);
ian@0 341
ian@0 342 /*
ian@0 343 * Init this IO7's hoses.
ian@0 344 */
ian@0 345 for (i = 0; i < IO7_NUM_PORTS; i++) {
ian@0 346 io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, i);
ian@0 347 if (csrs->POx_CACHE_CTL.csr == 8) {
ian@0 348 io7->ports[i].enabled = 1;
ian@0 349 io7_init_hose(io7, i);
ian@0 350 }
ian@0 351 }
ian@0 352 }
ian@0 353
ian@0 354 void
ian@0 355 marvel_io7_present(gct6_node *node)
ian@0 356 {
ian@0 357 int pe;
ian@0 358
ian@0 359 if (node->type != GCT_TYPE_HOSE ||
ian@0 360 node->subtype != GCT_SUBTYPE_IO_PORT_MODULE)
ian@0 361 return;
ian@0 362
ian@0 363 pe = (node->id >> 8) & 0xff;
ian@0 364 printk("Found an IO7 at PID %d\n", pe);
ian@0 365
ian@0 366 alloc_io7(pe);
ian@0 367 }
ian@0 368
ian@0 369 static void __init
ian@0 370 marvel_init_vga_hose(void)
ian@0 371 {
ian@0 372 #ifdef CONFIG_VGA_HOSE
ian@0 373 u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
ian@0 374
ian@0 375 if (pu64[7] == 3) { /* TERM_TYPE == graphics */
ian@0 376 struct pci_controller *hose = NULL;
ian@0 377 int h = (pu64[30] >> 24) & 0xff; /* TERM_OUT_LOC, hose # */
ian@0 378 struct io7 *io7;
ian@0 379 int pid, port;
ian@0 380
ian@0 381 /* FIXME - encoding is going to have to change for Marvel
ian@0 382 * since hose will be able to overflow a byte...
ian@0 383 * need to fix this decode when the console
ian@0 384 * changes its encoding
ian@0 385 */
ian@0 386 printk("console graphics is on hose %d (console)\n", h);
ian@0 387
ian@0 388 /*
ian@0 389 * The console's hose numbering is:
ian@0 390 *
ian@0 391 * hose<n:2>: PID
ian@0 392 * hose<1:0>: PORT
ian@0 393 *
ian@0 394 * We need to find the hose at that pid and port
ian@0 395 */
ian@0 396 pid = h >> 2;
ian@0 397 port = h & 3;
ian@0 398 if ((io7 = marvel_find_io7(pid)))
ian@0 399 hose = io7->ports[port].hose;
ian@0 400
ian@0 401 if (hose) {
ian@0 402 printk("Console graphics on hose %d\n", hose->index);
ian@0 403 pci_vga_hose = hose;
ian@0 404 }
ian@0 405 }
ian@0 406 #endif /* CONFIG_VGA_HOSE */
ian@0 407 }
ian@0 408
ian@0 409 gct6_search_struct gct_wanted_node_list[] = {
ian@0 410 { GCT_TYPE_HOSE, GCT_SUBTYPE_IO_PORT_MODULE, marvel_io7_present },
ian@0 411 { 0, 0, NULL }
ian@0 412 };
ian@0 413
ian@0 414 /*
ian@0 415 * In case the GCT is not complete, let the user specify PIDs with IO7s
ian@0 416 * at boot time. Syntax is 'io7=a,b,c,...,n' where a-n are the PIDs (decimal)
ian@0 417 * where IO7s are connected
ian@0 418 */
ian@0 419 static int __init
ian@0 420 marvel_specify_io7(char *str)
ian@0 421 {
ian@0 422 unsigned long pid;
ian@0 423 struct io7 *io7;
ian@0 424 char *pchar;
ian@0 425
ian@0 426 do {
ian@0 427 pid = simple_strtoul(str, &pchar, 0);
ian@0 428 if (pchar != str) {
ian@0 429 printk("User-specified IO7 at PID %lu\n", pid);
ian@0 430 io7 = alloc_io7(pid);
ian@0 431 if (io7) marvel_init_io7(io7);
ian@0 432 }
ian@0 433
ian@0 434 if (pchar == str) pchar++;
ian@0 435 str = pchar;
ian@0 436 } while(*str);
ian@0 437
ian@0 438 return 1;
ian@0 439 }
ian@0 440 __setup("io7=", marvel_specify_io7);
ian@0 441
ian@0 442 void __init
ian@0 443 marvel_init_arch(void)
ian@0 444 {
ian@0 445 struct io7 *io7;
ian@0 446
ian@0 447 /* With multiple PCI busses, we play with I/O as physical addrs. */
ian@0 448 ioport_resource.end = ~0UL;
ian@0 449
ian@0 450 /* PCI DMA Direct Mapping is 1GB at 2GB. */
ian@0 451 __direct_map_base = 0x80000000;
ian@0 452 __direct_map_size = 0x40000000;
ian@0 453
ian@0 454 /* Parse the config tree. */
ian@0 455 gct6_find_nodes(GCT_NODE_PTR(0), gct_wanted_node_list);
ian@0 456
ian@0 457 /* Init the io7s. */
ian@0 458 for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); )
ian@0 459 marvel_init_io7(io7);
ian@0 460
ian@0 461 /* Check for graphic console location (if any). */
ian@0 462 marvel_init_vga_hose();
ian@0 463 }
ian@0 464
ian@0 465 void
ian@0 466 marvel_kill_arch(int mode)
ian@0 467 {
ian@0 468 }
ian@0 469
ian@0 470
ian@0 471 /*
ian@0 472 * PCI Configuration Space access functions
ian@0 473 *
ian@0 474 * Configuration space addresses have the following format:
ian@0 475 *
ian@0 476 * |2 2 2 2|1 1 1 1|1 1 1 1|1 1
ian@0 477 * |3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
ian@0 478 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ian@0 479 * |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|R|R|
ian@0 480 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ian@0 481 *
ian@0 482 * n:24 reserved for hose base
ian@0 483 * 23:16 bus number (8 bits = 128 possible buses)
ian@0 484 * 15:11 Device number (5 bits)
ian@0 485 * 10:8 function number
ian@0 486 * 7:2 register number
ian@0 487 *
ian@0 488 * Notes:
ian@0 489 * IO7 determines whether to use a type 0 or type 1 config cycle
ian@0 490 * based on the bus number. Therefore the bus number must be set
ian@0 491 * to 0 for the root bus on any hose.
ian@0 492 *
ian@0 493 * The function number selects which function of a multi-function device
ian@0 494 * (e.g., SCSI and Ethernet).
ian@0 495 *
ian@0 496 */
ian@0 497
ian@0 498 static inline unsigned long
ian@0 499 build_conf_addr(struct pci_controller *hose, u8 bus,
ian@0 500 unsigned int devfn, int where)
ian@0 501 {
ian@0 502 return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
ian@0 503 }
ian@0 504
ian@0 505 static unsigned long
ian@0 506 mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where)
ian@0 507 {
ian@0 508 struct pci_controller *hose = pbus->sysdata;
ian@0 509 struct io7_port *io7_port;
ian@0 510 unsigned long addr = 0;
ian@0 511 u8 bus = pbus->number;
ian@0 512
ian@0 513 if (!hose)
ian@0 514 return addr;
ian@0 515
ian@0 516 /* Check for enabled. */
ian@0 517 io7_port = hose->sysdata;
ian@0 518 if (!io7_port->enabled)
ian@0 519 return addr;
ian@0 520
ian@0 521 if (!pbus->parent) { /* No parent means peer PCI bus. */
ian@0 522 /* Don't support idsel > 20 on primary bus. */
ian@0 523 if (devfn >= PCI_DEVFN(21, 0))
ian@0 524 return addr;
ian@0 525 bus = 0;
ian@0 526 }
ian@0 527
ian@0 528 addr = build_conf_addr(hose, bus, devfn, where);
ian@0 529
ian@0 530 DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
ian@0 531 return addr;
ian@0 532 }
ian@0 533
ian@0 534 static int
ian@0 535 marvel_read_config(struct pci_bus *bus, unsigned int devfn, int where,
ian@0 536 int size, u32 *value)
ian@0 537 {
ian@0 538 unsigned long addr;
ian@0 539
ian@0 540 if (0 == (addr = mk_conf_addr(bus, devfn, where)))
ian@0 541 return PCIBIOS_DEVICE_NOT_FOUND;
ian@0 542
ian@0 543 switch(size) {
ian@0 544 case 1:
ian@0 545 *value = __kernel_ldbu(*(vucp)addr);
ian@0 546 break;
ian@0 547 case 2:
ian@0 548 *value = __kernel_ldwu(*(vusp)addr);
ian@0 549 break;
ian@0 550 case 4:
ian@0 551 *value = *(vuip)addr;
ian@0 552 break;
ian@0 553 default:
ian@0 554 return PCIBIOS_FUNC_NOT_SUPPORTED;
ian@0 555 }
ian@0 556
ian@0 557 return PCIBIOS_SUCCESSFUL;
ian@0 558 }
ian@0 559
ian@0 560 static int
ian@0 561 marvel_write_config(struct pci_bus *bus, unsigned int devfn, int where,
ian@0 562 int size, u32 value)
ian@0 563 {
ian@0 564 unsigned long addr;
ian@0 565
ian@0 566 if (0 == (addr = mk_conf_addr(bus, devfn, where)))
ian@0 567 return PCIBIOS_DEVICE_NOT_FOUND;
ian@0 568
ian@0 569 switch (size) {
ian@0 570 case 1:
ian@0 571 __kernel_stb(value, *(vucp)addr);
ian@0 572 mb();
ian@0 573 __kernel_ldbu(*(vucp)addr);
ian@0 574 break;
ian@0 575 case 2:
ian@0 576 __kernel_stw(value, *(vusp)addr);
ian@0 577 mb();
ian@0 578 __kernel_ldwu(*(vusp)addr);
ian@0 579 break;
ian@0 580 case 4:
ian@0 581 *(vuip)addr = value;
ian@0 582 mb();
ian@0 583 *(vuip)addr;
ian@0 584 break;
ian@0 585 default:
ian@0 586 return PCIBIOS_FUNC_NOT_SUPPORTED;
ian@0 587 }
ian@0 588
ian@0 589 return PCIBIOS_SUCCESSFUL;
ian@0 590 }
ian@0 591
ian@0 592 struct pci_ops marvel_pci_ops =
ian@0 593 {
ian@0 594 .read = marvel_read_config,
ian@0 595 .write = marvel_write_config,
ian@0 596 };
ian@0 597
ian@0 598
ian@0 599 /*
ian@0 600 * Other PCI helper functions.
ian@0 601 */
ian@0 602 void
ian@0 603 marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
ian@0 604 {
ian@0 605 io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
ian@0 606
ian@0 607 wmb();
ian@0 608 csrs->POx_SG_TBIA.csr = 0;
ian@0 609 mb();
ian@0 610 csrs->POx_SG_TBIA.csr;
ian@0 611 }
ian@0 612
ian@0 613
ian@0 614
ian@0 615 /*
ian@0 616 * RTC Support
ian@0 617 */
ian@0 618 struct marvel_rtc_access_info {
ian@0 619 unsigned long function;
ian@0 620 unsigned long index;
ian@0 621 unsigned long data;
ian@0 622 };
ian@0 623
ian@0 624 static void
ian@0 625 __marvel_access_rtc(void *info)
ian@0 626 {
ian@0 627 struct marvel_rtc_access_info *rtc_access = info;
ian@0 628
ian@0 629 register unsigned long __r0 __asm__("$0");
ian@0 630 register unsigned long __r16 __asm__("$16") = rtc_access->function;
ian@0 631 register unsigned long __r17 __asm__("$17") = rtc_access->index;
ian@0 632 register unsigned long __r18 __asm__("$18") = rtc_access->data;
ian@0 633
ian@0 634 __asm__ __volatile__(
ian@0 635 "call_pal %4 # cserve rtc"
ian@0 636 : "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
ian@0 637 : "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
ian@0 638 : "$1", "$22", "$23", "$24", "$25");
ian@0 639
ian@0 640 rtc_access->data = __r0;
ian@0 641 }
ian@0 642
ian@0 643 static u8
ian@0 644 __marvel_rtc_io(u8 b, unsigned long addr, int write)
ian@0 645 {
ian@0 646 static u8 index = 0;
ian@0 647
ian@0 648 struct marvel_rtc_access_info rtc_access;
ian@0 649 u8 ret = 0;
ian@0 650
ian@0 651 switch(addr) {
ian@0 652 case 0x70: /* RTC_PORT(0) */
ian@0 653 if (write) index = b;
ian@0 654 ret = index;
ian@0 655 break;
ian@0 656
ian@0 657 case 0x71: /* RTC_PORT(1) */
ian@0 658 rtc_access.index = index;
ian@0 659 rtc_access.data = BCD_TO_BIN(b);
ian@0 660 rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */
ian@0 661
ian@0 662 #ifdef CONFIG_SMP
ian@0 663 if (smp_processor_id() != boot_cpuid)
ian@0 664 smp_call_function_on_cpu(__marvel_access_rtc,
ian@0 665 &rtc_access, 1, 1,
ian@0 666 cpumask_of_cpu(boot_cpuid));
ian@0 667 else
ian@0 668 __marvel_access_rtc(&rtc_access);
ian@0 669 #else
ian@0 670 __marvel_access_rtc(&rtc_access);
ian@0 671 #endif
ian@0 672 ret = BIN_TO_BCD(rtc_access.data);
ian@0 673 break;
ian@0 674
ian@0 675 default:
ian@0 676 printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
ian@0 677 break;
ian@0 678 }
ian@0 679
ian@0 680 return ret;
ian@0 681 }
ian@0 682
ian@0 683
ian@0 684 /*
ian@0 685 * IO map support.
ian@0 686 */
ian@0 687
ian@0 688 #define __marvel_is_mem_vga(a) (((a) >= 0xa0000) && ((a) <= 0xc0000))
ian@0 689
ian@0 690 void __iomem *
ian@0 691 marvel_ioremap(unsigned long addr, unsigned long size)
ian@0 692 {
ian@0 693 struct pci_controller *hose;
ian@0 694 unsigned long baddr, last;
ian@0 695 struct vm_struct *area;
ian@0 696 unsigned long vaddr;
ian@0 697 unsigned long *ptes;
ian@0 698 unsigned long pfn;
ian@0 699
ian@0 700 /*
ian@0 701 * Adjust the addr.
ian@0 702 */
ian@0 703 #ifdef CONFIG_VGA_HOSE
ian@0 704 if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
ian@0 705 addr += pci_vga_hose->mem_space->start;
ian@0 706 }
ian@0 707 #endif
ian@0 708
ian@0 709 /*
ian@0 710 * Find the hose.
ian@0 711 */
ian@0 712 for (hose = hose_head; hose; hose = hose->next) {
ian@0 713 if ((addr >> 32) == (hose->mem_space->start >> 32))
ian@0 714 break;
ian@0 715 }
ian@0 716 if (!hose)
ian@0 717 return NULL;
ian@0 718
ian@0 719 /*
ian@0 720 * We have the hose - calculate the bus limits.
ian@0 721 */
ian@0 722 baddr = addr - hose->mem_space->start;
ian@0 723 last = baddr + size - 1;
ian@0 724
ian@0 725 /*
ian@0 726 * Is it direct-mapped?
ian@0 727 */
ian@0 728 if ((baddr >= __direct_map_base) &&
ian@0 729 ((baddr + size - 1) < __direct_map_base + __direct_map_size)) {
ian@0 730 addr = IDENT_ADDR | (baddr - __direct_map_base);
ian@0 731 return (void __iomem *) addr;
ian@0 732 }
ian@0 733
ian@0 734 /*
ian@0 735 * Check the scatter-gather arena.
ian@0 736 */
ian@0 737 if (hose->sg_pci &&
ian@0 738 baddr >= (unsigned long)hose->sg_pci->dma_base &&
ian@0 739 last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size) {
ian@0 740
ian@0 741 /*
ian@0 742 * Adjust the limits (mappings must be page aligned)
ian@0 743 */
ian@0 744 baddr -= hose->sg_pci->dma_base;
ian@0 745 last -= hose->sg_pci->dma_base;
ian@0 746 baddr &= PAGE_MASK;
ian@0 747 size = PAGE_ALIGN(last) - baddr;
ian@0 748
ian@0 749 /*
ian@0 750 * Map it.
ian@0 751 */
ian@0 752 area = get_vm_area(size, VM_IOREMAP);
ian@0 753 if (!area)
ian@0 754 return NULL;
ian@0 755
ian@0 756 ptes = hose->sg_pci->ptes;
ian@0 757 for (vaddr = (unsigned long)area->addr;
ian@0 758 baddr <= last;
ian@0 759 baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
ian@0 760 pfn = ptes[baddr >> PAGE_SHIFT];
ian@0 761 if (!(pfn & 1)) {
ian@0 762 printk("ioremap failed... pte not valid...\n");
ian@0 763 vfree(area->addr);
ian@0 764 return NULL;
ian@0 765 }
ian@0 766 pfn >>= 1; /* make it a true pfn */
ian@0 767
ian@0 768 if (__alpha_remap_area_pages(vaddr,
ian@0 769 pfn << PAGE_SHIFT,
ian@0 770 PAGE_SIZE, 0)) {
ian@0 771 printk("FAILED to map...\n");
ian@0 772 vfree(area->addr);
ian@0 773 return NULL;
ian@0 774 }
ian@0 775 }
ian@0 776
ian@0 777 flush_tlb_all();
ian@0 778
ian@0 779 vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
ian@0 780
ian@0 781 return (void __iomem *) vaddr;
ian@0 782 }
ian@0 783
ian@0 784 return NULL;
ian@0 785 }
ian@0 786
ian@0 787 void
ian@0 788 marvel_iounmap(volatile void __iomem *xaddr)
ian@0 789 {
ian@0 790 unsigned long addr = (unsigned long) xaddr;
ian@0 791 if (addr >= VMALLOC_START)
ian@0 792 vfree((void *)(PAGE_MASK & addr));
ian@0 793 }
ian@0 794
ian@0 795 int
ian@0 796 marvel_is_mmio(const volatile void __iomem *xaddr)
ian@0 797 {
ian@0 798 unsigned long addr = (unsigned long) xaddr;
ian@0 799
ian@0 800 if (addr >= VMALLOC_START)
ian@0 801 return 1;
ian@0 802 else
ian@0 803 return (addr & 0xFF000000UL) == 0;
ian@0 804 }
ian@0 805
ian@0 806 #define __marvel_is_port_vga(a) \
ian@0 807 (((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3))
ian@0 808 #define __marvel_is_port_kbd(a) (((a) == 0x60) || ((a) == 0x64))
ian@0 809 #define __marvel_is_port_rtc(a) (((a) == 0x70) || ((a) == 0x71))
ian@0 810
ian@0 811 void __iomem *marvel_ioportmap (unsigned long addr)
ian@0 812 {
ian@0 813 if (__marvel_is_port_rtc (addr) || __marvel_is_port_kbd(addr))
ian@0 814 ;
ian@0 815 #ifdef CONFIG_VGA_HOSE
ian@0 816 else if (__marvel_is_port_vga (addr) && pci_vga_hose)
ian@0 817 addr += pci_vga_hose->io_space->start;
ian@0 818 #endif
ian@0 819 else
ian@0 820 return NULL;
ian@0 821 return (void __iomem *)addr;
ian@0 822 }
ian@0 823
ian@0 824 unsigned int
ian@0 825 marvel_ioread8(void __iomem *xaddr)
ian@0 826 {
ian@0 827 unsigned long addr = (unsigned long) xaddr;
ian@0 828 if (__marvel_is_port_kbd(addr))
ian@0 829 return 0;
ian@0 830 else if (__marvel_is_port_rtc(addr))
ian@0 831 return __marvel_rtc_io(0, addr, 0);
ian@0 832 else
ian@0 833 return __kernel_ldbu(*(vucp)addr);
ian@0 834 }
ian@0 835
ian@0 836 void
ian@0 837 marvel_iowrite8(u8 b, void __iomem *xaddr)
ian@0 838 {
ian@0 839 unsigned long addr = (unsigned long) xaddr;
ian@0 840 if (__marvel_is_port_kbd(addr))
ian@0 841 return;
ian@0 842 else if (__marvel_is_port_rtc(addr))
ian@0 843 __marvel_rtc_io(b, addr, 1);
ian@0 844 else
ian@0 845 __kernel_stb(b, *(vucp)addr);
ian@0 846 }
ian@0 847
ian@0 848 #ifndef CONFIG_ALPHA_GENERIC
ian@0 849 EXPORT_SYMBOL(marvel_ioremap);
ian@0 850 EXPORT_SYMBOL(marvel_iounmap);
ian@0 851 EXPORT_SYMBOL(marvel_is_mmio);
ian@0 852 EXPORT_SYMBOL(marvel_ioportmap);
ian@0 853 EXPORT_SYMBOL(marvel_ioread8);
ian@0 854 EXPORT_SYMBOL(marvel_iowrite8);
ian@0 855 #endif
ian@0 856
ian@0 857 /*
ian@0 858 * NUMA Support
ian@0 859 */
ian@0 860 /**********
ian@0 861 * FIXME - for now each cpu is a node by itself
ian@0 862 * -- no real support for striped mode
ian@0 863 **********
ian@0 864 */
ian@0 865 int
ian@0 866 marvel_pa_to_nid(unsigned long pa)
ian@0 867 {
ian@0 868 int cpuid;
ian@0 869
ian@0 870 if ((pa >> 43) & 1) /* I/O */
ian@0 871 cpuid = (~(pa >> 35) & 0xff);
ian@0 872 else /* mem */
ian@0 873 cpuid = ((pa >> 34) & 0x3) | ((pa >> (37 - 2)) & (0x1f << 2));
ian@0 874
ian@0 875 return marvel_cpuid_to_nid(cpuid);
ian@0 876 }
ian@0 877
ian@0 878 int
ian@0 879 marvel_cpuid_to_nid(int cpuid)
ian@0 880 {
ian@0 881 return cpuid;
ian@0 882 }
ian@0 883
ian@0 884 unsigned long
ian@0 885 marvel_node_mem_start(int nid)
ian@0 886 {
ian@0 887 unsigned long pa;
ian@0 888
ian@0 889 pa = (nid & 0x3) | ((nid & (0x1f << 2)) << 1);
ian@0 890 pa <<= 34;
ian@0 891
ian@0 892 return pa;
ian@0 893 }
ian@0 894
ian@0 895 unsigned long
ian@0 896 marvel_node_mem_size(int nid)
ian@0 897 {
ian@0 898 return 16UL * 1024 * 1024 * 1024; /* 16GB */
ian@0 899 }
ian@0 900
ian@0 901
ian@0 902 /*
ian@0 903 * AGP GART Support.
ian@0 904 */
ian@0 905 #include <linux/agp_backend.h>
ian@0 906 #include <asm/agp_backend.h>
ian@0 907 #include <linux/slab.h>
ian@0 908 #include <linux/delay.h>
ian@0 909
ian@0 910 struct marvel_agp_aperture {
ian@0 911 struct pci_iommu_arena *arena;
ian@0 912 long pg_start;
ian@0 913 long pg_count;
ian@0 914 };
ian@0 915
ian@0 916 static int
ian@0 917 marvel_agp_setup(alpha_agp_info *agp)
ian@0 918 {
ian@0 919 struct marvel_agp_aperture *aper;
ian@0 920
ian@0 921 if (!alpha_agpgart_size)
ian@0 922 return -ENOMEM;
ian@0 923
ian@0 924 aper = kmalloc(sizeof(*aper), GFP_KERNEL);
ian@0 925 if (aper == NULL) return -ENOMEM;
ian@0 926
ian@0 927 aper->arena = agp->hose->sg_pci;
ian@0 928 aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
ian@0 929 aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
ian@0 930 aper->pg_count - 1);
ian@0 931
ian@0 932 if (aper->pg_start < 0) {
ian@0 933 printk(KERN_ERR "Failed to reserve AGP memory\n");
ian@0 934 kfree(aper);
ian@0 935 return -ENOMEM;
ian@0 936 }
ian@0 937
ian@0 938 agp->aperture.bus_base =
ian@0 939 aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
ian@0 940 agp->aperture.size = aper->pg_count * PAGE_SIZE;
ian@0 941 agp->aperture.sysdata = aper;
ian@0 942
ian@0 943 return 0;
ian@0 944 }
ian@0 945
ian@0 946 static void
ian@0 947 marvel_agp_cleanup(alpha_agp_info *agp)
ian@0 948 {
ian@0 949 struct marvel_agp_aperture *aper = agp->aperture.sysdata;
ian@0 950 int status;
ian@0 951
ian@0 952 status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
ian@0 953 if (status == -EBUSY) {
ian@0 954 printk(KERN_WARNING
ian@0 955 "Attempted to release bound AGP memory - unbinding\n");
ian@0 956 iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
ian@0 957 status = iommu_release(aper->arena, aper->pg_start,
ian@0 958 aper->pg_count);
ian@0 959 }
ian@0 960 if (status < 0)
ian@0 961 printk(KERN_ERR "Failed to release AGP memory\n");
ian@0 962
ian@0 963 kfree(aper);
ian@0 964 kfree(agp);
ian@0 965 }
ian@0 966
ian@0 967 static int
ian@0 968 marvel_agp_configure(alpha_agp_info *agp)
ian@0 969 {
ian@0 970 io7_ioport_csrs *csrs = ((struct io7_port *)agp->hose->sysdata)->csrs;
ian@0 971 struct io7 *io7 = ((struct io7_port *)agp->hose->sysdata)->io7;
ian@0 972 unsigned int new_rate = 0;
ian@0 973 unsigned long agp_pll;
ian@0 974
ian@0 975 /*
ian@0 976 * Check the requested mode against the PLL setting.
ian@0 977 * The agpgart_be code has not programmed the card yet,
ian@0 978 * so we can still tweak mode here.
ian@0 979 */
ian@0 980 agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
ian@0 981 switch(IO7_PLL_RNGB(agp_pll)) {
ian@0 982 case 0x4: /* 2x only */
ian@0 983 /*
ian@0 984 * The PLL is only programmed for 2x, so adjust the
ian@0 985 * rate to 2x, if necessary.
ian@0 986 */
ian@0 987 if (agp->mode.bits.rate != 2)
ian@0 988 new_rate = 2;
ian@0 989 break;
ian@0 990
ian@0 991 case 0x6: /* 1x / 4x */
ian@0 992 /*
ian@0 993 * The PLL is programmed for 1x or 4x. Don't go faster
ian@0 994 * than requested, so if the requested rate is 2x, use 1x.
ian@0 995 */
ian@0 996 if (agp->mode.bits.rate == 2)
ian@0 997 new_rate = 1;
ian@0 998 break;
ian@0 999
ian@0 1000 default: /* ??????? */
ian@0 1001 /*
ian@0 1002 * Don't know what this PLL setting is, take the requested
ian@0 1003 * rate, but warn the user.
ian@0 1004 */
ian@0 1005 printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
ian@0 1006 __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
ian@0 1007 break;
ian@0 1008 }
ian@0 1009
ian@0 1010 /*
ian@0 1011 * Set the new rate, if necessary.
ian@0 1012 */
ian@0 1013 if (new_rate) {
ian@0 1014 printk("Requested AGP Rate %dX not compatible "
ian@0 1015 "with PLL setting - using %dX\n",
ian@0 1016 agp->mode.bits.rate,
ian@0 1017 new_rate);
ian@0 1018
ian@0 1019 agp->mode.bits.rate = new_rate;
ian@0 1020 }
ian@0 1021
ian@0 1022 printk("Enabling AGP on hose %d: %dX%s RQ %d\n",
ian@0 1023 agp->hose->index, agp->mode.bits.rate,
ian@0 1024 agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
ian@0 1025
ian@0 1026 csrs->AGP_CMD.csr = agp->mode.lw;
ian@0 1027
ian@0 1028 return 0;
ian@0 1029 }
ian@0 1030
ian@0 1031 static int
ian@0 1032 marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
ian@0 1033 {
ian@0 1034 struct marvel_agp_aperture *aper = agp->aperture.sysdata;
ian@0 1035 return iommu_bind(aper->arena, aper->pg_start + pg_start,
ian@0 1036 mem->page_count, mem->memory);
ian@0 1037 }
ian@0 1038
ian@0 1039 static int
ian@0 1040 marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
ian@0 1041 {
ian@0 1042 struct marvel_agp_aperture *aper = agp->aperture.sysdata;
ian@0 1043 return iommu_unbind(aper->arena, aper->pg_start + pg_start,
ian@0 1044 mem->page_count);
ian@0 1045 }
ian@0 1046
ian@0 1047 static unsigned long
ian@0 1048 marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
ian@0 1049 {
ian@0 1050 struct marvel_agp_aperture *aper = agp->aperture.sysdata;
ian@0 1051 unsigned long baddr = addr - aper->arena->dma_base;
ian@0 1052 unsigned long pte;
ian@0 1053
ian@0 1054 if (addr < agp->aperture.bus_base ||
ian@0 1055 addr >= agp->aperture.bus_base + agp->aperture.size) {
ian@0 1056 printk("%s: addr out of range\n", __FUNCTION__);
ian@0 1057 return -EINVAL;
ian@0 1058 }
ian@0 1059
ian@0 1060 pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
ian@0 1061 if (!(pte & 1)) {
ian@0 1062 printk("%s: pte not valid\n", __FUNCTION__);
ian@0 1063 return -EINVAL;
ian@0 1064 }
ian@0 1065 return (pte >> 1) << PAGE_SHIFT;
ian@0 1066 }
ian@0 1067
ian@0 1068 struct alpha_agp_ops marvel_agp_ops =
ian@0 1069 {
ian@0 1070 .setup = marvel_agp_setup,
ian@0 1071 .cleanup = marvel_agp_cleanup,
ian@0 1072 .configure = marvel_agp_configure,
ian@0 1073 .bind = marvel_agp_bind_memory,
ian@0 1074 .unbind = marvel_agp_unbind_memory,
ian@0 1075 .translate = marvel_agp_translate
ian@0 1076 };
ian@0 1077
ian@0 1078 alpha_agp_info *
ian@0 1079 marvel_agp_info(void)
ian@0 1080 {
ian@0 1081 struct pci_controller *hose;
ian@0 1082 io7_ioport_csrs *csrs;
ian@0 1083 alpha_agp_info *agp;
ian@0 1084 struct io7 *io7;
ian@0 1085
ian@0 1086 /*
ian@0 1087 * Find the first IO7 with an AGP card.
ian@0 1088 *
ian@0 1089 * FIXME -- there should be a better way (we want to be able to
ian@0 1090 * specify and what if the agp card is not video???)
ian@0 1091 */
ian@0 1092 hose = NULL;
ian@0 1093 for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
ian@0 1094 struct pci_controller *h;
ian@0 1095 vuip addr;
ian@0 1096
ian@0 1097 if (!io7->ports[IO7_AGP_PORT].enabled)
ian@0 1098 continue;
ian@0 1099
ian@0 1100 h = io7->ports[IO7_AGP_PORT].hose;
ian@0 1101 addr = (vuip)build_conf_addr(h, 0, PCI_DEVFN(5, 0), 0);
ian@0 1102
ian@0 1103 if (*addr != 0xffffffffu) {
ian@0 1104 hose = h;
ian@0 1105 break;
ian@0 1106 }
ian@0 1107 }
ian@0 1108
ian@0 1109 if (!hose || !hose->sg_pci)
ian@0 1110 return NULL;
ian@0 1111
ian@0 1112 printk("MARVEL - using hose %d as AGP\n", hose->index);
ian@0 1113
ian@0 1114 /*
ian@0 1115 * Get the csrs from the hose.
ian@0 1116 */
ian@0 1117 csrs = ((struct io7_port *)hose->sysdata)->csrs;
ian@0 1118
ian@0 1119 /*
ian@0 1120 * Allocate the info structure.
ian@0 1121 */
ian@0 1122 agp = kmalloc(sizeof(*agp), GFP_KERNEL);
ian@0 1123
ian@0 1124 /*
ian@0 1125 * Fill it in.
ian@0 1126 */
ian@0 1127 agp->hose = hose;
ian@0 1128 agp->private = NULL;
ian@0 1129 agp->ops = &marvel_agp_ops;
ian@0 1130
ian@0 1131 /*
ian@0 1132 * Aperture - not configured until ops.setup().
ian@0 1133 */
ian@0 1134 agp->aperture.bus_base = 0;
ian@0 1135 agp->aperture.size = 0;
ian@0 1136 agp->aperture.sysdata = NULL;
ian@0 1137
ian@0 1138 /*
ian@0 1139 * Capabilities.
ian@0 1140 *
ian@0 1141 * NOTE: IO7 reports through AGP_STAT that it can support a read queue
ian@0 1142 * depth of 17 (rq = 0x10). It actually only supports a depth of
ian@0 1143 * 16 (rq = 0xf).
ian@0 1144 */
ian@0 1145 agp->capability.lw = csrs->AGP_STAT.csr;
ian@0 1146 agp->capability.bits.rq = 0xf;
ian@0 1147
ian@0 1148 /*
ian@0 1149 * Mode.
ian@0 1150 */
ian@0 1151 agp->mode.lw = csrs->AGP_CMD.csr;
ian@0 1152
ian@0 1153 return agp;
ian@0 1154 }