]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/acpi.cc
ce148e0749f1b0f16f40afeff5e8526a7cffdfbe
[l4.git] / l4 / pkg / io / server / src / acpi.cc
1 /*
2  * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10
11 #include <cstdio>
12 #include <cstdlib>
13
14 #include "pci.h"
15 #include "acpi_l4.h"
16 #include "__acpi.h"
17 #include "cfg.h"
18 #include "main.h"
19 #include "phys_space.h"
20
21 extern "C" {
22 #include "acpi.h"
23 #include "accommon.h"
24 #include "acresrc.h"
25 #include "acnamesp.h"
26 }
27
28 #include <errno.h>
29 #include <l4/cxx/list>
30
31 #define _COMPONENT              ACPI_BUS_COMPONENT
32 ACPI_MODULE_NAME("l4main");
33
34 namespace {
35
36 struct Prt_entry : public cxx::List_item
37 {
38   unsigned slot;
39   unsigned char pin;
40   acpica_pci_irq irq;
41 };
42
43 class Acpi_pci_irq_router_rs : public Resource_space
44 {
45 public:
46   Prt_entry *_prt;
47
48 public:
49   Acpi_pci_irq_router_rs() : _prt(0) {}
50
51   int add_prt_entry(ACPI_HANDLE obj, ACPI_PCI_ROUTING_TABLE *e);
52   int find(int device, int pin, struct acpica_pci_irq **irq);
53   bool request(Resource *parent, Device *, Resource *child, Device *cdev);
54   bool alloc(Resource *, Device *, Resource *, Device *, bool)
55   { return false; }
56 };
57
58
59 bool
60 Acpi_pci_irq_router_rs::request(Resource *parent, Device *,
61                                 Resource *child, Device *cdev)
62 {
63 #if 0
64   printf("requesting IRQ resource: ");
65   child->dump();
66   printf(" at ACPI IRQ routing resource\n");
67 #endif
68   Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
69
70   if (!cr)
71     {
72       child->parent(parent);
73       return true;
74     }
75
76   Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
77
78   if (!cd)
79     return false;
80
81   struct acpica_pci_irq *irq = 0;
82
83   if (find(cd->adr() >> 16, cr->start(), &irq) < 0)
84     return false;
85
86   if (!irq)
87     return false;
88
89   cr->del_flags(Resource::F_relative);
90   cr->start(irq->irq);
91   cr->del_flags(Resource::Irq_info_base * 3);
92   unsigned flags = 0;
93   flags |= (!irq->trigger) * Resource::Irq_info_base;
94   flags |= (!!irq->polarity) * Resource::Irq_info_base * 2;
95   cr->add_flags(flags);
96
97   cr->parent(parent);
98
99   return true;
100 }
101
102 enum Acpi_irq_model_id {
103         ACPI_IRQ_MODEL_PIC = 0,
104         ACPI_IRQ_MODEL_IOAPIC,
105         ACPI_IRQ_MODEL_IOSAPIC,
106         ACPI_IRQ_MODEL_PLATFORM,
107         ACPI_IRQ_MODEL_COUNT
108 };
109
110 static ACPI_STATUS
111 get_irq_cb(ACPI_RESOURCE *res, void *ctxt)
112 {
113   acpica_pci_irq *irq = (acpica_pci_irq*)ctxt;
114   if (!res)
115     return AE_OK;
116
117   switch (res->Type)
118     {
119     case ACPI_RESOURCE_TYPE_IRQ:
120       irq->irq = res->Data.Irq.Interrupts[0];
121       irq->polarity = res->Data.Irq.Polarity;
122       irq->trigger  = res->Data.Irq.Triggering;
123       return AE_OK;
124
125     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
126       irq->irq = res->Data.ExtendedIrq.Interrupts[0];
127       irq->polarity = res->Data.ExtendedIrq.Polarity;
128       irq->trigger  = res->Data.ExtendedIrq.Triggering;
129       return AE_OK;
130
131     default:
132       return AE_OK;
133     }
134 }
135
136 int
137 Acpi_pci_irq_router_rs::add_prt_entry(ACPI_HANDLE obj,
138                                       ACPI_PCI_ROUTING_TABLE *e)
139 {
140   if (!e)
141     return -EINVAL;
142
143   Prt_entry *ne = new Prt_entry();
144   if (!ne)
145     return -ENOMEM;
146
147   ne->slot = (e->Address >> 16) & 0xffff;
148   ne->pin = e->Pin;
149
150   ne->irq.irq = e->SourceIndex;
151   ne->irq.polarity = ACPI_ACTIVE_LOW;
152   ne->irq.trigger = ACPI_LEVEL_SENSITIVE;
153   if (e->Source[0])
154     {
155       ACPI_HANDLE link;
156       if (Io_config::cfg->verbose() >= 2)
157         printf(" (dev[%s][%d]) ", e->Source, e->SourceIndex);
158       ACPI_STATUS status;
159       status = AcpiGetHandle(obj, e->Source, &link);
160       if (ACPI_FAILURE(status))
161         {
162           printf("\nWarning: Could not find PCI IRQ Link Device...\n");
163           return -ENODEV;
164         }
165
166       status = AcpiWalkResources(link, (char*)"_CRS", get_irq_cb, &ne->irq);
167       if (ACPI_FAILURE(status))
168         {
169           printf("\nWarning: Could not evaluate _CRS of PCI IRQ Link Device\n");
170           return -ENODEV;
171         }
172     }
173
174   _prt = cxx::List_item::push_back(_prt, ne);
175   return 0;
176 }
177
178 int
179 Acpi_pci_irq_router_rs::find(int device, int pin, struct acpica_pci_irq **irq)
180 {
181   Prt_entry::T_iter<Prt_entry> c = _prt;
182   while (*c)
183     {
184       if (c->slot == (unsigned)device && c->pin == pin)
185         {
186           *irq = &c->irq;
187           return 0;
188         }
189
190       ++c;
191     }
192
193   return -ENODEV;
194 }
195
196
197 static int acpi_bus_init_irq(void)
198 {
199   ACPI_STATUS status = AE_OK;
200   ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
201   ACPI_OBJECT_LIST arg_list = { 1, &arg };
202   char const *message = NULL;
203
204
205   //int acpi_irq_model = ACPI_IRQ_MODEL_PIC;
206   int acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
207   /*
208    * Let the system know what interrupt model we are using by
209    * evaluating the \_PIC object, if exists.
210    */
211
212   switch (acpi_irq_model) {
213     case ACPI_IRQ_MODEL_PIC:
214       message = "PIC";
215       break;
216     case ACPI_IRQ_MODEL_IOAPIC:
217       message = "IOAPIC";
218       break;
219     case ACPI_IRQ_MODEL_IOSAPIC:
220       message = "IOSAPIC";
221       break;
222     case ACPI_IRQ_MODEL_PLATFORM:
223       message = "platform specific model";
224       break;
225     default:
226       printf("Unknown interrupt routing model\n");
227       return -1;
228   }
229
230   printf("Using %s for interrupt routing\n", message);
231
232   arg.Integer.Value = acpi_irq_model;
233
234   status = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
235   if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
236       ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
237       return -1;
238   }
239
240   return 0;
241 }
242
243
244 struct Discover_ctxt
245 {
246   Hw::Device *last_device;
247   Hw::Device *current_bus;
248   unsigned level;
249 };
250
251 class Acpi_res_discover : public Hw::Discover_res_if
252 {
253 public:
254   Acpi_res_discover(ACPI_HANDLE obj) : obj(obj) {}
255
256   void discover_resources(Hw::Device *host);
257   void setup_resources(Hw::Device *) {}
258
259 private:
260   void discover_prt(Hw::Device *host);
261   void discover_crs(Hw::Device *host);
262
263   ACPI_HANDLE obj;
264 };
265
266 void
267 Acpi_res_discover::discover_prt(Hw::Device *host)
268 {
269   ACPI_BUFFER buf;
270   ACPI_STATUS status;
271   ACPI_HANDLE handle;
272
273   status = AcpiGetHandle(obj, (char*)"_PRT", &handle);
274
275   // no PRT!!
276   if (ACPI_FAILURE(status))
277     {
278       Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
279       host->add_resource(r);
280       return;
281     }
282
283 #if 0
284   ret_buf.Length = sizeof (buffer);
285   ret_buf.Pointer = buffer;
286
287   status = AcpiGetName (obj, ACPI_FULL_PATHNAME, &ret_buf);
288
289   if (ACPI_FAILURE (status))
290     AcpiOsPrintf ("Could not convert name to pathname\n");
291   else
292     AcpiOsPrintf ("ACPI: PCI IRQ routing [%s._PRT]\n", buffer);
293 #endif
294
295   buf.Length = ACPI_ALLOCATE_BUFFER;
296
297   status = AcpiGetIrqRoutingTable(obj, &buf);
298
299   if (ACPI_FAILURE(status))
300     {
301       printf("ERROR: while getting PRT for [%s]\n", "buffer");
302       Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
303       host->add_resource(r);
304       return;
305     }
306
307   typedef Pci_irq_router_res<Acpi_pci_irq_router_rs> Irq_res;
308   Irq_res *r = new Irq_res();
309
310   char *p = (char*)buf.Pointer;
311   char *e = (char*)buf.Pointer + buf.Length;
312   while (1)
313     {
314       ACPI_PCI_ROUTING_TABLE *prt = (ACPI_PCI_ROUTING_TABLE *)p;
315       if (prt->Length == 0)
316         break;
317
318       if (p + prt->Length > e)
319         break;
320
321       int err = r->provided()->add_prt_entry(obj, prt);
322       if (err < 0)
323         return;
324
325       p += prt->Length;
326     }
327
328   host->add_resource(r);
329 }
330
331 static unsigned acpi_adr_t_to_f(unsigned art)
332 {
333   switch (art)
334     {
335     case ACPI_MEMORY_RANGE: return Resource::Mmio_res;
336     case ACPI_IO_RANGE: return Resource::Io_res;
337     case ACPI_BUS_NUMBER_RANGE: return Resource::Bus_res;
338     default: return ~0;
339     }
340 }
341
342 static void
343 acpi_adr_res(Hw::Device *host, ACPI_RESOURCE_ADDRESS const *ar, l4_uint64_t s, l4_uint64_t l,
344              bool qw)
345 {
346   unsigned flags = acpi_adr_t_to_f(ar->ResourceType)
347                    | Resource::F_fixed_size | Resource::F_fixed_addr;
348
349   if (flags == ~0U)
350     return;
351
352   if (qw)
353     flags |= Resource::F_width_64bit;
354
355   Resource *r;
356   if (ar->ProducerConsumer == ACPI_PRODUCER)
357     r = new Adr_resource_provider(flags, s, s + l - 1);
358   else
359     r = new Adr_resource(flags, s, s + l -1);
360
361   host->add_resource(r);
362 }
363
364 void
365 Acpi_res_discover::discover_crs(Hw::Device *host)
366 {
367   ACPI_BUFFER buf;
368   buf.Length = ACPI_ALLOCATE_BUFFER;
369
370   if (ACPI_FAILURE(AcpiGetCurrentResources(obj, &buf)))
371     return;
372
373   char const *p = (char const *)buf.Pointer;
374   while (p)
375     {
376       ACPI_RESOURCE const *r = (ACPI_RESOURCE const *)p;
377       ACPI_RESOURCE_DATA const *d = &r->Data;
378       unsigned flags = 0;
379
380       switch (r->Type)
381         {
382         case ACPI_RESOURCE_TYPE_END_TAG:
383           AcpiOsFree(buf.Pointer);
384           return;
385
386         case ACPI_RESOURCE_TYPE_IRQ:
387           flags = Resource::Irq_res;
388           flags |= (!d->Irq.Triggering) * Resource::Irq_info_base;
389           flags |= (!!d->Irq.Polarity) * Resource::Irq_info_base * 2;
390           for (unsigned c = 0; c < d->Irq.InterruptCount; ++c)
391             host->add_resource(new Adr_resource(flags, d->Irq.Interrupts[c],
392                                                 d->Irq.Interrupts[c]));
393           break;
394
395         case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
396           flags = Resource::Irq_res;
397           flags |= (!d->ExtendedIrq.Triggering) * Resource::Irq_info_base;
398           flags |= (!!d->ExtendedIrq.Polarity) * Resource::Irq_info_base * 2;
399           if (d->ExtendedIrq.ResourceSource.StringPtr)
400             {
401               printf("hoo indirect IRQ resource found src=%s idx=%d\n",
402                      d->ExtendedIrq.ResourceSource.StringPtr,
403                      d->ExtendedIrq.ResourceSource.Index);
404             }
405           else
406             {
407               for (unsigned c = 0; c < d->ExtendedIrq.InterruptCount; ++c)
408                 host->add_resource(new Adr_resource(flags, d->ExtendedIrq.Interrupts[c],
409                       d->ExtendedIrq.Interrupts[c]));
410             }
411           break;
412
413         case ACPI_RESOURCE_TYPE_IO:
414           flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
415           host->add_resource(new Adr_resource(flags, d->Io.Minimum,
416                                               d->Io.Minimum + d->Io.AddressLength - 1));
417           break;
418
419         case ACPI_RESOURCE_TYPE_FIXED_IO:
420           flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
421           host->add_resource(new Adr_resource(flags, d->FixedIo.Address,
422                                               d->FixedIo.Address + d->FixedIo.AddressLength - 1));
423           break;
424
425         case ACPI_RESOURCE_TYPE_MEMORY24:
426           flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
427           host->add_resource(new Adr_resource(flags, d->Memory24.Minimum,
428                                               d->Memory24.Minimum + d->Memory24.AddressLength - 1));
429           break;
430
431         case ACPI_RESOURCE_TYPE_MEMORY32:
432           flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
433           host->add_resource(new Adr_resource(flags, d->Memory32.Minimum,
434                                               d->Memory32.Minimum + d->Memory32.AddressLength - 1));
435           break;
436
437         case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
438           flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
439           host->add_resource(new Adr_resource(flags, d->FixedMemory32.Address,
440                                d->FixedMemory32.Address + d->FixedMemory32.AddressLength - 1));
441           break;
442
443         case ACPI_RESOURCE_TYPE_ADDRESS16:
444           acpi_adr_res(host, &d->Address, d->Address16.Minimum, d->Address16.AddressLength, 0);
445           break;
446
447         case ACPI_RESOURCE_TYPE_ADDRESS32:
448           acpi_adr_res(host, &d->Address, d->Address32.Minimum, d->Address32.AddressLength, 0);
449           break;
450
451         case ACPI_RESOURCE_TYPE_ADDRESS64:
452           acpi_adr_res(host, &d->Address, d->Address64.Minimum, d->Address64.AddressLength, 1);
453           break;
454
455         default:
456           printf("IGNORE ACPI RES: %d\n", r->Type);
457           break;
458
459
460         }
461
462       p += r->Length;
463     }
464
465   AcpiOsFree(buf.Pointer);
466 }
467
468 void
469 Acpi_res_discover::discover_resources(Hw::Device *host)
470 {
471   if (dynamic_cast<Pci_bridge*>(host->discover_bus_if()))
472     discover_prt(host);
473
474   discover_crs(host);
475 }
476
477
478 static l4_uint32_t
479 get_adr(ACPI_HANDLE dev)
480 {
481   ACPI_HANDLE adr;
482   if (ACPI_FAILURE(AcpiGetHandle(dev, const_cast<char*>("_ADR"), &adr)))
483     return ~0U;
484
485   ACPI_OBJECT adro;
486   ACPI_BUFFER ret_buf;
487   ret_buf.Pointer = &adro;
488   ret_buf.Length = sizeof(adro);
489   if (ACPI_SUCCESS(AcpiEvaluateObject(adr, NULL, NULL, &ret_buf)))
490     {
491       switch (adro.Type)
492         {
493         case ACPI_TYPE_INTEGER:
494           return adro.Integer.Value;
495         default:
496           return ~0;
497         }
498     }
499
500   return ~0;
501 }
502
503 static void
504 get_name(ACPI_HANDLE dev, Hw::Device *hd)
505 {
506   char str[5];
507   ACPI_BUFFER buf;
508   buf.Pointer = &str;
509   buf.Length = sizeof(str);
510   if (ACPI_SUCCESS(AcpiGetName(dev, ACPI_SINGLE_NAME, &buf)))
511     hd->set_name(str);
512 }
513
514
515 static ACPI_STATUS
516 discover_pre_cb(ACPI_HANDLE obj, UINT32 nl, void *ctxt, void **)
517 {
518   Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
519
520   if (nl == 1)
521     return AE_OK;
522
523   if (nl > c->level)
524     {
525       c->current_bus = c->last_device;
526       c->level = nl;
527     }
528
529   l4_uint32_t adr = get_adr(obj);
530
531   Hw::Device *nd = c->current_bus->get_child_dev_uid((l4_umword_t)obj, adr, true);
532   c->last_device = nd;
533
534   get_name(obj, nd);
535
536   ACPI_DEVICE_ID *hid = 0;
537   ACPI_DEVICE_ID_LIST *cid = 0;
538   bool pci_rb = false;
539 #if 0
540   if (ACPI_FAILURE(AcpiUtAcquireMutex(ACPI_MTX_NAMESPACE)))
541     return AE_OK;
542 #endif
543
544   ACPI_NAMESPACE_NODE *node = AcpiNsValidateHandle(obj);
545   if (!node)
546     {
547       //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
548       return AE_OK;
549     }
550
551   if (ACPI_SUCCESS(AcpiUtExecute_HID(node, &hid)))
552     {
553       nd->set_hid(hid->String);
554       pci_rb |= AcpiUtIsPciRootBridge(hid->String);
555       ACPI_FREE(hid);
556     }
557
558   if (ACPI_SUCCESS(AcpiUtExecute_CID(node, &cid)))
559     {
560       for (unsigned i = 0; i < cid->Count; ++i)
561         {
562           nd->add_cid(cid->Ids[i].String);
563           pci_rb |= AcpiUtIsPciRootBridge(cid->Ids[i].String);
564         }
565       ACPI_FREE(cid);
566     }
567
568
569   //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
570
571   // hm, this seems very specific for PCI
572   if (pci_rb)
573     {
574       printf("Found PCI root bridge...\n");
575       if (Pci_root_bridge *rb = pci_root_bridge(0))
576         {
577           if (rb->host())
578             {
579               // we found a second root bridge
580               // create a new root pridge instance
581               rb = new Pci_port_root_bridge(nd);
582             }
583           else
584             rb->set_host(nd);
585
586           nd->set_discover_bus_if(rb);
587         }
588       else
589         printf("ERROR: there is no PCI bus driver for this platform\n");
590     }
591
592   nd->add_resource_discoverer(new Acpi_res_discover(obj));
593
594   return AE_OK;
595 }
596
597 static ACPI_STATUS
598 discover_post_cb(ACPI_HANDLE, UINT32 nl, void *ctxt, void **)
599 {
600   Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
601   if (nl < c->level)
602     {
603       c->level = nl;
604       c->current_bus = c->current_bus->parent();
605     }
606   return AE_OK;
607 }
608
609 }
610
611
612 int acpica_init()
613 {
614   printf("Hello from L4-ACPICA\n");
615
616   pci_register_root_bridge(0, new Pci_port_root_bridge(0));
617
618   AcpiDbgLevel =
619       ACPI_LV_INIT
620     //| ACPI_LV_INFO
621    // | ACPI_LV_FUNCTIONSkern/irq.cpp
622    //     | ACPI_LV_ALL_EXCEPTIONS 
623     //    | ACPI_LV_LOAD 
624     //    | ACPI_LV_INIT_NAMES 
625         | ACPI_LV_TABLES 
626     //    | ACPI_LV_RESOURCES 
627     //    | ACPI_LV_NAMES
628     //    | ACPI_LV_VALUES 
629     //    | ACPI_LV_OPREGION  
630         | ACPI_LV_VERBOSE_INFO 
631     //    | ACPI_LV_PARSE
632     //    | ACPI_LV_DISPATCH
633     //    | ACPI_LV_EXEC
634     //    | ACPI_LV_IO
635     ;
636
637 //0. enable workarounds, see include/acglobals.h
638   AcpiGbl_EnableInterpreterSlack = (1==1);
639   ACPI_STATUS status;
640
641   status = AcpiInitializeSubsystem();
642   if(status!=AE_OK)
643     return status;
644
645   status = AcpiInitializeTables (0, 0, TRUE);
646   if(status!=AE_OK)
647     return status;
648
649   status = AcpiReallocateRootTable ();
650 //  if(status!=AE_OK)
651 //    return status;
652
653   status = AcpiLoadTables ();
654
655   if(ACPI_FAILURE(status))
656     return status;
657
658   printf("enable ACPI subsystem\n");
659   status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
660
661   if (ACPI_FAILURE(status))
662     {
663       printf("Unable to start the ACPI Interpreter\n");
664       exit(status);
665     }
666
667   printf("initialize ACPI objects\n");
668   status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
669   if (ACPI_FAILURE(status)) {
670       printf("Unable to initialize ACPI objects\n");
671       exit(status);
672   }
673
674   printf("Interpreter enabled\n");
675
676   Discover_ctxt c;
677   c.last_device = system_bus();
678   c.current_bus = system_bus();
679   c.level = 1;
680
681
682   printf("scanning for PCI root bridge\n");
683   status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
684                              ACPI_UINT32_MAX,
685                              discover_pre_cb, discover_post_cb, &c, 0);
686
687   /*
688    * Get the system interrupt model and evaluate \_PIC.
689    */
690   int result = acpi_bus_init_irq();
691   if (result)
692     {
693       printf("Could not initialize ACPI IRQ stuff\n");
694       exit(1);
695     }
696   status = AcpiSubsystemStatus();
697
698   if (ACPI_FAILURE(status))
699       exit(status);
700   else if (Io_config::cfg->verbose() > 1)
701     printf("acpi_subsystem initialized\n");
702
703
704   ACPI_BUFFER ret_buffer;
705   ret_buffer.Length = ACPI_ALLOCATE_BUFFER;
706
707   status = AcpiGetSystemInfo(&ret_buffer);
708
709   if(ACPI_FAILURE(status))
710     exit(status);
711
712   acpi_print_system_info(ret_buffer.Pointer);
713
714   AcpiOsFree(ret_buffer.Pointer);
715
716   return 0;
717 }
718