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

Cache object: 34c738432ce3f2664e276f8941ab38dc


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