apic.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "mp.h"
  8. enum { /* Local APIC registers */
  9. LapicID = 0x0020, /* ID */
  10. LapicVER = 0x0030, /* Version */
  11. LapicTPR = 0x0080, /* Task Priority */
  12. LapicAPR = 0x0090, /* Arbitration Priority */
  13. LapicPPR = 0x00A0, /* Processor Priority */
  14. LapicEOI = 0x00B0, /* EOI */
  15. LapicLDR = 0x00D0, /* Logical Destination */
  16. LapicDFR = 0x00E0, /* Destination Format */
  17. LapicSVR = 0x00F0, /* Spurious Interrupt Vector */
  18. LapicISR = 0x0100, /* Interrupt Status (8 registers) */
  19. LapicTMR = 0x0180, /* Trigger Mode (8 registers) */
  20. LapicIRR = 0x0200, /* Interrupt Request (8 registers) */
  21. LapicESR = 0x0280, /* Error Status */
  22. LapicICRLO = 0x0300, /* Interrupt Command */
  23. LapicICRHI = 0x0310, /* Interrupt Command [63:32] */
  24. LapicTIMER = 0x0320, /* Local Vector Table 0 (TIMER) */
  25. LapicPCINT = 0x0340, /* Performance Counter LVT */
  26. LapicLINT0 = 0x0350, /* Local Vector Table 1 (LINT0) */
  27. LapicLINT1 = 0x0360, /* Local Vector Table 2 (LINT1) */
  28. LapicERROR = 0x0370, /* Local Vector Table 3 (ERROR) */
  29. LapicTICR = 0x0380, /* Timer Initial Count */
  30. LapicTCCR = 0x0390, /* Timer Current Count */
  31. LapicTDCR = 0x03E0, /* Timer Divide Configuration */
  32. };
  33. enum { /* LapicSVR */
  34. LapicENABLE = 0x00000100, /* Unit Enable */
  35. LapicFOCUS = 0x00000200, /* Focus Processor Checking Disable */
  36. };
  37. enum { /* LapicICRLO */
  38. /* [14] IPI Trigger Mode Level (RW) */
  39. LapicDEASSERT = 0x00000000, /* Deassert level-sensitive interrupt */
  40. LapicASSERT = 0x00004000, /* Assert level-sensitive interrupt */
  41. /* [17:16] Remote Read Status */
  42. LapicINVALID = 0x00000000, /* Invalid */
  43. LapicWAIT = 0x00010000, /* In-Progress */
  44. LapicVALID = 0x00020000, /* Valid */
  45. /* [19:18] Destination Shorthand */
  46. LapicFIELD = 0x00000000, /* No shorthand */
  47. LapicSELF = 0x00040000, /* Self is single destination */
  48. LapicALLINC = 0x00080000, /* All including self */
  49. LapicALLEXC = 0x000C0000, /* All Excluding self */
  50. };
  51. enum { /* LapicESR */
  52. LapicSENDCS = 0x00000001, /* Send CS Error */
  53. LapicRCVCS = 0x00000002, /* Receive CS Error */
  54. LapicSENDACCEPT = 0x00000004, /* Send Accept Error */
  55. LapicRCVACCEPT = 0x00000008, /* Receive Accept Error */
  56. LapicSENDVECTOR = 0x00000020, /* Send Illegal Vector */
  57. LapicRCVVECTOR = 0x00000040, /* Receive Illegal Vector */
  58. LapicREGISTER = 0x00000080, /* Illegal Register Address */
  59. };
  60. enum { /* LapicTIMER */
  61. /* [17] Timer Mode (RW) */
  62. LapicONESHOT = 0x00000000, /* One-shot */
  63. LapicPERIODIC = 0x00020000, /* Periodic */
  64. /* [19:18] Timer Base (RW) */
  65. LapicCLKIN = 0x00000000, /* use CLKIN as input */
  66. LapicTMBASE = 0x00040000, /* use TMBASE */
  67. LapicDIVIDER = 0x00080000, /* use output of the divider */
  68. };
  69. enum { /* LapicTDCR */
  70. LapicX2 = 0x00000000, /* divide by 2 */
  71. LapicX4 = 0x00000001, /* divide by 4 */
  72. LapicX8 = 0x00000002, /* divide by 8 */
  73. LapicX16 = 0x00000003, /* divide by 16 */
  74. LapicX32 = 0x00000008, /* divide by 32 */
  75. LapicX64 = 0x00000009, /* divide by 64 */
  76. LapicX128 = 0x0000000A, /* divide by 128 */
  77. LapicX1 = 0x0000000B, /* divide by 1 */
  78. };
  79. static ulong* lapicbase;
  80. struct
  81. {
  82. uvlong hz;
  83. ulong max;
  84. ulong min;
  85. ulong div;
  86. } lapictimer;
  87. static ulong
  88. lapicr(int r)
  89. {
  90. assert(lapicbase != 0);
  91. return *(lapicbase+(r/sizeof(*lapicbase)));
  92. }
  93. static void
  94. lapicw(int r, ulong data)
  95. {
  96. assert(lapicbase != 0);
  97. *(lapicbase+(r/sizeof(*lapicbase))) = data;
  98. data = *(lapicbase+(LapicID/sizeof(*lapicbase)));
  99. USED(data);
  100. }
  101. void
  102. lapiconline(void)
  103. {
  104. /*
  105. * Reload the timer to de-synchronise the processors,
  106. * then lower the task priority to allow interrupts to be
  107. * accepted by the APIC.
  108. */
  109. microdelay((TK2MS(1)*1000/conf.nmach) * m->machno);
  110. lapicw(LapicTICR, lapictimer.max);
  111. lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|(VectorPIC+IrqTIMER));
  112. lapicw(LapicTPR, 0);
  113. }
  114. /*
  115. * use the i8253 clock to figure out our lapic timer rate.
  116. */
  117. static void
  118. lapictimerinit(void)
  119. {
  120. uvlong x, v, hz;
  121. v = m->cpuhz/1000;
  122. lapicw(LapicTDCR, LapicX1);
  123. lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|(VectorPIC+IrqTIMER));
  124. if(lapictimer.hz == 0ULL){
  125. x = fastticks(&hz);
  126. x += hz/10;
  127. lapicw(LapicTICR, 0xffffffff);
  128. do{
  129. v = fastticks(nil);
  130. }while(v < x);
  131. lapictimer.hz = (0xffffffffUL-lapicr(LapicTCCR))*10;
  132. lapictimer.max = lapictimer.hz/HZ;
  133. lapictimer.min = lapictimer.hz/(100*HZ);
  134. if(lapictimer.hz > hz-(hz/10)){
  135. if(lapictimer.hz > hz+(hz/10))
  136. panic("lapic clock %lld > cpu clock > %lld\n",
  137. lapictimer.hz, hz);
  138. lapictimer.hz = hz;
  139. }
  140. assert(lapictimer.hz != 0);
  141. lapictimer.div = hz/lapictimer.hz;
  142. }
  143. }
  144. void
  145. lapicinit(Apic* apic)
  146. {
  147. ulong dfr, ldr, lvt;
  148. if(lapicbase == 0)
  149. lapicbase = apic->addr;
  150. /*
  151. * These don't really matter in Physical mode;
  152. * set the defaults anyway.
  153. */
  154. if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0)
  155. dfr = 0xf0000000;
  156. else
  157. dfr = 0xffffffff;
  158. ldr = 0x00000000;
  159. lapicw(LapicDFR, dfr);
  160. lapicw(LapicLDR, ldr);
  161. lapicw(LapicTPR, 0xff);
  162. lapicw(LapicSVR, LapicENABLE|(VectorPIC+IrqSPURIOUS));
  163. lapictimerinit();
  164. /*
  165. * Some Pentium revisions have a bug whereby spurious
  166. * interrupts are generated in the through-local mode.
  167. */
  168. switch(m->cpuidax & 0xFFF){
  169. case 0x526: /* stepping cB1 */
  170. case 0x52B: /* stepping E0 */
  171. case 0x52C: /* stepping cC0 */
  172. wrmsr(0x0E, 1<<14); /* TR12 */
  173. break;
  174. }
  175. /*
  176. * Set the local interrupts. It's likely these should just be
  177. * masked off for SMP mode as some Pentium Pros have problems if
  178. * LINT[01] are set to ExtINT.
  179. * Acknowledge any outstanding interrupts.
  180. lapicw(LapicLINT0, apic->lintr[0]);
  181. lapicw(LapicLINT1, apic->lintr[1]);
  182. */
  183. lapiceoi(0);
  184. lvt = (lapicr(LapicVER)>>16) & 0xFF;
  185. if(lvt >= 4)
  186. lapicw(LapicPCINT, ApicIMASK);
  187. lapicw(LapicERROR, VectorPIC+IrqERROR);
  188. lapicw(LapicESR, 0);
  189. lapicr(LapicESR);
  190. /*
  191. * Issue an INIT Level De-Assert to synchronise arbitration ID's.
  192. */
  193. lapicw(LapicICRHI, 0);
  194. lapicw(LapicICRLO, LapicALLINC|ApicLEVEL|LapicDEASSERT|ApicINIT);
  195. while(lapicr(LapicICRLO) & ApicDELIVS)
  196. ;
  197. /*
  198. * Do not allow acceptance of interrupts until all initialisation
  199. * for this processor is done. For the bootstrap processor this can be
  200. * early duing initialisation. For the application processors this should
  201. * be after the bootstrap processor has lowered priority and is accepting
  202. * interrupts.
  203. lapicw(LapicTPR, 0);
  204. */
  205. }
  206. void
  207. lapicstartap(Apic* apic, int v)
  208. {
  209. int i;
  210. ulong crhi;
  211. crhi = apic->apicno<<24;
  212. lapicw(LapicICRHI, crhi);
  213. lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicASSERT|ApicINIT);
  214. microdelay(200);
  215. lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicDEASSERT|ApicINIT);
  216. delay(10);
  217. for(i = 0; i < 2; i++){
  218. lapicw(LapicICRHI, crhi);
  219. lapicw(LapicICRLO, LapicFIELD|ApicEDGE|ApicSTARTUP|(v/BY2PG));
  220. microdelay(200);
  221. }
  222. }
  223. void
  224. lapicerror(Ureg*, void*)
  225. {
  226. ulong esr;
  227. lapicw(LapicESR, 0);
  228. esr = lapicr(LapicESR);
  229. switch(m->cpuidax & 0xFFF){
  230. case 0x526: /* stepping cB1 */
  231. case 0x52B: /* stepping E0 */
  232. case 0x52C: /* stepping cC0 */
  233. return;
  234. }
  235. print("cpu%d: lapicerror: 0x%8.8luX\n", m->machno, esr);
  236. }
  237. void
  238. lapicspurious(Ureg*, void*)
  239. {
  240. print("cpu%d: lapicspurious\n", m->machno);
  241. }
  242. int
  243. lapicisr(int v)
  244. {
  245. ulong isr;
  246. isr = lapicr(LapicISR + (v/32));
  247. return isr & (1<<(v%32));
  248. }
  249. int
  250. lapiceoi(int v)
  251. {
  252. lapicw(LapicEOI, 0);
  253. return v;
  254. }
  255. void
  256. lapicicrw(ulong hi, ulong lo)
  257. {
  258. lapicw(LapicICRHI, hi);
  259. lapicw(LapicICRLO, lo);
  260. }
  261. void
  262. ioapicrdtr(Apic* apic, int sel, int* hi, int* lo)
  263. {
  264. ulong *iowin;
  265. iowin = apic->addr+(0x10/sizeof(ulong));
  266. sel = IoapicRDT + 2*sel;
  267. lock(apic);
  268. *apic->addr = sel+1;
  269. if(hi)
  270. *hi = *iowin;
  271. *apic->addr = sel;
  272. if(lo)
  273. *lo = *iowin;
  274. unlock(apic);
  275. }
  276. void
  277. ioapicrdtw(Apic* apic, int sel, int hi, int lo)
  278. {
  279. ulong *iowin;
  280. iowin = apic->addr+(0x10/sizeof(ulong));
  281. sel = IoapicRDT + 2*sel;
  282. lock(apic);
  283. *apic->addr = sel+1;
  284. *iowin = hi;
  285. *apic->addr = sel;
  286. *iowin = lo;
  287. unlock(apic);
  288. }
  289. void
  290. ioapicinit(Apic* apic, int apicno)
  291. {
  292. int hi, lo, v;
  293. ulong *iowin;
  294. /*
  295. * Initialise the I/O APIC.
  296. * The MultiProcessor Specification says it is the responsibility
  297. * of the O/S to set the APIC id.
  298. * Make sure interrupts are all masked off for now.
  299. */
  300. iowin = apic->addr+(0x10/sizeof(ulong));
  301. lock(apic);
  302. *apic->addr = IoapicVER;
  303. apic->mre = (*iowin>>16) & 0xFF;
  304. *apic->addr = IoapicID;
  305. *iowin = apicno<<24;
  306. unlock(apic);
  307. hi = 0;
  308. lo = ApicIMASK;
  309. for(v = 0; v <= apic->mre; v++)
  310. ioapicrdtw(apic, v, hi, lo);
  311. }
  312. void
  313. lapictimerset(uvlong next)
  314. {
  315. vlong period;
  316. int x;
  317. x = splhi();
  318. lock(&m->apictimerlock);
  319. period = lapictimer.max;
  320. if(next != 0){
  321. period = next - fastticks(nil);
  322. if (lapictimer.div == 0)
  323. panic("lapictimerset: zero lapictimer.div");
  324. period /= lapictimer.div;
  325. if(period < lapictimer.min)
  326. period = lapictimer.min;
  327. else if(period > lapictimer.max - lapictimer.min)
  328. period = lapictimer.max;
  329. }
  330. lapicw(LapicTICR, period);
  331. unlock(&m->apictimerlock);
  332. splx(x);
  333. }
  334. void
  335. lapicclock(Ureg *u, void*)
  336. {
  337. /*
  338. * since the MTRR updates need to be synchronized across processors,
  339. * we want to do this within the clock tick.
  340. */
  341. mtrrclock();
  342. timerintr(u, 0);
  343. }
  344. void
  345. lapicintron(void)
  346. {
  347. lapicw(LapicTPR, 0);
  348. }
  349. void
  350. lapicintroff(void)
  351. {
  352. lapicw(LapicTPR, 0xFF);
  353. }
  354. void
  355. lapicnmienable(void)
  356. {
  357. lapicw(LapicPCINT, ApicNMI);
  358. }
  359. void
  360. lapicnmidisable(void)
  361. {
  362. lapicw(LapicPCINT, ApicIMASK);
  363. }