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 "opt_smp.h"
   29 
   30 #include <sys/types.h>
   31 #include <sys/systm.h>
   32 
   33 #include <machine/smptests.h>   /** TEST_TEST1 */
   34 #include <machine/smp.h>
   35 #include <machine/mpapic.h>
   36 #include <machine/segments.h>
   37 
   38 #include <i386/isa/intr_machdep.h>      /* Xspuriousint() */
   39 
   40 /* EISA Edge/Level trigger control registers */
   41 #define ELCR0   0x4d0                   /* eisa irq 0-7 */
   42 #define ELCR1   0x4d1                   /* eisa irq 8-15 */
   43 
   44 /*
   45  * pointers to pmapped apic hardware.
   46  */
   47 
   48 #if defined(APIC_IO)
   49 volatile ioapic_t       *ioapic[NAPIC];
   50 #endif  /* APIC_IO */
   51 
   52 /*
   53  * Enable APIC, configure interrupts.
   54  */
   55 void
   56 apic_initialize(void)
   57 {
   58         u_int   temp;
   59 
   60         /* setup LVT1 as ExtINT */
   61         temp = lapic.lvt_lint0;
   62         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
   63         if (cpuid == 0)
   64                 temp |= 0x00000700;     /* process ExtInts */
   65         else
   66                 temp |= 0x00010700;     /* mask ExtInts */
   67         lapic.lvt_lint0 = temp;
   68 
   69         /* setup LVT2 as NMI, masked till later... */
   70         temp = lapic.lvt_lint1;
   71         temp &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM);
   72         temp |= 0x00010400;             /* masked, edge trigger, active hi */
   73 
   74         lapic.lvt_lint1 = temp;
   75 
   76         /* set the Task Priority Register as needed */
   77         temp = lapic.tpr;
   78         temp &= ~APIC_TPR_PRIO;         /* clear priority field */
   79         temp |= LOPRIO_LEVEL;           /* allow INT arbitration */
   80 
   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 /*
  147  * Setup the IO APIC.
  148  */
  149 extern int      apic_pin_trigger;       /* 'opaque' */
  150 int
  151 io_apic_setup(int apic)
  152 {
  153         int             maxpin;
  154         u_char          select;         /* the select register is 8 bits */
  155         u_int32_t       flags;          /* the window register is 32 bits */
  156         u_int32_t       target;         /* the window register is 32 bits */
  157         u_int32_t       vector;         /* the window register is 32 bits */
  158         int             pin, level;
  159 
  160         target = IOART_DEST;
  161 
  162         if (apic == 0)
  163                 apic_pin_trigger = 0;   /* default to edge-triggered */
  164 
  165         maxpin = REDIRCNT_IOAPIC(apic);         /* pins in APIC */
  166         printf("Programming %d pins in IOAPIC #%d\n", maxpin, apic);
  167         
  168         for (pin = 0; pin < maxpin; ++pin) {
  169                 int bus, bustype, irq;
  170                 
  171                 /* we only deal with vectored INTs here */
  172                 if (apic_int_type(apic, pin) != 0)
  173                         continue;
  174 
  175                 irq = apic_irq(apic, pin);
  176                 if (irq == 0xff)
  177                         continue;
  178                 
  179                 /* determine the bus type for this pin */
  180                 bus = apic_src_bus_id(apic, pin);
  181                 if (bus == -1)
  182                         continue;
  183                 bustype = apic_bus_type(bus);
  184                 
  185                 /* the "ISA" type INTerrupts */
  186                 if ((bustype == ISA) &&
  187                     (pin < IOAPIC_ISA_INTS) && 
  188                     (irq == pin) &&
  189                     (apic_polarity(apic, pin) == 0x1) &&
  190                     (apic_trigger(apic, pin) == 0x3)) {
  191                         flags = DEFAULT_ISA_FLAGS;
  192                 }
  193                 
  194                 /* PCI or other bus */
  195                 else {
  196                         flags = DEFAULT_FLAGS;
  197                         level = trigger(apic, pin, &flags);
  198                         if (level == 1)
  199                                 apic_pin_trigger |= (1 << irq);
  200                         polarity(apic, pin, &flags, level);
  201                 }
  202                 
  203                 /* program the appropriate registers */
  204                 if (apic != 0 || pin != irq)
  205                         printf("IOAPIC #%d intpint %d -> irq %d\n",
  206                                apic, pin, irq);
  207                 select = pin * 2 + IOAPIC_REDTBL0;      /* register */
  208                 vector = NRSVIDT + irq;                 /* IDT vec */
  209                 io_apic_write(apic, select, flags | vector);
  210                 io_apic_write(apic, select + 1, target);
  211         }
  212 
  213         /* return GOOD status */
  214         return 0;
  215 }
  216 #undef DEFAULT_ISA_FLAGS
  217 #undef DEFAULT_FLAGS
  218 
  219 
  220 #define DEFAULT_EXTINT_FLAGS    \
  221         ((u_int32_t)            \
  222          (IOART_INTMSET |       \
  223           IOART_TRGREDG |       \
  224           IOART_INTAHI |        \
  225           IOART_DESTPHY |       \
  226           IOART_DELLOPRI))
  227 
  228 /*
  229  * Setup the source of External INTerrupts.
  230  */
  231 int
  232 ext_int_setup(int apic, int intr)
  233 {
  234         u_char  select;         /* the select register is 8 bits */
  235         u_int32_t flags;        /* the window register is 32 bits */
  236         u_int32_t target;       /* the window register is 32 bits */
  237         u_int32_t vector;       /* the window register is 32 bits */
  238 
  239         if (apic_int_type(apic, intr) != 3)
  240                 return -1;
  241 
  242         target = IOART_DEST;
  243         select = IOAPIC_REDTBL0 + (2 * intr);
  244         vector = NRSVIDT + intr;
  245         flags = DEFAULT_EXTINT_FLAGS;
  246 
  247         io_apic_write(apic, select, flags | vector);
  248         io_apic_write(apic, select + 1, target);
  249 
  250         return 0;
  251 }
  252 #undef DEFAULT_EXTINT_FLAGS
  253 
  254 
  255 /*
  256  * Set the trigger level for an IO APIC pin.
  257  */
  258 static int
  259 trigger(int apic, int pin, u_int32_t * flags)
  260 {
  261         int     id;
  262         int     eirq;
  263         int     level;
  264         static int intcontrol = -1;
  265 
  266         switch (apic_trigger(apic, pin)) {
  267 
  268         case 0x00:
  269                 break;
  270 
  271         case 0x01:
  272                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG */
  273                 return 0;
  274 
  275         case 0x03:
  276                 *flags |= IOART_TRGRLVL;
  277                 return 1;
  278 
  279         case -1:
  280         default:
  281                 goto bad;
  282         }
  283 
  284         if ((id = apic_src_bus_id(apic, pin)) == -1)
  285                 goto bad;
  286 
  287         switch (apic_bus_type(id)) {
  288         case ISA:
  289                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG; */
  290                 return 0;
  291 
  292         case EISA:
  293                 eirq = apic_src_bus_irq(apic, pin);
  294 
  295                 if (eirq < 0 || eirq > 15) {
  296                         printf("EISA IRQ %d?!?!\n", eirq);
  297                         goto bad;
  298                 }
  299 
  300                 if (intcontrol == -1) {
  301                         intcontrol = inb(ELCR1) << 8;
  302                         intcontrol |= inb(ELCR0);
  303                         printf("EISA INTCONTROL = %08x\n", intcontrol);
  304                 }
  305 
  306                 /* Use ELCR settings to determine level or edge mode */
  307                 level = (intcontrol >> eirq) & 1;
  308 
  309                 /*
  310                  * Note that on older Neptune chipset based systems, any
  311                  * pci interrupts often show up here and in the ELCR as well
  312                  * as level sensitive interrupts attributed to the EISA bus.
  313                  */
  314 
  315                 if (level)
  316                         *flags |= IOART_TRGRLVL;
  317                 else
  318                         *flags &= ~IOART_TRGRLVL;
  319 
  320                 return level;
  321 
  322         case PCI:
  323                 *flags |= IOART_TRGRLVL;
  324                 return 1;
  325 
  326         case -1:
  327         default:
  328                 goto bad;
  329         }
  330 
  331 bad:
  332         panic("bad APIC IO INT flags");
  333 }
  334 
  335 
  336 /*
  337  * Set the polarity value for an IO APIC pin.
  338  */
  339 static void
  340 polarity(int apic, int pin, u_int32_t * flags, int level)
  341 {
  342         int     id;
  343 
  344         switch (apic_polarity(apic, pin)) {
  345 
  346         case 0x00:
  347                 break;
  348 
  349         case 0x01:
  350                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
  351                 return;
  352 
  353         case 0x03:
  354                 *flags |= IOART_INTALO;
  355                 return;
  356 
  357         case -1:
  358         default:
  359                 goto bad;
  360         }
  361 
  362         if ((id = apic_src_bus_id(apic, pin)) == -1)
  363                 goto bad;
  364 
  365         switch (apic_bus_type(id)) {
  366         case ISA:
  367                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
  368                 return;
  369 
  370         case EISA:
  371                 /* polarity converter always gives active high */
  372                 *flags &= ~IOART_INTALO;
  373                 return;
  374 
  375         case PCI:
  376                 *flags |= IOART_INTALO;
  377                 return;
  378 
  379         case -1:
  380         default:
  381                 goto bad;
  382         }
  383 
  384 bad:
  385         panic("bad APIC IO INT flags");
  386 }
  387 
  388 
  389 /*
  390  * Print contents of apic_imen.
  391  */
  392 extern  u_int apic_imen;                /* keep apic_imen 'opaque' */
  393 void
  394 imen_dump(void)
  395 {
  396         int x;
  397 
  398         printf("SMP: enabled INTs: ");
  399         for (x = 0; x < 24; ++x)
  400                 if ((apic_imen & (1 << x)) == 0)
  401                         printf("%d, ", x);
  402         printf("apic_imen: 0x%08x\n", apic_imen);
  403 }
  404 
  405 
  406 /*
  407  * Inter Processor Interrupt functions.
  408  */
  409 
  410 
  411 /*
  412  * Send APIC IPI 'vector' to 'destType' via 'deliveryMode'.
  413  *
  414  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
  415  *  vector is any valid SYSTEM INT vector
  416  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
  417  */
  418 #define DETECT_DEADLOCK
  419 int
  420 apic_ipi(int dest_type, int vector, int delivery_mode)
  421 {
  422         u_long  icr_lo;
  423 
  424 #if defined(DETECT_DEADLOCK)
  425 #define MAX_SPIN1       10000000
  426 #define MAX_SPIN2       1000
  427         int     x;
  428 
  429         /* "lazy delivery", ie we only barf if they stack up on us... */
  430         for (x = MAX_SPIN1; x; --x) {
  431                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  432                         break;
  433         }
  434         if (x == 0)
  435                 panic("apic_ipi was stuck");
  436 #endif  /* DETECT_DEADLOCK */
  437 
  438         /* build IRC_LOW */
  439         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
  440             | dest_type | delivery_mode | vector;
  441 
  442         /* write APIC ICR */
  443         lapic.icr_lo = icr_lo;
  444 
  445         /* wait for pending status end */
  446 #if defined(DETECT_DEADLOCK)
  447         for (x = MAX_SPIN2; x; --x) {
  448                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  449                         break;
  450         }
  451 #ifdef needsattention
  452 /*
  453  * XXX FIXME:
  454  *      The above loop waits for the message to actually be delivered.
  455  *      It breaks out after an arbitrary timout on the theory that it eventually
  456  *      will be delivered and we will catch a real failure on the next entry to
  457  *      this function, which would panic().
  458  *      We could skip this wait entirely, EXCEPT it probably protects us from
  459  *      other "less robust" routines that assume the message was delivered and
  460  *      acted upon when this function returns.  TLB shootdowns are one such
  461  *      "less robust" function.
  462  */
  463         if (x == 0)
  464                 printf("apic_ipi might be stuck\n");
  465 #endif
  466 #undef MAX_SPIN2
  467 #undef MAX_SPIN1
  468 #else
  469         while (lapic.icr_lo & APIC_DELSTAT_MASK)
  470                  /* spin */ ;
  471 #endif  /* DETECT_DEADLOCK */
  472 
  473         /** XXX FIXME: return result */
  474         return 0;
  475 }
  476 
  477 static int
  478 apic_ipi_singledest(int cpu, int vector, int delivery_mode)
  479 {
  480         u_long  icr_lo;
  481         u_long  icr_hi;
  482         u_long  eflags;
  483 
  484 #if defined(DETECT_DEADLOCK)
  485 #define MAX_SPIN1       10000000
  486 #define MAX_SPIN2       1000
  487         int     x;
  488 
  489         /* "lazy delivery", ie we only barf if they stack up on us... */
  490         for (x = MAX_SPIN1; x; --x) {
  491                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  492                         break;
  493         }
  494         if (x == 0)
  495                 panic("apic_ipi was stuck");
  496 #endif  /* DETECT_DEADLOCK */
  497 
  498         eflags = read_eflags();
  499         __asm __volatile("cli" : : : "memory");
  500         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
  501         icr_hi |= (CPU_TO_ID(cpu) << 24);
  502         lapic.icr_hi = icr_hi;
  503 
  504         /* build IRC_LOW */
  505         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
  506             | APIC_DEST_DESTFLD | delivery_mode | vector;
  507 
  508         /* write APIC ICR */
  509         lapic.icr_lo = icr_lo;
  510         write_eflags(eflags);
  511 
  512         /* wait for pending status end */
  513 #if defined(DETECT_DEADLOCK)
  514         for (x = MAX_SPIN2; x; --x) {
  515                 if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
  516                         break;
  517         }
  518 #ifdef needsattention
  519 /*
  520  * XXX FIXME:
  521  *      The above loop waits for the message to actually be delivered.
  522  *      It breaks out after an arbitrary timout on the theory that it eventually
  523  *      will be delivered and we will catch a real failure on the next entry to
  524  *      this function, which would panic().
  525  *      We could skip this wait entirely, EXCEPT it probably protects us from
  526  *      other "less robust" routines that assume the message was delivered and
  527  *      acted upon when this function returns.  TLB shootdowns are one such
  528  *      "less robust" function.
  529  */
  530         if (x == 0)
  531                 printf("apic_ipi might be stuck\n");
  532 #endif
  533 #undef MAX_SPIN2
  534 #undef MAX_SPIN1
  535 #else
  536         while (lapic.icr_lo & APIC_DELSTAT_MASK)
  537                  /* spin */ ;
  538 #endif  /* DETECT_DEADLOCK */
  539 
  540         /** XXX FIXME: return result */
  541         return 0;
  542 }
  543 
  544 
  545 /*
  546  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
  547  *
  548  *  target contains a bitfield with a bit set for selected APICs.
  549  *  vector is any valid SYSTEM INT vector
  550  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
  551  */
  552 int
  553 selected_apic_ipi(u_int target, int vector, int delivery_mode)
  554 {
  555         int     x;
  556         int     status;
  557 
  558         if (target & ~0x7fff)
  559                 return -1;      /* only 15 targets allowed */
  560 
  561         for (status = 0, x = 0; x <= 14; ++x)
  562                 if (target & (1 << x)) {
  563 
  564                         /* send the IPI */
  565                         if (apic_ipi_singledest(x, vector, 
  566                                                 delivery_mode) == -1)
  567                                 status |= (1 << x);
  568                 }
  569         return status;
  570 }
  571 
  572 
  573 #if defined(READY)
  574 /*
  575  * Send an IPI INTerrupt containing 'vector' to CPU 'target'
  576  *   NOTE: target is a LOGICAL APIC ID
  577  */
  578 int
  579 selected_proc_ipi(int target, int vector)
  580 {
  581         u_long  icr_lo;
  582         u_long  icr_hi;
  583 
  584         /* write the destination field for the target AP */
  585         icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) |
  586             (cpu_num_to_apic_id[target] << 24);
  587         lapic.icr_hi = icr_hi;
  588 
  589         /* write command */
  590         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) |
  591             APIC_DEST_DESTFLD | APIC_DELMODE_FIXED | vector;
  592         lapic.icr_lo = icr_lo;
  593 
  594         /* wait for pending status end */
  595         while (lapic.icr_lo & APIC_DELSTAT_MASK)
  596                 /* spin */ ;
  597 
  598         return 0;       /** XXX FIXME: return result */
  599 }
  600 #endif /* READY */
  601 
  602 #endif  /* APIC_IO */
  603 
  604 
  605 /*
  606  * Timer code, in development...
  607  *  - suggested by rgrimes@gndrsh.aac.dev.com
  608  */
  609 
  610 /** XXX FIXME: temp hack till we can determin bus clock */
  611 #ifndef BUS_CLOCK
  612 #define BUS_CLOCK       66000000
  613 #define bus_clock()     66000000
  614 #endif
  615 
  616 #if defined(READY)
  617 int acquire_apic_timer __P((void));
  618 int release_apic_timer __P((void));
  619 
  620 /*
  621  * Acquire the APIC timer for exclusive use.
  622  */
  623 int
  624 acquire_apic_timer(void)
  625 {
  626 #if 1
  627         return 0;
  628 #else
  629         /** XXX FIXME: make this really do something */
  630         panic("APIC timer in use when attempting to aquire");
  631 #endif
  632 }
  633 
  634 
  635 /*
  636  * Return the APIC timer.
  637  */
  638 int
  639 release_apic_timer(void)
  640 {
  641 #if 1
  642         return 0;
  643 #else
  644         /** XXX FIXME: make this really do something */
  645         panic("APIC timer was already released");
  646 #endif
  647 }
  648 #endif  /* READY */
  649 
  650 
  651 /*
  652  * Load a 'downcount time' in uSeconds.
  653  */
  654 void
  655 set_apic_timer(int value)
  656 {
  657         u_long  lvtt;
  658         long    ticks_per_microsec;
  659 
  660         /*
  661          * Calculate divisor and count from value:
  662          * 
  663          *  timeBase == CPU bus clock divisor == [1,2,4,8,16,32,64,128]
  664          *  value == time in uS
  665          */
  666         lapic.dcr_timer = APIC_TDCR_1;
  667         ticks_per_microsec = bus_clock() / 1000000;
  668 
  669         /* configure timer as one-shot */
  670         lvtt = lapic.lvt_timer;
  671         lvtt &= ~(APIC_LVTT_VECTOR | APIC_LVTT_DS | APIC_LVTT_M | APIC_LVTT_TM);
  672         lvtt |= APIC_LVTT_M;                    /* no INT, one-shot */
  673         lapic.lvt_timer = lvtt;
  674 
  675         /* */
  676         lapic.icr_timer = value * ticks_per_microsec;
  677 }
  678 
  679 
  680 /*
  681  * Read remaining time in timer.
  682  */
  683 int
  684 read_apic_timer(void)
  685 {
  686 #if 0
  687         /** XXX FIXME: we need to return the actual remaining time,
  688          *         for now we just return the remaining count.
  689          */
  690 #else
  691         return lapic.ccr_timer;
  692 #endif
  693 }
  694 
  695 
  696 /*
  697  * Spin-style delay, set delay time in uS, spin till it drains.
  698  */
  699 void
  700 u_sleep(int count)
  701 {
  702         set_apic_timer(count);
  703         while (read_apic_timer())
  704                  /* spin */ ;
  705 }

Cache object: afcec94e3f678e65278a2678c56af4ee


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