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/dev/acpica/acpi_hpet.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) 2005 Poul-Henning Kamp
    3  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include "opt_acpi.h"
   32 
   33 #if defined(__amd64__)
   34 #define DEV_APIC
   35 #else
   36 #include "opt_apic.h"
   37 #endif
   38 #include <sys/param.h>
   39 #include <sys/conf.h>
   40 #include <sys/bus.h>
   41 #include <sys/kernel.h>
   42 #include <sys/module.h>
   43 #include <sys/proc.h>
   44 #include <sys/rman.h>
   45 #include <sys/mman.h>
   46 #include <sys/time.h>
   47 #include <sys/smp.h>
   48 #include <sys/sysctl.h>
   49 #include <sys/timeet.h>
   50 #include <sys/timetc.h>
   51 #include <sys/vdso.h>
   52 
   53 #include <contrib/dev/acpica/include/acpi.h>
   54 #include <contrib/dev/acpica/include/accommon.h>
   55 
   56 #include <dev/acpica/acpivar.h>
   57 #include <dev/acpica/acpi_hpet.h>
   58 
   59 #ifdef DEV_APIC
   60 #include "pcib_if.h"
   61 #endif
   62 
   63 #define HPET_VENDID_AMD         0x4353
   64 #define HPET_VENDID_AMD2        0x1022
   65 #define HPET_VENDID_HYGON       0x1d94
   66 #define HPET_VENDID_INTEL       0x8086
   67 #define HPET_VENDID_NVIDIA      0x10de
   68 #define HPET_VENDID_SW          0x1166
   69 
   70 ACPI_SERIAL_DECL(hpet, "ACPI HPET support");
   71 
   72 /* ACPI CA debugging */
   73 #define _COMPONENT      ACPI_TIMER
   74 ACPI_MODULE_NAME("HPET")
   75 
   76 struct hpet_softc {
   77         device_t                dev;
   78         int                     mem_rid;
   79         int                     intr_rid;
   80         int                     irq;
   81         int                     useirq;
   82         int                     legacy_route;
   83         int                     per_cpu;
   84         uint32_t                allowed_irqs;
   85         struct resource         *mem_res;
   86         struct resource         *intr_res;
   87         void                    *intr_handle;
   88         ACPI_HANDLE             handle;
   89         uint32_t                acpi_uid;
   90         uint64_t                freq;
   91         uint32_t                caps;
   92         struct timecounter      tc;
   93         struct hpet_timer {
   94                 struct eventtimer       et;
   95                 struct hpet_softc       *sc;
   96                 int                     num;
   97                 int                     mode;
   98 #define TIMER_STOPPED   0
   99 #define TIMER_PERIODIC  1
  100 #define TIMER_ONESHOT   2
  101                 int                     intr_rid;
  102                 int                     irq;
  103                 int                     pcpu_cpu;
  104                 int                     pcpu_misrouted;
  105                 int                     pcpu_master;
  106                 int                     pcpu_slaves[MAXCPU];
  107                 struct resource         *intr_res;
  108                 void                    *intr_handle;
  109                 uint32_t                caps;
  110                 uint32_t                vectors;
  111                 uint32_t                div;
  112                 uint32_t                next;
  113                 char                    name[8];
  114         }                       t[32];
  115         int                     num_timers;
  116         struct cdev             *pdev;
  117         int                     mmap_allow;
  118         int                     mmap_allow_write;
  119 };
  120 
  121 static d_open_t hpet_open;
  122 static d_mmap_t hpet_mmap;
  123 
  124 static struct cdevsw hpet_cdevsw = {
  125         .d_version =    D_VERSION,
  126         .d_name =       "hpet",
  127         .d_open =       hpet_open,
  128         .d_mmap =       hpet_mmap,
  129 };
  130 
  131 static u_int hpet_get_timecount(struct timecounter *tc);
  132 static void hpet_test(struct hpet_softc *sc);
  133 
  134 static char *hpet_ids[] = { "PNP0103", NULL };
  135 
  136 /* Knob to disable acpi_hpet device */
  137 bool acpi_hpet_disabled = false;
  138 
  139 static u_int
  140 hpet_get_timecount(struct timecounter *tc)
  141 {
  142         struct hpet_softc *sc;
  143 
  144         sc = tc->tc_priv;
  145         return (bus_read_4(sc->mem_res, HPET_MAIN_COUNTER));
  146 }
  147 
  148 uint32_t
  149 hpet_vdso_timehands(struct vdso_timehands *vdso_th, struct timecounter *tc)
  150 {
  151         struct hpet_softc *sc;
  152 
  153         sc = tc->tc_priv;
  154         vdso_th->th_algo = VDSO_TH_ALGO_X86_HPET;
  155         vdso_th->th_x86_shift = 0;
  156         vdso_th->th_x86_hpet_idx = device_get_unit(sc->dev);
  157         vdso_th->th_x86_pvc_last_systime = 0;
  158         vdso_th->th_x86_pvc_stable_mask = 0;
  159         bzero(vdso_th->th_res, sizeof(vdso_th->th_res));
  160         return (sc->mmap_allow != 0);
  161 }
  162 
  163 #ifdef COMPAT_FREEBSD32
  164 uint32_t
  165 hpet_vdso_timehands32(struct vdso_timehands32 *vdso_th32,
  166     struct timecounter *tc)
  167 {
  168         struct hpet_softc *sc;
  169 
  170         sc = tc->tc_priv;
  171         vdso_th32->th_algo = VDSO_TH_ALGO_X86_HPET;
  172         vdso_th32->th_x86_shift = 0;
  173         vdso_th32->th_x86_hpet_idx = device_get_unit(sc->dev);
  174         vdso_th32->th_x86_pvc_last_systime = 0;
  175         vdso_th32->th_x86_pvc_stable_mask = 0;
  176         bzero(vdso_th32->th_res, sizeof(vdso_th32->th_res));
  177         return (sc->mmap_allow != 0);
  178 }
  179 #endif
  180 
  181 static void
  182 hpet_enable(struct hpet_softc *sc)
  183 {
  184         uint32_t val;
  185 
  186         val = bus_read_4(sc->mem_res, HPET_CONFIG);
  187         if (sc->legacy_route)
  188                 val |= HPET_CNF_LEG_RT;
  189         else
  190                 val &= ~HPET_CNF_LEG_RT;
  191         val |= HPET_CNF_ENABLE;
  192         bus_write_4(sc->mem_res, HPET_CONFIG, val);
  193 }
  194 
  195 static void
  196 hpet_disable(struct hpet_softc *sc)
  197 {
  198         uint32_t val;
  199 
  200         val = bus_read_4(sc->mem_res, HPET_CONFIG);
  201         val &= ~HPET_CNF_ENABLE;
  202         bus_write_4(sc->mem_res, HPET_CONFIG, val);
  203 }
  204 
  205 static int
  206 hpet_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  207 {
  208         struct hpet_timer *mt = (struct hpet_timer *)et->et_priv;
  209         struct hpet_timer *t;
  210         struct hpet_softc *sc = mt->sc;
  211         uint32_t fdiv, now;
  212 
  213         t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]];
  214         if (period != 0) {
  215                 t->mode = TIMER_PERIODIC;
  216                 t->div = (sc->freq * period) >> 32;
  217         } else {
  218                 t->mode = TIMER_ONESHOT;
  219                 t->div = 0;
  220         }
  221         if (first != 0)
  222                 fdiv = (sc->freq * first) >> 32;
  223         else
  224                 fdiv = t->div;
  225         if (t->irq < 0)
  226                 bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
  227         t->caps |= HPET_TCNF_INT_ENB;
  228         now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  229 restart:
  230         t->next = now + fdiv;
  231         if (t->mode == TIMER_PERIODIC && (t->caps & HPET_TCAP_PER_INT)) {
  232                 t->caps |= HPET_TCNF_TYPE;
  233                 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
  234                     t->caps | HPET_TCNF_VAL_SET);
  235                 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  236                     t->next);
  237                 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  238                     t->div);
  239         } else {
  240                 t->caps &= ~HPET_TCNF_TYPE;
  241                 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
  242                     t->caps);
  243                 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  244                     t->next);
  245         }
  246         now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  247         if ((int32_t)(now - t->next + HPET_MIN_CYCLES) >= 0) {
  248                 fdiv *= 2;
  249                 goto restart;
  250         }
  251         return (0);
  252 }
  253 
  254 static int
  255 hpet_stop(struct eventtimer *et)
  256 {
  257         struct hpet_timer *mt = (struct hpet_timer *)et->et_priv;
  258         struct hpet_timer *t;
  259         struct hpet_softc *sc = mt->sc;
  260 
  261         t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]];
  262         t->mode = TIMER_STOPPED;
  263         t->caps &= ~(HPET_TCNF_INT_ENB | HPET_TCNF_TYPE);
  264         bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
  265         return (0);
  266 }
  267 
  268 static int
  269 hpet_intr_single(void *arg)
  270 {
  271         struct hpet_timer *t = (struct hpet_timer *)arg;
  272         struct hpet_timer *mt;
  273         struct hpet_softc *sc = t->sc;
  274         uint32_t now;
  275 
  276         if (t->mode == TIMER_STOPPED)
  277                 return (FILTER_STRAY);
  278         /* Check that per-CPU timer interrupt reached right CPU. */
  279         if (t->pcpu_cpu >= 0 && t->pcpu_cpu != curcpu) {
  280                 if ((++t->pcpu_misrouted) % 32 == 0) {
  281                         printf("HPET interrupt routed to the wrong CPU"
  282                             " (timer %d CPU %d -> %d)!\n",
  283                             t->num, t->pcpu_cpu, curcpu);
  284                 }
  285 
  286                 /*
  287                  * Reload timer, hoping that next time may be more lucky
  288                  * (system will manage proper interrupt binding).
  289                  */
  290                 if ((t->mode == TIMER_PERIODIC &&
  291                     (t->caps & HPET_TCAP_PER_INT) == 0) ||
  292                     t->mode == TIMER_ONESHOT) {
  293                         t->next = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER) +
  294                             sc->freq / 8;
  295                         bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  296                             t->next);
  297                 }
  298                 return (FILTER_HANDLED);
  299         }
  300         if (t->mode == TIMER_PERIODIC &&
  301             (t->caps & HPET_TCAP_PER_INT) == 0) {
  302                 t->next += t->div;
  303                 now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  304                 if ((int32_t)((now + t->div / 2) - t->next) > 0)
  305                         t->next = now + t->div / 2;
  306                 bus_write_4(sc->mem_res,
  307                     HPET_TIMER_COMPARATOR(t->num), t->next);
  308         } else if (t->mode == TIMER_ONESHOT)
  309                 t->mode = TIMER_STOPPED;
  310         mt = (t->pcpu_master < 0) ? t : &sc->t[t->pcpu_master];
  311         if (mt->et.et_active)
  312                 mt->et.et_event_cb(&mt->et, mt->et.et_arg);
  313         return (FILTER_HANDLED);
  314 }
  315 
  316 static int
  317 hpet_intr(void *arg)
  318 {
  319         struct hpet_softc *sc = (struct hpet_softc *)arg;
  320         int i;
  321         uint32_t val;
  322 
  323         val = bus_read_4(sc->mem_res, HPET_ISR);
  324         if (val) {
  325                 bus_write_4(sc->mem_res, HPET_ISR, val);
  326                 val &= sc->useirq;
  327                 for (i = 0; i < sc->num_timers; i++) {
  328                         if ((val & (1 << i)) == 0)
  329                                 continue;
  330                         hpet_intr_single(&sc->t[i]);
  331                 }
  332                 return (FILTER_HANDLED);
  333         }
  334         return (FILTER_STRAY);
  335 }
  336 
  337 uint32_t
  338 hpet_get_uid(device_t dev)
  339 {
  340         struct hpet_softc *sc;
  341 
  342         sc = device_get_softc(dev);
  343         return (sc->acpi_uid);
  344 }
  345 
  346 static ACPI_STATUS
  347 hpet_find(ACPI_HANDLE handle, UINT32 level, void *context,
  348     void **status)
  349 {
  350         char            **ids;
  351         uint32_t        id = (uint32_t)(uintptr_t)context;
  352         uint32_t        uid = 0;
  353 
  354         for (ids = hpet_ids; *ids != NULL; ids++) {
  355                 if (acpi_MatchHid(handle, *ids))
  356                         break;
  357         }
  358         if (*ids == NULL)
  359                 return (AE_OK);
  360         if (ACPI_FAILURE(acpi_GetInteger(handle, "_UID", &uid)) ||
  361             id == uid)
  362                 *status = acpi_get_device(handle);
  363         return (AE_OK);
  364 }
  365 
  366 /*
  367  * Find an existing IRQ resource that matches the requested IRQ range
  368  * and return its RID.  If one is not found, use a new RID.
  369  */
  370 static int
  371 hpet_find_irq_rid(device_t dev, u_long start, u_long end)
  372 {
  373         rman_res_t irq;
  374         int error, rid;
  375 
  376         for (rid = 0;; rid++) {
  377                 error = bus_get_resource(dev, SYS_RES_IRQ, rid, &irq, NULL);
  378                 if (error != 0 || (start <= irq && irq <= end))
  379                         return (rid);
  380         }
  381 }
  382 
  383 static int
  384 hpet_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
  385 {
  386         struct hpet_softc *sc;
  387 
  388         sc = cdev->si_drv1;
  389         if (!sc->mmap_allow)
  390                 return (EPERM);
  391         else
  392                 return (0);
  393 }
  394 
  395 static int
  396 hpet_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
  397     int nprot, vm_memattr_t *memattr)
  398 {
  399         struct hpet_softc *sc;
  400 
  401         sc = cdev->si_drv1;
  402         if (offset >= rman_get_size(sc->mem_res))
  403                 return (EINVAL);
  404         if (!sc->mmap_allow_write && (nprot & PROT_WRITE))
  405                 return (EPERM);
  406         *paddr = rman_get_start(sc->mem_res) + offset;
  407         *memattr = VM_MEMATTR_UNCACHEABLE;
  408 
  409         return (0);
  410 }
  411 
  412 /* Discover the HPET via the ACPI table of the same name. */
  413 static void
  414 hpet_identify(driver_t *driver, device_t parent)
  415 {
  416         ACPI_TABLE_HPET *hpet;
  417         ACPI_STATUS     status;
  418         device_t        child;
  419         int             i;
  420 
  421         /* Only one HPET device can be added. */
  422         if (devclass_get_device(devclass_find("hpet"), 0))
  423                 return;
  424         for (i = 1; ; i++) {
  425                 /* Search for HPET table. */
  426                 status = AcpiGetTable(ACPI_SIG_HPET, i, (ACPI_TABLE_HEADER **)&hpet);
  427                 if (ACPI_FAILURE(status))
  428                         return;
  429                 /* Search for HPET device with same ID. */
  430                 child = NULL;
  431                 AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
  432                     100, hpet_find, NULL, (void *)(uintptr_t)hpet->Sequence,
  433                     (void *)&child);
  434                 /* If found - let it be probed in normal way. */
  435                 if (child) {
  436                         if (bus_get_resource(child, SYS_RES_MEMORY, 0,
  437                             NULL, NULL) != 0)
  438                                 bus_set_resource(child, SYS_RES_MEMORY, 0,
  439                                     hpet->Address.Address, HPET_MEM_WIDTH);
  440                         continue;
  441                 }
  442                 /* If not - create it from table info. */
  443                 child = BUS_ADD_CHILD(parent, 2, "hpet", 0);
  444                 if (child == NULL) {
  445                         printf("%s: can't add child\n", __func__);
  446                         continue;
  447                 }
  448                 bus_set_resource(child, SYS_RES_MEMORY, 0, hpet->Address.Address,
  449                     HPET_MEM_WIDTH);
  450         }
  451 }
  452 
  453 static int
  454 hpet_probe(device_t dev)
  455 {
  456         int rv;
  457 
  458         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  459         if (acpi_disabled("hpet") || acpi_hpet_disabled)
  460                 return (ENXIO);
  461         if (acpi_get_handle(dev) != NULL)
  462                 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, hpet_ids, NULL);
  463         else
  464                 rv = 0;
  465         if (rv <= 0)
  466                 device_set_desc(dev, "High Precision Event Timer");
  467         return (rv);
  468 }
  469 
  470 static int
  471 hpet_attach(device_t dev)
  472 {
  473         struct hpet_softc *sc;
  474         struct hpet_timer *t;
  475         struct make_dev_args mda;
  476         int i, j, num_msi, num_timers, num_percpu_et, num_percpu_t, cur_cpu;
  477         int pcpu_master, error;
  478         rman_res_t hpet_region_size;
  479         static int maxhpetet = 0;
  480         uint32_t val, val2, cvectors, dvectors;
  481         uint16_t vendor, rev;
  482 
  483         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  484 
  485         sc = device_get_softc(dev);
  486         sc->dev = dev;
  487         sc->handle = acpi_get_handle(dev);
  488 
  489         sc->mem_rid = 0;
  490         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
  491             RF_ACTIVE);
  492         if (sc->mem_res == NULL)
  493                 return (ENOMEM);
  494 
  495         hpet_region_size = rman_get_size(sc->mem_res);
  496         /* Validate that the region is big enough for the control registers. */
  497         if (hpet_region_size < HPET_MEM_MIN_WIDTH) {
  498                 device_printf(dev, "memory region width %jd too small\n",
  499                     hpet_region_size);
  500                 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
  501                 return (ENXIO);
  502         }
  503 
  504         /* Be sure timer is enabled. */
  505         hpet_enable(sc);
  506 
  507         /* Read basic statistics about the timer. */
  508         val = bus_read_4(sc->mem_res, HPET_PERIOD);
  509         if (val == 0) {
  510                 device_printf(dev, "invalid period\n");
  511                 hpet_disable(sc);
  512                 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
  513                 return (ENXIO);
  514         }
  515 
  516         sc->freq = (1000000000000000LL + val / 2) / val;
  517         sc->caps = bus_read_4(sc->mem_res, HPET_CAPABILITIES);
  518         vendor = (sc->caps & HPET_CAP_VENDOR_ID) >> 16;
  519         rev = sc->caps & HPET_CAP_REV_ID;
  520         num_timers = 1 + ((sc->caps & HPET_CAP_NUM_TIM) >> 8);
  521         /*
  522          * ATI/AMD violates IA-PC HPET (High Precision Event Timers)
  523          * Specification and provides an off by one number
  524          * of timers/comparators.
  525          * Additionally, they use unregistered value in VENDOR_ID field.
  526          */
  527         if (vendor == HPET_VENDID_AMD && rev < 0x10 && num_timers > 0)
  528                 num_timers--;
  529         /*
  530          * Now validate that the region is big enough to address all counters.
  531          */
  532         if (hpet_region_size < HPET_TIMER_CAP_CNF(num_timers)) {
  533                 device_printf(dev,
  534                     "memory region width %jd too small for %d timers\n",
  535                     hpet_region_size, num_timers);
  536                 hpet_disable(sc);
  537                 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
  538                 return (ENXIO);
  539         }
  540 
  541         sc->num_timers = num_timers;
  542         if (bootverbose) {
  543                 device_printf(dev,
  544                     "vendor 0x%x, rev 0x%x, %jdHz%s, %d timers,%s\n",
  545                     vendor, rev, sc->freq,
  546                     (sc->caps & HPET_CAP_COUNT_SIZE) ? " 64bit" : "",
  547                     num_timers,
  548                     (sc->caps & HPET_CAP_LEG_RT) ? " legacy route" : "");
  549         }
  550         for (i = 0; i < num_timers; i++) {
  551                 t = &sc->t[i];
  552                 t->sc = sc;
  553                 t->num = i;
  554                 t->mode = TIMER_STOPPED;
  555                 t->intr_rid = -1;
  556                 t->irq = -1;
  557                 t->pcpu_cpu = -1;
  558                 t->pcpu_misrouted = 0;
  559                 t->pcpu_master = -1;
  560                 t->caps = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i));
  561                 t->vectors = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i) + 4);
  562                 if (bootverbose) {
  563                         device_printf(dev,
  564                             " t%d: irqs 0x%08x (%d)%s%s%s\n", i,
  565                             t->vectors, (t->caps & HPET_TCNF_INT_ROUTE) >> 9,
  566                             (t->caps & HPET_TCAP_FSB_INT_DEL) ? ", MSI" : "",
  567                             (t->caps & HPET_TCAP_SIZE) ? ", 64bit" : "",
  568                             (t->caps & HPET_TCAP_PER_INT) ? ", periodic" : "");
  569                 }
  570         }
  571         if (testenv("debug.acpi.hpet_test"))
  572                 hpet_test(sc);
  573         /*
  574          * Don't attach if the timer never increments.  Since the spec
  575          * requires it to be at least 10 MHz, it has to change in 1 us.
  576          */
  577         val = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  578         DELAY(1);
  579         val2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  580         if (val == val2) {
  581                 device_printf(dev, "HPET never increments, disabling\n");
  582                 hpet_disable(sc);
  583                 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
  584                 return (ENXIO);
  585         }
  586         /* Announce first HPET as timecounter. */
  587         if (device_get_unit(dev) == 0) {
  588                 sc->tc.tc_get_timecount = hpet_get_timecount,
  589                 sc->tc.tc_counter_mask = ~0u,
  590                 sc->tc.tc_name = "HPET",
  591                 sc->tc.tc_quality = 950,
  592                 sc->tc.tc_frequency = sc->freq;
  593                 sc->tc.tc_priv = sc;
  594                 sc->tc.tc_fill_vdso_timehands = hpet_vdso_timehands;
  595 #ifdef COMPAT_FREEBSD32
  596                 sc->tc.tc_fill_vdso_timehands32 = hpet_vdso_timehands32;
  597 #endif
  598                 tc_init(&sc->tc);
  599         }
  600         /* If not disabled - setup and announce event timers. */
  601         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
  602              "clock", &i) == 0 && i == 0)
  603                 return (0);
  604 
  605         /* Check whether we can and want legacy routing. */
  606         sc->legacy_route = 0;
  607         resource_int_value(device_get_name(dev), device_get_unit(dev),
  608              "legacy_route", &sc->legacy_route);
  609         if ((sc->caps & HPET_CAP_LEG_RT) == 0)
  610                 sc->legacy_route = 0;
  611         if (sc->legacy_route) {
  612                 sc->t[0].vectors = 0;
  613                 sc->t[1].vectors = 0;
  614         }
  615 
  616         /* Check what IRQs we want use. */
  617         /* By default allow any PCI IRQs. */
  618         sc->allowed_irqs = 0xffff0000;
  619         /*
  620          * HPETs in AMD chipsets before SB800 have problems with IRQs >= 16
  621          * Lower are also not always working for different reasons.
  622          * SB800 fixed it, but seems do not implements level triggering
  623          * properly, that makes it very unreliable - it freezes after any
  624          * interrupt loss. Avoid legacy IRQs for AMD.
  625          */
  626         if (vendor == HPET_VENDID_AMD || vendor == HPET_VENDID_AMD2 ||
  627             vendor == HPET_VENDID_HYGON)
  628                 sc->allowed_irqs = 0x00000000;
  629         /*
  630          * NVidia MCP5x chipsets have number of unexplained interrupt
  631          * problems. For some reason, using HPET interrupts breaks HDA sound.
  632          */
  633         if (vendor == HPET_VENDID_NVIDIA && rev <= 0x01)
  634                 sc->allowed_irqs = 0x00000000;
  635         /*
  636          * ServerWorks HT1000 reported to have problems with IRQs >= 16.
  637          * Lower IRQs are working, but allowed mask is not set correctly.
  638          * Legacy_route mode works fine.
  639          */
  640         if (vendor == HPET_VENDID_SW && rev <= 0x01)
  641                 sc->allowed_irqs = 0x00000000;
  642         /*
  643          * Neither QEMU nor VirtualBox report supported IRQs correctly.
  644          * The only way to use HPET there is to specify IRQs manually
  645          * and/or use legacy_route. Legacy_route mode works on both.
  646          */
  647         if (vm_guest)
  648                 sc->allowed_irqs = 0x00000000;
  649         /* Let user override. */
  650         resource_int_value(device_get_name(dev), device_get_unit(dev),
  651              "allowed_irqs", &sc->allowed_irqs);
  652 
  653         /* Get how much per-CPU timers we should try to provide. */
  654         sc->per_cpu = 1;
  655         resource_int_value(device_get_name(dev), device_get_unit(dev),
  656              "per_cpu", &sc->per_cpu);
  657 
  658         num_msi = 0;
  659         sc->useirq = 0;
  660         /* Find IRQ vectors for all timers. */
  661         cvectors = sc->allowed_irqs & 0xffff0000;
  662         dvectors = sc->allowed_irqs & 0x0000ffff;
  663         if (sc->legacy_route)
  664                 dvectors &= 0x0000fefe;
  665         for (i = 0; i < num_timers; i++) {
  666                 t = &sc->t[i];
  667                 if (sc->legacy_route && i < 2)
  668                         t->irq = (i == 0) ? 0 : 8;
  669 #ifdef DEV_APIC
  670                 else if (t->caps & HPET_TCAP_FSB_INT_DEL) {
  671                         if ((j = PCIB_ALLOC_MSIX(
  672                             device_get_parent(device_get_parent(dev)), dev,
  673                             &t->irq))) {
  674                                 device_printf(dev,
  675                                     "Can't allocate interrupt for t%d: %d\n",
  676                                     i, j);
  677                         }
  678                 }
  679 #endif
  680                 else if (dvectors & t->vectors) {
  681                         t->irq = ffs(dvectors & t->vectors) - 1;
  682                         dvectors &= ~(1 << t->irq);
  683                 }
  684                 if (t->irq >= 0) {
  685                         t->intr_rid = hpet_find_irq_rid(dev, t->irq, t->irq);
  686                         t->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
  687                             &t->intr_rid, t->irq, t->irq, 1, RF_ACTIVE);
  688                         if (t->intr_res == NULL) {
  689                                 t->irq = -1;
  690                                 device_printf(dev,
  691                                     "Can't map interrupt for t%d.\n", i);
  692                         } else if (bus_setup_intr(dev, t->intr_res,
  693                             INTR_TYPE_CLK, hpet_intr_single, NULL, t,
  694                             &t->intr_handle) != 0) {
  695                                 t->irq = -1;
  696                                 device_printf(dev,
  697                                     "Can't setup interrupt for t%d.\n", i);
  698                         } else {
  699                                 bus_describe_intr(dev, t->intr_res,
  700                                     t->intr_handle, "t%d", i);
  701                                 num_msi++;
  702                         }
  703                 }
  704                 if (t->irq < 0 && (cvectors & t->vectors) != 0) {
  705                         cvectors &= t->vectors;
  706                         sc->useirq |= (1 << i);
  707                 }
  708         }
  709         if (sc->legacy_route && sc->t[0].irq < 0 && sc->t[1].irq < 0)
  710                 sc->legacy_route = 0;
  711         if (sc->legacy_route)
  712                 hpet_enable(sc);
  713         /* Group timers for per-CPU operation. */
  714         num_percpu_et = min(num_msi / mp_ncpus, sc->per_cpu);
  715         num_percpu_t = num_percpu_et * mp_ncpus;
  716         pcpu_master = 0;
  717         cur_cpu = CPU_FIRST();
  718         for (i = 0; i < num_timers; i++) {
  719                 t = &sc->t[i];
  720                 if (t->irq >= 0 && num_percpu_t > 0) {
  721                         if (cur_cpu == CPU_FIRST())
  722                                 pcpu_master = i;
  723                         t->pcpu_cpu = cur_cpu;
  724                         t->pcpu_master = pcpu_master;
  725                         sc->t[pcpu_master].
  726                             pcpu_slaves[cur_cpu] = i;
  727                         bus_bind_intr(dev, t->intr_res, cur_cpu);
  728                         cur_cpu = CPU_NEXT(cur_cpu);
  729                         num_percpu_t--;
  730                 } else if (t->irq >= 0)
  731                         bus_bind_intr(dev, t->intr_res, CPU_FIRST());
  732         }
  733         bus_write_4(sc->mem_res, HPET_ISR, 0xffffffff);
  734         sc->irq = -1;
  735         /* If at least one timer needs legacy IRQ - set it up. */
  736         if (sc->useirq) {
  737                 j = i = fls(cvectors) - 1;
  738                 while (j > 0 && (cvectors & (1 << (j - 1))) != 0)
  739                         j--;
  740                 sc->intr_rid = hpet_find_irq_rid(dev, j, i);
  741                 sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
  742                     &sc->intr_rid, j, i, 1, RF_SHAREABLE | RF_ACTIVE);
  743                 if (sc->intr_res == NULL)
  744                         device_printf(dev, "Can't map interrupt.\n");
  745                 else if (bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
  746                     hpet_intr, NULL, sc, &sc->intr_handle) != 0) {
  747                         device_printf(dev, "Can't setup interrupt.\n");
  748                 } else {
  749                         sc->irq = rman_get_start(sc->intr_res);
  750                         /* Bind IRQ to BSP to avoid live migration. */
  751                         bus_bind_intr(dev, sc->intr_res, CPU_FIRST());
  752                 }
  753         }
  754         /* Program and announce event timers. */
  755         for (i = 0; i < num_timers; i++) {
  756                 t = &sc->t[i];
  757                 t->caps &= ~(HPET_TCNF_FSB_EN | HPET_TCNF_INT_ROUTE);
  758                 t->caps &= ~(HPET_TCNF_VAL_SET | HPET_TCNF_INT_ENB);
  759                 t->caps &= ~(HPET_TCNF_INT_TYPE);
  760                 t->caps |= HPET_TCNF_32MODE;
  761                 if (t->irq >= 0 && sc->legacy_route && i < 2) {
  762                         /* Legacy route doesn't need more configuration. */
  763                 } else
  764 #ifdef DEV_APIC
  765                 if ((t->caps & HPET_TCAP_FSB_INT_DEL) && t->irq >= 0) {
  766                         uint64_t addr;
  767                         uint32_t data;
  768 
  769                         if (PCIB_MAP_MSI(
  770                             device_get_parent(device_get_parent(dev)), dev,
  771                             t->irq, &addr, &data) == 0) {
  772                                 bus_write_4(sc->mem_res,
  773                                     HPET_TIMER_FSB_ADDR(i), addr);
  774                                 bus_write_4(sc->mem_res,
  775                                     HPET_TIMER_FSB_VAL(i), data);
  776                                 t->caps |= HPET_TCNF_FSB_EN;
  777                         } else
  778                                 t->irq = -2;
  779                 } else
  780 #endif
  781                 if (t->irq >= 0)
  782                         t->caps |= (t->irq << 9);
  783                 else if (sc->irq >= 0 && (t->vectors & (1 << sc->irq)))
  784                         t->caps |= (sc->irq << 9) | HPET_TCNF_INT_TYPE;
  785                 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(i), t->caps);
  786                 /* Skip event timers without set up IRQ. */
  787                 if (t->irq < 0 &&
  788                     (sc->irq < 0 || (t->vectors & (1 << sc->irq)) == 0))
  789                         continue;
  790                 /* Announce the reset. */
  791                 if (maxhpetet == 0)
  792                         t->et.et_name = "HPET";
  793                 else {
  794                         sprintf(t->name, "HPET%d", maxhpetet);
  795                         t->et.et_name = t->name;
  796                 }
  797                 t->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
  798                 t->et.et_quality = 450;
  799                 if (t->pcpu_master >= 0) {
  800                         t->et.et_flags |= ET_FLAGS_PERCPU;
  801                         t->et.et_quality += 100;
  802                 } else if (mp_ncpus >= 8)
  803                         t->et.et_quality -= 100;
  804                 if ((t->caps & HPET_TCAP_PER_INT) == 0)
  805                         t->et.et_quality -= 10;
  806                 t->et.et_frequency = sc->freq;
  807                 t->et.et_min_period =
  808                     ((uint64_t)(HPET_MIN_CYCLES * 2) << 32) / sc->freq;
  809                 t->et.et_max_period = (0xfffffffeLLU << 32) / sc->freq;
  810                 t->et.et_start = hpet_start;
  811                 t->et.et_stop = hpet_stop;
  812                 t->et.et_priv = &sc->t[i];
  813                 if (t->pcpu_master < 0 || t->pcpu_master == i) {
  814                         et_register(&t->et);
  815                         maxhpetet++;
  816                 }
  817         }
  818         acpi_GetInteger(sc->handle, "_UID", &sc->acpi_uid);
  819 
  820         make_dev_args_init(&mda);
  821         mda.mda_devsw = &hpet_cdevsw;
  822         mda.mda_uid = UID_ROOT;
  823         mda.mda_gid = GID_WHEEL;
  824         mda.mda_mode = 0644;
  825         mda.mda_si_drv1 = sc;
  826         error = make_dev_s(&mda, &sc->pdev, "hpet%d", device_get_unit(dev));
  827         if (error == 0) {
  828                 sc->mmap_allow = 1;
  829                 TUNABLE_INT_FETCH("hw.acpi.hpet.mmap_allow",
  830                     &sc->mmap_allow);
  831                 sc->mmap_allow_write = 0;
  832                 TUNABLE_INT_FETCH("hw.acpi.hpet.mmap_allow_write",
  833                     &sc->mmap_allow_write);
  834                 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  835                     SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  836                     OID_AUTO, "mmap_allow",
  837                     CTLFLAG_RW, &sc->mmap_allow, 0,
  838                     "Allow userland to memory map HPET");
  839                 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  840                     SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  841                     OID_AUTO, "mmap_allow_write",
  842                     CTLFLAG_RW, &sc->mmap_allow_write, 0,
  843                     "Allow userland write to the HPET register space");
  844         } else {
  845                 device_printf(dev, "could not create /dev/hpet%d, error %d\n",
  846                     device_get_unit(dev), error);
  847         }
  848 
  849         return (0);
  850 }
  851 
  852 static int
  853 hpet_detach(device_t dev)
  854 {
  855         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  856 
  857         /* XXX Without a tc_remove() function, we can't detach. */
  858         return (EBUSY);
  859 }
  860 
  861 static int
  862 hpet_suspend(device_t dev)
  863 {
  864 //      struct hpet_softc *sc;
  865 
  866         /*
  867          * Disable the timer during suspend.  The timer will not lose
  868          * its state in S1 or S2, but we are required to disable
  869          * it.
  870          */
  871 //      sc = device_get_softc(dev);
  872 //      hpet_disable(sc);
  873 
  874         return (0);
  875 }
  876 
  877 static int
  878 hpet_resume(device_t dev)
  879 {
  880         struct hpet_softc *sc;
  881         struct hpet_timer *t;
  882         int i;
  883 
  884         /* Re-enable the timer after a resume to keep the clock advancing. */
  885         sc = device_get_softc(dev);
  886         hpet_enable(sc);
  887         /* Restart event timers that were running on suspend. */
  888         for (i = 0; i < sc->num_timers; i++) {
  889                 t = &sc->t[i];
  890 #ifdef DEV_APIC
  891                 if (t->irq >= 0 && (sc->legacy_route == 0 || i >= 2)) {
  892                         uint64_t addr;
  893                         uint32_t data;
  894 
  895                         if (PCIB_MAP_MSI(
  896                             device_get_parent(device_get_parent(dev)), dev,
  897                             t->irq, &addr, &data) == 0) {
  898                                 bus_write_4(sc->mem_res,
  899                                     HPET_TIMER_FSB_ADDR(i), addr);
  900                                 bus_write_4(sc->mem_res,
  901                                     HPET_TIMER_FSB_VAL(i), data);
  902                         }
  903                 }
  904 #endif
  905                 if (t->mode == TIMER_STOPPED)
  906                         continue;
  907                 t->next = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  908                 if (t->mode == TIMER_PERIODIC &&
  909                     (t->caps & HPET_TCAP_PER_INT) != 0) {
  910                         t->caps |= HPET_TCNF_TYPE;
  911                         t->next += t->div;
  912                         bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
  913                             t->caps | HPET_TCNF_VAL_SET);
  914                         bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  915                             t->next);
  916                         bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num));
  917                         bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  918                             t->div);
  919                 } else {
  920                         t->next += sc->freq / 1024;
  921                         bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
  922                             t->next);
  923                 }
  924                 bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
  925                 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
  926         }
  927         return (0);
  928 }
  929 
  930 /* Print some basic latency/rate information to assist in debugging. */
  931 static void
  932 hpet_test(struct hpet_softc *sc)
  933 {
  934         int i;
  935         uint32_t u1, u2;
  936         struct bintime b0, b1, b2;
  937         struct timespec ts;
  938 
  939         binuptime(&b0);
  940         binuptime(&b0);
  941         binuptime(&b1);
  942         u1 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  943         for (i = 1; i < 1000; i++)
  944                 u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  945         binuptime(&b2);
  946         u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
  947 
  948         bintime_sub(&b2, &b1);
  949         bintime_sub(&b1, &b0);
  950         bintime_sub(&b2, &b1);
  951         bintime2timespec(&b2, &ts);
  952 
  953         device_printf(sc->dev, "%ld.%09ld: %u ... %u = %u\n",
  954             (long)ts.tv_sec, ts.tv_nsec, u1, u2, u2 - u1);
  955 
  956         device_printf(sc->dev, "time per call: %ld ns\n", ts.tv_nsec / 1000);
  957 }
  958 
  959 #ifdef DEV_APIC
  960 static int
  961 hpet_remap_intr(device_t dev, device_t child, u_int irq)
  962 {
  963         struct hpet_softc *sc = device_get_softc(dev);
  964         struct hpet_timer *t;
  965         uint64_t addr;
  966         uint32_t data;
  967         int error, i;
  968 
  969         for (i = 0; i < sc->num_timers; i++) {
  970                 t = &sc->t[i];
  971                 if (t->irq != irq)
  972                         continue;
  973                 error = PCIB_MAP_MSI(
  974                     device_get_parent(device_get_parent(dev)), dev,
  975                     irq, &addr, &data);
  976                 if (error)
  977                         return (error);
  978                 hpet_disable(sc); /* Stop timer to avoid interrupt loss. */
  979                 bus_write_4(sc->mem_res, HPET_TIMER_FSB_ADDR(i), addr);
  980                 bus_write_4(sc->mem_res, HPET_TIMER_FSB_VAL(i), data);
  981                 hpet_enable(sc);
  982                 return (0);
  983         }
  984         return (ENOENT);
  985 }
  986 #endif
  987 
  988 static device_method_t hpet_methods[] = {
  989         /* Device interface */
  990         DEVMETHOD(device_identify, hpet_identify),
  991         DEVMETHOD(device_probe, hpet_probe),
  992         DEVMETHOD(device_attach, hpet_attach),
  993         DEVMETHOD(device_detach, hpet_detach),
  994         DEVMETHOD(device_suspend, hpet_suspend),
  995         DEVMETHOD(device_resume, hpet_resume),
  996 
  997 #ifdef DEV_APIC
  998         DEVMETHOD(bus_remap_intr, hpet_remap_intr),
  999 #endif
 1000 
 1001         DEVMETHOD_END
 1002 };
 1003 
 1004 static driver_t hpet_driver = {
 1005         "hpet",
 1006         hpet_methods,
 1007         sizeof(struct hpet_softc),
 1008 };
 1009 
 1010 DRIVER_MODULE(hpet, acpi, hpet_driver, 0, 0);
 1011 MODULE_DEPEND(hpet, acpi, 1, 1, 1);

Cache object: 89de6a8120d5ff6f0b87676870521e0f


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