After this has been brought up many times before, rename src/arch/i386 to
[coreboot.git] / src / arch / x86 / boot / mpspec.c
1 #include <console/console.h>
2 #include <device/path.h>
3 #include <device/pci_ids.h>
4 #include <cpu/cpu.h>
5 #include <arch/smp/mpspec.h>
6 #include <string.h>
7 #include <arch/cpu.h>
8 #include <cpu/x86/lapic.h>
9
10 /* Initialize the specified "mc" struct with initial values. */
11 void mptable_init(struct mp_config_table *mc, const char *productid,
12                   u32 lapic_addr)
13 {
14         /* Error out if 'product_id' length doesn't match exactly. */
15         if (strlen(productid) != 12)
16                 die("ERROR: 'productid' must be 12 bytes long!");
17
18         memset(mc, 0, sizeof(*mc));
19         memcpy(mc->mpc_signature, MPC_SIGNATURE, 4);
20         mc->mpc_length = sizeof(*mc);   /* Initially just the header size. */
21         mc->mpc_spec = 0x04;            /* MultiProcessor specification 1.4 */
22         mc->mpc_checksum = 0;           /* Not yet computed. */
23         memcpy(mc->mpc_oem, "COREBOOT", 8);
24         memcpy(mc->mpc_productid, productid, 12);
25         mc->mpc_oemptr = 0;
26         mc->mpc_oemsize = 0;
27         mc->mpc_entry_count = 0;        /* No entries yet... */
28         mc->mpc_lapic = lapic_addr;
29         mc->mpe_length = 0;
30         mc->mpe_checksum = 0;
31         mc->reserved = 0;
32 }
33
34 unsigned char smp_compute_checksum(void *v, int len)
35 {
36         unsigned char *bytes;
37         unsigned char checksum;
38         int i;
39         bytes = v;
40         checksum = 0;
41         for(i = 0; i < len; i++) {
42                 checksum -= bytes[i];
43         }
44         return checksum;
45 }
46
47 void *smp_write_floating_table(unsigned long addr)
48 {
49         /* 16 byte align the table address */
50         addr = (addr + 0xf) & (~0xf);
51         return smp_write_floating_table_physaddr(addr, addr + SMP_FLOATING_TABLE_LEN);
52 }
53
54 void *smp_write_floating_table_physaddr(unsigned long addr, unsigned long mpf_physptr)
55 {
56         struct intel_mp_floating *mf;
57         void *v;
58
59         v = (void *)addr;
60         mf = v;
61         mf->mpf_signature[0] = '_';
62         mf->mpf_signature[1] = 'M';
63         mf->mpf_signature[2] = 'P';
64         mf->mpf_signature[3] = '_';
65         mf->mpf_physptr = mpf_physptr;
66         mf->mpf_length = 1;
67         mf->mpf_specification = 4;
68         mf->mpf_checksum = 0;
69         mf->mpf_feature1 = 0;
70         mf->mpf_feature2 = 0;
71         mf->mpf_feature3 = 0;
72         mf->mpf_feature4 = 0;
73         mf->mpf_feature5 = 0;
74         mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
75         return v;
76 }
77
78 void *smp_next_mpc_entry(struct mp_config_table *mc)
79 {
80         void *v;
81         v = (void *)(((char *)mc) + mc->mpc_length);
82         return v;
83 }
84 static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
85 {
86         mc->mpc_length += length;
87         mc->mpc_entry_count++;
88 }
89
90 void *smp_next_mpe_entry(struct mp_config_table *mc)
91 {
92         void *v;
93         v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
94         return v;
95 }
96 static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
97 {
98         mc->mpe_length += mpe->mpe_length;
99 }
100
101 void smp_write_processor(struct mp_config_table *mc,
102         unsigned char apicid, unsigned char apicver,
103         unsigned char cpuflag, unsigned int cpufeature,
104         unsigned int featureflag)
105 {
106         struct mpc_config_processor *mpc;
107         mpc = smp_next_mpc_entry(mc);
108         memset(mpc, '\0', sizeof(*mpc));
109         mpc->mpc_type = MP_PROCESSOR;
110         mpc->mpc_apicid = apicid;
111         mpc->mpc_apicver = apicver;
112         mpc->mpc_cpuflag = cpuflag;
113         mpc->mpc_cpufeature = cpufeature;
114         mpc->mpc_featureflag = featureflag;
115         smp_add_mpc_entry(mc, sizeof(*mpc));
116 }
117
118 /* If we assume a symmetric processor configuration we can
119  * get all of the information we need to write the processor
120  * entry from the bootstrap processor.
121  * Plus I don't think linux really even cares.
122  * Having the proper apicid's in the table so the non-bootstrap
123  *  processors can be woken up should be enough.
124  */
125 void smp_write_processors(struct mp_config_table *mc)
126 {
127         int boot_apic_id;
128         unsigned apic_version;
129         unsigned cpu_features;
130         unsigned cpu_feature_flags;
131         struct cpuid_result result;
132         device_t cpu;
133
134         boot_apic_id = lapicid();
135         apic_version = lapic_read(LAPIC_LVR) & 0xff;
136         result = cpuid(1);
137         cpu_features = result.eax;
138         cpu_feature_flags = result.edx;
139         for(cpu = all_devices; cpu; cpu = cpu->next) {
140                 unsigned long cpu_flag;
141                 if ((cpu->path.type != DEVICE_PATH_APIC) ||
142                         (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER))
143                 {
144                         continue;
145                 }
146                 if (!cpu->enabled) {
147                         continue;
148                 }
149                 cpu_flag = MPC_CPU_ENABLED;
150                 if (boot_apic_id == cpu->path.apic.apic_id) {
151                         cpu_flag = MPC_CPU_ENABLED | MPC_CPU_BOOTPROCESSOR;
152                 }
153                 smp_write_processor(mc,
154                         cpu->path.apic.apic_id, apic_version,
155                         cpu_flag, cpu_features, cpu_feature_flags
156                 );
157         }
158 }
159
160 static void smp_write_bus(struct mp_config_table *mc,
161         unsigned char id, const char *bustype)
162 {
163         struct mpc_config_bus *mpc;
164         mpc = smp_next_mpc_entry(mc);
165         memset(mpc, '\0', sizeof(*mpc));
166         mpc->mpc_type = MP_BUS;
167         mpc->mpc_busid = id;
168         memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
169         smp_add_mpc_entry(mc, sizeof(*mpc));
170 }
171
172 void smp_write_ioapic(struct mp_config_table *mc,
173         unsigned char id, unsigned char ver,
174         unsigned long apicaddr)
175 {
176         struct mpc_config_ioapic *mpc;
177         mpc = smp_next_mpc_entry(mc);
178         memset(mpc, '\0', sizeof(*mpc));
179         mpc->mpc_type = MP_IOAPIC;
180         mpc->mpc_apicid = id;
181         mpc->mpc_apicver = ver;
182         mpc->mpc_flags = MPC_APIC_USABLE;
183         mpc->mpc_apicaddr = apicaddr;
184         smp_add_mpc_entry(mc, sizeof(*mpc));
185 }
186
187 void smp_write_intsrc(struct mp_config_table *mc,
188         unsigned char irqtype, unsigned short irqflag,
189         unsigned char srcbus, unsigned char srcbusirq,
190         unsigned char dstapic, unsigned char dstirq)
191 {
192         struct mpc_config_intsrc *mpc;
193         mpc = smp_next_mpc_entry(mc);
194         memset(mpc, '\0', sizeof(*mpc));
195         mpc->mpc_type = MP_INTSRC;
196         mpc->mpc_irqtype = irqtype;
197         mpc->mpc_irqflag = irqflag;
198         mpc->mpc_srcbus = srcbus;
199         mpc->mpc_srcbusirq = srcbusirq;
200         mpc->mpc_dstapic = dstapic;
201         mpc->mpc_dstirq = dstirq;
202         smp_add_mpc_entry(mc, sizeof(*mpc));
203 #ifdef DEBUG_MPTABLE
204         printk(BIOS_DEBUG, "add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n",
205                                 srcbus, srcbusirq, dstapic, dstirq);
206         hexdump(__func__, mpc, sizeof(*mpc));
207 #endif
208 }
209
210 void smp_write_intsrc_pci_bridge(struct mp_config_table *mc,
211         unsigned char irqtype, unsigned short irqflag,
212         struct device *dev,
213         unsigned char dstapic, unsigned char *dstirq)
214 {
215         struct device *child;
216
217         int i;
218         int srcbus;
219         int slot;
220
221         struct bus *link;
222         unsigned char dstirq_x[4];
223
224         for (link = dev->link_list; link; link = link->next) {
225
226                 child = link->children;
227                 srcbus = link->secondary;
228
229                 while (child) {
230                         if (child->path.type != DEVICE_PATH_PCI)
231                                 goto next;
232
233                         slot = (child->path.pci.devfn >> 3);
234                         /* round pins */
235                         for (i = 0; i < 4; i++)
236                                 dstirq_x[i] = dstirq[(i + slot) % 4];
237
238                         if ((child->class >> 16) != PCI_BASE_CLASS_BRIDGE) {
239                                 /* pci device */
240                                 printk(BIOS_DEBUG, "route irq: %s\n", dev_path(child));
241                                 for (i = 0; i < 4; i++)
242                                         smp_write_intsrc(mc, irqtype, irqflag, srcbus, (slot<<2)|i, dstapic, dstirq_x[i]);
243                                 goto next;
244                         }
245
246                         switch (child->class>>8) {
247                         case PCI_CLASS_BRIDGE_PCI:
248                         case PCI_CLASS_BRIDGE_PCMCIA:
249                         case PCI_CLASS_BRIDGE_CARDBUS:
250                                 printk(BIOS_DEBUG, "route irq bridge: %s\n", dev_path(child));
251                                 smp_write_intsrc_pci_bridge(mc, irqtype, irqflag, child, dstapic, dstirq_x);
252                         }
253
254                 next:
255                         child = child->sibling;
256                 }
257
258         }
259 }
260
261 void smp_write_lintsrc(struct mp_config_table *mc,
262         unsigned char irqtype, unsigned short irqflag,
263         unsigned char srcbusid, unsigned char srcbusirq,
264         unsigned char destapic, unsigned char destapiclint)
265 {
266         struct mpc_config_lintsrc *mpc;
267         mpc = smp_next_mpc_entry(mc);
268         memset(mpc, '\0', sizeof(*mpc));
269         mpc->mpc_type = MP_LINTSRC;
270         mpc->mpc_irqtype = irqtype;
271         mpc->mpc_irqflag = irqflag;
272         mpc->mpc_srcbusid = srcbusid;
273         mpc->mpc_srcbusirq = srcbusirq;
274         mpc->mpc_destapic = destapic;
275         mpc->mpc_destapiclint = destapiclint;
276         smp_add_mpc_entry(mc, sizeof(*mpc));
277 }
278
279 void smp_write_address_space(struct mp_config_table *mc,
280         unsigned char busid, unsigned char address_type,
281         unsigned int address_base_low, unsigned int address_base_high,
282         unsigned int address_length_low, unsigned int address_length_high)
283 {
284         struct mp_exten_system_address_space *mpe;
285         mpe = smp_next_mpe_entry(mc);
286         memset(mpe, '\0', sizeof(*mpe));
287         mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
288         mpe->mpe_length = sizeof(*mpe);
289         mpe->mpe_busid = busid;
290         mpe->mpe_address_type = address_type;
291         mpe->mpe_address_base_low  = address_base_low;
292         mpe->mpe_address_base_high = address_base_high;
293         mpe->mpe_address_length_low  = address_length_low;
294         mpe->mpe_address_length_high = address_length_high;
295         smp_add_mpe_entry(mc, (mpe_t)mpe);
296 }
297
298
299 void smp_write_bus_hierarchy(struct mp_config_table *mc,
300         unsigned char busid, unsigned char bus_info,
301         unsigned char parent_busid)
302 {
303         struct mp_exten_bus_hierarchy *mpe;
304         mpe = smp_next_mpe_entry(mc);
305         memset(mpe, '\0', sizeof(*mpe));
306         mpe->mpe_type = MPE_BUS_HIERARCHY;
307         mpe->mpe_length = sizeof(*mpe);
308         mpe->mpe_busid = busid;
309         mpe->mpe_bus_info = bus_info;
310         mpe->mpe_parent_busid = parent_busid;
311         smp_add_mpe_entry(mc, (mpe_t)mpe);
312 }
313
314 void smp_write_compatibility_address_space(struct mp_config_table *mc,
315         unsigned char busid, unsigned char address_modifier,
316         unsigned int range_list)
317 {
318         struct mp_exten_compatibility_address_space *mpe;
319         mpe = smp_next_mpe_entry(mc);
320         memset(mpe, '\0', sizeof(*mpe));
321         mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
322         mpe->mpe_length = sizeof(*mpe);
323         mpe->mpe_busid = busid;
324         mpe->mpe_address_modifier = address_modifier;
325         mpe->mpe_range_list = range_list;
326         smp_add_mpe_entry(mc, (mpe_t)mpe);
327 }
328
329 void mptable_add_isa_interrupts(struct mp_config_table *mc, unsigned long bus_isa, unsigned long apicid, int external_int2)
330 {
331 /*I/O Ints:                   Type         Trigger            Polarity         Bus ID   IRQ  APIC ID   PIN# */
332         smp_write_intsrc(mc, external_int2?mp_INT:mp_ExtINT,
333                                      MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x0, apicid, 0x0);
334         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x1, apicid, 0x1);
335         smp_write_intsrc(mc, external_int2?mp_ExtINT:mp_INT,
336                                      MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x0, apicid, 0x2);
337         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x3, apicid, 0x3);
338         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x4, apicid, 0x4);
339         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x6, apicid, 0x6);
340         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x7, apicid, 0x7);
341         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x8, apicid, 0x8);
342         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x9, apicid, 0x9);
343         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xa, apicid, 0xa);
344         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xb, apicid, 0xb);
345         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xc, apicid, 0xc);
346         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xd, apicid, 0xd);
347         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xe, apicid, 0xe);
348         smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xf, apicid, 0xf);
349 }
350
351 void mptable_write_buses(struct mp_config_table *mc, int *max_pci_bus, int *isa_bus) {
352         int dummy, i, highest;
353         char buses[256];
354         struct device *dev;
355
356         if (!max_pci_bus) max_pci_bus = &dummy;
357         if (!isa_bus) isa_bus = &dummy;
358
359         *max_pci_bus = 0;
360         highest = 0;
361         memset(buses, 0, sizeof(buses));
362
363         for (dev = all_devices; dev; dev = dev->next) {
364                 struct bus *bus;
365                 for (bus = dev->link_list; bus; bus = bus->next) {
366                         if (bus->secondary > 255) {
367                                 printk(BIOS_ERR, "A bus claims to have a bus ID > 255?!? Aborting");
368                                 return;
369                         }
370                         buses[bus->secondary] = 1;
371                         if (highest < bus->secondary) highest = bus->secondary;
372                 }
373         }
374         for (i=0; i <= highest; i++) {
375                 if (buses[i]) {
376                         smp_write_bus(mc, i, "PCI   ");
377                         *max_pci_bus = i;
378                 }
379         }
380         *isa_bus = *max_pci_bus + 1;
381         smp_write_bus(mc, *isa_bus, "ISA   ");
382 }
383