apic.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "apic.h"
  15. #include "io.h"
  16. enum { /* Local APIC registers */
  17. Id = 0x0020, /* Identification */
  18. Ver = 0x0030, /* Version */
  19. Tp = 0x0080, /* Task Priority */
  20. Ap = 0x0090, /* Arbitration Priority */
  21. Pp = 0x00a0, /* Processor Priority */
  22. Eoi = 0x00b0, /* EOI */
  23. Ld = 0x00d0, /* Logical Destination */
  24. Df = 0x00e0, /* Destination Format */
  25. Siv = 0x00f0, /* Spurious Interrupt Vector */
  26. Is = 0x0100, /* Interrupt Status (8) */
  27. Tm = 0x0180, /* Trigger Mode (8) */
  28. Ir = 0x0200, /* Interrupt Request (8) */
  29. Es = 0x0280, /* Error Status */
  30. Iclo = 0x0300, /* Interrupt Command */
  31. Ichi = 0x0310, /* Interrupt Command [63:32] */
  32. Lvt0 = 0x0320, /* Local Vector Table 0 */
  33. Lvt5 = 0x0330, /* Local Vector Table 5 */
  34. Lvt4 = 0x0340, /* Local Vector Table 4 */
  35. Lvt1 = 0x0350, /* Local Vector Table 1 */
  36. Lvt2 = 0x0360, /* Local Vector Table 2 */
  37. Lvt3 = 0x0370, /* Local Vector Table 3 */
  38. Tic = 0x0380, /* Timer Initial Count */
  39. Tcc = 0x0390, /* Timer Current Count */
  40. Tdc = 0x03e0, /* Timer Divide Configuration */
  41. Tlvt = Lvt0, /* Timer */
  42. Lint0 = Lvt1, /* Local Interrupt 0 */
  43. Lint1 = Lvt2, /* Local Interrupt 1 */
  44. Elvt = Lvt3, /* Error */
  45. Pclvt = Lvt4, /* Performance Counter */
  46. Tslvt = Lvt5, /* Thermal Sensor */
  47. };
  48. enum { /* Siv */
  49. Swen = 0x00000100, /* Software Enable */
  50. Fdis = 0x00000200, /* Focus Disable */
  51. };
  52. enum { /* Iclo */
  53. Lassert = 0x00004000, /* Assert level */
  54. DSnone = 0x00000000, /* Use Destination Field */
  55. DSself = 0x00040000, /* Self is only destination */
  56. DSallinc = 0x00080000, /* All including self */
  57. DSallexc = 0x000c0000, /* All Excluding self */
  58. };
  59. enum { /* Tlvt */
  60. Periodic = 0x00020000, /* Periodic Timer Mode */
  61. };
  62. enum { /* Tdc */
  63. DivX2 = 0x00000000, /* Divide by 2 */
  64. DivX4 = 0x00000001, /* Divide by 4 */
  65. DivX8 = 0x00000002, /* Divide by 8 */
  66. DivX16 = 0x00000003, /* Divide by 16 */
  67. DivX32 = 0x00000008, /* Divide by 32 */
  68. DivX64 = 0x00000009, /* Divide by 64 */
  69. DivX128 = 0x0000000a, /* Divide by 128 */
  70. DivX1 = 0x0000000b, /* Divide by 1 */
  71. };
  72. static uint8_t* apicbase;
  73. static int apmachno = 1;
  74. Apic xlapic[Napic];
  75. Mach *xlapicmachptr[Napic]; /* maintained, but unused */
  76. static uint32_t
  77. apicrget(int r)
  78. {
  79. return *((uint32_t*)(apicbase+r));
  80. }
  81. static void
  82. apicrput(int r, uint32_t data)
  83. {
  84. *((uint32_t*)(apicbase+r)) = data;
  85. }
  86. int
  87. apiceoi(int vecno)
  88. {
  89. apicrput(Eoi, 0);
  90. return vecno;
  91. }
  92. int
  93. apicisr(int vecno)
  94. {
  95. int isr;
  96. isr = apicrget(Is + (vecno/32)*16);
  97. return isr & (1<<(vecno%32));
  98. }
  99. void
  100. apicinit(int apicno, uintmem pa, int isbp)
  101. {
  102. Apic *apic;
  103. /*
  104. * Mark the APIC useable if it has a good ID
  105. * and the registers can be mapped.
  106. * The APIC Extended Broadcast and ID bits in the HyperTransport
  107. * Transaction Control register determine whether 4 or 8 bits
  108. * are used for the APIC ID. There is also xAPIC and x2APIC
  109. * to be dealt with sometime.
  110. */
  111. DBG("apicinit: apicno %d pa %#p isbp %d\n", apicno, pa, isbp);
  112. if(apicno >= Napic){
  113. print("apicinit%d: out of range\n", apicno);
  114. return;
  115. }
  116. if((apic = &xlapic[apicno])->useable){
  117. print("apicinit%d: already initialised\n", apicno);
  118. return;
  119. }
  120. if(apicbase == nil){
  121. if((apicbase = vmap(pa, 1024)) == nil){
  122. print("apicinit%d: can't map apicbase\n", apicno);
  123. return;
  124. }
  125. DBG("apicinit%d: apicbase %#p -> %#p\n", apicno, pa, apicbase);
  126. }
  127. apic->useable = 1;
  128. /*
  129. * Assign a machno to the processor associated with this
  130. * APIC, it may not be an identity map.
  131. * Machno 0 is always the bootstrap processor.
  132. */
  133. if(isbp){
  134. apic->machno = 0;
  135. machp()->apicno = apicno;
  136. }
  137. else
  138. apic->machno = apmachno++;
  139. }
  140. static void
  141. apicdump0(Apic *apic, int i)
  142. {
  143. if(!apic->useable || apic->addr != 0)
  144. return;
  145. DBG("apic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n",
  146. i, apic->machno, apic->lvt[0], apic->lvt[1]);
  147. DBG(" tslvt %#8.8ux pclvt %#8.8ux elvt %#8.8ux\n",
  148. apicrget(Tslvt), apicrget(Pclvt), apicrget(Elvt));
  149. DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n",
  150. apicrget(Tlvt), apicrget(Lint0),
  151. apicrget(Lint1), apicrget(Siv));
  152. }
  153. void
  154. apicdump(void)
  155. {
  156. int i;
  157. if(!DBGFLG)
  158. return;
  159. DBG("apicbase %#p apmachno %d\n", apicbase, apmachno);
  160. for(i = 0; i < Napic; i++)
  161. apicdump0(xlapic + i, i);
  162. for(i = 0; i < Napic; i++)
  163. apicdump0(xioapic + i, i);
  164. }
  165. static void
  166. apictimer(Ureg* ureg, void* v)
  167. {
  168. timerintr(ureg, 0);
  169. }
  170. int
  171. apiconline(void)
  172. {
  173. Apic *apic;
  174. uint64_t tsc;
  175. uint32_t dfr, ver;
  176. int apicno, nlvt;
  177. if(apicbase == nil)
  178. return 0;
  179. if((apicno = ((apicrget(Id)>>24) & 0xff)) >= Napic)
  180. return 0;
  181. apic = &xlapic[apicno];
  182. if(!apic->useable || apic->addr != nil)
  183. return 0;
  184. /*
  185. * Things that can only be done when on the processor
  186. * owning the APIC, apicinit above runs on the bootstrap
  187. * processor.
  188. */
  189. ver = apicrget(Ver);
  190. nlvt = ((ver>>16) & 0xff) + 1;
  191. if(nlvt > nelem(apic->lvt)){
  192. print("apicinit%d: nlvt %d > max (%d)\n",
  193. apicno, nlvt, nelem(apic->lvt));
  194. nlvt = nelem(apic->lvt);
  195. }
  196. apic->nlvt = nlvt;
  197. apic->ver = ver & 0xff;
  198. /*
  199. * These don't really matter in Physical mode;
  200. * set the defaults anyway.
  201. */
  202. if(memcmp(machp()->CPU.cpuinfo, "AuthenticAMD", 12) == 0)
  203. dfr = 0xf0000000;
  204. else
  205. dfr = 0xffffffff;
  206. apicrput(Df, dfr);
  207. apicrput(Ld, 0x00000000);
  208. /*
  209. * Disable interrupts until ready by setting the Task Priority
  210. * register to 0xff.
  211. */
  212. apicrput(Tp, 0xff);
  213. /*
  214. * Software-enable the APIC in the Spurious Interrupt Vector
  215. * register and set the vector number. The vector number must have
  216. * bits 3-0 0x0f unless the Extended Spurious Vector Enable bit
  217. * is set in the HyperTransport Transaction Control register.
  218. */
  219. apicrput(Siv, Swen|IdtSPURIOUS);
  220. /*
  221. * Acknowledge any outstanding interrupts.
  222. */
  223. apicrput(Eoi, 0);
  224. /*
  225. * Use the TSC to determine the APIC timer frequency.
  226. * It might be possible to snarf this from a chipset
  227. * register instead.
  228. */
  229. apicrput(Tdc, DivX1);
  230. apicrput(Tlvt, Im);
  231. tsc = rdtsc() + machp()->cpuhz/10;
  232. apicrput(Tic, 0xffffffff);
  233. while(rdtsc() < tsc)
  234. ;
  235. apic->hz = (0xffffffff-apicrget(Tcc))*10;
  236. apic->max = apic->hz/HZ;
  237. apic->min = apic->hz/(100*HZ);
  238. apic->div = ((machp()->cpuhz/apic->max)+HZ/2)/HZ;
  239. if(machp()->machno == 0 || DBGFLG){
  240. print("apic%d: hz %lld max %lld min %lld div %lld\n", apicno,
  241. apic->hz, apic->max, apic->min, apic->div);
  242. }
  243. /*
  244. * Mask interrupts on Performance Counter overflow and
  245. * Thermal Sensor if implemented, and on Lintr0 (Legacy INTR),
  246. * and Lintr1 (Legacy NMI).
  247. * Clear any Error Status (write followed by read) and enable
  248. * the Error interrupt.
  249. */
  250. switch(apic->nlvt){
  251. case 6:
  252. apicrput(Tslvt, Im);
  253. /*FALLTHROUGH*/
  254. case 5:
  255. apicrput(Pclvt, Im);
  256. /*FALLTHROUGH*/
  257. default:
  258. break;
  259. }
  260. apicrput(Lint1, apic->lvt[1]|Im|IdtLINT1);
  261. apicrput(Lint0, apic->lvt[0]|Im|IdtLINT0);
  262. apicrput(Es, 0);
  263. apicrget(Es);
  264. apicrput(Elvt, IdtERROR);
  265. /*
  266. * Issue an INIT Level De-Assert to synchronise arbitration ID's.
  267. * (Necessary in this implementation? - not if Pentium 4 or Xeon
  268. * (APIC Version >= 0x14), or AMD).
  269. apicrput(Ichi, 0);
  270. apicrput(Iclo, DSallinc|Lassert|MTir);
  271. while(apicrget(Iclo) & Ds)
  272. ;
  273. */
  274. /*
  275. * Reload the timer to de-synchronise the processors,
  276. * then lower the task priority to allow interrupts to be
  277. * accepted by the APIC.
  278. */
  279. microdelay((TK2MS(1)*1000/apmachno) * machp()->machno);
  280. if(apic->machno == 0){
  281. apicrput(Tic, apic->max);
  282. intrenable(IdtTIMER, apictimer, 0, -1, "APIC timer");
  283. apicrput(Tlvt, Periodic|IrqTIMER);
  284. }
  285. if(machp()->machno == 0)
  286. apicrput(Tp, 0);
  287. xlapicmachptr[apicno] = machp();
  288. return 1;
  289. }
  290. /* To start timers on TCs as part of the boot process. */
  291. void
  292. apictimerenab(void)
  293. {
  294. Apic *apic;
  295. apic = &xlapic[(apicrget(Id)>>24) & 0xff];
  296. apiceoi(IdtTIMER);
  297. apicrput(Tic, apic->max);
  298. apicrput(Tlvt, Periodic|IrqTIMER);
  299. }
  300. void
  301. apictimerset(uint64_t next)
  302. {
  303. Mpl pl;
  304. Apic *apic;
  305. int64_t period;
  306. apic = &xlapic[(apicrget(Id)>>24) & 0xff];
  307. pl = splhi();
  308. lock(&machp()->apictimerlock);
  309. period = apic->max;
  310. if(next != 0){
  311. period = next - fastticks(nil); /* fastticks is just rdtsc() */
  312. period /= apic->div;
  313. if(period < apic->min)
  314. period = apic->min;
  315. else if(period > apic->max - apic->min)
  316. period = apic->max;
  317. }
  318. apicrput(Tic, period);
  319. unlock(&machp()->apictimerlock);
  320. splx(pl);
  321. }
  322. void
  323. apicsipi(int apicno, uintmem pa)
  324. {
  325. int i;
  326. uint32_t crhi, crlo;
  327. /*
  328. * SIPI - Start-up IPI.
  329. * To do: checks on apic validity.
  330. */
  331. crhi = apicno<<24;
  332. apicrput(Ichi, crhi);
  333. apicrput(Iclo, DSnone|TMlevel|Lassert|MTir);
  334. microdelay(200);
  335. apicrput(Iclo, DSnone|TMlevel|MTir);
  336. millidelay(10);
  337. crlo = DSnone|TMedge|MTsipi|((uint32_t)pa/(4*KiB));
  338. for(i = 0; i < 2; i++){
  339. apicrput(Ichi, crhi);
  340. apicrput(Iclo, crlo);
  341. microdelay(200);
  342. }
  343. }
  344. void
  345. apicipi(int apicno)
  346. {
  347. apicrput(Ichi, apicno<<24);
  348. apicrput(Iclo, DSnone|TMedge|Lassert|MTf|IdtIPI);
  349. while(apicrget(Iclo) & Ds)
  350. ;
  351. }
  352. void
  353. apicpri(int pri)
  354. {
  355. apicrput(Tp, pri);
  356. }