ia64/linux-2.6.18-xen.hg

annotate drivers/nubus/nubus.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 * Macintosh Nubus Interface Code
ian@0 3 *
ian@0 4 * Originally by Alan Cox
ian@0 5 *
ian@0 6 * Mostly rewritten by David Huggins-Daines, C. Scott Ananian,
ian@0 7 * and others.
ian@0 8 */
ian@0 9
ian@0 10 #include <linux/types.h>
ian@0 11 #include <linux/kernel.h>
ian@0 12 #include <linux/string.h>
ian@0 13 #include <linux/nubus.h>
ian@0 14 #include <linux/errno.h>
ian@0 15 #include <linux/init.h>
ian@0 16 #include <linux/delay.h>
ian@0 17 #include <asm/setup.h>
ian@0 18 #include <asm/system.h>
ian@0 19 #include <asm/page.h>
ian@0 20 #include <asm/hwtest.h>
ian@0 21 #include <linux/proc_fs.h>
ian@0 22 #include <asm/mac_via.h>
ian@0 23 #include <asm/mac_oss.h>
ian@0 24
ian@0 25 extern void via_nubus_init(void);
ian@0 26 extern void oss_nubus_init(void);
ian@0 27
ian@0 28 /* Constants */
ian@0 29
ian@0 30 /* This is, of course, the size in bytelanes, rather than the size in
ian@0 31 actual bytes */
ian@0 32 #define FORMAT_BLOCK_SIZE 20
ian@0 33 #define ROM_DIR_OFFSET 0x24
ian@0 34
ian@0 35 #define NUBUS_TEST_PATTERN 0x5A932BC7
ian@0 36
ian@0 37 /* Define this if you like to live dangerously - it is known not to
ian@0 38 work on pretty much every machine except the Quadra 630 and the LC
ian@0 39 III. */
ian@0 40 #undef I_WANT_TO_PROBE_SLOT_ZERO
ian@0 41
ian@0 42 /* This sometimes helps combat failure to boot */
ian@0 43 #undef TRY_TO_DODGE_WSOD
ian@0 44
ian@0 45 /* Globals */
ian@0 46
ian@0 47 struct nubus_dev* nubus_devices;
ian@0 48 struct nubus_board* nubus_boards;
ian@0 49
ian@0 50 /* Meaning of "bytelanes":
ian@0 51
ian@0 52 The card ROM may appear on any or all bytes of each long word in
ian@0 53 NuBus memory. The low 4 bits of the "map" value found in the
ian@0 54 format block (at the top of the slot address space, as well as at
ian@0 55 the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
ian@0 56 offsets within each longword, are valid. Thus:
ian@0 57
ian@0 58 A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
ian@0 59 are valid.
ian@0 60
ian@0 61 A map of 0xf0 means that no bytelanes are valid (We pray that we
ian@0 62 will never encounter this, but stranger things have happened)
ian@0 63
ian@0 64 A map of 0xe1 means that only the MSB of each long word is actually
ian@0 65 part of the card ROM. (We hope to never encounter NuBus on a
ian@0 66 little-endian machine. Again, stranger things have happened)
ian@0 67
ian@0 68 A map of 0x78 means that only the LSB of each long word is valid.
ian@0 69
ian@0 70 Etcetera, etcetera. Hopefully this clears up some confusion over
ian@0 71 what the following code actually does. */
ian@0 72
ian@0 73 static inline int not_useful(void *p, int map)
ian@0 74 {
ian@0 75 unsigned long pv=(unsigned long)p;
ian@0 76 pv &= 3;
ian@0 77 if(map & (1<<pv))
ian@0 78 return 0;
ian@0 79 return 1;
ian@0 80 }
ian@0 81
ian@0 82 static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
ian@0 83 {
ian@0 84 /* This will hold the result */
ian@0 85 unsigned long v = 0;
ian@0 86 unsigned char *p = *ptr;
ian@0 87
ian@0 88 while(len)
ian@0 89 {
ian@0 90 v <<= 8;
ian@0 91 while(not_useful(p,map))
ian@0 92 p++;
ian@0 93 v |= *p++;
ian@0 94 len--;
ian@0 95 }
ian@0 96 *ptr = p;
ian@0 97 return v;
ian@0 98 }
ian@0 99
ian@0 100 static void nubus_rewind(unsigned char **ptr, int len, int map)
ian@0 101 {
ian@0 102 unsigned char *p=*ptr;
ian@0 103
ian@0 104 /* Sanity check */
ian@0 105 if(len > 65536)
ian@0 106 printk(KERN_ERR "rewind of 0x%08x!\n", len);
ian@0 107 while(len)
ian@0 108 {
ian@0 109 do
ian@0 110 {
ian@0 111 p--;
ian@0 112 }
ian@0 113 while(not_useful(p, map));
ian@0 114 len--;
ian@0 115 }
ian@0 116 *ptr=p;
ian@0 117 }
ian@0 118
ian@0 119 static void nubus_advance(unsigned char **ptr, int len, int map)
ian@0 120 {
ian@0 121 unsigned char *p = *ptr;
ian@0 122 if(len>65536)
ian@0 123 printk(KERN_ERR "advance of 0x%08x!\n", len);
ian@0 124 while(len)
ian@0 125 {
ian@0 126 while(not_useful(p,map))
ian@0 127 p++;
ian@0 128 p++;
ian@0 129 len--;
ian@0 130 }
ian@0 131 *ptr = p;
ian@0 132 }
ian@0 133
ian@0 134 static void nubus_move(unsigned char **ptr, int len, int map)
ian@0 135 {
ian@0 136 if(len > 0)
ian@0 137 nubus_advance(ptr, len, map);
ian@0 138 else if(len < 0)
ian@0 139 nubus_rewind(ptr, -len, map);
ian@0 140 }
ian@0 141
ian@0 142 /* Now, functions to read the sResource tree */
ian@0 143
ian@0 144 /* Each sResource entry consists of a 1-byte ID and a 3-byte data
ian@0 145 field. If that data field contains an offset, then obviously we
ian@0 146 have to expand it from a 24-bit signed number to a 32-bit signed
ian@0 147 number. */
ian@0 148
ian@0 149 static inline long nubus_expand32(long foo)
ian@0 150 {
ian@0 151 if(foo & 0x00800000) /* 24bit negative */
ian@0 152 foo |= 0xFF000000;
ian@0 153 return foo;
ian@0 154 }
ian@0 155
ian@0 156 static inline void *nubus_rom_addr(int slot)
ian@0 157 {
ian@0 158 /*
ian@0 159 * Returns the first byte after the card. We then walk
ian@0 160 * backwards to get the lane register and the config
ian@0 161 */
ian@0 162 return (void *)(0xF1000000+(slot<<24));
ian@0 163 }
ian@0 164
ian@0 165 static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
ian@0 166 {
ian@0 167 unsigned char *p = nd->base;
ian@0 168 /* Essentially, just step over the bytelanes using whatever
ian@0 169 offset we might have found */
ian@0 170 nubus_move(&p, nubus_expand32(nd->data), nd->mask);
ian@0 171 /* And return the value */
ian@0 172 return p;
ian@0 173 }
ian@0 174
ian@0 175 /* These two are for pulling resource data blocks (i.e. stuff that's
ian@0 176 pointed to with offsets) out of the card ROM. */
ian@0 177
ian@0 178 void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent* dirent,
ian@0 179 int len)
ian@0 180 {
ian@0 181 unsigned char *t = (unsigned char *)dest;
ian@0 182 unsigned char *p = nubus_dirptr(dirent);
ian@0 183 while(len)
ian@0 184 {
ian@0 185 *t++ = nubus_get_rom(&p, 1, dirent->mask);
ian@0 186 len--;
ian@0 187 }
ian@0 188 }
ian@0 189
ian@0 190 void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent,
ian@0 191 int len)
ian@0 192 {
ian@0 193 unsigned char *t=(unsigned char *)dest;
ian@0 194 unsigned char *p = nubus_dirptr(dirent);
ian@0 195 while(len)
ian@0 196 {
ian@0 197 *t = nubus_get_rom(&p, 1, dirent->mask);
ian@0 198 if(!*t++)
ian@0 199 break;
ian@0 200 len--;
ian@0 201 }
ian@0 202 }
ian@0 203
ian@0 204 int nubus_get_root_dir(const struct nubus_board* board,
ian@0 205 struct nubus_dir* dir)
ian@0 206 {
ian@0 207 dir->ptr = dir->base = board->directory;
ian@0 208 dir->done = 0;
ian@0 209 dir->mask = board->lanes;
ian@0 210 return 0;
ian@0 211 }
ian@0 212
ian@0 213 /* This is a slyly renamed version of the above */
ian@0 214 int nubus_get_func_dir(const struct nubus_dev* dev,
ian@0 215 struct nubus_dir* dir)
ian@0 216 {
ian@0 217 dir->ptr = dir->base = dev->directory;
ian@0 218 dir->done = 0;
ian@0 219 dir->mask = dev->board->lanes;
ian@0 220 return 0;
ian@0 221 }
ian@0 222
ian@0 223 int nubus_get_board_dir(const struct nubus_board* board,
ian@0 224 struct nubus_dir* dir)
ian@0 225 {
ian@0 226 struct nubus_dirent ent;
ian@0 227
ian@0 228 dir->ptr = dir->base = board->directory;
ian@0 229 dir->done = 0;
ian@0 230 dir->mask = board->lanes;
ian@0 231
ian@0 232 /* Now dereference it (the first directory is always the board
ian@0 233 directory) */
ian@0 234 if (nubus_readdir(dir, &ent) == -1)
ian@0 235 return -1;
ian@0 236 if (nubus_get_subdir(&ent, dir) == -1)
ian@0 237 return -1;
ian@0 238 return 0;
ian@0 239 }
ian@0 240
ian@0 241 int nubus_get_subdir(const struct nubus_dirent *ent,
ian@0 242 struct nubus_dir *dir)
ian@0 243 {
ian@0 244 dir->ptr = dir->base = nubus_dirptr(ent);
ian@0 245 dir->done = 0;
ian@0 246 dir->mask = ent->mask;
ian@0 247 return 0;
ian@0 248 }
ian@0 249
ian@0 250 int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
ian@0 251 {
ian@0 252 u32 resid;
ian@0 253 if (nd->done)
ian@0 254 return -1;
ian@0 255
ian@0 256 /* Do this first, otherwise nubus_rewind & co are off by 4 */
ian@0 257 ent->base = nd->ptr;
ian@0 258
ian@0 259 /* This moves nd->ptr forward */
ian@0 260 resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
ian@0 261
ian@0 262 /* EOL marker, as per the Apple docs */
ian@0 263 if((resid&0xff000000) == 0xff000000)
ian@0 264 {
ian@0 265 /* Mark it as done */
ian@0 266 nd->done = 1;
ian@0 267 return -1;
ian@0 268 }
ian@0 269
ian@0 270 /* First byte is the resource ID */
ian@0 271 ent->type = resid >> 24;
ian@0 272 /* Low 3 bytes might contain data (or might not) */
ian@0 273 ent->data = resid & 0xffffff;
ian@0 274 ent->mask = nd->mask;
ian@0 275 return 0;
ian@0 276 }
ian@0 277
ian@0 278 int nubus_rewinddir(struct nubus_dir* dir)
ian@0 279 {
ian@0 280 dir->ptr = dir->base;
ian@0 281 return 0;
ian@0 282 }
ian@0 283
ian@0 284 /* Driver interface functions, more or less like in pci.c */
ian@0 285
ian@0 286 struct nubus_dev*
ian@0 287 nubus_find_device(unsigned short category,
ian@0 288 unsigned short type,
ian@0 289 unsigned short dr_hw,
ian@0 290 unsigned short dr_sw,
ian@0 291 const struct nubus_dev* from)
ian@0 292 {
ian@0 293 struct nubus_dev* itor =
ian@0 294 from ? from->next : nubus_devices;
ian@0 295
ian@0 296 while (itor) {
ian@0 297 if (itor->category == category
ian@0 298 && itor->type == type
ian@0 299 && itor->dr_hw == dr_hw
ian@0 300 && itor->dr_sw == dr_sw)
ian@0 301 return itor;
ian@0 302 itor = itor->next;
ian@0 303 }
ian@0 304 return NULL;
ian@0 305 }
ian@0 306
ian@0 307 struct nubus_dev*
ian@0 308 nubus_find_type(unsigned short category,
ian@0 309 unsigned short type,
ian@0 310 const struct nubus_dev* from)
ian@0 311 {
ian@0 312 struct nubus_dev* itor =
ian@0 313 from ? from->next : nubus_devices;
ian@0 314
ian@0 315 while (itor) {
ian@0 316 if (itor->category == category
ian@0 317 && itor->type == type)
ian@0 318 return itor;
ian@0 319 itor = itor->next;
ian@0 320 }
ian@0 321 return NULL;
ian@0 322 }
ian@0 323
ian@0 324 struct nubus_dev*
ian@0 325 nubus_find_slot(unsigned int slot,
ian@0 326 const struct nubus_dev* from)
ian@0 327 {
ian@0 328 struct nubus_dev* itor =
ian@0 329 from ? from->next : nubus_devices;
ian@0 330
ian@0 331 while (itor) {
ian@0 332 if (itor->board->slot == slot)
ian@0 333 return itor;
ian@0 334 itor = itor->next;
ian@0 335 }
ian@0 336 return NULL;
ian@0 337 }
ian@0 338
ian@0 339 int
ian@0 340 nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type,
ian@0 341 struct nubus_dirent* ent)
ian@0 342 {
ian@0 343 while (nubus_readdir(dir, ent) != -1) {
ian@0 344 if (ent->type == rsrc_type)
ian@0 345 return 0;
ian@0 346 }
ian@0 347 return -1;
ian@0 348 }
ian@0 349
ian@0 350 /* Initialization functions - decide which slots contain stuff worth
ian@0 351 looking at, and print out lots and lots of information from the
ian@0 352 resource blocks. */
ian@0 353
ian@0 354 /* FIXME: A lot of this stuff will eventually be useful after
ian@0 355 initializaton, for intelligently probing Ethernet and video chips,
ian@0 356 among other things. The rest of it should go in the /proc code.
ian@0 357 For now, we just use it to give verbose boot logs. */
ian@0 358
ian@0 359 static int __init nubus_show_display_resource(struct nubus_dev* dev,
ian@0 360 const struct nubus_dirent* ent)
ian@0 361 {
ian@0 362 switch (ent->type) {
ian@0 363 case NUBUS_RESID_GAMMADIR:
ian@0 364 printk(KERN_INFO " gamma directory offset: 0x%06x\n", ent->data);
ian@0 365 break;
ian@0 366 case 0x0080 ... 0x0085:
ian@0 367 printk(KERN_INFO " mode %02X info offset: 0x%06x\n",
ian@0 368 ent->type, ent->data);
ian@0 369 break;
ian@0 370 default:
ian@0 371 printk(KERN_INFO " unknown resource %02X, data 0x%06x\n",
ian@0 372 ent->type, ent->data);
ian@0 373 }
ian@0 374 return 0;
ian@0 375 }
ian@0 376
ian@0 377 static int __init nubus_show_network_resource(struct nubus_dev* dev,
ian@0 378 const struct nubus_dirent* ent)
ian@0 379 {
ian@0 380 switch (ent->type) {
ian@0 381 case NUBUS_RESID_MAC_ADDRESS:
ian@0 382 {
ian@0 383 char addr[6];
ian@0 384 int i;
ian@0 385
ian@0 386 nubus_get_rsrc_mem(addr, ent, 6);
ian@0 387 printk(KERN_INFO " MAC address: ");
ian@0 388 for (i = 0; i < 6; i++)
ian@0 389 printk("%02x%s", addr[i] & 0xff,
ian@0 390 i == 5 ? "" : ":");
ian@0 391 printk("\n");
ian@0 392 break;
ian@0 393 }
ian@0 394 default:
ian@0 395 printk(KERN_INFO " unknown resource %02X, data 0x%06x\n",
ian@0 396 ent->type, ent->data);
ian@0 397 }
ian@0 398 return 0;
ian@0 399 }
ian@0 400
ian@0 401 static int __init nubus_show_cpu_resource(struct nubus_dev* dev,
ian@0 402 const struct nubus_dirent* ent)
ian@0 403 {
ian@0 404 switch (ent->type) {
ian@0 405 case NUBUS_RESID_MEMINFO:
ian@0 406 {
ian@0 407 unsigned long meminfo[2];
ian@0 408 nubus_get_rsrc_mem(&meminfo, ent, 8);
ian@0 409 printk(KERN_INFO " memory: [ 0x%08lx 0x%08lx ]\n",
ian@0 410 meminfo[0], meminfo[1]);
ian@0 411 break;
ian@0 412 }
ian@0 413 case NUBUS_RESID_ROMINFO:
ian@0 414 {
ian@0 415 unsigned long rominfo[2];
ian@0 416 nubus_get_rsrc_mem(&rominfo, ent, 8);
ian@0 417 printk(KERN_INFO " ROM: [ 0x%08lx 0x%08lx ]\n",
ian@0 418 rominfo[0], rominfo[1]);
ian@0 419 break;
ian@0 420 }
ian@0 421 default:
ian@0 422 printk(KERN_INFO " unknown resource %02X, data 0x%06x\n",
ian@0 423 ent->type, ent->data);
ian@0 424 }
ian@0 425 return 0;
ian@0 426 }
ian@0 427
ian@0 428 static int __init nubus_show_private_resource(struct nubus_dev* dev,
ian@0 429 const struct nubus_dirent* ent)
ian@0 430 {
ian@0 431 switch (dev->category) {
ian@0 432 case NUBUS_CAT_DISPLAY:
ian@0 433 nubus_show_display_resource(dev, ent);
ian@0 434 break;
ian@0 435 case NUBUS_CAT_NETWORK:
ian@0 436 nubus_show_network_resource(dev, ent);
ian@0 437 break;
ian@0 438 case NUBUS_CAT_CPU:
ian@0 439 nubus_show_cpu_resource(dev, ent);
ian@0 440 break;
ian@0 441 default:
ian@0 442 printk(KERN_INFO " unknown resource %02X, data 0x%06x\n",
ian@0 443 ent->type, ent->data);
ian@0 444 }
ian@0 445 return 0;
ian@0 446 }
ian@0 447
ian@0 448 static struct nubus_dev* __init
ian@0 449 nubus_get_functional_resource(struct nubus_board* board,
ian@0 450 int slot,
ian@0 451 const struct nubus_dirent* parent)
ian@0 452 {
ian@0 453 struct nubus_dir dir;
ian@0 454 struct nubus_dirent ent;
ian@0 455 struct nubus_dev* dev;
ian@0 456
ian@0 457 printk(KERN_INFO " Function 0x%02x:\n", parent->type);
ian@0 458 nubus_get_subdir(parent, &dir);
ian@0 459
ian@0 460 /* Apple seems to have botched the ROM on the IIx */
ian@0 461 if (slot == 0 && (unsigned long)dir.base % 2)
ian@0 462 dir.base += 1;
ian@0 463
ian@0 464 if (console_loglevel >= 10)
ian@0 465 printk(KERN_DEBUG "nubus_get_functional_resource: parent is 0x%p, dir is 0x%p\n",
ian@0 466 parent->base, dir.base);
ian@0 467
ian@0 468 /* Actually we should probably panic if this fails */
ian@0 469 if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
ian@0 470 return NULL;
ian@0 471 memset(dev, 0, sizeof(*dev));
ian@0 472 dev->resid = parent->type;
ian@0 473 dev->directory = dir.base;
ian@0 474 dev->board = board;
ian@0 475
ian@0 476 while (nubus_readdir(&dir, &ent) != -1)
ian@0 477 {
ian@0 478 switch(ent.type)
ian@0 479 {
ian@0 480 case NUBUS_RESID_TYPE:
ian@0 481 {
ian@0 482 unsigned short nbtdata[4];
ian@0 483 nubus_get_rsrc_mem(nbtdata, &ent, 8);
ian@0 484 dev->category = nbtdata[0];
ian@0 485 dev->type = nbtdata[1];
ian@0 486 dev->dr_sw = nbtdata[2];
ian@0 487 dev->dr_hw = nbtdata[3];
ian@0 488 printk(KERN_INFO " type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n",
ian@0 489 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
ian@0 490 break;
ian@0 491 }
ian@0 492 case NUBUS_RESID_NAME:
ian@0 493 {
ian@0 494 nubus_get_rsrc_str(dev->name, &ent, 64);
ian@0 495 printk(KERN_INFO " name: %s\n", dev->name);
ian@0 496 break;
ian@0 497 }
ian@0 498 case NUBUS_RESID_DRVRDIR:
ian@0 499 {
ian@0 500 /* MacOS driver. If we were NetBSD we might
ian@0 501 use this :-) */
ian@0 502 struct nubus_dir drvr_dir;
ian@0 503 struct nubus_dirent drvr_ent;
ian@0 504 nubus_get_subdir(&ent, &drvr_dir);
ian@0 505 nubus_readdir(&drvr_dir, &drvr_ent);
ian@0 506 dev->driver = nubus_dirptr(&drvr_ent);
ian@0 507 printk(KERN_INFO " driver at: 0x%p\n",
ian@0 508 dev->driver);
ian@0 509 break;
ian@0 510 }
ian@0 511 case NUBUS_RESID_MINOR_BASEOS:
ian@0 512 /* We will need this in order to support
ian@0 513 multiple framebuffers. It might be handy
ian@0 514 for Ethernet as well */
ian@0 515 nubus_get_rsrc_mem(&dev->iobase, &ent, 4);
ian@0 516 printk(KERN_INFO " memory offset: 0x%08lx\n",
ian@0 517 dev->iobase);
ian@0 518 break;
ian@0 519 case NUBUS_RESID_MINOR_LENGTH:
ian@0 520 /* Ditto */
ian@0 521 nubus_get_rsrc_mem(&dev->iosize, &ent, 4);
ian@0 522 printk(KERN_INFO " memory length: 0x%08lx\n",
ian@0 523 dev->iosize);
ian@0 524 break;
ian@0 525 case NUBUS_RESID_FLAGS:
ian@0 526 dev->flags = ent.data;
ian@0 527 printk(KERN_INFO " flags: 0x%06x\n", dev->flags);
ian@0 528 break;
ian@0 529 case NUBUS_RESID_HWDEVID:
ian@0 530 dev->hwdevid = ent.data;
ian@0 531 printk(KERN_INFO " hwdevid: 0x%06x\n", dev->hwdevid);
ian@0 532 break;
ian@0 533 default:
ian@0 534 /* Local/Private resources have their own
ian@0 535 function */
ian@0 536 nubus_show_private_resource(dev, &ent);
ian@0 537 }
ian@0 538 }
ian@0 539
ian@0 540 return dev;
ian@0 541 }
ian@0 542
ian@0 543 /* This is cool. */
ian@0 544 static int __init nubus_get_vidnames(struct nubus_board* board,
ian@0 545 const struct nubus_dirent* parent)
ian@0 546 {
ian@0 547 struct nubus_dir dir;
ian@0 548 struct nubus_dirent ent;
ian@0 549 /* FIXME: obviously we want to put this in a header file soon */
ian@0 550 struct vidmode {
ian@0 551 u32 size;
ian@0 552 /* Don't know what this is yet */
ian@0 553 u16 id;
ian@0 554 /* Longest one I've seen so far is 26 characters */
ian@0 555 char name[32];
ian@0 556 };
ian@0 557
ian@0 558 printk(KERN_INFO " video modes supported:\n");
ian@0 559 nubus_get_subdir(parent, &dir);
ian@0 560 if (console_loglevel >= 10)
ian@0 561 printk(KERN_DEBUG "nubus_get_vidnames: parent is 0x%p, dir is 0x%p\n",
ian@0 562 parent->base, dir.base);
ian@0 563
ian@0 564 while(nubus_readdir(&dir, &ent) != -1)
ian@0 565 {
ian@0 566 struct vidmode mode;
ian@0 567 u32 size;
ian@0 568
ian@0 569 /* First get the length */
ian@0 570 nubus_get_rsrc_mem(&size, &ent, 4);
ian@0 571
ian@0 572 /* Now clobber the whole thing */
ian@0 573 if (size > sizeof(mode) - 1)
ian@0 574 size = sizeof(mode) - 1;
ian@0 575 memset(&mode, 0, sizeof(mode));
ian@0 576 nubus_get_rsrc_mem(&mode, &ent, size);
ian@0 577 printk (KERN_INFO " %02X: (%02X) %s\n", ent.type,
ian@0 578 mode.id, mode.name);
ian@0 579 }
ian@0 580 return 0;
ian@0 581 }
ian@0 582
ian@0 583 /* This is *really* cool. */
ian@0 584 static int __init nubus_get_icon(struct nubus_board* board,
ian@0 585 const struct nubus_dirent* ent)
ian@0 586 {
ian@0 587 /* Should be 32x32 if my memory serves me correctly */
ian@0 588 unsigned char icon[128];
ian@0 589 int x, y;
ian@0 590
ian@0 591 nubus_get_rsrc_mem(&icon, ent, 128);
ian@0 592 printk(KERN_INFO " icon:\n");
ian@0 593
ian@0 594 /* We should actually plot these somewhere in the framebuffer
ian@0 595 init. This is just to demonstrate that they do, in fact,
ian@0 596 exist */
ian@0 597 for (y = 0; y < 32; y++) {
ian@0 598 printk(KERN_INFO " ");
ian@0 599 for (x = 0; x < 32; x++) {
ian@0 600 if (icon[y*4 + x/8]
ian@0 601 & (0x80 >> (x%8)))
ian@0 602 printk("*");
ian@0 603 else
ian@0 604 printk(" ");
ian@0 605 }
ian@0 606 printk("\n");
ian@0 607 }
ian@0 608 return 0;
ian@0 609 }
ian@0 610
ian@0 611 static int __init nubus_get_vendorinfo(struct nubus_board* board,
ian@0 612 const struct nubus_dirent* parent)
ian@0 613 {
ian@0 614 struct nubus_dir dir;
ian@0 615 struct nubus_dirent ent;
ian@0 616 static char* vendor_fields[6] = {"ID", "serial", "revision",
ian@0 617 "part", "date", "unknown field"};
ian@0 618
ian@0 619 printk(KERN_INFO " vendor info:\n");
ian@0 620 nubus_get_subdir(parent, &dir);
ian@0 621 if (console_loglevel >= 10)
ian@0 622 printk(KERN_DEBUG "nubus_get_vendorinfo: parent is 0x%p, dir is 0x%p\n",
ian@0 623 parent->base, dir.base);
ian@0 624
ian@0 625 while(nubus_readdir(&dir, &ent) != -1)
ian@0 626 {
ian@0 627 char name[64];
ian@0 628
ian@0 629 /* These are all strings, we think */
ian@0 630 nubus_get_rsrc_str(name, &ent, 64);
ian@0 631 if (ent.type > 5)
ian@0 632 ent.type = 5;
ian@0 633 printk(KERN_INFO " %s: %s\n",
ian@0 634 vendor_fields[ent.type-1], name);
ian@0 635 }
ian@0 636 return 0;
ian@0 637 }
ian@0 638
ian@0 639 static int __init nubus_get_board_resource(struct nubus_board* board, int slot,
ian@0 640 const struct nubus_dirent* parent)
ian@0 641 {
ian@0 642 struct nubus_dir dir;
ian@0 643 struct nubus_dirent ent;
ian@0 644
ian@0 645 nubus_get_subdir(parent, &dir);
ian@0 646 if (console_loglevel >= 10)
ian@0 647 printk(KERN_DEBUG "nubus_get_board_resource: parent is 0x%p, dir is 0x%p\n",
ian@0 648 parent->base, dir.base);
ian@0 649
ian@0 650 while(nubus_readdir(&dir, &ent) != -1)
ian@0 651 {
ian@0 652 switch (ent.type) {
ian@0 653 case NUBUS_RESID_TYPE:
ian@0 654 {
ian@0 655 unsigned short nbtdata[4];
ian@0 656 /* This type is always the same, and is not
ian@0 657 useful except insofar as it tells us that
ian@0 658 we really are looking at a board resource. */
ian@0 659 nubus_get_rsrc_mem(nbtdata, &ent, 8);
ian@0 660 printk(KERN_INFO " type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n",
ian@0 661 nbtdata[0], nbtdata[1], nbtdata[2],
ian@0 662 nbtdata[3]);
ian@0 663 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
ian@0 664 nbtdata[2] != 0 || nbtdata[3] != 0)
ian@0 665 printk(KERN_ERR "this sResource is not a board resource!\n");
ian@0 666 break;
ian@0 667 }
ian@0 668 case NUBUS_RESID_NAME:
ian@0 669 nubus_get_rsrc_str(board->name, &ent, 64);
ian@0 670 printk(KERN_INFO " name: %s\n", board->name);
ian@0 671 break;
ian@0 672 case NUBUS_RESID_ICON:
ian@0 673 nubus_get_icon(board, &ent);
ian@0 674 break;
ian@0 675 case NUBUS_RESID_BOARDID:
ian@0 676 printk(KERN_INFO " board id: 0x%x\n", ent.data);
ian@0 677 break;
ian@0 678 case NUBUS_RESID_PRIMARYINIT:
ian@0 679 printk(KERN_INFO " primary init offset: 0x%06x\n", ent.data);
ian@0 680 break;
ian@0 681 case NUBUS_RESID_VENDORINFO:
ian@0 682 nubus_get_vendorinfo(board, &ent);
ian@0 683 break;
ian@0 684 case NUBUS_RESID_FLAGS:
ian@0 685 printk(KERN_INFO " flags: 0x%06x\n", ent.data);
ian@0 686 break;
ian@0 687 case NUBUS_RESID_HWDEVID:
ian@0 688 printk(KERN_INFO " hwdevid: 0x%06x\n", ent.data);
ian@0 689 break;
ian@0 690 case NUBUS_RESID_SECONDINIT:
ian@0 691 printk(KERN_INFO " secondary init offset: 0x%06x\n", ent.data);
ian@0 692 break;
ian@0 693 /* WTF isn't this in the functional resources? */
ian@0 694 case NUBUS_RESID_VIDNAMES:
ian@0 695 nubus_get_vidnames(board, &ent);
ian@0 696 break;
ian@0 697 /* Same goes for this */
ian@0 698 case NUBUS_RESID_VIDMODES:
ian@0 699 printk(KERN_INFO " video mode parameter directory offset: 0x%06x\n",
ian@0 700 ent.data);
ian@0 701 break;
ian@0 702 default:
ian@0 703 printk(KERN_INFO " unknown resource %02X, data 0x%06x\n",
ian@0 704 ent.type, ent.data);
ian@0 705 }
ian@0 706 }
ian@0 707 return 0;
ian@0 708 }
ian@0 709
ian@0 710 /* Attempt to bypass the somewhat non-obvious arrangement of
ian@0 711 sResources in the motherboard ROM */
ian@0 712 static void __init nubus_find_rom_dir(struct nubus_board* board)
ian@0 713 {
ian@0 714 unsigned char* rp;
ian@0 715 unsigned char* romdir;
ian@0 716 struct nubus_dir dir;
ian@0 717 struct nubus_dirent ent;
ian@0 718
ian@0 719 /* Check for the extra directory just under the format block */
ian@0 720 rp = board->fblock;
ian@0 721 nubus_rewind(&rp, 4, board->lanes);
ian@0 722 if (nubus_get_rom(&rp, 4, board->lanes) != NUBUS_TEST_PATTERN) {
ian@0 723 /* OK, the ROM was telling the truth */
ian@0 724 board->directory = board->fblock;
ian@0 725 nubus_move(&board->directory,
ian@0 726 nubus_expand32(board->doffset),
ian@0 727 board->lanes);
ian@0 728 return;
ian@0 729 }
ian@0 730
ian@0 731 /* On "slot zero", you have to walk down a few more
ian@0 732 directories to get to the equivalent of a real card's root
ian@0 733 directory. We don't know what they were smoking when they
ian@0 734 came up with this. */
ian@0 735 romdir = nubus_rom_addr(board->slot);
ian@0 736 nubus_rewind(&romdir, ROM_DIR_OFFSET, board->lanes);
ian@0 737 dir.base = dir.ptr = romdir;
ian@0 738 dir.done = 0;
ian@0 739 dir.mask = board->lanes;
ian@0 740
ian@0 741 /* This one points to an "Unknown Macintosh" directory */
ian@0 742 if (nubus_readdir(&dir, &ent) == -1)
ian@0 743 goto badrom;
ian@0 744
ian@0 745 if (console_loglevel >= 10)
ian@0 746 printk(KERN_INFO "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
ian@0 747 /* This one takes us to where we want to go. */
ian@0 748 if (nubus_readdir(&dir, &ent) == -1)
ian@0 749 goto badrom;
ian@0 750 if (console_loglevel >= 10)
ian@0 751 printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
ian@0 752 nubus_get_subdir(&ent, &dir);
ian@0 753
ian@0 754 /* Resource ID 01, also an "Unknown Macintosh" */
ian@0 755 if (nubus_readdir(&dir, &ent) == -1)
ian@0 756 goto badrom;
ian@0 757 if (console_loglevel >= 10)
ian@0 758 printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
ian@0 759
ian@0 760 /* FIXME: the first one is *not* always the right one. We
ian@0 761 suspect this has something to do with the ROM revision.
ian@0 762 "The HORROR ROM" (LC-series) uses 0x7e, while "The HORROR
ian@0 763 Continues" (Q630) uses 0x7b. The DAFB Macs evidently use
ian@0 764 something else. Please run "Slots" on your Mac (see
ian@0 765 include/linux/nubus.h for where to get this program) and
ian@0 766 tell us where the 'SiDirPtr' for Slot 0 is. If you feel
ian@0 767 brave, you should also use MacsBug to walk down the ROM
ian@0 768 directories like this function does and try to find the
ian@0 769 path to that address... */
ian@0 770 if (nubus_readdir(&dir, &ent) == -1)
ian@0 771 goto badrom;
ian@0 772 if (console_loglevel >= 10)
ian@0 773 printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
ian@0 774
ian@0 775 /* Bwahahahaha... */
ian@0 776 nubus_get_subdir(&ent, &dir);
ian@0 777 board->directory = dir.base;
ian@0 778 return;
ian@0 779
ian@0 780 /* Even more evil laughter... */
ian@0 781 badrom:
ian@0 782 board->directory = board->fblock;
ian@0 783 nubus_move(&board->directory, nubus_expand32(board->doffset), board->lanes);
ian@0 784 printk(KERN_ERR "nubus_get_rom_dir: ROM weirdness! Notify the developers...\n");
ian@0 785 }
ian@0 786
ian@0 787 /* Add a board (might be many devices) to the list */
ian@0 788 static struct nubus_board* __init nubus_add_board(int slot, int bytelanes)
ian@0 789 {
ian@0 790 struct nubus_board* board;
ian@0 791 struct nubus_board** boardp;
ian@0 792
ian@0 793 unsigned char *rp;
ian@0 794 unsigned long dpat;
ian@0 795 struct nubus_dir dir;
ian@0 796 struct nubus_dirent ent;
ian@0 797
ian@0 798 /* Move to the start of the format block */
ian@0 799 rp = nubus_rom_addr(slot);
ian@0 800 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
ian@0 801
ian@0 802 /* Actually we should probably panic if this fails */
ian@0 803 if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
ian@0 804 return NULL;
ian@0 805 memset(board, 0, sizeof(*board));
ian@0 806 board->fblock = rp;
ian@0 807
ian@0 808 /* Dump the format block for debugging purposes */
ian@0 809 if (console_loglevel >= 10) {
ian@0 810 int i;
ian@0 811 printk(KERN_DEBUG "Slot %X, format block at 0x%p\n",
ian@0 812 slot, rp);
ian@0 813 printk(KERN_DEBUG "Format block: ");
ian@0 814 for (i = 0; i < FORMAT_BLOCK_SIZE; i += 4) {
ian@0 815 unsigned short foo, bar;
ian@0 816 foo = nubus_get_rom(&rp, 2, bytelanes);
ian@0 817 bar = nubus_get_rom(&rp, 2, bytelanes);
ian@0 818 printk("%04x %04x ", foo, bar);
ian@0 819 }
ian@0 820 printk("\n");
ian@0 821 rp = board->fblock;
ian@0 822 }
ian@0 823
ian@0 824 board->slot = slot;
ian@0 825 board->slot_addr = (unsigned long) nubus_slot_addr(slot);
ian@0 826 board->doffset = nubus_get_rom(&rp, 4, bytelanes);
ian@0 827 /* rom_length is *supposed* to be the total length of the
ian@0 828 * ROM. In practice it is the "amount of ROM used to compute
ian@0 829 * the CRC." So some jokers decide to set it to zero and
ian@0 830 * set the crc to zero so they don't have to do any math.
ian@0 831 * See the Performa 460 ROM, for example. Those Apple "engineers".
ian@0 832 */
ian@0 833 board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
ian@0 834 board->crc = nubus_get_rom(&rp, 4, bytelanes);
ian@0 835 board->rev = nubus_get_rom(&rp, 1, bytelanes);
ian@0 836 board->format = nubus_get_rom(&rp,1, bytelanes);
ian@0 837 board->lanes = bytelanes;
ian@0 838
ian@0 839 /* Directory offset should be small and negative... */
ian@0 840 if(!(board->doffset & 0x00FF0000))
ian@0 841 printk(KERN_WARNING "Dodgy doffset!\n");
ian@0 842 dpat = nubus_get_rom(&rp, 4, bytelanes);
ian@0 843 if(dpat != NUBUS_TEST_PATTERN)
ian@0 844 printk(KERN_WARNING "Wrong test pattern %08lx!\n", dpat);
ian@0 845
ian@0 846 /*
ian@0 847 * I wonder how the CRC is meant to work -
ian@0 848 * any takers ?
ian@0 849 * CSA: According to MAC docs, not all cards pass the CRC anyway,
ian@0 850 * since the initial Macintosh ROM releases skipped the check.
ian@0 851 */
ian@0 852
ian@0 853 /* Attempt to work around slot zero weirdness */
ian@0 854 nubus_find_rom_dir(board);
ian@0 855 nubus_get_root_dir(board, &dir);
ian@0 856
ian@0 857 /* We're ready to rock */
ian@0 858 printk(KERN_INFO "Slot %X:\n", slot);
ian@0 859
ian@0 860 /* Each slot should have one board resource and any number of
ian@0 861 functional resources. So we'll fill in some fields in the
ian@0 862 struct nubus_board from the board resource, then walk down
ian@0 863 the list of functional resources, spinning out a nubus_dev
ian@0 864 for each of them. */
ian@0 865 if (nubus_readdir(&dir, &ent) == -1) {
ian@0 866 /* We can't have this! */
ian@0 867 printk(KERN_ERR "Board resource not found!\n");
ian@0 868 return NULL;
ian@0 869 } else {
ian@0 870 printk(KERN_INFO " Board resource:\n");
ian@0 871 nubus_get_board_resource(board, slot, &ent);
ian@0 872 }
ian@0 873
ian@0 874 /* Aaaarrrrgghh! The LC III motherboard has *two* board
ian@0 875 resources. I have no idea WTF to do about this. */
ian@0 876
ian@0 877 while (nubus_readdir(&dir, &ent) != -1) {
ian@0 878 struct nubus_dev* dev;
ian@0 879 struct nubus_dev** devp;
ian@0 880 dev = nubus_get_functional_resource(board, slot, &ent);
ian@0 881 if (dev == NULL)
ian@0 882 continue;
ian@0 883
ian@0 884 /* We zeroed this out above */
ian@0 885 if (board->first_dev == NULL)
ian@0 886 board->first_dev = dev;
ian@0 887
ian@0 888 /* Put it on the global NuBus device chain. Keep entries in order. */
ian@0 889 for (devp=&nubus_devices; *devp!=NULL; devp=&((*devp)->next))
ian@0 890 /* spin */;
ian@0 891 *devp = dev;
ian@0 892 dev->next = NULL;
ian@0 893 }
ian@0 894
ian@0 895 /* Put it on the global NuBus board chain. Keep entries in order. */
ian@0 896 for (boardp=&nubus_boards; *boardp!=NULL; boardp=&((*boardp)->next))
ian@0 897 /* spin */;
ian@0 898 *boardp = board;
ian@0 899 board->next = NULL;
ian@0 900
ian@0 901 return board;
ian@0 902 }
ian@0 903
ian@0 904 void __init nubus_probe_slot(int slot)
ian@0 905 {
ian@0 906 unsigned char dp;
ian@0 907 unsigned char* rp;
ian@0 908 int i;
ian@0 909
ian@0 910 rp = nubus_rom_addr(slot);
ian@0 911 for(i = 4; i; i--)
ian@0 912 {
ian@0 913 unsigned long flags;
ian@0 914 int card_present;
ian@0 915
ian@0 916 rp--;
ian@0 917 local_irq_save(flags);
ian@0 918 card_present = hwreg_present(rp);
ian@0 919 local_irq_restore(flags);
ian@0 920
ian@0 921 if (!card_present)
ian@0 922 continue;
ian@0 923
ian@0 924 printk(KERN_DEBUG "Now probing slot %X at %p\n", slot, rp);
ian@0 925 dp = *rp;
ian@0 926 if(dp == 0)
ian@0 927 continue;
ian@0 928
ian@0 929 /* The last byte of the format block consists of two
ian@0 930 nybbles which are "mirror images" of each other.
ian@0 931 These show us the valid bytelanes */
ian@0 932 if ((((dp>>4) ^ dp) & 0x0F) != 0x0F)
ian@0 933 continue;
ian@0 934 /* Check that this value is actually *on* one of the
ian@0 935 bytelanes it claims are valid! */
ian@0 936 if ((dp & 0x0F) >= (1<<i))
ian@0 937 continue;
ian@0 938
ian@0 939 /* Looks promising. Let's put it on the list. */
ian@0 940 nubus_add_board(slot, dp);
ian@0 941
ian@0 942 return;
ian@0 943 }
ian@0 944 }
ian@0 945
ian@0 946 #if defined(CONFIG_PROC_FS)
ian@0 947
ian@0 948 /* /proc/nubus stuff */
ian@0 949
ian@0 950 static int sprint_nubus_board(struct nubus_board* board, char* ptr, int len)
ian@0 951 {
ian@0 952 if(len < 100)
ian@0 953 return -1;
ian@0 954
ian@0 955 sprintf(ptr, "Slot %X: %s\n",
ian@0 956 board->slot, board->name);
ian@0 957
ian@0 958 return strlen(ptr);
ian@0 959 }
ian@0 960
ian@0 961 static int nubus_read_proc(char *page, char **start, off_t off,
ian@0 962 int count, int *eof, void *data)
ian@0 963 {
ian@0 964 int nprinted, len, begin = 0;
ian@0 965 int size = PAGE_SIZE;
ian@0 966 struct nubus_board* board;
ian@0 967
ian@0 968 len = sprintf(page, "Nubus devices found:\n");
ian@0 969 /* Walk the list of NuBus boards */
ian@0 970 for (board = nubus_boards; board != NULL; board = board->next)
ian@0 971 {
ian@0 972 nprinted = sprint_nubus_board(board, page + len, size - len);
ian@0 973 if (nprinted < 0)
ian@0 974 break;
ian@0 975 len += nprinted;
ian@0 976 if (len+begin < off) {
ian@0 977 begin += len;
ian@0 978 len = 0;
ian@0 979 }
ian@0 980 if (len+begin >= off+count)
ian@0 981 break;
ian@0 982 }
ian@0 983 if (len+begin < off)
ian@0 984 *eof = 1;
ian@0 985 off -= begin;
ian@0 986 *start = page + off;
ian@0 987 len -= off;
ian@0 988 if (len>count)
ian@0 989 len = count;
ian@0 990 if (len<0)
ian@0 991 len = 0;
ian@0 992 return len;
ian@0 993 }
ian@0 994 #endif
ian@0 995
ian@0 996 void __init nubus_scan_bus(void)
ian@0 997 {
ian@0 998 int slot;
ian@0 999 /* This might not work on your machine */
ian@0 1000 #ifdef I_WANT_TO_PROBE_SLOT_ZERO
ian@0 1001 nubus_probe_slot(0);
ian@0 1002 #endif
ian@0 1003 for(slot = 9; slot < 15; slot++)
ian@0 1004 {
ian@0 1005 nubus_probe_slot(slot);
ian@0 1006 }
ian@0 1007 }
ian@0 1008
ian@0 1009 static int __init nubus_init(void)
ian@0 1010 {
ian@0 1011 if (!MACH_IS_MAC)
ian@0 1012 return 0;
ian@0 1013
ian@0 1014 /* Initialize the NuBus interrupts */
ian@0 1015 if (oss_present) {
ian@0 1016 oss_nubus_init();
ian@0 1017 } else {
ian@0 1018 via_nubus_init();
ian@0 1019 }
ian@0 1020
ian@0 1021 #ifdef TRY_TO_DODGE_WSOD
ian@0 1022 /* Rogue Ethernet interrupts can kill the machine if we don't
ian@0 1023 do this. Obviously this is bogus. Hopefully the local VIA
ian@0 1024 gurus can fix the real cause of the problem. */
ian@0 1025 mdelay(1000);
ian@0 1026 #endif
ian@0 1027
ian@0 1028 /* And probe */
ian@0 1029 printk("NuBus: Scanning NuBus slots.\n");
ian@0 1030 nubus_devices = NULL;
ian@0 1031 nubus_boards = NULL;
ian@0 1032 nubus_scan_bus();
ian@0 1033
ian@0 1034 #ifdef CONFIG_PROC_FS
ian@0 1035 create_proc_read_entry("nubus", 0, NULL, nubus_read_proc, NULL);
ian@0 1036 nubus_proc_init();
ian@0 1037 #endif
ian@0 1038 return 0;
ian@0 1039 }
ian@0 1040
ian@0 1041 subsys_initcall(nubus_init);