svn commit: r273598 - in head: include sys/dev/acpica

Andriy Gapon avg at FreeBSD.org
Fri Oct 24 19:06:06 UTC 2014


On 24/10/2014 21:39, Rui Paulo wrote:
> Author: rpaulo
> Date: Fri Oct 24 18:39:15 2014
> New Revision: 273598
> URL: https://svnweb.freebsd.org/changeset/base/273598
> 
> Log:
>   HPET: create /dev/hpetN as a way to access HPET from userland.
>   
>   In some cases, TSC is broken and special applications might benefit
>   from memory mapping HPET and reading the registers to count time.
>   Most often the main HPET counter is 32-bit only[1], so this only gives
>   the application a 300 second window based on the default HPET
>   interval.
>   Other applications, such as Intel's DPDK, expect /dev/hpet to be
>   present and use it to count time as well.

Does this device attempt to play nice with eventtimer infrastructure that may
use the same timer?

>   Although we have an almost userland version of gettimeofday() which
>   uses rdtsc in userland, it's not always possible to use it, depending
>   on how broken the multi-socket hardware is.
>   
>   Install the acpi_hpet.h so that applications can use the HPET register
>   definitions.
>   
>   [1] I haven't found a system where HPET's main counter uses more than
>   32 bit.  There seems to be a discrepancy in the Intel documentation
>   (claiming it's a 64-bit counter) and the actual implementation (a
>   32-bit counter in a 64-bit memory area).
>   
>   MFC after:	1 week
>   Relnotes:	yes
> 
> Modified:
>   head/include/Makefile
>   head/sys/dev/acpica/acpi_hpet.c
> 
> Modified: head/include/Makefile
> ==============================================================================
> --- head/include/Makefile	Fri Oct 24 17:40:32 2014	(r273597)
> +++ head/include/Makefile	Fri Oct 24 18:39:15 2014	(r273598)
> @@ -159,6 +159,8 @@ copies:
>  	cd ${.CURDIR}/../sys/dev/acpica; \
>  	${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 acpiio.h \
>  	    ${DESTDIR}${INCLUDEDIR}/dev/acpica
> +	${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 acpi_hpet.h \
> +	    ${DESTDIR}${INCLUDEDIR}/dev/acpica
>  	cd ${.CURDIR}/../sys/dev/agp; \
>  	${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 agpreg.h \
>  	    ${DESTDIR}${INCLUDEDIR}/dev/agp
> @@ -243,7 +245,7 @@ symlinks:
>  	done
>  .endfor
>  	cd ${.CURDIR}/../sys/dev/acpica; \
> -	for h in acpiio.h; do \
> +	for h in acpiio.h acpi_hpet.h; do \
>  		ln -fs ../../../../sys/dev/acpica/$$h \
>  		    ${DESTDIR}${INCLUDEDIR}/dev/acpica; \
>  	done
> 
> Modified: head/sys/dev/acpica/acpi_hpet.c
> ==============================================================================
> --- head/sys/dev/acpica/acpi_hpet.c	Fri Oct 24 17:40:32 2014	(r273597)
> +++ head/sys/dev/acpica/acpi_hpet.c	Fri Oct 24 18:39:15 2014	(r273598)
> @@ -35,11 +35,13 @@ __FBSDID("$FreeBSD$");
>  #include "opt_apic.h"
>  #endif
>  #include <sys/param.h>
> +#include <sys/conf.h>
>  #include <sys/bus.h>
>  #include <sys/kernel.h>
>  #include <sys/module.h>
>  #include <sys/proc.h>
>  #include <sys/rman.h>
> +#include <sys/mman.h>
>  #include <sys/time.h>
>  #include <sys/smp.h>
>  #include <sys/sysctl.h>
> @@ -106,6 +108,23 @@ struct hpet_softc {
>  		char			name[8];
>  	} 			t[32];
>  	int			num_timers;
> +	struct cdev		*pdev;
> +	int			mmap_allow;
> +	int			mmap_allow_write;
> +	int			devinuse;
> +};
> +
> +static d_open_t hpet_open;
> +static d_close_t hpet_close;
> +static d_mmap_t hpet_mmap;
> +
> +static struct cdevsw hpet_cdevsw = {
> +	.d_version =	D_VERSION,
> +	.d_flags =	D_TRACKCLOSE,
> +	.d_name =	"hpet",
> +	.d_open =	hpet_open,
> +	.d_close =	hpet_close,
> +	.d_mmap =	hpet_mmap,
>  };
>  
>  static u_int hpet_get_timecount(struct timecounter *tc);
> @@ -317,6 +336,47 @@ hpet_find_irq_rid(device_t dev, u_long s
>  	}
>  }
>  
> +static int
> +hpet_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
> +{
> +	struct hpet_softc *sc;
> +
> +	sc = cdev->si_drv1;
> +	if (!sc->mmap_allow)
> +		return (EPERM);
> +	if (atomic_cmpset_32(&sc->devinuse, 0, 1) == 0)
> +		return (EBUSY);
> +	else
> +		return (0);
> +}
> +
> +static int
> +hpet_close(struct cdev *cdev, int fflag, int devtype, struct thread *td)
> +{
> +	struct hpet_softc *sc;
> +
> +	sc = cdev->si_drv1;
> +	sc->devinuse = 0;
> +
> +	return (0);
> +}
> +
> +static int
> +hpet_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
> +    int nprot, vm_memattr_t *memattr)
> +{
> +	struct hpet_softc *sc;
> +
> +	sc = cdev->si_drv1;
> +	if (offset > rman_get_size(sc->mem_res))
> +		return (EINVAL);
> +	if (!sc->mmap_allow_write && (nprot & PROT_WRITE))
> +		return (EPERM);
> +	*paddr = rman_get_start(sc->mem_res) + offset;
> +
> +	return (0);
> +}
> +
>  /* Discover the HPET via the ACPI table of the same name. */
>  static void 
>  hpet_identify(driver_t *driver, device_t parent)
> @@ -701,6 +761,26 @@ hpet_attach(device_t dev)
>  			maxhpetet++;
>  		}
>  	}
> +
> +	sc->pdev = make_dev(&hpet_cdevsw, 0, UID_ROOT, GID_WHEEL,
> +	    0600, "hpet%d", device_get_unit(dev));
> +	if (sc->pdev) {
> +		sc->pdev->si_drv1 = sc;
> +		sc->mmap_allow = 1;
> +		TUNABLE_INT_FETCH("hw.acpi.hpet.mmap_allow",
> +		    &sc->mmap_allow);
> +		sc->mmap_allow_write = 1;
> +		TUNABLE_INT_FETCH("hw.acpi.hpet.mmap_allow_write",
> +		    &sc->mmap_allow_write);
> +		SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
> +		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
> +		    OID_AUTO, "mmap_allow",
> +		    CTLFLAG_RW, &sc->mmap_allow, 0,
> +		    "Allow userland to memory map HPET");
> +	} else
> +		device_printf(dev, "could not create /dev/hpet%d\n",
> +		    device_get_unit(dev));
> +
>  	return (0);
>  }
>  
> 


-- 
Andriy Gapon


More information about the svn-src-all mailing list