Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.4 608 lines 15 kB view raw
1/* 2 * SGI Visual Workstation support and quirks, unmaintained. 3 * 4 * Split out from setup.c by davej@suse.de 5 * 6 * Copyright (C) 1999 Bent Hagemark, Ingo Molnar 7 * 8 * SGI Visual Workstation interrupt controller 9 * 10 * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC 11 * which serves as the main interrupt controller in the system. Non-legacy 12 * hardware in the system uses this controller directly. Legacy devices 13 * are connected to the PIIX4 which in turn has its 8259(s) connected to 14 * a of the Cobalt APIC entry. 15 * 16 * 09/02/2000 - Updated for 2.4 by jbarnes@sgi.com 17 * 18 * 25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru> 19 */ 20#include <linux/interrupt.h> 21#include <linux/module.h> 22#include <linux/init.h> 23#include <linux/smp.h> 24 25#include <asm/visws/cobalt.h> 26#include <asm/visws/piix4.h> 27#include <asm/io_apic.h> 28#include <asm/fixmap.h> 29#include <asm/reboot.h> 30#include <asm/setup.h> 31#include <asm/apic.h> 32#include <asm/e820.h> 33#include <asm/time.h> 34#include <asm/io.h> 35 36#include <linux/kernel_stat.h> 37 38#include <asm/i8259.h> 39#include <asm/irq_vectors.h> 40#include <asm/visws/lithium.h> 41 42#include <linux/sched.h> 43#include <linux/kernel.h> 44#include <linux/pci.h> 45#include <linux/pci_ids.h> 46 47extern int no_broadcast; 48 49char visws_board_type = -1; 50char visws_board_rev = -1; 51 52static void __init visws_time_init(void) 53{ 54 printk(KERN_INFO "Starting Cobalt Timer system clock\n"); 55 56 /* Set the countdown value */ 57 co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); 58 59 /* Start the timer */ 60 co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); 61 62 /* Enable (unmask) the timer interrupt */ 63 co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); 64 65 setup_default_timer_irq(); 66} 67 68/* Replaces the default init_ISA_irqs in the generic setup */ 69static void __init visws_pre_intr_init(void); 70 71/* Quirk for machine specific memory setup. */ 72 73#define MB (1024 * 1024) 74 75unsigned long sgivwfb_mem_phys; 76unsigned long sgivwfb_mem_size; 77EXPORT_SYMBOL(sgivwfb_mem_phys); 78EXPORT_SYMBOL(sgivwfb_mem_size); 79 80long long mem_size __initdata = 0; 81 82static char * __init visws_memory_setup(void) 83{ 84 long long gfx_mem_size = 8 * MB; 85 86 mem_size = boot_params.alt_mem_k; 87 88 if (!mem_size) { 89 printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n"); 90 mem_size = 128 * MB; 91 } 92 93 /* 94 * this hardcodes the graphics memory to 8 MB 95 * it really should be sized dynamically (or at least 96 * set as a boot param) 97 */ 98 if (!sgivwfb_mem_size) { 99 printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n"); 100 sgivwfb_mem_size = 8 * MB; 101 } 102 103 /* 104 * Trim to nearest MB 105 */ 106 sgivwfb_mem_size &= ~((1 << 20) - 1); 107 sgivwfb_mem_phys = mem_size - gfx_mem_size; 108 109 e820_add_region(0, LOWMEMSIZE(), E820_RAM); 110 e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM); 111 e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED); 112 113 return "PROM"; 114} 115 116static void visws_machine_emergency_restart(void) 117{ 118 /* 119 * Visual Workstations restart after this 120 * register is poked on the PIIX4 121 */ 122 outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT); 123} 124 125static void visws_machine_power_off(void) 126{ 127 unsigned short pm_status; 128/* extern unsigned int pci_bus0; */ 129 130 while ((pm_status = inw(PMSTS_PORT)) & 0x100) 131 outw(pm_status, PMSTS_PORT); 132 133 outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT); 134 135 mdelay(10); 136 137#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ 138 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) 139 140/* outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */ 141 outl(PIIX_SPECIAL_STOP, 0xCFC); 142} 143 144static void __init visws_get_smp_config(unsigned int early) 145{ 146} 147 148/* 149 * The Visual Workstation is Intel MP compliant in the hardware 150 * sense, but it doesn't have a BIOS(-configuration table). 151 * No problem for Linux. 152 */ 153 154static void __init MP_processor_info(struct mpc_cpu *m) 155{ 156 int ver, logical_apicid; 157 physid_mask_t apic_cpus; 158 159 if (!(m->cpuflag & CPU_ENABLED)) 160 return; 161 162 logical_apicid = m->apicid; 163 printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n", 164 m->cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "", 165 m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8, 166 (m->cpufeature & CPU_MODEL_MASK) >> 4, m->apicver); 167 168 if (m->cpuflag & CPU_BOOTPROCESSOR) 169 boot_cpu_physical_apicid = m->apicid; 170 171 ver = m->apicver; 172 if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) { 173 printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n", 174 m->apicid, MAX_LOCAL_APIC); 175 return; 176 } 177 178 apic->apicid_to_cpu_present(m->apicid, &apic_cpus); 179 physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus); 180 /* 181 * Validate version 182 */ 183 if (ver == 0x0) { 184 printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! " 185 "fixing up to 0x10. (tell your hw vendor)\n", 186 m->apicid); 187 ver = 0x10; 188 } 189 apic_version[m->apicid] = ver; 190} 191 192static void __init visws_find_smp_config(void) 193{ 194 struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS); 195 unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS)); 196 197 if (ncpus > CO_CPU_MAX) { 198 printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n", 199 ncpus, mp); 200 201 ncpus = CO_CPU_MAX; 202 } 203 204 if (ncpus > setup_max_cpus) 205 ncpus = setup_max_cpus; 206 207#ifdef CONFIG_X86_LOCAL_APIC 208 smp_found_config = 1; 209#endif 210 while (ncpus--) 211 MP_processor_info(mp++); 212 213 mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; 214} 215 216static void visws_trap_init(void); 217 218void __init visws_early_detect(void) 219{ 220 int raw; 221 222 visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) 223 >> PIIX_GPI_BD_SHIFT; 224 225 if (visws_board_type < 0) 226 return; 227 228 /* 229 * Override the default platform setup functions 230 */ 231 x86_init.resources.memory_setup = visws_memory_setup; 232 x86_init.mpparse.get_smp_config = visws_get_smp_config; 233 x86_init.mpparse.find_smp_config = visws_find_smp_config; 234 x86_init.irqs.pre_vector_init = visws_pre_intr_init; 235 x86_init.irqs.trap_init = visws_trap_init; 236 x86_init.timers.timer_init = visws_time_init; 237 x86_init.pci.init = pci_visws_init; 238 x86_init.pci.init_irq = x86_init_noop; 239 240 /* 241 * Install reboot quirks: 242 */ 243 pm_power_off = visws_machine_power_off; 244 machine_ops.emergency_restart = visws_machine_emergency_restart; 245 246 /* 247 * Do not use broadcast IPIs: 248 */ 249 no_broadcast = 0; 250 251#ifdef CONFIG_X86_IO_APIC 252 /* 253 * Turn off IO-APIC detection and initialization: 254 */ 255 skip_ioapic_setup = 1; 256#endif 257 258 /* 259 * Get Board rev. 260 * First, we have to initialize the 307 part to allow us access 261 * to the GPIO registers. Let's map them at 0x0fc0 which is right 262 * after the PIIX4 PM section. 263 */ 264 outb_p(SIO_DEV_SEL, SIO_INDEX); 265 outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ 266 267 outb_p(SIO_DEV_MSB, SIO_INDEX); 268 outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ 269 270 outb_p(SIO_DEV_LSB, SIO_INDEX); 271 outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ 272 273 outb_p(SIO_DEV_ENB, SIO_INDEX); 274 outb_p(1, SIO_DATA); /* Enable GPIO registers. */ 275 276 /* 277 * Now, we have to map the power management section to write 278 * a bit which enables access to the GPIO registers. 279 * What lunatic came up with this shit? 280 */ 281 outb_p(SIO_DEV_SEL, SIO_INDEX); 282 outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ 283 284 outb_p(SIO_DEV_MSB, SIO_INDEX); 285 outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ 286 287 outb_p(SIO_DEV_LSB, SIO_INDEX); 288 outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ 289 290 outb_p(SIO_DEV_ENB, SIO_INDEX); 291 outb_p(1, SIO_DATA); /* Enable PM registers. */ 292 293 /* 294 * Now, write the PM register which enables the GPIO registers. 295 */ 296 outb_p(SIO_PM_FER2, SIO_PM_INDEX); 297 outb_p(SIO_PM_GP_EN, SIO_PM_DATA); 298 299 /* 300 * Now, initialize the GPIO registers. 301 * We want them all to be inputs which is the 302 * power on default, so let's leave them alone. 303 * So, let's just read the board rev! 304 */ 305 raw = inb_p(SIO_GP_DATA1); 306 raw &= 0x7f; /* 7 bits of valid board revision ID. */ 307 308 if (visws_board_type == VISWS_320) { 309 if (raw < 0x6) { 310 visws_board_rev = 4; 311 } else if (raw < 0xc) { 312 visws_board_rev = 5; 313 } else { 314 visws_board_rev = 6; 315 } 316 } else if (visws_board_type == VISWS_540) { 317 visws_board_rev = 2; 318 } else { 319 visws_board_rev = raw; 320 } 321 322 printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n", 323 (visws_board_type == VISWS_320 ? "320" : 324 (visws_board_type == VISWS_540 ? "540" : 325 "unknown")), visws_board_rev); 326} 327 328#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4) 329#define BCD (LI_INTB | LI_INTC | LI_INTD) 330#define ALLDEVS (A01234 | BCD) 331 332static __init void lithium_init(void) 333{ 334 set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); 335 set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); 336 337 if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) || 338 (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) { 339 printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A'); 340/* panic("This machine is not SGI Visual Workstation 320/540"); */ 341 } 342 343 if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) || 344 (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) { 345 printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B'); 346/* panic("This machine is not SGI Visual Workstation 320/540"); */ 347 } 348 349 li_pcia_write16(LI_PCI_INTEN, ALLDEVS); 350 li_pcib_write16(LI_PCI_INTEN, ALLDEVS); 351} 352 353static __init void cobalt_init(void) 354{ 355 /* 356 * On normal SMP PC this is used only with SMP, but we have to 357 * use it and set it up here to start the Cobalt clock 358 */ 359 set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); 360 setup_local_APIC(); 361 printk(KERN_INFO "Local APIC Version %#x, ID %#x\n", 362 (unsigned int)apic_read(APIC_LVR), 363 (unsigned int)apic_read(APIC_ID)); 364 365 set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); 366 set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); 367 printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n", 368 co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID)); 369 370 /* Enable Cobalt APIC being careful to NOT change the ID! */ 371 co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE); 372 373 printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n", 374 co_apic_read(CO_APIC_ID)); 375} 376 377static void __init visws_trap_init(void) 378{ 379 lithium_init(); 380 cobalt_init(); 381} 382 383/* 384 * IRQ controller / APIC support: 385 */ 386 387static DEFINE_SPINLOCK(cobalt_lock); 388 389/* 390 * Set the given Cobalt APIC Redirection Table entry to point 391 * to the given IDT vector/index. 392 */ 393static inline void co_apic_set(int entry, int irq) 394{ 395 co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR)); 396 co_apic_write(CO_APIC_HI(entry), 0); 397} 398 399/* 400 * Cobalt (IO)-APIC functions to handle PCI devices. 401 */ 402static inline int co_apic_ide0_hack(void) 403{ 404 extern char visws_board_type; 405 extern char visws_board_rev; 406 407 if (visws_board_type == VISWS_320 && visws_board_rev == 5) 408 return 5; 409 return CO_APIC_IDE0; 410} 411 412static int is_co_apic(unsigned int irq) 413{ 414 if (IS_CO_APIC(irq)) 415 return CO_APIC(irq); 416 417 switch (irq) { 418 case 0: return CO_APIC_CPU; 419 case CO_IRQ_IDE0: return co_apic_ide0_hack(); 420 case CO_IRQ_IDE1: return CO_APIC_IDE1; 421 default: return -1; 422 } 423} 424 425 426/* 427 * This is the SGI Cobalt (IO-)APIC: 428 */ 429static void enable_cobalt_irq(struct irq_data *data) 430{ 431 co_apic_set(is_co_apic(data->irq), data->irq); 432} 433 434static void disable_cobalt_irq(struct irq_data *data) 435{ 436 int entry = is_co_apic(data->irq); 437 438 co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK); 439 co_apic_read(CO_APIC_LO(entry)); 440} 441 442static void ack_cobalt_irq(struct irq_data *data) 443{ 444 unsigned long flags; 445 446 spin_lock_irqsave(&cobalt_lock, flags); 447 disable_cobalt_irq(data); 448 apic_write(APIC_EOI, APIC_EIO_ACK); 449 spin_unlock_irqrestore(&cobalt_lock, flags); 450} 451 452static struct irq_chip cobalt_irq_type = { 453 .name = "Cobalt-APIC", 454 .irq_enable = enable_cobalt_irq, 455 .irq_disable = disable_cobalt_irq, 456 .irq_ack = ack_cobalt_irq, 457}; 458 459 460/* 461 * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt 462 * -- not the manner expected by the code in i8259.c. 463 * 464 * there is a 'master' physical interrupt source that gets sent to 465 * the CPU. But in the chipset there are various 'virtual' interrupts 466 * waiting to be handled. We represent this to Linux through a 'master' 467 * interrupt controller type, and through a special virtual interrupt- 468 * controller. Device drivers only see the virtual interrupt sources. 469 */ 470static unsigned int startup_piix4_master_irq(struct irq_data *data) 471{ 472 legacy_pic->init(0); 473 enable_cobalt_irq(data); 474 return 0; 475} 476 477static struct irq_chip piix4_master_irq_type = { 478 .name = "PIIX4-master", 479 .irq_startup = startup_piix4_master_irq, 480 .irq_ack = ack_cobalt_irq, 481}; 482 483static void pii4_mask(struct irq_data *data) { } 484 485static struct irq_chip piix4_virtual_irq_type = { 486 .name = "PIIX4-virtual", 487 .irq_mask = pii4_mask, 488}; 489 490/* 491 * PIIX4-8259 master/virtual functions to handle interrupt requests 492 * from legacy devices: floppy, parallel, serial, rtc. 493 * 494 * None of these get Cobalt APIC entries, neither do they have IDT 495 * entries. These interrupts are purely virtual and distributed from 496 * the 'master' interrupt source: CO_IRQ_8259. 497 * 498 * When the 8259 interrupts its handler figures out which of these 499 * devices is interrupting and dispatches to its handler. 500 * 501 * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/ 502 * enable_irq gets the right irq. This 'master' irq is never directly 503 * manipulated by any driver. 504 */ 505static irqreturn_t piix4_master_intr(int irq, void *dev_id) 506{ 507 unsigned long flags; 508 int realirq; 509 510 raw_spin_lock_irqsave(&i8259A_lock, flags); 511 512 /* Find out what's interrupting in the PIIX4 master 8259 */ 513 outb(0x0c, 0x20); /* OCW3 Poll command */ 514 realirq = inb(0x20); 515 516 /* 517 * Bit 7 == 0 means invalid/spurious 518 */ 519 if (unlikely(!(realirq & 0x80))) 520 goto out_unlock; 521 522 realirq &= 7; 523 524 if (unlikely(realirq == 2)) { 525 outb(0x0c, 0xa0); 526 realirq = inb(0xa0); 527 528 if (unlikely(!(realirq & 0x80))) 529 goto out_unlock; 530 531 realirq = (realirq & 7) + 8; 532 } 533 534 /* mask and ack interrupt */ 535 cached_irq_mask |= 1 << realirq; 536 if (unlikely(realirq > 7)) { 537 inb(0xa1); 538 outb(cached_slave_mask, 0xa1); 539 outb(0x60 + (realirq & 7), 0xa0); 540 outb(0x60 + 2, 0x20); 541 } else { 542 inb(0x21); 543 outb(cached_master_mask, 0x21); 544 outb(0x60 + realirq, 0x20); 545 } 546 547 raw_spin_unlock_irqrestore(&i8259A_lock, flags); 548 549 /* 550 * handle this 'virtual interrupt' as a Cobalt one now. 551 */ 552 generic_handle_irq(realirq); 553 554 return IRQ_HANDLED; 555 556out_unlock: 557 raw_spin_unlock_irqrestore(&i8259A_lock, flags); 558 return IRQ_NONE; 559} 560 561static struct irqaction master_action = { 562 .handler = piix4_master_intr, 563 .name = "PIIX4-8259", 564 .flags = IRQF_NO_THREAD, 565}; 566 567static struct irqaction cascade_action = { 568 .handler = no_action, 569 .name = "cascade", 570 .flags = IRQF_NO_THREAD, 571}; 572 573static inline void set_piix4_virtual_irq_type(void) 574{ 575 piix4_virtual_irq_type.irq_enable = i8259A_chip.irq_unmask; 576 piix4_virtual_irq_type.irq_disable = i8259A_chip.irq_mask; 577 piix4_virtual_irq_type.irq_unmask = i8259A_chip.irq_unmask; 578} 579 580static void __init visws_pre_intr_init(void) 581{ 582 int i; 583 584 set_piix4_virtual_irq_type(); 585 586 for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) { 587 struct irq_chip *chip = NULL; 588 589 if (i == 0) 590 chip = &cobalt_irq_type; 591 else if (i == CO_IRQ_IDE0) 592 chip = &cobalt_irq_type; 593 else if (i == CO_IRQ_IDE1) 594 chip = &cobalt_irq_type; 595 else if (i == CO_IRQ_8259) 596 chip = &piix4_master_irq_type; 597 else if (i < CO_IRQ_APIC0) 598 chip = &piix4_virtual_irq_type; 599 else if (IS_CO_APIC(i)) 600 chip = &cobalt_irq_type; 601 602 if (chip) 603 irq_set_chip(i, chip); 604 } 605 606 setup_irq(CO_IRQ_8259, &master_action); 607 setup_irq(2, &cascade_action); 608}