Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / sparc / kernel / starfire.c
1 /*
2  * starfire.c: Starfire/E10000 support.
3  *
4  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
5  * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
10
11 #include <asm/page.h>
12 #include <asm/oplib.h>
13 #include <asm/smp.h>
14 #include <asm/upa.h>
15 #include <asm/starfire.h>
16
17 /*
18  * A few places around the kernel check this to see if
19  * they need to call us to do things in a Starfire specific
20  * way.
21  */
22 int this_is_starfire = 0;
23
24 void check_if_starfire(void)
25 {
26         phandle ssnode = prom_finddevice("/ssp-serial");
27         if (ssnode != 0 && (s32)ssnode != -1)
28                 this_is_starfire = 1;
29 }
30
31 /*
32  * Each Starfire board has 32 registers which perform translation
33  * and delivery of traditional interrupt packets into the extended
34  * Starfire hardware format.  Essentially UPAID's now have 2 more
35  * bits than in all previous Sun5 systems.
36  */
37 struct starfire_irqinfo {
38         unsigned long imap_slots[32];
39         unsigned long tregs[32];
40         struct starfire_irqinfo *next;
41         int upaid, hwmid;
42 };
43
44 static struct starfire_irqinfo *sflist = NULL;
45
46 /* Beam me up Scott(McNeil)y... */
47 void starfire_hookup(int upaid)
48 {
49         struct starfire_irqinfo *p;
50         unsigned long treg_base, hwmid, i;
51
52         p = kmalloc(sizeof(*p), GFP_KERNEL);
53         if (!p) {
54                 prom_printf("starfire_hookup: No memory, this is insane.\n");
55                 prom_halt();
56         }
57         treg_base = 0x100fc000000UL;
58         hwmid = ((upaid & 0x3c) << 1) |
59                 ((upaid & 0x40) >> 4) |
60                 (upaid & 0x3);
61         p->hwmid = hwmid;
62         treg_base += (hwmid << 33UL);
63         treg_base += 0x200UL;
64         for (i = 0; i < 32; i++) {
65                 p->imap_slots[i] = 0UL;
66                 p->tregs[i] = treg_base + (i * 0x10UL);
67                 /* Lets play it safe and not overwrite existing mappings */
68                 if (upa_readl(p->tregs[i]) != 0)
69                         p->imap_slots[i] = 0xdeadbeaf;
70         }
71         p->upaid = upaid;
72         p->next = sflist;
73         sflist = p;
74 }
75
76 unsigned int starfire_translate(unsigned long imap,
77                                 unsigned int upaid)
78 {
79         struct starfire_irqinfo *p;
80         unsigned int bus_hwmid;
81         unsigned int i;
82
83         bus_hwmid = (((unsigned long)imap) >> 33) & 0x7f;
84         for (p = sflist; p != NULL; p = p->next)
85                 if (p->hwmid == bus_hwmid)
86                         break;
87         if (p == NULL) {
88                 prom_printf("XFIRE: Cannot find irqinfo for imap %016lx\n",
89                             ((unsigned long)imap));
90                 prom_halt();
91         }
92         for (i = 0; i < 32; i++) {
93                 if (p->imap_slots[i] == imap ||
94                     p->imap_slots[i] == 0UL)
95                         break;
96         }
97         if (i == 32) {
98                 printk("starfire_translate: Are you kidding me?\n");
99                 panic("Lucy in the sky....");
100         }
101         p->imap_slots[i] = imap;
102
103         /* map to real upaid */
104         upaid = (((upaid & 0x3c) << 1) |
105                  ((upaid & 0x40) >> 4) |
106                  (upaid & 0x3));
107
108         upa_writel(upaid, p->tregs[i]);
109
110         return i;
111 }