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