diff options
author | phk <phk@FreeBSD.org> | 1998-10-24 19:47:42 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1998-10-24 19:47:42 +0000 |
commit | 14fa987f115eeb5e92e8e4fcb694c1e0694103d5 (patch) | |
tree | 04281d9a87059a61487a09fd0c53c7970ab0be18 | |
parent | a3db931d4af10f71dcae4535106bc9a656c79f94 (diff) | |
download | FreeBSD-src-14fa987f115eeb5e92e8e4fcb694c1e0694103d5.zip FreeBSD-src-14fa987f115eeb5e92e8e4fcb694c1e0694103d5.tar.gz |
Update and add timekeeping code.
-rw-r--r-- | sys/pci/xrpu.c | 206 |
1 files changed, 182 insertions, 24 deletions
diff --git a/sys/pci/xrpu.c b/sys/pci/xrpu.c index b46a395..c34a73d 100644 --- a/sys/pci/xrpu.c +++ b/sys/pci/xrpu.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: xrpu.c,v 1.1 1998/05/30 18:28:11 phk Exp $ + * $Id: xrpu.c,v 1.2 1998/08/18 00:32:48 bde Exp $ * * A very simple device driver for PCI cards based on Xilinx 6200 series * FPGA/RPU devices. Current Functionality is to allow you to open and @@ -17,12 +17,15 @@ * */ -#ifndef DEVFS +#include "xrpu.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> #include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/timepps.h> #include <sys/devfsext.h> +#include <sys/xrpuio.h> #include <pci/pcireg.h> #include <pci/pcivar.h> @@ -30,39 +33,183 @@ static char* xrpu_probe (pcici_t tag, pcidi_t type); static void xrpu_attach (pcici_t tag, int unit); static u_long xrpu_count; -static vm_offset_t virbase, physbase; +static void xrpu_poll_pps(struct timecounter *tc); + +/* + * Device driver initialization stuff + */ + +static d_open_t xrpu_open; +static d_close_t xrpu_close; +static d_ioctl_t xrpu_ioctl; +static d_mmap_t xrpu_mmap; + +#define CDEV_MAJOR 100 +static struct cdevsw xrpudevsw = { + xrpu_open, xrpu_close, noread, nowrite, + xrpu_ioctl, nullstop, noreset, nodevtotty, + seltrue, xrpu_mmap, nostrategy, "xrpu", + NULL, -1 +}; + +static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related"); + +#define dev2unit(devt) (minor(devt) & 0xff) +#define dev2pps(devt) ((minor(devt) >> 16)-1) + +static struct softc { + pcici_t tag; + enum { NORMAL, TIMECOUNTER } mode; + vm_offset_t virbase, physbase; + u_int *virbase62; + struct timecounter tc; + u_int *trigger, *latch, dummy; + struct { + pps_params_t params; + pps_info_t info; + int cap; + u_int *assert, last_assert; + u_int *clear, last_clear; + } pps[XRPU_MAX_PPS]; +} *softc[NXRPU]; + +static unsigned +xrpu_get_timecount(struct timecounter *tc) +{ + struct softc *sc = tc->tc_priv; + + sc->dummy += *sc->trigger; + return (*sc->latch & tc->tc_counter_mask); +} + +void +xrpu_poll_pps(struct timecounter *tc) +{ + struct softc *sc = tc->tc_priv; + int i; + unsigned count1, ppscount; + + for (i = 0; i < XRPU_MAX_PPS; i++) { + if (sc->pps[i].assert) { + ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask; + do { + count1 = ppscount; + ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask; + } while (ppscount != count1); + if (ppscount != sc->pps[i].last_assert) { + timecounter_timespec(ppscount, &sc->pps[i].info.assert_timestamp); + if (sc->pps[i].params.mode & PPS_OFFSETASSERT) { + timespecadd(&sc->pps[i].info.assert_timestamp, + &sc->pps[i].params.assert_offset); + if (sc->pps[i].info.assert_timestamp.tv_nsec < 0) { + sc->pps[i].info.assert_timestamp.tv_nsec += 1000000000; + sc->pps[i].info.assert_timestamp.tv_sec -= 1; + } + } + sc->pps[i].info.assert_sequence++; + sc->pps[i].last_assert = ppscount; + } + } + if (sc->pps[i].clear) { + ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask; + do { + count1 = ppscount; + ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask; + } while (ppscount != count1); + if (ppscount != sc->pps[i].last_clear) { + timecounter_timespec(ppscount, &sc->pps[i].info.clear_timestamp); + if (sc->pps[i].params.mode & PPS_OFFSETASSERT) { + timespecadd(&sc->pps[i].info.clear_timestamp, + &sc->pps[i].params.clear_offset); + if (sc->pps[i].info.clear_timestamp.tv_nsec < 0) { + sc->pps[i].info.clear_timestamp.tv_nsec += 1000000000; + sc->pps[i].info.clear_timestamp.tv_sec -= 1; + } + } + sc->pps[i].info.clear_sequence++; + sc->pps[i].last_clear = ppscount; + } + } + } +} static int -xrpuopen(dev_t dev, int flag, int mode, struct proc *p) +xrpu_open(dev_t dev, int flag, int mode, struct proc *p) { return (0); } static int -xrpuclose(dev_t dev, int flag, int mode, struct proc *p) +xrpu_close(dev_t dev, int flag, int mode, struct proc *p) { return (0); } static int -xrpummap(dev_t dev, int offset, int nprot) +xrpu_mmap(dev_t dev, int offset, int nprot) { + struct softc *sc = softc[dev2unit(dev)]; if (offset >= 0x1000000) return (-1); - return (i386_btop(physbase + offset)); + return (i386_btop(sc->physbase + offset)); } -/* - * Device driver initialization stuff - */ +static int +xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr) +{ + struct softc *sc = softc[dev2unit(dev)]; + int i, error; -#define CDEV_MAJOR 100 -static struct cdevsw xrpudevsw = { - xrpuopen, xrpuclose, noread, nowrite, - noioctl, nullstop, noreset, nodevtotty, - seltrue, xrpummap, nostrategy, "xrpu", - NULL, -1 -}; + if (sc->mode == TIMECOUNTER) { + i = dev2pps(dev); + if (i < 0 || i >= XRPU_MAX_PPS) + return ENODEV; + if (!sc->pps[i].cap) + return ENODEV; + error = std_pps_ioctl(cmd, arg, &sc->pps[i].params, + &sc->pps[i].info, sc->pps[i].cap); + return (error); + } + + if (cmd == XRPU_IOC_TIMECOUNTING) { + struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg; + + /* Name SHALL be zero terminated */ + xt->xt_name[sizeof xt->xt_name - 1] = '\0'; + i = strlen(xt->xt_name); + sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK); + strcpy(sc->tc.tc_name, xt->xt_name); + sc->tc.tc_frequency = xt->xt_frequency; + sc->tc.tc_get_timecount = xrpu_get_timecount; + sc->tc.tc_poll_pps = xrpu_poll_pps; + sc->tc.tc_priv = sc; + sc->tc.tc_counter_mask = xt->xt_mask; + sc->trigger = sc->virbase62 + xt->xt_addr_trigger; + sc->latch = sc->virbase62 + xt->xt_addr_latch; + + for (i = 0; i < XRPU_MAX_PPS; i++) { + if (xt->xt_pps[i].xt_addr_assert == 0 + && xt->xt_pps[i].xt_addr_clear == 0) + continue; + devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL, 0600, + "xpps%d", i); + /* DEVFS */ + if (xt->xt_pps[i].xt_addr_assert) { + sc->pps[i].assert = sc->virbase62 + xt->xt_pps[i].xt_addr_assert; + sc->pps[i].cap |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT; + } + if (xt->xt_pps[i].xt_addr_clear) { + sc->pps[i].clear = sc->virbase62 + xt->xt_pps[i].xt_addr_clear; + sc->pps[i].cap |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; + } + } + sc->mode = TIMECOUNTER; + init_timecounter(&sc->tc); + return (0); + } + error = ENOTTY; + return (error); +} /* * PCI initialization stuff @@ -96,16 +243,27 @@ xrpu_probe (pcici_t tag, pcidi_t typea) static void xrpu_attach (pcici_t tag, int unit) { - dev_t cdev = makedev(CDEV_MAJOR, 0); + struct softc *sc; + dev_t cdev = makedev(CDEV_MAJOR, unit); + + sc = (struct softc *)malloc(sizeof *sc, M_XRPU, M_WAITOK); + softc[unit] = sc; + bzero(sc, sizeof *sc); + + sc->tag = tag; + sc->mode = NORMAL; + + pci_map_mem(tag, PCI_MAP_REG_START, &sc->virbase, &sc->physbase); - pci_map_mem(tag, PCI_MAP_REG_START, &virbase, &physbase); + sc->virbase62 = (u_int *)(sc->virbase + 0x800000); - printf("Mapped physbase %#lx to virbase %#lx\n", - (u_long)physbase, (u_long)virbase); + if (bootverbose) + printf("Mapped physbase %#lx to virbase %#lx\n", + (u_long)sc->physbase, (u_long)sc->virbase); - cdevsw_add(&cdev, &xrpudevsw, NULL); + if (!unit) + cdevsw_add(&cdev, &xrpudevsw, NULL); devfs_add_devswf(&xrpudevsw, 0, DV_CHR, UID_ROOT, GID_WHEEL, 0600, - "xrpu0"); + "xrpu%d", unit); } -#endif /* DEVFS */ |