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/mp.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 #include "ureg.h"
    8 
    9 #include "mp.h"
   10 #include "apbootstrap.h"
   11 
   12 static Bus* mpbus;
   13 static Bus* mpbuslast;
   14 static int mpisabus = -1;
   15 static int mpeisabus = -1;
   16 extern int i8259elcr;                   /* mask of level-triggered interrupts */
   17 static Apic mpapic[MaxAPICNO+1];
   18 static int machno2apicno[MaxAPICNO+1];  /* inverse map: machno -> APIC ID */
   19 static Lock mprdthilock;
   20 static int mprdthi;
   21 static Ref mpvnoref;                    /* unique vector assignment */
   22 static int mpmachno = 1;
   23 
   24 static char* buses[] = {
   25         "CBUSI ",
   26         "CBUSII",
   27         "EISA  ",
   28         "FUTURE",
   29         "INTERN",
   30         "ISA   ",
   31         "MBI   ",
   32         "MBII  ",
   33         "MCA   ",
   34         "MPI   ",
   35         "MPSA  ",
   36         "NUBUS ",
   37         "PCI   ",
   38         "PCMCIA",
   39         "TC    ",
   40         "VL    ",
   41         "VME   ",
   42         "XPRESS",
   43         0,
   44 };
   45 
   46 static Apic*
   47 mkprocessor(PCMPprocessor* p)
   48 {
   49         Apic *apic;
   50 
   51         if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO)
   52                 return 0;
   53 
   54         apic = &mpapic[p->apicno];
   55         apic->type = PcmpPROCESSOR;
   56         apic->apicno = p->apicno;
   57         apic->flags = p->flags;
   58         apic->lintr[0] = ApicIMASK;
   59         apic->lintr[1] = ApicIMASK;
   60 
   61         if(p->flags & PcmpBP){
   62                 machno2apicno[0] = p->apicno;
   63                 apic->machno = 0;
   64         }
   65         else{
   66                 machno2apicno[mpmachno] = p->apicno;
   67                 apic->machno = mpmachno;
   68                 mpmachno++;
   69         }
   70 
   71         return apic;
   72 }
   73 
   74 static Bus*
   75 mkbus(PCMPbus* p)
   76 {
   77         Bus *bus;
   78         int i;
   79 
   80         for(i = 0; buses[i]; i++){
   81                 if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
   82                         break;
   83         }
   84         if(buses[i] == 0)
   85                 return 0;
   86 
   87         bus = xalloc(sizeof(Bus));
   88         if(mpbus)
   89                 mpbuslast->next = bus;
   90         else
   91                 mpbus = bus;
   92         mpbuslast = bus;
   93 
   94         bus->type = i;
   95         bus->busno = p->busno;
   96         if(bus->type == BusEISA){
   97                 bus->po = PcmpLOW;
   98                 bus->el = PcmpLEVEL;
   99                 if(mpeisabus != -1)
  100                         print("mkbus: more than one EISA bus\n");
  101                 mpeisabus = bus->busno;
  102         }
  103         else if(bus->type == BusPCI){
  104                 bus->po = PcmpLOW;
  105                 bus->el = PcmpLEVEL;
  106         }
  107         else if(bus->type == BusISA){
  108                 bus->po = PcmpHIGH;
  109                 bus->el = PcmpEDGE;
  110                 if(mpisabus != -1)
  111                         print("mkbus: more than one ISA bus\n");
  112                 mpisabus = bus->busno;
  113         }
  114         else{
  115                 bus->po = PcmpHIGH;
  116                 bus->el = PcmpEDGE;
  117         }
  118 
  119         return bus;
  120 }
  121 
  122 static Bus*
  123 mpgetbus(int busno)
  124 {
  125         Bus *bus;
  126 
  127         for(bus = mpbus; bus; bus = bus->next){
  128                 if(bus->busno == busno)
  129                         return bus;
  130         }
  131         print("mpgetbus: can't find bus %d\n", busno);
  132 
  133         return 0;
  134 }
  135 
  136 static Apic*
  137 mkioapic(PCMPioapic* p)
  138 {
  139         Apic *apic;
  140         void *va;
  141 
  142         if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO)
  143                 return 0;
  144 
  145         /*
  146          * Map the I/O APIC.
  147          */
  148         if((va = vmap(p->addr, 1024)) == nil)
  149                 return 0;
  150 
  151         apic = &mpapic[p->apicno];
  152         apic->type = PcmpIOAPIC;
  153         apic->apicno = p->apicno;
  154         apic->addr = va;
  155         apic->paddr = p->addr;
  156         apic->flags = p->flags;
  157 
  158         return apic;
  159 }
  160 
  161 static Aintr*
  162 mkiointr(PCMPintr* p)
  163 {
  164         Bus *bus;
  165         Aintr *aintr;
  166 
  167         /*
  168          * According to the MultiProcessor Specification, a destination
  169          * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
  170          * It's unclear how that can possibly be correct so treat it as
  171          * an error for now.
  172          */
  173         if(p->apicno == 0xFF)
  174                 return 0;
  175         if((bus = mpgetbus(p->busno)) == 0)
  176                 return 0;
  177 
  178         aintr = xalloc(sizeof(Aintr));
  179         aintr->intr = p;
  180         aintr->apic = &mpapic[p->apicno];
  181         aintr->next = bus->aintr;
  182         bus->aintr = aintr;
  183 
  184         return aintr;
  185 }
  186 
  187 static int
  188 mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
  189 {
  190         int el, po, v;
  191 
  192         /*
  193          * Parse an I/O or Local APIC interrupt table entry and
  194          * return the encoded vector.
  195          */
  196         v = vno;
  197 
  198         po = intr->flags & PcmpPOMASK;
  199         el = intr->flags & PcmpELMASK;
  200 
  201         switch(intr->intr){
  202 
  203         default:                                /* PcmpINT */
  204                 v |= ApicLOWEST;
  205                 break;
  206 
  207         case PcmpNMI:
  208                 v |= ApicNMI;
  209                 po = PcmpHIGH;
  210                 el = PcmpEDGE;
  211                 break;
  212 
  213         case PcmpSMI:
  214                 v |= ApicSMI;
  215                 break;
  216 
  217         case PcmpExtINT:
  218                 v |= ApicExtINT;
  219                 /*
  220                  * The AMI Goliath doesn't boot successfully with it's LINTR0
  221                  * entry which decodes to low+level. The PPro manual says ExtINT
  222                  * should be level, whereas the Pentium is edge. Setting the
  223                  * Goliath to edge+high seems to cure the problem. Other PPro
  224                  * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes
  225                  * to edge+high, so who knows.
  226                  * Perhaps it would be best just to not set an ExtINT entry at
  227                  * all, it shouldn't be needed for SMP mode.
  228                  */
  229                 po = PcmpHIGH;
  230                 el = PcmpEDGE;
  231                 break;
  232         }
  233 
  234         /*
  235          */
  236         if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
  237                 po = PcmpHIGH;
  238                 el = PcmpEDGE;
  239         }
  240         if(!po)
  241                 po = bus->po;
  242         if(po == PcmpLOW)
  243                 v |= ApicLOW;
  244         else if(po != PcmpHIGH){
  245                 print("mpintrinit: bad polarity 0x%uX\n", po);
  246                 return ApicIMASK;
  247         }
  248 
  249         if(!el)
  250                 el = bus->el;
  251         if(el == PcmpLEVEL)
  252                 v |= ApicLEVEL;
  253         else if(el != PcmpEDGE){
  254                 print("mpintrinit: bad trigger 0x%uX\n", el);
  255                 return ApicIMASK;
  256         }
  257 
  258         return v;
  259 }
  260 
  261 static int
  262 mklintr(PCMPintr* p)
  263 {
  264         Apic *apic;
  265         Bus *bus;
  266         int intin, v;
  267 
  268         /*
  269          * The offsets of vectors for LINT[01] are known to be
  270          * 0 and 1 from the local APIC vector space at VectorLAPIC.
  271          */
  272         if((bus = mpgetbus(p->busno)) == 0)
  273                 return 0;
  274         intin = p->intin;
  275 
  276         /*
  277          * Pentium Pros have problems if LINT[01] are set to ExtINT
  278          * so just bag it, SMP mode shouldn't need ExtINT anyway.
  279          */
  280         if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
  281                 v = ApicIMASK;
  282         else
  283                 v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
  284 
  285         if(p->apicno == 0xFF){
  286                 for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
  287                         if((apic->flags & PcmpEN)
  288                         && apic->type == PcmpPROCESSOR)
  289                                 apic->lintr[intin] = v;
  290                 }
  291         }
  292         else{
  293                 apic = &mpapic[p->apicno];
  294                 if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR)
  295                         apic->lintr[intin] = v;
  296         }
  297 
  298         return v;
  299 }
  300 
  301 static void
  302 checkmtrr(void)
  303 {
  304         int i, vcnt;
  305         Mach *mach0;
  306 
  307         /*
  308          * If there are MTRR registers, snarf them for validation.
  309          */
  310         if(!(m->cpuiddx & 0x1000))
  311                 return;
  312 
  313         rdmsr(0x0FE, &m->mtrrcap);
  314         rdmsr(0x2FF, &m->mtrrdef);
  315         if(m->mtrrcap & 0x0100){
  316                 rdmsr(0x250, &m->mtrrfix[0]);
  317                 rdmsr(0x258, &m->mtrrfix[1]);
  318                 rdmsr(0x259, &m->mtrrfix[2]);
  319                 for(i = 0; i < 8; i++)
  320                         rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
  321         }
  322         vcnt = m->mtrrcap & 0x00FF;
  323         if(vcnt > nelem(m->mtrrvar))
  324                 vcnt = nelem(m->mtrrvar);
  325         for(i = 0; i < vcnt; i++)
  326                 rdmsr(0x200+i, &m->mtrrvar[i]);
  327 
  328         /*
  329          * If not the bootstrap processor, compare.
  330          */
  331         if(m->machno == 0)
  332                 return;
  333 
  334         mach0 = MACHP(0);
  335         if(mach0->mtrrcap != m->mtrrcap)
  336                 print("mtrrcap%d: %lluX %lluX\n",
  337                         m->machno, mach0->mtrrcap, m->mtrrcap);
  338         if(mach0->mtrrdef != m->mtrrdef)
  339                 print("mtrrdef%d: %lluX %lluX\n",
  340                         m->machno, mach0->mtrrdef, m->mtrrdef);
  341         for(i = 0; i < 11; i++){
  342                 if(mach0->mtrrfix[i] != m->mtrrfix[i])
  343                         print("mtrrfix%d: i%d: %lluX %lluX\n",
  344                                 m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
  345         }
  346         for(i = 0; i < vcnt; i++){
  347                 if(mach0->mtrrvar[i] != m->mtrrvar[i])
  348                         print("mtrrvar%d: i%d: %lluX %lluX\n",
  349                                 m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
  350         }
  351 }
  352 
  353 static void
  354 squidboy(Apic* apic)
  355 {
  356 //      iprint("Hello Squidboy\n");
  357 
  358         machinit();
  359         mmuinit();
  360 
  361         cpuidentify();
  362         cpuidprint();
  363         checkmtrr();
  364 
  365         lock(&mprdthilock);
  366         mprdthi |= (1<<apic->apicno)<<24;
  367         unlock(&mprdthilock);
  368 
  369         lapicinit(apic);
  370         lapiconline();
  371         syncclock();
  372         timersinit();
  373 
  374         fpoff();
  375 
  376         lock(&active);
  377         active.machs |= 1<<m->machno;
  378         unlock(&active);
  379 
  380         while(!active.thunderbirdsarego)
  381                 microdelay(100);
  382 
  383         schedinit();
  384 }
  385 
  386 static void
  387 mpstartap(Apic* apic)
  388 {
  389         ulong *apbootp, *pdb, *pte;
  390         Mach *mach, *mach0;
  391         int i, machno;
  392         uchar *p;
  393 
  394         mach0 = MACHP(0);
  395 
  396         /*
  397          * Initialise the AP page-tables and Mach structure. The page-tables
  398          * are the same as for the bootstrap processor with the exception of
  399          * the PTE for the Mach structure.
  400          * Xspanalloc will panic if an allocation can't be made.
  401          */
  402         p = xspanalloc(4*BY2PG, BY2PG, 0);
  403         pdb = (ulong*)p;
  404         memmove(pdb, mach0->pdb, BY2PG);
  405         p += BY2PG;
  406 
  407         if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
  408                 return;
  409         memmove(p, KADDR(PPN(*pte)), BY2PG);
  410         *pte = PADDR(p)|PTEWRITE|PTEVALID;
  411         if(mach0->havepge)
  412                 *pte |= PTEGLOBAL;
  413         p += BY2PG;
  414 
  415         mach = (Mach*)p;
  416         if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
  417                 return;
  418         *pte = PADDR(mach)|PTEWRITE|PTEVALID;
  419         if(mach0->havepge)
  420                 *pte |= PTEGLOBAL;
  421         p += BY2PG;
  422 
  423         machno = apic->machno;
  424         MACHP(machno) = mach;
  425         mach->machno = machno;
  426         mach->pdb = pdb;
  427         mach->gdt = (Segdesc*)p;        /* filled by mmuinit */
  428 
  429         /*
  430          * Tell the AP where its kernel vector and pdb are.
  431          * The offsets are known in the AP bootstrap code.
  432          */
  433         apbootp = (ulong*)(APBOOTSTRAP+0x08);
  434         *apbootp++ = (ulong)squidboy;
  435         *apbootp++ = PADDR(pdb);
  436         *apbootp = (ulong)apic;
  437 
  438         /*
  439          * Universal Startup Algorithm.
  440          */
  441         p = KADDR(0x467);
  442         *p++ = PADDR(APBOOTSTRAP);
  443         *p++ = PADDR(APBOOTSTRAP)>>8;
  444         i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
  445         /* code assumes i==0 */
  446         if(i != 0)
  447                 print("mp: bad APBOOTSTRAP\n");
  448         *p++ = i;
  449         *p = i>>8;
  450 
  451         nvramwrite(0x0F, 0x0A);
  452         lapicstartap(apic, PADDR(APBOOTSTRAP));
  453         for(i = 0; i < 1000; i++){
  454                 lock(&mprdthilock);
  455                 if(mprdthi & ((1<<apic->apicno)<<24)){
  456                         unlock(&mprdthilock);
  457                         break;
  458                 }
  459                 unlock(&mprdthilock);
  460                 delay(10);
  461         }
  462         nvramwrite(0x0F, 0x00);
  463 }
  464 
  465 void
  466 mpinit(void)
  467 {
  468         int ncpu;
  469         char *cp;
  470         PCMP *pcmp;
  471         uchar *e, *p;
  472         Apic *apic, *bpapic;
  473         void *va;
  474 
  475         i8259init();
  476         syncclock();
  477 
  478         if(_mp_ == 0)
  479                 return;
  480         pcmp = KADDR(_mp_->physaddr);
  481 
  482         /*
  483          * Map the local APIC.
  484          */
  485         if((va = vmap(pcmp->lapicbase, 1024)) == nil)
  486                 return;
  487         print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
  488 
  489         bpapic = nil;
  490 
  491         /*
  492          * Run through the table saving information needed for starting
  493          * application processors and initialising any I/O APICs. The table
  494          * is guaranteed to be in order such that only one pass is necessary.
  495          */
  496         p = ((uchar*)pcmp)+sizeof(PCMP);
  497         e = ((uchar*)pcmp)+pcmp->length;
  498         while(p < e) switch(*p){
  499 
  500         default:
  501                 print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
  502                         *p, e-p);
  503                 while(p < e){
  504                         print("%uX ", *p);
  505                         p++;
  506                 }
  507                 break;
  508 
  509         case PcmpPROCESSOR:
  510                 if(apic = mkprocessor((PCMPprocessor*)p)){
  511                         /*
  512                          * Must take a note of bootstrap processor APIC
  513                          * now as it will be needed in order to start the
  514                          * application processors later and there's no
  515                          * guarantee that the bootstrap processor appears
  516                          * first in the table before the others.
  517                          */
  518                         apic->addr = va;
  519                         apic->paddr = pcmp->lapicbase;
  520                         if(apic->flags & PcmpBP)
  521                                 bpapic = apic;
  522                 }
  523                 p += sizeof(PCMPprocessor);
  524                 continue;
  525 
  526         case PcmpBUS:
  527                 mkbus((PCMPbus*)p);
  528                 p += sizeof(PCMPbus);
  529                 continue;
  530 
  531         case PcmpIOAPIC:
  532                 if(apic = mkioapic((PCMPioapic*)p))
  533                         ioapicinit(apic, ((PCMPioapic*)p)->apicno);
  534                 p += sizeof(PCMPioapic);
  535                 continue;
  536 
  537         case PcmpIOINTR:
  538                 mkiointr((PCMPintr*)p);
  539                 p += sizeof(PCMPintr);
  540                 continue;
  541 
  542         case PcmpLINTR:
  543                 mklintr((PCMPintr*)p);
  544                 p += sizeof(PCMPintr);
  545                 continue;
  546         }
  547 
  548         /*
  549          * No bootstrap processor, no need to go further.
  550          */
  551         if(bpapic == 0)
  552                 return;
  553 
  554         lapicinit(bpapic);
  555         lock(&mprdthilock);
  556         mprdthi |= (1<<bpapic->apicno)<<24;
  557         unlock(&mprdthilock);
  558 
  559         /*
  560          * These interrupts are local to the processor
  561          * and do not appear in the I/O APIC so it is OK
  562          * to set them now.
  563          */
  564         intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
  565         intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
  566         intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
  567         lapiconline();
  568 
  569         checkmtrr();
  570 
  571         /*
  572          * Initialise the application processors.
  573          */
  574         if(cp = getconf("*ncpu")){
  575                 ncpu = strtol(cp, 0, 0);
  576                 if(ncpu < 1)
  577                         ncpu = 1;
  578         }
  579         else
  580                 ncpu = MaxAPICNO;
  581         memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
  582         for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
  583                 if(ncpu <= 1)
  584                         break;
  585                 if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN
  586                 && apic->type == PcmpPROCESSOR){
  587                         mpstartap(apic);
  588                         conf.nmach++;
  589                         ncpu--;
  590                 }
  591         }
  592 
  593         /*
  594          *  we don't really know the number of processors till
  595          *  here.
  596          *
  597          *  set conf.copymode here if nmach > 1.
  598          *  Should look for an ExtINT line and enable it.
  599          */
  600         if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
  601                 conf.copymode = 1;
  602 }
  603 
  604 static int
  605 mpintrenablex(Vctl* v, int tbdf)
  606 {
  607         Bus *bus;
  608         Aintr *aintr;
  609         Apic *apic;
  610         Pcidev *pcidev;
  611         int bno, dno, irq, lo, n, type, vno;
  612 
  613         /*
  614          * Find the bus.
  615          */
  616         type = BUSTYPE(tbdf);
  617         bno = BUSBNO(tbdf);
  618         dno = BUSDNO(tbdf);
  619         if(type == BusISA)
  620                 bno = mpisabus;
  621         for(bus = mpbus; bus != nil; bus = bus->next){
  622                 if(bus->type != type)
  623                         continue;
  624                 if(bus->busno == bno)
  625                         break;
  626         }
  627         if(bus == nil){
  628                 print("ioapicirq: can't find bus type %d\n", type);
  629                 return -1;
  630         }
  631 
  632         /*
  633          * For PCI devices the interrupt pin (INT[ABCD]) and device
  634          * number are encoded into the entry irq field, so create something
  635          * to match on. The interrupt pin used by the device has to be
  636          * obtained from the PCI config space.
  637          */
  638         if(bus->type == BusPCI){
  639                 pcidev = pcimatchtbdf(tbdf);
  640                 if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
  641                         irq = (dno<<2)|(n-1);
  642                 else
  643                         irq = -1;
  644                 //print("pcidev %uX: irq %uX v->irq %uX\n", tbdf, irq, v->irq);
  645         }
  646         else
  647                 irq = v->irq;
  648 
  649         /*
  650          * Find a matching interrupt entry from the list of interrupts
  651          * attached to this bus.
  652          */
  653         for(aintr = bus->aintr; aintr; aintr = aintr->next){
  654                 if(aintr->intr->irq != irq)
  655                         continue;
  656 
  657                 /*
  658                  * Check if already enabled. Multifunction devices may share
  659                  * INT[A-D]# so, if already enabled, check the polarity matches
  660                  * and the trigger is level.
  661                  *
  662                  * Should check the devices differ only in the function number,
  663                  * but that can wait for the planned enable/disable rewrite.
  664                  * The RDT read here is safe for now as currently interrupts
  665                  * are never disabled once enabled.
  666                  */
  667                 apic = aintr->apic;
  668                 ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
  669 
  670                 if(!(lo & ApicIMASK)){
  671                         vno = lo & 0xFF;
  672                         n = mpintrinit(bus, aintr->intr, vno, v->irq);
  673                         n |= ApicLOGICAL;
  674                         lo &= ~(ApicRemoteIRR|ApicDELIVS);
  675                         if(n != lo || !(n & ApicLEVEL)){
  676                                 print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
  677                                         v->irq, tbdf, lo, n);
  678                                 return -1;
  679                         }
  680 
  681                         v->isr = lapicisr;
  682                         v->eoi = lapiceoi;
  683 
  684                         return vno;
  685                 }
  686 
  687                 /*
  688                  * With the APIC a unique vector can be assigned to each
  689                  * request to enable an interrupt. There are two reasons this
  690                  * is a good idea:
  691                  * 1) to prevent lost interrupts, no more than 2 interrupts
  692                  *    should be assigned per block of 16 vectors (there is an
  693                  *    in-service entry and a holding entry for each priority
  694                  *    level and there is one priority level per block of 16
  695                  *    interrupts).
  696                  * 2) each input pin on the IOAPIC will receive a different
  697                  *    vector regardless of whether the devices on that pin use
  698                  *    the same IRQ as devices on another pin.
  699                  */
  700                 vno = VectorAPIC + (incref(&mpvnoref)-1)*8;
  701                 if(vno > MaxVectorAPIC){
  702                         print("mpintrenable: vno %d, irq %d, tbdf %uX\n",
  703                                 vno, v->irq, tbdf);
  704                         return -1;
  705                 }
  706                 lo = mpintrinit(bus, aintr->intr, vno, v->irq);
  707                 //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n",
  708                 //      lo, bus->busno, aintr->intr->irq, vno,
  709                 //      v->irq, i8259elcr);
  710                 if(lo & ApicIMASK)
  711                         return -1;
  712                 lo |= ApicLOGICAL;
  713 
  714                 if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC){
  715                         lock(&mprdthilock);
  716                         ioapicrdtw(apic, aintr->intr->intin, mprdthi, lo);
  717                         unlock(&mprdthilock);
  718                 }
  719                 //else
  720                 //      print("lo not enabled 0x%uX %d\n",
  721                 //              apic->flags, apic->type);
  722 
  723                 v->isr = lapicisr;
  724                 v->eoi = lapiceoi;
  725 
  726                 return vno;
  727         }
  728 
  729         return -1;
  730 }
  731 
  732 int
  733 mpintrenable(Vctl* v)
  734 {
  735         int irq, tbdf, vno;
  736 
  737         /*
  738          * If the bus is known, try it.
  739          * BUSUNKNOWN is given both by [E]ISA devices and by
  740          * interrupts local to the processor (local APIC, coprocessor
  741          * breakpoint and page-fault).
  742          */
  743         tbdf = v->tbdf;
  744         if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
  745                 return vno;
  746 
  747         irq = v->irq;
  748         if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
  749                 if(irq != IrqSPURIOUS)
  750                         v->isr = lapiceoi;
  751                 return VectorPIC+irq;
  752         }
  753         if(irq < 0 || irq > MaxIrqPIC){
  754                 print("mpintrenable: irq %d out of range\n", irq);
  755                 return -1;
  756         }
  757 
  758         /*
  759          * Either didn't find it or have to try the default buses
  760          * (ISA and EISA). This hack is due to either over-zealousness 
  761          * or laziness on the part of some manufacturers.
  762          *
  763          * The MP configuration table on some older systems
  764          * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
  765          * but none for ISA. It also has the interrupt type and
  766          * polarity set to 'default for this bus' which wouldn't
  767          * be compatible with ISA.
  768          */
  769         if(mpeisabus != -1){
  770                 vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
  771                 if(vno != -1)
  772                         return vno;
  773         }
  774         if(mpisabus != -1){
  775                 vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
  776                 if(vno != -1)
  777                         return vno;
  778         }
  779         print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n",
  780                 mpeisabus, mpisabus, v->tbdf, v->irq);
  781         return -1;
  782 }
  783 
  784 static Lock mpshutdownlock;
  785 
  786 void
  787 mpshutdown(void)
  788 {
  789         /*
  790          * To be done...
  791          */
  792         if(!canlock(&mpshutdownlock)){
  793                 /*
  794                  * If this processor received the CTRL-ALT-DEL from
  795                  * the keyboard, acknowledge it. Send an INIT to self.
  796                  */
  797 #ifdef FIXTHIS
  798                 if(lapicisr(VectorKBD))
  799                         lapiceoi(VectorKBD);
  800 #endif /* FIX THIS */
  801                 idle();
  802         }
  803 
  804         print("apshutdown: active = 0x%2.2uX\n", active.machs);
  805         delay(1000);
  806         splhi();
  807 
  808         /*
  809          * INIT all excluding self.
  810          */
  811         lapicicrw(0, 0x000C0000|ApicINIT);
  812 
  813         pcireset();
  814         i8042reset();
  815 
  816         /*
  817          * Often the BIOS hangs during restart if a conventional 8042
  818          * warm-boot sequence is tried. The following is Intel specific and
  819          * seems to perform a cold-boot, but at least it comes back.
  820          * And sometimes there is no keyboard...
  821          *
  822          * The reset register (0xcf9) is usually in one of the bridge
  823          * chips. The actual location and sequence could be extracted from
  824          * ACPI but why bother, this is the end of the line anyway.
  825          */
  826         print("no kbd; trying bios warm boot...");
  827         *(ushort*)KADDR(0x472) = 0x1234;        /* BIOS warm-boot flag */
  828         outb(0xCF9, 0x02);
  829         outb(0xCF9, 0x06);
  830 
  831         print("can't reset\n");
  832         for(;;)
  833                 idle();
  834 }

Cache object: afa87712b8747f8ff513885fbfac9ee6


[ 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.