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

Cache object: 43cc9fd720a9160746f0b48c611b3856


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