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/i386/i386/mpapic.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 /*
    2  * Copyright (c) 1996, by Steve Passe
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. The name of the developer may NOT be used to endorse or promote products
   11  *    derived from this software without specific prior written permission.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  * $FreeBSD$
   26  */
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 
   31 #include <machine/smptests.h>   /** TEST_TEST1, GRAB_LOPRIO */
   32 #include <machine/smp.h>
   33 #include <machine/mpapic.h>
   34 #include <machine/segments.h>
   35 
   36 #include <i386/isa/intr_machdep.h>      /* Xspuriousint() */
   37 
   38 /* EISA Edge/Level trigger control registers */
   39 #define ELCR0   0x4d0                   /* eisa irq 0-7 */
   40 #define ELCR1   0x4d1                   /* eisa irq 8-15 */
   41 
   42 /*
   43  * pointers to pmapped apic hardware.
   44  */
   45 
   46 #if defined(APIC_IO)
   47 volatile ioapic_t       **ioapic;
   48 #endif  /* APIC_IO */
   49 
   50 /*
   51  * Enable APIC, configure interrupts.
   52  */
   53 void
   54 apic_initialize(void)
   55 {
   56         u_int   temp;
   57 
   58         /* setup LVT1 as ExtINT */
   59         temp = lapic.lvt_lint0;
   60         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
   61         if (cpuid == 0)
   62                 temp |= 0x00000700;     /* process ExtInts */
   63         else
   64                 temp |= 0x00010700;     /* mask ExtInts */
   65         lapic.lvt_lint0 = temp;
   66 
   67         /* setup LVT2 as NMI, masked till later... */
   68         temp = lapic.lvt_lint1;
   69         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
   70         temp |= 0x00010400;             /* masked, edge trigger, active hi */
   71         lapic.lvt_lint1 = temp;
   72 
   73         /* set the Task Priority Register as needed */
   74         temp = lapic.tpr;
   75         temp &= ~APIC_TPR_PRIO;         /* clear priority field */
   76 #ifdef GRAB_LOPRIO
   77         /* Leave the BSP at TPR 0 during boot to make sure it gets interrupts */
   78         if (cpuid != 0)
   79                 temp |= LOPRIO_LEVEL;   /* allow INT arbitration */
   80 #endif
   81         lapic.tpr = temp;
   82 
   83         /* enable the local APIC */
   84         temp = lapic.svr;
   85         temp |= APIC_SVR_SWEN;          /* software enable APIC */
   86         temp &= ~APIC_SVR_FOCUS;        /* enable 'focus processor' */
   87 
   88         /* set the 'spurious INT' vector */
   89         if ((XSPURIOUSINT_OFFSET & APIC_SVR_VEC_FIX) != APIC_SVR_VEC_FIX)
   90                 panic("bad XSPURIOUSINT_OFFSET: 0x%08x", XSPURIOUSINT_OFFSET);
   91         temp &= ~APIC_SVR_VEC_PROG;     /* clear (programmable) vector field */
   92         temp |= (XSPURIOUSINT_OFFSET & APIC_SVR_VEC_PROG);
   93 
   94 #if defined(TEST_TEST1)
   95         if (cpuid == GUARD_CPU) {
   96                 temp &= ~APIC_SVR_SWEN; /* software DISABLE APIC */
   97         }
   98 #endif  /** TEST_TEST1 */
   99 
  100         lapic.svr = temp;
  101 
  102         if (bootverbose)
  103                 apic_dump("apic_initialize()");
  104 }
  105 
  106 
  107 /*
  108  * dump contents of local APIC registers
  109  */
  110 void
  111 apic_dump(char* str)
  112 {
  113         printf("SMP: CPU%d %s:\n", cpuid, str);
  114         printf("     lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
  115                 lapic.lvt_lint0, lapic.lvt_lint1, lapic.tpr, lapic.svr);
  116 }
  117 
  118 
  119 #if defined(APIC_IO)
  120 
  121 /*
  122  * IO APIC code,
  123  */
  124 
  125 #define IOAPIC_ISA_INTS         16
  126 #define REDIRCNT_IOAPIC(A) \
  127             ((int)((io_apic_versions[(A)] & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1)
  128 
  129 static int trigger __P((int apic, int pin, u_int32_t * flags));
  130 static void polarity __P((int apic, int pin, u_int32_t * flags, int level));
  131 
  132 #define DEFAULT_FLAGS           \
  133         ((u_int32_t)            \
  134          (IOART_INTMSET |       \
  135           IOART_DESTPHY |       \
  136           IOART_DELLOPRI))
  137 
  138 #define DEFAULT_ISA_FLAGS       \
  139         ((u_int32_t)            \
  140          (IOART_INTMSET |       \
  141           IOART_TRGREDG |       \
  142           IOART_INTAHI |        \
  143           IOART_DESTPHY |       \
  144           IOART_DELLOPRI))
  145 
  146 void
  147 io_apic_set_id(int apic, int id)
  148 {
  149         u_int32_t ux;
  150         
  151         ux = io_apic_read(apic, IOAPIC_ID);     /* get current contents */
  152         if (((ux & APIC_ID_MASK) >> 24) != id) {
  153                 printf("Changing APIC ID for IO APIC #%d"
  154                        " from %d to %d on chip\n",
  155                        apic, ((ux & APIC_ID_MASK) >> 24), id);
  156                 ux &= ~APIC_ID_MASK;    /* clear the ID field */
  157                 ux |= (id << 24);
  158                 io_apic_write(apic, IOAPIC_ID, ux);     /* write new value */
  159                 ux = io_apic_read(apic, IOAPIC_ID);     /* re-read && test */
  160                 if (((ux & APIC_ID_MASK) >> 24) != id)
  161                         panic("can't control IO APIC #%d ID, reg: 0x%08x",
  162                               apic, ux);
  163         }
  164 }
  165 
  166 
  167 int
  168 io_apic_get_id(int apic)
  169 {
  170   return (io_apic_read(apic, IOAPIC_ID) & APIC_ID_MASK) >> 24;
  171 }
  172   
  173 
  174 
  175 /*
  176  * Setup the IO APIC.
  177  */
  178 
  179 extern int      apic_pin_trigger;       /* 'opaque' */
  180 
  181 void
  182 io_apic_setup_intpin(int apic, int pin)
  183 {
  184         int bus, bustype, irq;
  185         u_char          select;         /* the select register is 8 bits */
  186         u_int32_t       flags;          /* the window register is 32 bits */
  187         u_int32_t       target;         /* the window register is 32 bits */
  188         u_int32_t       vector;         /* the window register is 32 bits */
  189         int             level;
  190         u_int           eflags;
  191 
  192         target = IOART_DEST;
  193 
  194         select = pin * 2 + IOAPIC_REDTBL0;      /* register */
  195         /* 
  196          * Always disable interrupts, and by default map
  197          * pin X to IRQX because the disable doesn't stick
  198          * and the uninitialize vector will get translated 
  199          * into a panic.
  200          *
  201          * This is correct for IRQs 1 and 3-15.  In the other cases, 
  202          * any robust driver will handle the spurious interrupt, and 
  203          * the effective NOP beats a panic.
  204          *
  205          * A dedicated "bogus interrupt" entry in the IDT would
  206          * be a nicer hack, although some one should find out 
  207          * why some systems are generating interrupts when they
  208          * shouldn't and stop the carnage.
  209          */
  210         vector = NRSVIDT + pin;                 /* IDT vec */
  211         eflags = read_eflags();
  212         __asm __volatile("cli" : : : "memory");
  213         s_lock(&imen_lock);
  214         io_apic_write(apic, select,
  215                       (io_apic_read(apic, select) & ~IOART_INTMASK 
  216                        & ~0xff)|IOART_INTMSET|vector);
  217         s_unlock(&imen_lock);
  218         write_eflags(eflags);
  219         
  220         /* we only deal with vectored INTs here */
  221         if (apic_int_type(apic, pin) != 0)
  222                 return;
  223         
  224         irq = apic_irq(apic, pin);
  225         if (irq < 0)
  226                 return;
  227         
  228         /* determine the bus type for this pin */
  229         bus = apic_src_bus_id(apic, pin);
  230         if (bus == -1)
  231                 return;
  232         bustype = apic_bus_type(bus);
  233         
  234         if ((bustype == ISA) &&
  235             (pin < IOAPIC_ISA_INTS) && 
  236             (irq == pin) &&
  237             (apic_polarity(apic, pin) == 0x1) &&
  238             (apic_trigger(apic, pin) == 0x3)) {
  239                 /* 
  240                  * A broken BIOS might describe some ISA 
  241                  * interrupts as active-high level-triggered.
  242                  * Use default ISA flags for those interrupts.
  243                  */
  244                 flags = DEFAULT_ISA_FLAGS;
  245         } else {
  246                 /* 
  247                  * Program polarity and trigger mode according to 
  248                  * interrupt entry.
  249                  */
  250                 flags = DEFAULT_FLAGS;
  251                 level = trigger(apic, pin, &flags);
  252                 if (level == 1)
  253                         apic_pin_trigger |= (1 << irq);
  254                 polarity(apic, pin, &flags, level);
  255         }
  256         
  257         /* program the appropriate registers */
  258         if (apic != 0 || pin != irq)
  259                 printf("IOAPIC #%d intpin %d -> irq %d\n",
  260                        apic, pin, irq);
  261         vector = NRSVIDT + irq;                 /* IDT vec */
  262         eflags = read_eflags();
  263         __asm __volatile("cli" : : : "memory");
  264         s_lock(&imen_lock);
  265         io_apic_write(apic, select, flags | vector);
  266         io_apic_write(apic, select + 1, target);
  267         s_unlock(&imen_lock);
  268         write_eflags(eflags);
  269 }
  270 
  271 int
  272 io_apic_setup(int apic)
  273 {
  274         int             maxpin;
  275         int             pin;
  276 
  277         if (apic == 0)
  278                 apic_pin_trigger = 0;   /* default to edge-triggered */
  279 
  280         maxpin = REDIRCNT_IOAPIC(apic);         /* pins in APIC */
  281         printf("Programming %d pins in IOAPIC #%d\n", maxpin, apic);
  282         
  283         for (pin = 0; pin < maxpin; ++pin) {
  284                 io_apic_setup_intpin(apic, pin);
  285         }
  286 
  287         /* return GOOD status */
  288         return 0;
  289 }
  290 #undef DEFAULT_ISA_FLAGS
  291 #undef DEFAULT_FLAGS
  292 
  293 
  294 #define DEFAULT_EXTINT_FLAGS    \
  295         ((u_int32_t)            \
  296          (IOART_INTMSET |       \
  297           IOART_TRGREDG |       \
  298           IOART_INTAHI |        \
  299           IOART_DESTPHY |       \
  300           IOART_DELLOPRI))
  301 
  302 /*
  303  * Setup the source of External INTerrupts.
  304  */
  305 int
  306 ext_int_setup(int apic, int intr)
  307 {
  308         u_char  select;         /* the select register is 8 bits */
  309         u_int32_t flags;        /* the window register is 32 bits */
  310         u_int32_t target;       /* the window register is 32 bits */
  311         u_int32_t vector;       /* the window register is 32 bits */
  312 
  313         if (apic_int_type(apic, intr) != 3)
  314                 return -1;
  315 
  316         target = IOART_DEST;
  317         select = IOAPIC_REDTBL0 + (2 * intr);
  318         vector = NRSVIDT + intr;
  319         flags = DEFAULT_EXTINT_FLAGS;
  320 
  321         io_apic_write(apic, select, flags | vector);
  322         io_apic_write(apic, select + 1, target);
  323 
  324         return 0;
  325 }
  326 #undef DEFAULT_EXTINT_FLAGS
  327 
  328 
  329 /*
  330  * Set the trigger level for an IO APIC pin.
  331  */
  332 static int
  333 trigger(int apic, int pin, u_int32_t * flags)
  334 {
  335         int     id;
  336         int     eirq;
  337         int     level;
  338         static int intcontrol = -1;
  339 
  340         switch (apic_trigger(apic, pin)) {
  341 
  342         case 0x00:
  343                 break;
  344 
  345         case 0x01:
  346                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG */
  347                 return 0;
  348 
  349         case 0x03:
  350                 *flags |= IOART_TRGRLVL;
  351                 return 1;
  352 
  353         case -1:
  354         default:
  355                 goto bad;
  356         }
  357 
  358         if ((id = apic_src_bus_id(apic, pin)) == -1)
  359                 goto bad;
  360 
  361         switch (apic_bus_type(id)) {
  362         case ISA:
  363                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG; */
  364                 return 0;
  365 
  366         case EISA:
  367                 eirq = apic_src_bus_irq(apic, pin);
  368 
  369                 if (eirq < 0 || eirq > 15) {
  370                         printf("EISA IRQ %d?!?!\n", eirq);
  371                         goto bad;
  372                 }
  373 
  374                 if (intcontrol == -1) {
  375                         intcontrol = inb(ELCR1) << 8;
  376                         intcontrol |= inb(ELCR0);
  377                         printf("EISA INTCONTROL = %08x\n", intcontrol);
  378                 }
  379 
  380                 /* Use ELCR settings to determine level or edge mode */
  381                 level = (intcontrol >> eirq) & 1;
  382 
  383                 /*
  384                  * Note that on older Neptune chipset based systems, any
  385                  * pci interrupts often show up here and in the ELCR as well
  386                  * as level sensitive interrupts attributed to the EISA bus.
  387                  */
  388 
  389                 if (level)
  390                         *flags |= IOART_TRGRLVL;
  391                 else
  392                         *flags &= ~IOART_TRGRLVL;
  393 
  394                 return level;
  395 
  396         case PCI:
  397                 *flags |= IOART_TRGRLVL;
  398                 return 1;
  399 
  400         case -1:
  401         default:
  402                 goto bad;
  403         }
  404 
  405 bad:
  406         panic("bad APIC IO INT flags");
  407 }
  408 
  409 
  410 /*
  411  * Set the polarity value for an IO APIC pin.
  412  */
  413 static void
  414 polarity(int apic, int pin, u_int32_t * flags, int level)
  415 {
  416         int     id;
  417 
  418         switch (apic_polarity(apic, pin)) {
  419 
  420         case 0x00:
  421                 break;
  422 
  423         case 0x01:
  424                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
  425                 return;
  426 
  427         case 0x03:
  428                 *flags |= IOART_INTALO;
  429                 return;
  430 
  431         case -1:
  432         default:
  433                 goto bad;
  434         }
  435 
  436         if ((id = apic_src_bus_id(apic, pin)) == -1)
  437                 goto bad;
  438 
  439         switch (apic_bus_type(id)) {
  440         case ISA:
  441                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
  442                 return;
  443 
  444         case EISA:
  445                 /* polarity converter always gives active high */
  446                 *flags &= ~IOART_INTALO;
  447                 return;
  448 
  449         case PCI:
  450                 *flags |= IOART_INTALO;
  451                 return;
  452 
  453         case -1:
  454         default:
  455                 goto bad;
  456         }
  457 
  458 bad:
  459         panic("bad APIC IO INT flags");
  460 }
  461 
  462 
  463 /*
  464  * Print contents of apic_imen.
  465  */
  466 extern  u_int apic_imen;                /* keep apic_imen 'opaque' */
  467 void
  468 imen_dump(void)
  469 {
  470         int x;
  471 
  472         printf("SMP: enabled INTs: ");
  473         for (x = 0; x < 24; ++x)
  474                 if ((apic_imen & (1 << x)) == 0)
  475                         printf("%d, ", x);
  476         printf("apic_imen: 0x%08x\n", apic_imen);
  477 }
  478 
  479 
  480 /*
  481  * Inter Processor Interrupt functions.
  482  */
  483 
  484 
  485 /*
  486  * Send APIC IPI 'vector' to 'destType' via 'deliveryMode'.
  487  *
  488  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
  489  *  vector is any valid SYSTEM INT vector
  490  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
  491  */
  492 #define DETECT_DEADLOCK
  493 int
  494 apic_ipi(int dest_type, int vector, int delivery_mode)
  495 {
  496         u_long  icr_lo;
  497 
  498 #if defined(DETECT_DEADLOCK)
  499 #define MAX_SPIN1       10000000
  500 #define MAX_SPIN2       1000
  501         int     x;
  502 
  503         /* "lazy delivery", ie we only barf if they stack up on us... */
  504         for (x = MAX_SPIN1; x; --x) {
  505                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  506                         break;
  507         }
  508         if (x == 0)
  509                 panic("apic_ipi was stuck");
  510 #endif  /* DETECT_DEADLOCK */
  511 
  512         /* build IRC_LOW */
  513         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
  514             | dest_type | delivery_mode | vector;
  515 
  516         /* write APIC ICR */
  517         lapic.icr_lo = icr_lo;
  518 
  519         /* wait for pending status end */
  520 #if defined(DETECT_DEADLOCK)
  521         for (x = MAX_SPIN2; x; --x) {
  522                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  523                         break;
  524         }
  525 #ifdef needsattention
  526 /*
  527  * XXX FIXME:
  528  *      The above loop waits for the message to actually be delivered.
  529  *      It breaks out after an arbitrary timout on the theory that it eventually
  530  *      will be delivered and we will catch a real failure on the next entry to
  531  *      this function, which would panic().
  532  *      We could skip this wait entirely, EXCEPT it probably protects us from
  533  *      other "less robust" routines that assume the message was delivered and
  534  *      acted upon when this function returns.  TLB shootdowns are one such
  535  *      "less robust" function.
  536  */
  537         if (x == 0)
  538                 printf("apic_ipi might be stuck\n");
  539 #endif
  540 #undef MAX_SPIN2
  541 #undef MAX_SPIN1
  542 #else
  543         while (lapic.icr_lo & APIC_DELSTAT_MASK)
  544                  /* spin */ ;
  545 #endif  /* DETECT_DEADLOCK */
  546 
  547         /** XXX FIXME: return result */
  548         return 0;
  549 }
  550 
  551 static int
  552 apic_ipi_singledest(int cpu, int vector, int delivery_mode)
  553 {
  554         u_long  icr_lo;
  555         u_long  icr_hi;
  556         u_long  eflags;
  557 
  558 #if defined(DETECT_DEADLOCK)
  559 #define MAX_SPIN1       10000000
  560 #define MAX_SPIN2       1000
  561         int     x;
  562 
  563         /* "lazy delivery", ie we only barf if they stack up on us... */
  564         for (x = MAX_SPIN1; x; --x) {
  565                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  566                         break;
  567         }
  568         if (x == 0)
  569                 panic("apic_ipi was stuck");
  570 #endif  /* DETECT_DEADLOCK */
  571 
  572         eflags = read_eflags();
  573         __asm __volatile("cli" : : : "memory");
  574         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
  575         icr_hi |= (CPU_TO_ID(cpu) << 24);
  576         lapic.icr_hi = icr_hi;
  577 
  578         /* build IRC_LOW */
  579         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
  580             | APIC_DEST_DESTFLD | delivery_mode | vector;
  581 
  582         /* write APIC ICR */
  583         lapic.icr_lo = icr_lo;
  584         write_eflags(eflags);
  585 
  586         /* wait for pending status end */
  587 #if defined(DETECT_DEADLOCK)
  588         for (x = MAX_SPIN2; x; --x) {
  589                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  590                         break;
  591         }
  592 #ifdef needsattention
  593 /*
  594  * XXX FIXME:
  595  *      The above loop waits for the message to actually be delivered.
  596  *      It breaks out after an arbitrary timout on the theory that it eventually
  597  *      will be delivered and we will catch a real failure on the next entry to
  598  *      this function, which would panic().
  599  *      We could skip this wait entirely, EXCEPT it probably protects us from
  600  *      other "less robust" routines that assume the message was delivered and
  601  *      acted upon when this function returns.  TLB shootdowns are one such
  602  *      "less robust" function.
  603  */
  604         if (x == 0)
  605                 printf("apic_ipi might be stuck\n");
  606 #endif
  607 #undef MAX_SPIN2
  608 #undef MAX_SPIN1
  609 #else
  610         while (lapic.icr_lo & APIC_DELSTAT_MASK)
  611                  /* spin */ ;
  612 #endif  /* DETECT_DEADLOCK */
  613 
  614         /** XXX FIXME: return result */
  615         return 0;
  616 }
  617 
  618 
  619 /*
  620  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
  621  *
  622  *  target contains a bitfield with a bit set for selected APICs.
  623  *  vector is any valid SYSTEM INT vector
  624  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
  625  */
  626 int
  627 selected_apic_ipi(u_int target, int vector, int delivery_mode)
  628 {
  629         int     x;
  630         int     status;
  631 
  632         if (target & ~0x7fff)
  633                 return -1;      /* only 15 targets allowed */
  634 
  635         for (status = 0, x = 0; x <= 14; ++x)
  636                 if (target & (1 << x)) {
  637 
  638                         /* send the IPI */
  639                         if (apic_ipi_singledest(x, vector, 
  640                                                 delivery_mode) == -1)
  641                                 status |= (1 << x);
  642                 }
  643         return status;
  644 }
  645 
  646 
  647 #if defined(READY)
  648 /*
  649  * Send an IPI INTerrupt containing 'vector' to CPU 'target'
  650  *   NOTE: target is a LOGICAL APIC ID
  651  */
  652 int
  653 selected_proc_ipi(int target, int vector)
  654 {
  655         u_long  icr_lo;
  656         u_long  icr_hi;
  657 
  658         /* write the destination field for the target AP */
  659         icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
  660             (cpu_num_to_apic_id[target] << 24);
  661         lapic.icr_hi = icr_hi;
  662 
  663         /* write command */
  664         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
  665             APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
  666         lapic.icr_lo = icr_lo;
  667 
  668         /* wait for pending status end */
  669         while (lapic.icr_lo & APIC_DELSTAT_MASK)
  670                 /* spin */ ;
  671 
  672         return 0;       /** XXX FIXME: return result */
  673 }
  674 #endif /* READY */
  675 
  676 #endif  /* APIC_IO */
  677 
  678 
  679 /*
  680  * Timer code, in development...
  681  *  - suggested by rgrimes@gndrsh.aac.dev.com
  682  */
  683 
  684 /** XXX FIXME: temp hack till we can determin bus clock */
  685 #ifndef BUS_CLOCK
  686 #define BUS_CLOCK       66000000
  687 #define bus_clock()     66000000
  688 #endif
  689 
  690 #if defined(READY)
  691 int acquire_apic_timer __P((void));
  692 int release_apic_timer __P((void));
  693 
  694 /*
  695  * Acquire the APIC timer for exclusive use.
  696  */
  697 int
  698 acquire_apic_timer(void)
  699 {
  700 #if 1
  701         return 0;
  702 #else
  703         /** XXX FIXME: make this really do something */
  704         panic("APIC timer in use when attempting to aquire");
  705 #endif
  706 }
  707 
  708 
  709 /*
  710  * Return the APIC timer.
  711  */
  712 int
  713 release_apic_timer(void)
  714 {
  715 #if 1
  716         return 0;
  717 #else
  718         /** XXX FIXME: make this really do something */
  719         panic("APIC timer was already released");
  720 #endif
  721 }
  722 #endif  /* READY */
  723 
  724 
  725 /*
  726  * Load a 'downcount time' in uSeconds.
  727  */
  728 void
  729 set_apic_timer(int value)
  730 {
  731         u_long  lvtt;
  732         long    ticks_per_microsec;
  733 
  734         /*
  735          * Calculate divisor and count from value:
  736          * 
  737          *  timeBase == CPU bus clock divisor == [1,2,4,8,16,32,64,128]
  738          *  value == time in uS
  739          */
  740         lapic.dcr_timer = APIC_TDCR_1;
  741         ticks_per_microsec = bus_clock() / 1000000;
  742 
  743         /* configure timer as one-shot */
  744         lvtt = lapic.lvt_timer;
  745         lvtt &= ~(APIC_LVTT_VECTOR | APIC_LVTT_DS | APIC_LVTT_M | APIC_LVTT_TM);
  746         lvtt |= APIC_LVTT_M;                    /* no INT, one-shot */
  747         lapic.lvt_timer = lvtt;
  748 
  749         /* */
  750         lapic.icr_timer = value * ticks_per_microsec;
  751 }
  752 
  753 
  754 /*
  755  * Read remaining time in timer.
  756  */
  757 int
  758 read_apic_timer(void)
  759 {
  760 #if 0
  761         /** XXX FIXME: we need to return the actual remaining time,
  762          *         for now we just return the remaining count.
  763          */
  764 #else
  765         return lapic.ccr_timer;
  766 #endif
  767 }
  768 
  769 
  770 /*
  771  * Spin-style delay, set delay time in uS, spin till it drains.
  772  */
  773 void
  774 u_sleep(int count)
  775 {
  776         set_apic_timer(count);
  777         while (read_apic_timer())
  778                  /* spin */ ;
  779 }

Cache object: c25f18276107c6b11ff6c5566c40c297


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