olsneracpi.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /*
  2. Copyright (c) 2014 Simon Brenner
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "acpi.h"
  20. #include "accommon.h"
  21. #include "acapps.h"
  22. #include "actables.h"
  23. #include "acutils.h"
  24. #define DBGFLG 0
  25. #define _COMPONENT ACPI_UTILITIES
  26. ACPI_MODULE_NAME ("harvey")
  27. /******************************************************************************
  28. *
  29. * Example ACPICA handler and handler installation
  30. *
  31. *****************************************************************************/
  32. #if 0
  33. static void NotifyHandler (
  34. ACPI_HANDLE Device,
  35. UINT32 Value,
  36. void *Context)
  37. {
  38. ACPI_INFO ((AE_INFO, "Received a notify 0x%x (device %p, context %p)", Value, Device, Context));
  39. }
  40. static ACPI_STATUS InstallHandlers (void)
  41. {
  42. ACPI_STATUS Status;
  43. /* Install global notify handler */
  44. Status = AcpiInstallNotifyHandler (ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
  45. NotifyHandler, NULL);
  46. if (ACPI_FAILURE (Status))
  47. {
  48. ACPI_EXCEPTION ((AE_INFO, Status, "While installing Notify handler"));
  49. return (Status);
  50. }
  51. return (AE_OK);
  52. }
  53. /******************************************************************************
  54. *
  55. * Example ACPICA initialization code. This shows a full initialization with
  56. * no early ACPI table access.
  57. *
  58. *****************************************************************************/
  59. static ACPI_STATUS InitializeFullAcpi (void)
  60. {
  61. ACPI_STATUS Status;
  62. /* Initialize the ACPICA subsystem */
  63. Status = AcpiInitializeSubsystem ();
  64. if (ACPI_FAILURE (Status))
  65. {
  66. ACPI_EXCEPTION ((AE_INFO, Status, "While initializing ACPICA"));
  67. return (Status);
  68. }
  69. /* Initialize the ACPICA Table Manager and get all ACPI tables */
  70. Status = AcpiInitializeTables (NULL, 0, FALSE);
  71. if (ACPI_FAILURE (Status))
  72. {
  73. ACPI_EXCEPTION ((AE_INFO, Status, "While initializing Table Manager"));
  74. return (Status);
  75. }
  76. /* Create the ACPI namespace from ACPI tables */
  77. Status = AcpiLoadTables ();
  78. if (ACPI_FAILURE (Status))
  79. {
  80. ACPI_EXCEPTION ((AE_INFO, Status, "While loading ACPI tables"));
  81. return (Status);
  82. }
  83. /* Install local handlers */
  84. Status = InstallHandlers ();
  85. if (ACPI_FAILURE (Status))
  86. {
  87. ACPI_EXCEPTION ((AE_INFO, Status, "While installing handlers"));
  88. return (Status);
  89. }
  90. /* Initialize the ACPI hardware */
  91. Status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
  92. if (ACPI_FAILURE (Status))
  93. {
  94. ACPI_EXCEPTION ((AE_INFO, Status, "While enabling ACPICA"));
  95. return (Status);
  96. }
  97. /* Complete the ACPI namespace object initialization */
  98. Status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
  99. if (ACPI_FAILURE (Status))
  100. {
  101. ACPI_EXCEPTION ((AE_INFO, Status, "While initializing ACPICA objects"));
  102. return (Status);
  103. }
  104. return (AE_OK);
  105. }
  106. #endif
  107. ACPI_STATUS ExecuteOSI(int pic_mode)
  108. {
  109. ACPI_STATUS Status;
  110. ACPI_OBJECT_LIST ArgList;
  111. ACPI_OBJECT Arg[1];
  112. ACPI_BUFFER ReturnValue;
  113. /* Setup input argument */
  114. ArgList.Count = 1;
  115. ArgList.Pointer = Arg;
  116. Arg[0].Type = ACPI_TYPE_INTEGER;
  117. Arg[0].Integer.Value = pic_mode;
  118. ACPI_INFO ((AE_INFO, "Executing _PIC(%ld)", Arg[0].Integer.Value));
  119. /* Ask ACPICA to allocate space for the return object */
  120. ReturnValue.Length = ACPI_ALLOCATE_BUFFER;
  121. Status = AcpiEvaluateObject (NULL, "\\_PIC", &ArgList, &ReturnValue);
  122. ////ACPI_FREE_BUFFER(ReturnValue);
  123. if (Status == AE_NOT_FOUND)
  124. {
  125. if (DBGFLG) printf("\\_PIC was not found. Assuming that's ok.\n");
  126. return AE_OK;
  127. }
  128. if (ACPI_FAILURE (Status))
  129. {
  130. ACPI_EXCEPTION ((AE_INFO, Status, "While executing _PIC"));
  131. return Status;
  132. }
  133. if (DBGFLG) printf("_PIC returned.\n");
  134. return Status;
  135. }
  136. #define CHECK_STATUS(fmt, ...) do { if (ACPI_FAILURE(status)) { \
  137. if (DBGFLG) printf("ACPI failed (%d): " fmt "\n", status, ## __VA_ARGS__); \
  138. goto failed; \
  139. } } while(0)
  140. #pragma pack(1)
  141. typedef union acpi_apic_struct
  142. {
  143. struct {
  144. UINT8 Type;
  145. UINT8 Length;
  146. };
  147. ACPI_MADT_LOCAL_APIC LocalApic;
  148. ACPI_MADT_IO_APIC IOApic;
  149. ACPI_MADT_INTERRUPT_OVERRIDE InterruptOverride;
  150. ACPI_MADT_LOCAL_APIC_NMI LocalApicNMI;
  151. } ACPI_APIC_STRUCT;
  152. #pragma pack()
  153. typedef struct {
  154. int irqs[8];
  155. } PRT;
  156. PRT prts[256];
  157. ACPI_STATUS FindIOAPICs(int *pic_mode) {
  158. ACPI_TABLE_MADT* table = NULL;
  159. ACPI_STATUS status = AcpiGetTable("APIC", 0, (ACPI_TABLE_HEADER**)&table);
  160. CHECK_STATUS("AcpiGetTable");
  161. char* endOfTable = (char*)table + table->Header.Length;
  162. char* p = (char*)(table + 1);
  163. int n = 0;
  164. while (p < endOfTable) {
  165. ACPI_APIC_STRUCT* apic = (ACPI_APIC_STRUCT*)p;
  166. p += apic->Length;
  167. n++;
  168. switch (apic->Type)
  169. {
  170. case ACPI_MADT_TYPE_IO_APIC:
  171. if (DBGFLG) printf("Found I/O APIC. ID %#x Addr %#x GSI base %#x.\n",
  172. (int)apic->IOApic.Id,
  173. apic->IOApic.Address,
  174. apic->IOApic.GlobalIrqBase);
  175. //AddIOAPIC(&apic->IOApic);
  176. *pic_mode = 1;
  177. break;
  178. }
  179. }
  180. if (*pic_mode)
  181. {
  182. if (DBGFLG) printf("I/O APICs found, setting APIC mode\n");
  183. }
  184. else
  185. {
  186. if (DBGFLG) printf("I/O APICs NOT found, setting PIC mode\n");
  187. //AddPIC();
  188. }
  189. failed:
  190. return AE_OK;
  191. }
  192. static ACPI_STATUS PrintAPICTable(void) {
  193. static const char *polarities[] = {
  194. "Bus-Conformant",
  195. "Active-High",
  196. "Reserved",
  197. "Active-Low"
  198. };
  199. static const char *triggerings[] = {
  200. "Bus-Conformant",
  201. "Edge-Triggered",
  202. "Reserved",
  203. "Level-Triggered"
  204. };
  205. ACPI_TABLE_MADT* table = NULL;
  206. ACPI_STATUS status = AcpiGetTable("APIC", 0, (ACPI_TABLE_HEADER**)&table);
  207. CHECK_STATUS("AcpiGetTable");
  208. if (DBGFLG) printf("Found APIC table: %p\n", table);
  209. if (DBGFLG) printf("Address of Local APIC: %#x\n", table->Address);
  210. if (DBGFLG) printf("Flags: %#x\n", table->Flags);
  211. char* endOfTable = (char*)table + table->Header.Length;
  212. char* p = (char*)(table + 1);
  213. int n = 0;
  214. while (p < endOfTable) {
  215. ACPI_APIC_STRUCT* apic = (ACPI_APIC_STRUCT*)p;
  216. p += apic->Length;
  217. n++;
  218. switch (apic->Type)
  219. {
  220. case ACPI_MADT_TYPE_LOCAL_APIC:
  221. if (DBGFLG) printf("%d: Local APIC. Processor ID %#x APIC ID %#x En=%d (%#x)\n", n,
  222. (int)apic->LocalApic.ProcessorId,
  223. (int)apic->LocalApic.Id,
  224. apic->LocalApic.LapicFlags & 1,
  225. apic->LocalApic.LapicFlags);
  226. break;
  227. case ACPI_MADT_TYPE_IO_APIC:
  228. if (DBGFLG) printf("%d: I/O APIC. ID %#x Addr %#x GSI base %#x\n", n,
  229. (int)apic->IOApic.Id,
  230. apic->IOApic.Address,
  231. apic->IOApic.GlobalIrqBase);
  232. break;
  233. case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
  234. {
  235. UINT32 flags = apic->InterruptOverride.IntiFlags;
  236. if (DBGFLG) printf("%d: Interrupt Override. Source %#x GSI %#x Pol=%s Trigger=%s\n", n,
  237. apic->InterruptOverride.SourceIrq,
  238. apic->InterruptOverride.GlobalIrq,
  239. polarities[flags & 3], triggerings[(flags >> 2) & 3]);
  240. break;
  241. }
  242. case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
  243. {
  244. UINT32 flags = apic->InterruptOverride.IntiFlags;
  245. if (DBGFLG) printf("%d: Local APIC NMI. Processor ID %#x Pol=%s Trigger=%s LINT# %#x\n", n,
  246. apic->LocalApicNMI.ProcessorId,
  247. polarities[flags & 3], triggerings[(flags >> 2) & 3],
  248. apic->LocalApicNMI.Lint);
  249. break;
  250. }
  251. default:
  252. if (DBGFLG) printf("%d: Unknown APIC type %d\n", n, apic->Type);
  253. break;
  254. }
  255. }
  256. failed:
  257. return status;
  258. }
  259. ACPI_STATUS PrintAcpiDevice(ACPI_HANDLE Device)
  260. {
  261. ACPI_DEVICE_INFO* info = NULL;
  262. ACPI_STATUS status = AcpiGetObjectInfo(Device, &info);
  263. if (ACPI_SUCCESS(status)) {
  264. if (DBGFLG) printf("Device %p type %#x\n", Device, info->Type);
  265. }
  266. //ACPI_FREE(info);
  267. return_ACPI_STATUS(status);
  268. }
  269. static ACPI_STATUS PrintDeviceCallback(ACPI_HANDLE Device, UINT32 Depth, void *Context, void** ReturnValue)
  270. {
  271. return PrintAcpiDevice(Device);
  272. }
  273. // PNP0C0F = PCI Interrupt Link Device
  274. // PNP0A03 = PCI Root Bridge
  275. ACPI_STATUS PrintDevices(void) {
  276. ACPI_STATUS status = AE_OK;
  277. if (DBGFLG) printf("Searching for PNP0A03\n");
  278. status = AcpiGetDevices("PNP0A03", PrintDeviceCallback, NULL, NULL);
  279. CHECK_STATUS("AcpiGetDevices PNP0A03");
  280. if (DBGFLG) printf("Searching for PNP0C0F\n");
  281. status = AcpiGetDevices("PNP0C0F", PrintDeviceCallback, NULL, NULL);
  282. CHECK_STATUS("AcpiGetDevices PNP0C0F");
  283. failed:
  284. return_ACPI_STATUS(status);
  285. }
  286. typedef struct IRQRouteData
  287. {
  288. ACPI_PCI_ID pci;
  289. unsigned pin;
  290. int8_t gsi;
  291. // triggering: 1 = edge triggered, 0 = level
  292. int8_t triggering;
  293. // polarity: 1 = active-low, 0 = active-high
  294. int8_t polarity;
  295. BOOLEAN found;
  296. } IRQRouteData;
  297. static void ResetBuffer(ACPI_BUFFER* buffer) {
  298. ////ACPI_FREE_BUFFER((*buffer));
  299. buffer->Pointer = 0;
  300. buffer->Length = ACPI_ALLOCATE_BUFFER;
  301. }
  302. static ACPI_STATUS RouteIRQLinkDevice(ACPI_HANDLE Device, ACPI_PCI_ROUTING_TABLE* found, IRQRouteData* data) {
  303. ACPI_STATUS status = AE_OK;
  304. ACPI_HANDLE LinkDevice = NULL;
  305. ACPI_BUFFER buffer = {0, NULL};
  306. if (DBGFLG) printf("Routing IRQ Link device %s\n", found->Source);
  307. status = AcpiGetHandle(Device, found->Source, &LinkDevice);
  308. CHECK_STATUS("AcpiGetHandle %s", found->Source);
  309. ResetBuffer(&buffer);
  310. status = AcpiGetCurrentResources(LinkDevice, &buffer);
  311. CHECK_STATUS("AcpiGetCurrentResources");
  312. if (DBGFLG) printf("Got %lu bytes of current resources\n", buffer.Length);
  313. ACPI_RESOURCE* resource = (ACPI_RESOURCE*)buffer.Pointer;
  314. switch (resource->Type) {
  315. case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  316. // The interrupt count must be 1 when returned from _CRS, supposedly.
  317. // I think the "possible resource setting" may list several.
  318. if (DBGFLG) printf("Extended IRQ: %d interrupts, first one %#x. %s triggered, Active-%s.\n",
  319. resource->Data.ExtendedIrq.InterruptCount,
  320. resource->Data.ExtendedIrq.Interrupts[0],
  321. resource->Data.ExtendedIrq.Triggering ? "Edge" : "Level",
  322. resource->Data.ExtendedIrq.Polarity ? "Low" : "High");
  323. data->gsi = resource->Data.ExtendedIrq.Interrupts[0];
  324. data->triggering = resource->Data.ExtendedIrq.Triggering;
  325. data->polarity = resource->Data.ExtendedIrq.Polarity;
  326. break;
  327. case ACPI_RESOURCE_TYPE_IRQ:
  328. if (DBGFLG) printf("IRQ: %d interrupts, first one %#x.\n",
  329. resource->Data.Irq.InterruptCount,
  330. resource->Data.Irq.Interrupts[0]);
  331. data->gsi = resource->Data.Irq.Interrupts[0];
  332. // PIC interrupts can't be set up for specific polarity and triggering,
  333. // I think.
  334. break;
  335. default:
  336. if (DBGFLG) printf("RouteIRQLinkDevice: unknown resource type %d\n", resource->Type);
  337. status = AE_BAD_DATA;
  338. goto failed;
  339. }
  340. status = AcpiSetCurrentResources(LinkDevice, &buffer);
  341. CHECK_STATUS("AcpiSetCurrentResources");
  342. failed:
  343. //ACPI_FREE_BUFFER(buffer);
  344. return_ACPI_STATUS(status);
  345. }
  346. static int readfile(char *path, char *buf, size_t buflen)
  347. {
  348. int fd = open(path, OREAD);
  349. int amt;
  350. if (fd < 0)
  351. return fd;
  352. amt = read(fd, buf, buflen);
  353. (void)close(fd);
  354. return amt;
  355. }
  356. static ACPI_STATUS
  357. resource(ACPI_RESOURCE *r, void *Context)
  358. {
  359. ACPI_RESOURCE_IRQ *i = &r->Data.Irq;
  360. if (DBGFLG) print("\tACPI_RESOURCE_TYPE_%d: Length %d\n", r->Type, r->Length);
  361. if (r->Type != ACPI_RESOURCE_TYPE_IRQ)
  362. return 0;
  363. if (DBGFLG) print("\t\tIRQ Triggering %d Polarity %d Sharable %d InterruptCount %d: ",
  364. i->Triggering, i->Polarity, i->Sharable, i->InterruptCount);
  365. for(int j = 0; j < i->InterruptCount; j++)
  366. if (DBGFLG) print("%d,", i->Interrupts[j]);
  367. if (DBGFLG) print("\n");
  368. if (DBGFLG) print("apic %d, pin 0x%x\n", 1, i->Interrupts[0]);
  369. return 0;
  370. }
  371. ACPI_STATUS
  372. device(ACPI_HANDLE Object,
  373. UINT32 NestingLevel,
  374. void *Context,
  375. void **ReturnValue)
  376. {
  377. ACPI_STATUS as;
  378. ACPI_DEVICE_INFO *info;
  379. as = AcpiGetObjectInfo(Object, &info);
  380. if (DBGFLG) print("as is %d\n", as);
  381. if (!ACPI_SUCCESS(as))
  382. return 0;
  383. ACPI_BUFFER out;
  384. out.Length = ACPI_ALLOCATE_BUFFER;
  385. out.Pointer = nil;
  386. char n[5];
  387. memmove(n, &info->Name, sizeof(info->Name));
  388. n[4] = 0;
  389. if (DBGFLG) print("%s\n", n);
  390. as = AcpiGetIrqRoutingTable(Object, &out);
  391. if (DBGFLG) print("get the PRT: %d\n", as);
  392. if (DBGFLG) print("Length is %u ptr is %p\n", out.Length, out.Pointer);
  393. if (ACPI_SUCCESS(as)) {
  394. void *p = (void *)out.Pointer;
  395. while(((ACPI_PCI_ROUTING_TABLE*)p)->Length > 0) {
  396. ACPI_PCI_ROUTING_TABLE *t = p;
  397. if (DBGFLG) print("%s: ", t->Source);
  398. if (DBGFLG) print("Pin 0x%x, Address 0x%llx, SourceIndex 0x%x\n",
  399. t->Pin, t->Address, t->SourceIndex);
  400. int adr = t->Address>>16;
  401. prts[adr].irqs[t->Pin] = t->SourceIndex;
  402. p += t->Length;
  403. }
  404. }
  405. as = AcpiWalkResources(Object, "_CRS", resource, nil);
  406. if (DBGFLG) print("Walk resources: as is %d\n", as);
  407. return 0;
  408. }
  409. int GetPRT(void)
  410. {
  411. ACPI_BUFFER out;
  412. static char path[128];
  413. static char buf[1024];
  414. ACPI_STATUS as;
  415. /* There are, potentially, 256 levels. Unlikely but ... */
  416. char *f[255];
  417. int nf;
  418. char *bridges;
  419. out.Length = ACPI_ALLOCATE_BUFFER;
  420. out.Pointer = nil;
  421. /* this is the part I don't know well. for now, let's try
  422. * getting the _PRT for everything in the path from ROOT.
  423. */
  424. snprint(path, sizeof(path), "\\_SB.PCI0._PRT");
  425. if (DBGFLG) print("OK, try to evaluate %s\n", path);
  426. as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, path, NULL, &out);
  427. if (DBGFLG) print("returns %d\n", as);
  428. if (!ACPI_SUCCESS(as))
  429. return as;
  430. if (DBGFLG) print("------>GOT the PRT: for 0\n");
  431. if (DBGFLG) print("Length is %u ptr is %p\n", out.Length, out.Pointer);
  432. /* now get all PRTs for all devices. */
  433. as = AcpiGetDevices (nil, device, nil, nil);
  434. if (DBGFLG) print("acpigetdevices %d\n", as);
  435. return AE_OK;
  436. }
  437. static int mapit(ACPI_HANDLE dev, IRQRouteData*d, int r)
  438. {
  439. static char path[128];
  440. static char buf[1024];
  441. int BridgeDevice;
  442. int gsi;
  443. ACPI_STATUS as;
  444. ACPI_STATUS status;
  445. /* There are, potentially, 256 levels. Unlikely but ... */
  446. char *f[255];
  447. int nf;
  448. char *bridges;
  449. /* try namespace, then device. */
  450. snprint(path, sizeof(path), "/dev/pci/%d.%d.0ctl", d->pci.Bus, d->pci.Device);
  451. if (readfile(path, buf, sizeof(buf)) < 0) {
  452. snprint(path, sizeof(path), "#$/pci/%d.%d.0ctl", d->pci.Bus, d->pci.Device);
  453. if (readfile(path, buf, sizeof(buf)) < 0)
  454. return -1;
  455. }
  456. nf = tokenize(buf, f, 5);
  457. if (nf < 5)
  458. return -1;
  459. if (DBGFLG) print("Path is %s\n", f[3]);
  460. bridges = f[3];
  461. nf = gettokens(bridges, f, nelem(f), "/");
  462. if (DBGFLG) print("Path as %d componenents\n", nf);
  463. if (nf < 2)
  464. return 0;
  465. /* OK, FOR NOW, we're just doing one level. */
  466. if (nf > 2)
  467. sysfatal("PANIC: Can't do more than one level of bridge");
  468. /* and, further, we take the root bridge as kind of a given. So we only care about
  469. * the bridge in f[1].
  470. */
  471. char *bridgeno = f[1];
  472. nf = gettokens(bridgeno, f, 3, ".");
  473. if (nf < 3)
  474. sysfatal("BOTCH! the bridge device requires 3 fields, only had %d\n", nf);
  475. BridgeDevice = strtoul(f[1], 0, 0);
  476. if (DBGFLG) print("BridgeDevice is 0x%x, pin is %d\n", BridgeDevice, d->pin);
  477. /* and the swizzling is fixed, per the PCI standard. take the low 2 bits (for now)
  478. * of device #, add pin, mod3, that's it. */
  479. /* confusing: pin numbers are 1-relative. But for this to work they need to be
  480. * zero-relative. Sorry. */
  481. int pin = (d->pin - 1 + d->pci.Device) % 4;
  482. gsi = prts[BridgeDevice].irqs[pin];
  483. if (DBGFLG) print("GSI is 0x%x\n", gsi);
  484. if (DBGFLG) print("echo -n %d %d %d %d 0x%x > /dev/irqmap\n", 0, d->pci.Bus, d->pci.Device, 0, gsi);
  485. d->gsi = gsi;
  486. d->found = 1;
  487. return 0;
  488. }
  489. static ACPI_STATUS RouteIRQCallback(ACPI_HANDLE Device, UINT32 Depth, void *Context, void** ReturnValue)
  490. {
  491. IRQRouteData* data = (IRQRouteData*)Context;
  492. ACPI_STATUS status = AE_OK;
  493. ACPI_RESOURCE* resource = NULL;
  494. ACPI_BUFFER buffer = {0, NULL};
  495. buffer.Length = ACPI_ALLOCATE_BUFFER;
  496. ACPI_PCI_ROUTING_TABLE* found = NULL;
  497. ACPI_DEVICE_INFO* info = NULL;
  498. status = AcpiGetObjectInfo(Device, &info);
  499. CHECK_STATUS("AcpiGetObjectInfo");
  500. if (!(info->Flags & ACPI_PCI_ROOT_BRIDGE)) {
  501. if (DBGFLG) printf("RouteIRQCallback: not a root bridge.\n");
  502. goto failed;
  503. }
  504. if (DBGFLG) printf("RouteIRQ: Root bridge with address %#x:\n", info->Address);
  505. int rootBus = -1;
  506. // Get _CRS, parse, check if the bus number range includes the one in
  507. // data->pci.Bus - then we've found the right *root* PCI bridge.
  508. // Though this might actually be a lot more complicated if we allow for
  509. // multiple root pci bridges.
  510. status = AcpiGetCurrentResources(Device, &buffer);
  511. CHECK_STATUS("AcpiGetCurrentResources");
  512. if (DBGFLG) printf("Got %lu bytes of current resources\n", buffer.Length);
  513. status = AcpiBufferToResource(buffer.Pointer, buffer.Length, &resource);
  514. resource = (ACPI_RESOURCE*)buffer.Pointer;
  515. if (DBGFLG) printf("Got resources %p (status %#x)\n", resource, status);
  516. //CHECK_STATUS();
  517. while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
  518. if (DBGFLG) printf("Got resource type %d\n", resource->Type);
  519. ACPI_RESOURCE_ADDRESS64 addr64;
  520. ACPI_STATUS status = AcpiResourceToAddress64(resource, &addr64);
  521. if (DBGFLG) printf("Processed and got type\n", addr64.ResourceType);
  522. if (status == AE_OK && addr64.ResourceType == ACPI_BUS_NUMBER_RANGE)
  523. {
  524. if (DBGFLG) printf("RouteIRQ: Root bridge bus range %#x..%#x\n",
  525. addr64.Address.Minimum,
  526. addr64.Address.Maximum);
  527. if (data->pci.Bus < addr64.Address.Minimum ||
  528. data->pci.Bus > addr64.Address.Maximum)
  529. {
  530. // This is not the root bridge we're looking for...
  531. goto failed;
  532. }
  533. rootBus = addr64.Address.Minimum;
  534. break;
  535. }
  536. resource = ACPI_NEXT_RESOURCE(resource);
  537. }
  538. // dunno!
  539. if (rootBus == -1)
  540. {
  541. if (DBGFLG) printf("Couldn't figure out the bus number for root bridge %#x\n",
  542. info->Address);
  543. goto failed;
  544. }
  545. /* this is the easy case, and the most common: it's all on Bus 0
  546. * and it Just Works. */
  547. if (rootBus == data->pci.Bus) {
  548. ResetBuffer(&buffer);
  549. status = AcpiGetIrqRoutingTable(Device, &buffer);
  550. CHECK_STATUS("AcpiGetIrqRoutingTable");
  551. if (DBGFLG) printf("Got %u bytes of IRQ routing table\n", buffer.Length);
  552. ACPI_PCI_ROUTING_TABLE* route = buffer.Pointer;
  553. ACPI_PCI_ROUTING_TABLE* const end = buffer.Pointer + buffer.Length;
  554. if (DBGFLG) printf("Routing table: %p..%p\n", route, end);
  555. UINT64 pciAddr = data->pci.Device;
  556. if (DBGFLG) print("pciAddr: 0x%x\n", pciAddr);
  557. while (route < end && route->Length) {
  558. if (DBGFLG) print("Route: %p, Address: 0x%08x, Pin: %d\n", route, route->Address, route->Pin);
  559. if ((route->Address >> 16) == pciAddr && route->Pin == data->pin) {
  560. if (DBGFLG) print("FOUND!\n");
  561. found = route;
  562. break;
  563. }
  564. if (DBGFLG) print("Route Length 0x%x\n", route->Length);
  565. route = (ACPI_PCI_ROUTING_TABLE*)((char*)route + route->Length);
  566. }
  567. if (!found) {
  568. if (DBGFLG) print("NOT FOUND! FAIL!\n");
  569. goto failed;
  570. }
  571. if (DBGFLG) printf("RouteIRQ: %02x:%02x.%d pin %d -> %c%c%c%c:%d\n",
  572. data->pci.Bus, data->pci.Device, data->pci.Function,
  573. found->Pin,
  574. found->Source[0],
  575. found->Source[1],
  576. found->Source[2],
  577. found->Source[3],
  578. found->SourceIndex);
  579. if (found->Source[0]) {
  580. status = RouteIRQLinkDevice(Device, found, data);
  581. if (DBGFLG) printf("status %#x irq %#x\n", status, data->gsi);
  582. CHECK_STATUS("RouteIRQLinkDevice");
  583. } else {
  584. if (DBGFLG) printf("found->Source[0] is zero since it's PIC 1\n");
  585. data->gsi = found->SourceIndex;
  586. }
  587. data->found = TRUE;
  588. status = AE_CTRL_TERMINATE;
  589. status = AE_OK;
  590. return status;
  591. }
  592. // This requires us to walk the chain of pci-pci bridges between the
  593. // root bridge and the device. Unimplemented.
  594. if (DBGFLG) printf("Unimplemented! Device on bus %#x, but root is %#x\n",
  595. data->pci.Bus, rootBus);
  596. status = mapit(Device, data, rootBus);
  597. failed:
  598. //ACPI_FREE_BUFFER(buffer);
  599. ACPI_FREE(info);
  600. if (DBGFLG) print("MAPIT: status %d\n", status);
  601. return_ACPI_STATUS(status);
  602. }
  603. ACPI_STATUS RouteIRQ(ACPI_PCI_ID* device, int pin, int* irq) {
  604. IRQRouteData data = { *device, pin, 0, 0, 0, FALSE };
  605. ACPI_STATUS status = AE_OK;
  606. status = AcpiGetDevices("PNP0A03", RouteIRQCallback, &data, NULL);
  607. if (status == AE_OK)
  608. {
  609. if (DBGFLG) printf("Data f %d 0x%x\n", data.found, data.pci);
  610. if (data.found)
  611. {
  612. *irq = data.gsi
  613. | (data.triggering ? 0x100 : 0)
  614. | (data.polarity ? 0x200 : 0);
  615. }
  616. else
  617. {
  618. status = AE_NOT_FOUND;
  619. }
  620. }
  621. return_ACPI_STATUS(status);
  622. }
  623. #if 0
  624. // reserve some virtual memory space (never touched) to keep track pci device
  625. // handles.
  626. static const char pci_device_handles[65536] PLACEHOLDER_SECTION;
  627. static void MsgFindPci(uintptr_t rcpt, uintptr_t arg)
  628. {
  629. ACPI_PCI_ID temp = { 0, 0, 0, 0 };
  630. u16 vendor = arg >> 16;
  631. u16 device = arg;
  632. uintptr_t addr = -1;
  633. if (DBGFLG) printf("acpica: find pci %#x:%#x.\n", vendor, device);
  634. ACPI_STATUS status = FindPCIDevByVendor(vendor, device, &temp);
  635. if (ACPI_SUCCESS(status)) {
  636. addr = temp.Bus << 16 | temp.Device << 3 | temp.Function;
  637. }
  638. send1(MSG_ACPI_FIND_PCI, rcpt, addr);
  639. }
  640. static void MsgClaimPci(uintptr_t rcpt, uintptr_t addr, uintptr_t pins)
  641. {
  642. addr &= 0xffff;
  643. ACPI_PCI_ID id = { 0, (addr >> 8) & 0xff, (addr >> 3) & 31, addr & 7 };
  644. if (DBGFLG) printf("acpica: claim pci %02x:%02x.%x\n", id.Bus, id.Device, id.Function);
  645. // Set up whatever stuff to track PCI device drivers in general
  646. int irqs[4] = {0};
  647. for (int pin = 0; pin < 4; pin++) {
  648. if (!(pins & (1 << pin))) continue;
  649. ACPI_STATUS status = RouteIRQ(&id, 0, &irqs[pin]);
  650. CHECK_STATUS("RouteIRQ");
  651. if (DBGFLG) printf("acpica: %02x:%02x.%x pin %d routed to IRQ %#x\n",
  652. id.Bus, id.Device, id.Function,
  653. pin, irqs[pin]);
  654. }
  655. if (pins & ACPI_PCI_CLAIM_MASTER) {
  656. u64 value;
  657. AcpiOsReadPciConfiguration(&id, PCI_COMMAND, &value, 16);
  658. if (!(value & PCI_COMMAND_MASTER)) {
  659. value |= PCI_COMMAND_MASTER;
  660. AcpiOsWritePciConfiguration(&id, PCI_COMMAND, value, 16);
  661. }
  662. }
  663. pins = (u64)irqs[3] << 48 | (u64)irqs[2] << 32 | irqs[1] << 16 | irqs[0];
  664. send2(MSG_ACPI_CLAIM_PCI, rcpt, addr, pins);
  665. hmod(rcpt, (uintptr_t)pci_device_handles + addr, 0);
  666. return;
  667. failed:
  668. send2(MSG_ACPI_CLAIM_PCI, rcpt, 0, 0);
  669. }
  670. static size_t debugger_buffer_pos = 0;
  671. static void debugger_pre_cmd(void) {
  672. debugger_buffer_pos = 0;
  673. AcpiGbl_MethodExecuting = FALSE;
  674. AcpiGbl_StepToNextCall = FALSE;
  675. AcpiDbSetOutputDestination(ACPI_DB_CONSOLE_OUTPUT);
  676. }
  677. void GlobalEventHandler(UINT32 EventType, ACPI_HANDLE Device,
  678. UINT32 EventNumber, void *Context) {
  679. if (EventType == ACPI_EVENT_TYPE_FIXED &&
  680. EventNumber == ACPI_EVENT_POWER_BUTTON) {
  681. if (DBGFLG) printf("POWER BUTTON! Shutting down.\n");
  682. AcpiEnterSleepStatePrep(ACPI_STATE_S5);
  683. AcpiEnterSleepState(ACPI_STATE_S5);
  684. }
  685. }
  686. #endif
  687. #if 0
  688. void start() {
  689. ACPI_STATUS status = AE_OK;
  690. if (DBGFLG) printf("ACPICA: start\n");
  691. // NB! Must be at least as large as physical memory - the ACPI tables could
  692. // be anywhere. (Could be handled by AcpiOsMapMemory though.)
  693. map(0, MAP_PHYS | PROT_READ | PROT_WRITE | PROT_NO_CACHE,
  694. (void*)ACPI_PHYS_BASE, 0, USER_MAP_MAX - ACPI_PHYS_BASE);
  695. char* p = ((char*)ACPI_PHYS_BASE) + 0x100000;
  696. if (DBGFLG) printf("Testing physical memory access: %p (0x100000): %x\n", p, *(u32*)p);
  697. __default_section_init();
  698. init_heap();
  699. ACPI_DEBUG_INITIALIZE (); /* For debug version only */
  700. status = InitializeFullAcpi ();
  701. CHECK_STATUS("InitializeFullAcpi");
  702. /* Enable debug output, example debug print */
  703. AcpiDbgLayer = ACPI_EXAMPLE; //ACPI_ALL_COMPONENTS;
  704. AcpiDbgLevel = ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_INTERRUPTS;
  705. int pic_mode = 0; // Default is PIC mode if something fails
  706. status = FindIOAPICs(&pic_mode);
  707. CHECK_STATUS("Find IOAPIC");
  708. status = ExecuteOSI(pic_mode);
  709. CHECK_STATUS("ExecuteOSI");
  710. // Tables we get in Bochs:
  711. // * DSDT: All the AML code
  712. // * FACS
  713. // * FACP
  714. // * APIC (= MADT)
  715. // * SSDT: Secondary System Description Table
  716. // Contains more AML code loaded automatically by ACPICA
  717. // More tables on qemu:
  718. // * Another SSDT (Loaded by ACPICA)
  719. // * HPET table
  720. // PrintFACSTable();
  721. // PrintFACPTable();
  722. PrintAPICTable();
  723. CHECK_STATUS("PrintAPICTable");
  724. // TODO Do something like PrintDevices to disable all pci interrupt link
  725. // devices (call _DIS). Then we'll enable them as we go along.
  726. PrintDevices();
  727. EnumeratePCI();
  728. AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, 1);
  729. //AcpiWriteBitRegister(ACPI_BITREG_POWER_BUTTON_ENABLE, 1);
  730. AcpiInstallGlobalEventHandler(GlobalEventHandler, NULL);
  731. AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, 0);
  732. if (DBGFLG) printf("Waiting for SCI interrupts...\n");
  733. for (;;) {
  734. uintptr_t rcpt = 0x100;
  735. uintptr_t arg = 0;
  736. uintptr_t arg2 = 0;
  737. uintptr_t msg = recv2(&rcpt, &arg, &arg2);
  738. //if (DBGFLG) printf("acpica: Received %#lx from %#lx: %#lx %#lx\n", msg, rcpt, arg, arg2);
  739. if (msg == MSG_PULSE) {
  740. if (AcpiOsCheckInterrupt(rcpt, arg)) {
  741. continue;
  742. } else {
  743. if (DBGFLG) printf("acpica: Unhandled pulse: %#x from %#lx\n", arg, rcpt);
  744. }
  745. }
  746. switch (msg & 0xff)
  747. {
  748. case MSG_ACPI_FIND_PCI:
  749. MsgFindPci(rcpt, arg);
  750. break;
  751. case MSG_ACPI_CLAIM_PCI:
  752. MsgClaimPci(rcpt, arg, arg2);
  753. break;
  754. // This feels a bit wrong, but as long as we use PIO access to PCI
  755. // configuration space, we need to serialize all accesses.
  756. case MSG_ACPI_READ_PCI:
  757. arg = PciReadWord((arg & 0x7ffffffc) | 0x80000000);
  758. send1(MSG_ACPI_READ_PCI, rcpt, arg);
  759. break;
  760. case MSG_ACPI_DEBUGGER_INIT:
  761. debugger_pre_cmd();
  762. send0(MSG_ACPI_DEBUGGER_INIT, rcpt);
  763. break;
  764. case MSG_ACPI_DEBUGGER_BUFFER:
  765. assert(debugger_buffer_pos < ACPI_DB_LINE_BUFFER_SIZE);
  766. AcpiGbl_DbLineBuf[debugger_buffer_pos++] = arg;
  767. send0(MSG_ACPI_DEBUGGER_BUFFER, rcpt);
  768. break;
  769. case MSG_ACPI_DEBUGGER_CMD:
  770. assert(debugger_buffer_pos < ACPI_DB_LINE_BUFFER_SIZE);
  771. AcpiGbl_DbLineBuf[debugger_buffer_pos++] = 0;
  772. AcpiDbCommandDispatch(AcpiGbl_DbLineBuf, NULL, NULL);
  773. debugger_pre_cmd();
  774. send0(MSG_ACPI_DEBUGGER_CMD, rcpt);
  775. break;
  776. case MSG_ACPI_DEBUGGER_CLR_BUFFER:
  777. debugger_pre_cmd();
  778. send0(MSG_ACPI_DEBUGGER_CLR_BUFFER, rcpt);
  779. break;
  780. case MSG_REG_IRQ:
  781. RegIRQ(rcpt, arg);
  782. continue;
  783. case MSG_IRQ_ACK:
  784. AckIRQ(rcpt);
  785. continue;
  786. }
  787. // TODO Handle other stuff.
  788. if (rcpt == 0x100)
  789. {
  790. hmod(rcpt, 0, 0);
  791. }
  792. }
  793. status = AcpiTerminate();
  794. CHECK_STATUS("AcpiTerminate");
  795. if (DBGFLG) printf("Acpi terminated... Halting.\n");
  796. failed:
  797. if (DBGFLG) printf("ACPI failed :( (status %x)\n", status);
  798. abort();
  799. }
  800. #endif