Thu Apr 23 20:33:57 2020 UTC ()
Implement a HPET based DELAY().


(ad)
diff -r1.13 -r1.14 src/sys/dev/ic/hpet.c
diff -r1.4 -r1.5 src/sys/dev/ic/hpetvar.h

cvs diff -r1.13 -r1.14 src/sys/dev/ic/hpet.c (expand / switch to unified diff)

--- src/sys/dev/ic/hpet.c 2011/10/31 12:47:15 1.13
+++ src/sys/dev/ic/hpet.c 2020/04/23 20:33:57 1.14
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $ */ 1/* $NetBSD: hpet.c,v 1.14 2020/04/23 20:33:57 ad Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Nicolas Joly 4 * Copyright (c) 2006 Nicolas Joly
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -23,136 +23,178 @@ @@ -23,136 +23,178 @@
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE. 28 * POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31/* 31/*
32 * High Precision Event Timer. 32 * High Precision Event Timer.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $"); 36__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.14 2020/04/23 20:33:57 ad Exp $");
37 37
38#include <sys/systm.h> 38#include <sys/systm.h>
39#include <sys/device.h> 39#include <sys/device.h>
40#include <sys/module.h> 40#include <sys/module.h>
41 41
42#include <sys/time.h> 42#include <sys/time.h>
43#include <sys/timetc.h> 43#include <sys/timetc.h>
44 44
45#include <sys/bus.h> 45#include <sys/bus.h>
 46#include <sys/lock.h>
46 47
47#include <dev/ic/hpetreg.h> 48#include <dev/ic/hpetreg.h>
48#include <dev/ic/hpetvar.h> 49#include <dev/ic/hpetvar.h>
49 50
50static u_int hpet_get_timecount(struct timecounter *); 51static u_int hpet_get_timecount(struct timecounter *);
51static bool hpet_resume(device_t, const pmf_qual_t *); 52static bool hpet_resume(device_t, const pmf_qual_t *);
52 53
 54static struct hpet_softc *hpet0 __read_mostly;
 55
53int 56int
54hpet_detach(device_t dv, int flags) 57hpet_detach(device_t dv, int flags)
55{ 58{
 59#if 0 /* XXX DELAY() is based off this, detaching is not a good idea. */
56 struct hpet_softc *sc = device_private(dv); 60 struct hpet_softc *sc = device_private(dv);
57 int rc; 61 int rc;
58 62
59 if ((rc = tc_detach(&sc->sc_tc)) != 0) 63 if ((rc = tc_detach(&sc->sc_tc)) != 0)
60 return rc; 64 return rc;
61 65
62 pmf_device_deregister(dv); 66 pmf_device_deregister(dv);
63 67
64 bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, sc->sc_config); 68 bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, sc->sc_config);
65 69
66 return 0; 70 return 0;
 71#else
 72 return EBUSY;
 73#endif
67} 74}
68 75
69void 76void
70hpet_attach_subr(device_t dv) 77hpet_attach_subr(device_t dv)
71{ 78{
72 struct hpet_softc *sc = device_private(dv); 79 struct hpet_softc *sc = device_private(dv);
73 struct timecounter *tc; 80 struct timecounter *tc;
74 uint64_t tmp; 81 uint64_t tmp;
75 uint32_t val; 82 uint32_t val;
76 int i; 83 int i;
77 84
78 tc = &sc->sc_tc; 85 tc = &sc->sc_tc;
79 86
80 tc->tc_name = device_xname(dv); 87 tc->tc_name = device_xname(dv);
81 tc->tc_get_timecount = hpet_get_timecount; 88 tc->tc_get_timecount = hpet_get_timecount;
82 tc->tc_quality = 2000; 89 tc->tc_quality = 2000;
83 90
84 tc->tc_counter_mask = 0xffffffff; 91 tc->tc_counter_mask = 0xffffffff;
85 92
86 /* Get frequency */ 93 /* Get frequency */
87 val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD); 94 sc->sc_period = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD);
88 if (val == 0 || val > HPET_PERIOD_MAX) { 95 if (sc->sc_period == 0 || sc->sc_period > HPET_PERIOD_MAX) {
89 aprint_error_dev(dv, "invalid timer period\n"); 96 aprint_error_dev(dv, "invalid timer period\n");
90 return; 97 return;
91 } 98 }
92 99
93 /* 100 /*
94 * The following loop is a workaround for AMD SB700 based systems. 101 * The following loop is a workaround for AMD SB700 based systems.
95 * http://kerneltrap.org/mailarchive/git-commits-head/2008/8/17/2964724 102 * http://kerneltrap.org/mailarchive/git-commits-head/2008/8/17/2964724
96 * http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a6825f1c1fa83b1e92b6715ee5771a4d6524d3b9 103 * http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a6825f1c1fa83b1e92b6715ee5771a4d6524d3b9
97 */ 104 */
98 for (i = 0; bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG) 105 for (i = 0; bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG)
99 == 0xffffffff; i++) { 106 == 0xffffffff; i++) {
100 if (i >= 1000) { 107 if (i >= 1000) {
101 aprint_error_dev(dv, 108 aprint_error_dev(dv,
102 "HPET_CONFIG value = 0xffffffff\n"); 109 "HPET_CONFIG value = 0xffffffff\n");
103 return; 110 return;
104 } 111 }
105 } 112 }
106 113
107 tmp = (1000000000000000ULL * 2) / val; 114 tmp = (1000000000000000ULL * 2) / sc->sc_period;
108 tc->tc_frequency = (tmp / 2) + (tmp & 1); 115 tc->tc_frequency = (tmp / 2) + (tmp & 1);
109 116
110 /* Enable timer */ 117 /* Enable timer */
111 val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG); 118 val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG);
112 sc->sc_config = val; 119 sc->sc_config = val;
113 if ((val & HPET_CONFIG_ENABLE) == 0) { 120 if ((val & HPET_CONFIG_ENABLE) == 0) {
114 val |= HPET_CONFIG_ENABLE; 121 val |= HPET_CONFIG_ENABLE;
115 bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, val); 122 bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, val);
116 } 123 }
117 124
118 tc->tc_priv = sc; 125 tc->tc_priv = sc;
119 tc_init(tc); 126 tc_init(tc);
120 127
121 if (!pmf_device_register(dv, NULL, hpet_resume)) 128 if (!pmf_device_register(dv, NULL, hpet_resume))
122 aprint_error_dev(dv, "couldn't establish power handler\n"); 129 aprint_error_dev(dv, "couldn't establish power handler\n");
 130
 131 if (device_unit(dv) == 0)
 132 hpet0 = sc;
123} 133}
124 134
125static u_int 135static u_int
126hpet_get_timecount(struct timecounter *tc) 136hpet_get_timecount(struct timecounter *tc)
127{ 137{
128 struct hpet_softc *sc = tc->tc_priv; 138 struct hpet_softc *sc = tc->tc_priv;
129 139
130 return bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_MCOUNT_LO); 140 return bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_MCOUNT_LO);
131} 141}
132 142
133static bool 143static bool
134hpet_resume(device_t dv, const pmf_qual_t *qual) 144hpet_resume(device_t dv, const pmf_qual_t *qual)
135{ 145{
136 struct hpet_softc *sc = device_private(dv); 146 struct hpet_softc *sc = device_private(dv);
137 uint32_t val; 147 uint32_t val;
138 148
139 val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG); 149 val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG);
140 val |= HPET_CONFIG_ENABLE; 150 val |= HPET_CONFIG_ENABLE;
141 bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, val); 151 bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, val);
142 152
143 return true; 153 return true;
144} 154}
145 155
 156bool
 157hpet_delay_p(void)
 158{
 159
 160 return hpet0 != NULL;
 161}
 162
 163void
 164hpet_delay(unsigned int us)
 165{
 166 struct hpet_softc *sc;
 167 uint32_t ntick, otick;
 168 int64_t delta;
 169
 170 /*
 171 * Read timer before slow division. Assume that each read of the
 172 * HPET costs ~500ns. Aim for the middle and subtract 750ns for
 173 * overhead.
 174 */
 175 sc = hpet0;
 176 otick = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_MCOUNT_LO);
 177 delta = (((int64_t)us * 1000000000) - 750000000) / sc->sc_period;
 178
 179 while (delta > 0) {
 180 SPINLOCK_BACKOFF_HOOK;
 181 ntick = bus_space_read_4(sc->sc_memt, sc->sc_memh,
 182 HPET_MCOUNT_LO);
 183 delta -= (uint32_t)(ntick - otick);
 184 otick = ntick;
 185 }
 186}
 187
146MODULE(MODULE_CLASS_DRIVER, hpet, NULL); 188MODULE(MODULE_CLASS_DRIVER, hpet, NULL);
147 189
148#ifdef _MODULE 190#ifdef _MODULE
149#include "ioconf.c" 191#include "ioconf.c"
150#endif 192#endif
151 193
152static int 194static int
153hpet_modcmd(modcmd_t cmd, void *aux) 195hpet_modcmd(modcmd_t cmd, void *aux)
154{ 196{
155 int rv = 0; 197 int rv = 0;
156 198
157 switch (cmd) { 199 switch (cmd) {
158 200

cvs diff -r1.4 -r1.5 src/sys/dev/ic/hpetvar.h (expand / switch to unified diff)

--- src/sys/dev/ic/hpetvar.h 2011/06/14 16:33:51 1.4
+++ src/sys/dev/ic/hpetvar.h 2020/04/23 20:33:57 1.5
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: hpetvar.h,v 1.4 2011/06/14 16:33:51 jruoho Exp $ */ 1/* $NetBSD: hpetvar.h,v 1.5 2020/04/23 20:33:57 ad Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Nicolas Joly 4 * Copyright (c) 2006 Nicolas Joly
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -21,27 +21,32 @@ @@ -21,27 +21,32 @@
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE. 28 * POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31#ifndef _DEV_IC_HPETVAR_H_ 31#ifndef _DEV_IC_HPETVAR_H_
32#define _DEV_IC_HPETVAR_H_ 32#define _DEV_IC_HPETVAR_H_
33 33
 34#include <sys/timetc.h>
 35
34struct hpet_softc { 36struct hpet_softc {
35 bus_size_t sc_mems; 37 bus_size_t sc_mems;
36 bus_space_tag_t sc_memt; 38 bus_space_tag_t sc_memt;
37 bus_space_handle_t sc_memh; 39 bus_space_handle_t sc_memh;
38 40
39 bool sc_mapped; 41 bool sc_mapped;
40 uint32_t sc_config; 42 uint32_t sc_config;
 43 int32_t sc_period;
41 struct timecounter sc_tc; 44 struct timecounter sc_tc;
42}; 45};
43 46
44void hpet_attach_subr(device_t); 47void hpet_attach_subr(device_t);
45int hpet_detach(device_t, int flags); 48int hpet_detach(device_t, int flags);
 49void hpet_delay(unsigned int);
 50bool hpet_delay_p(void);
46 51
47#endif /* _DEV_IC_HPETVAR_H_ */ 52#endif /* _DEV_IC_HPETVAR_H_ */