The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/apic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0e6c76646c23340dec12df4ca156b01d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.