apic.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  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. Proc *up = machp()->externup;
  103. Apic *apic;
  104. /*
  105. * Mark the APIC useable if it has a good ID
  106. * and the registers can be mapped.
  107. * The APIC Extended Broadcast and ID bits in the HyperTransport
  108. * Transaction Control register determine whether 4 or 8 bits
  109. * are used for the APIC ID. There is also xAPIC and x2APIC
  110. * to be dealt with sometime.
  111. */
  112. DBG("apicinit: apicno %d pa %#p isbp %d\n", apicno, pa, isbp);
  113. if(apicno >= Napic){
  114. print("apicinit%d: out of range\n", apicno);
  115. return;
  116. }
  117. if((apic = &xlapic[apicno])->useable){
  118. print("apicinit%d: already initialised\n", apicno);
  119. return;
  120. }
  121. if(apicbase == nil){
  122. if((apicbase = vmap(pa, 1024)) == nil){
  123. print("apicinit%d: can't map apicbase\n", apicno);
  124. return;
  125. }
  126. DBG("apicinit%d: apicbase %#p -> %#p\n", apicno, pa, apicbase);
  127. }
  128. apic->useable = 1;
  129. /*
  130. * Assign a machno to the processor associated with this
  131. * APIC, it may not be an identity map.
  132. * Machno 0 is always the bootstrap processor.
  133. */
  134. if(isbp){
  135. apic->machno = 0;
  136. m->apicno = apicno;
  137. }
  138. else
  139. apic->machno = apmachno++;
  140. }
  141. static void
  142. apicdump0(Apic *apic, int i)
  143. {
  144. if(!apic->useable || apic->addr != 0)
  145. return;
  146. DBG("apic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n",
  147. i, apic->machno, apic->lvt[0], apic->lvt[1]);
  148. DBG(" tslvt %#8.8ux pclvt %#8.8ux elvt %#8.8ux\n",
  149. apicrget(Tslvt), apicrget(Pclvt), apicrget(Elvt));
  150. DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n",
  151. apicrget(Tlvt), apicrget(Lint0),
  152. apicrget(Lint1), apicrget(Siv));
  153. }
  154. void
  155. apicdump(void)
  156. {
  157. int i;
  158. if(!DBGFLG)
  159. return;
  160. DBG("apicbase %#p apmachno %d\n", apicbase, apmachno);
  161. for(i = 0; i < Napic; i++)
  162. apicdump0(xlapic + i, i);
  163. for(i = 0; i < Napic; i++)
  164. apicdump0(xioapic + i, i);
  165. }
  166. static void
  167. apictimer(Ureg* ureg, void* v)
  168. {
  169. timerintr(ureg, 0);
  170. }
  171. int
  172. apiconline(void)
  173. {
  174. Proc *up = machp()->externup;
  175. Apic *apic;
  176. uint64_t tsc;
  177. uint32_t dfr, ver;
  178. int apicno, nlvt;
  179. if(apicbase == nil)
  180. return 0;
  181. if((apicno = ((apicrget(Id)>>24) & 0xff)) >= Napic)
  182. return 0;
  183. apic = &xlapic[apicno];
  184. if(!apic->useable || apic->addr != nil)
  185. return 0;
  186. /*
  187. * Things that can only be done when on the processor
  188. * owning the APIC, apicinit above runs on the bootstrap
  189. * processor.
  190. */
  191. ver = apicrget(Ver);
  192. nlvt = ((ver>>16) & 0xff) + 1;
  193. if(nlvt > nelem(apic->lvt)){
  194. print("apicinit%d: nlvt %d > max (%d)\n",
  195. apicno, nlvt, nelem(apic->lvt));
  196. nlvt = nelem(apic->lvt);
  197. }
  198. apic->nlvt = nlvt;
  199. apic->ver = ver & 0xff;
  200. /*
  201. * These don't really matter in Physical mode;
  202. * set the defaults anyway.
  203. */
  204. if(memcmp(m->cpuinfo, "AuthenticAMD", 12) == 0)
  205. dfr = 0xf0000000;
  206. else
  207. dfr = 0xffffffff;
  208. apicrput(Df, dfr);
  209. apicrput(Ld, 0x00000000);
  210. /*
  211. * Disable interrupts until ready by setting the Task Priority
  212. * register to 0xff.
  213. */
  214. apicrput(Tp, 0xff);
  215. /*
  216. * Software-enable the APIC in the Spurious Interrupt Vector
  217. * register and set the vector number. The vector number must have
  218. * bits 3-0 0x0f unless the Extended Spurious Vector Enable bit
  219. * is set in the HyperTransport Transaction Control register.
  220. */
  221. apicrput(Siv, Swen|IdtSPURIOUS);
  222. /*
  223. * Acknowledge any outstanding interrupts.
  224. */
  225. apicrput(Eoi, 0);
  226. /*
  227. * Use the TSC to determine the APIC timer frequency.
  228. * It might be possible to snarf this from a chipset
  229. * register instead.
  230. */
  231. apicrput(Tdc, DivX1);
  232. apicrput(Tlvt, Im);
  233. tsc = rdtsc() + m->cpuhz/10;
  234. apicrput(Tic, 0xffffffff);
  235. while(rdtsc() < tsc)
  236. ;
  237. apic->hz = (0xffffffff-apicrget(Tcc))*10;
  238. apic->max = apic->hz/HZ;
  239. apic->min = apic->hz/(100*HZ);
  240. apic->div = ((m->cpuhz/apic->max)+HZ/2)/HZ;
  241. if(machp()->machno == 0 || DBGFLG){
  242. print("apic%d: hz %lld max %lld min %lld div %lld\n", apicno,
  243. apic->hz, apic->max, apic->min, apic->div);
  244. }
  245. /*
  246. * Mask interrupts on Performance Counter overflow and
  247. * Thermal Sensor if implemented, and on Lintr0 (Legacy INTR),
  248. * and Lintr1 (Legacy NMI).
  249. * Clear any Error Status (write followed by read) and enable
  250. * the Error interrupt.
  251. */
  252. switch(apic->nlvt){
  253. case 6:
  254. apicrput(Tslvt, Im);
  255. /*FALLTHROUGH*/
  256. case 5:
  257. apicrput(Pclvt, Im);
  258. /*FALLTHROUGH*/
  259. default:
  260. break;
  261. }
  262. apicrput(Lint1, apic->lvt[1]|Im|IdtLINT1);
  263. apicrput(Lint0, apic->lvt[0]|Im|IdtLINT0);
  264. apicrput(Es, 0);
  265. apicrget(Es);
  266. apicrput(Elvt, IdtERROR);
  267. /*
  268. * Issue an INIT Level De-Assert to synchronise arbitration ID's.
  269. * (Necessary in this implementation? - not if Pentium 4 or Xeon
  270. * (APIC Version >= 0x14), or AMD).
  271. apicrput(Ichi, 0);
  272. apicrput(Iclo, DSallinc|Lassert|MTir);
  273. while(apicrget(Iclo) & Ds)
  274. ;
  275. */
  276. /*
  277. * Reload the timer to de-synchronise the processors,
  278. * then lower the task priority to allow interrupts to be
  279. * accepted by the APIC.
  280. */
  281. microdelay((TK2MS(1)*1000/apmachno) * machp()->machno);
  282. if(apic->machno == 0){
  283. apicrput(Tic, apic->max);
  284. intrenable(IdtTIMER, apictimer, 0, -1, "APIC timer");
  285. apicrput(Tlvt, Periodic|IrqTIMER);
  286. }
  287. if(machp()->machno == 0)
  288. apicrput(Tp, 0);
  289. xlapicmachptr[apicno] = m;
  290. return 1;
  291. }
  292. /* To start timers on TCs as part of the boot process. */
  293. void
  294. apictimerenab(void)
  295. {
  296. Apic *apic;
  297. apic = &xlapic[(apicrget(Id)>>24) & 0xff];
  298. apiceoi(IdtTIMER);
  299. apicrput(Tic, apic->max);
  300. apicrput(Tlvt, Periodic|IrqTIMER);
  301. }
  302. void
  303. apictimerset(uint64_t next)
  304. {
  305. Proc *up = machp()->externup;
  306. Mpl pl;
  307. Apic *apic;
  308. int64_t period;
  309. apic = &xlapic[(apicrget(Id)>>24) & 0xff];
  310. pl = splhi();
  311. lock(&m->apictimerlock);
  312. period = apic->max;
  313. if(next != 0){
  314. period = next - fastticks(nil); /* fastticks is just rdtsc() */
  315. period /= apic->div;
  316. if(period < apic->min)
  317. period = apic->min;
  318. else if(period > apic->max - apic->min)
  319. period = apic->max;
  320. }
  321. apicrput(Tic, period);
  322. unlock(&m->apictimerlock);
  323. splx(pl);
  324. }
  325. void
  326. apicsipi(int apicno, uintmem pa)
  327. {
  328. int i;
  329. uint32_t crhi, crlo;
  330. /*
  331. * SIPI - Start-up IPI.
  332. * To do: checks on apic validity.
  333. */
  334. crhi = apicno<<24;
  335. apicrput(Ichi, crhi);
  336. apicrput(Iclo, DSnone|TMlevel|Lassert|MTir);
  337. microdelay(200);
  338. apicrput(Iclo, DSnone|TMlevel|MTir);
  339. millidelay(10);
  340. crlo = DSnone|TMedge|MTsipi|((uint32_t)pa/(4*KiB));
  341. for(i = 0; i < 2; i++){
  342. apicrput(Ichi, crhi);
  343. apicrput(Iclo, crlo);
  344. microdelay(200);
  345. }
  346. }
  347. void
  348. apicipi(int apicno)
  349. {
  350. apicrput(Ichi, apicno<<24);
  351. apicrput(Iclo, DSnone|TMedge|Lassert|MTf|IdtIPI);
  352. while(apicrget(Iclo) & Ds)
  353. ;
  354. }
  355. void
  356. apicpri(int pri)
  357. {
  358. apicrput(Tp, pri);
  359. }