FreeBSD/Linux Kernel Cross Reference
sys/pci/xrpu.c
1 /*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: releng/5.0/sys/pci/xrpu.c 95528 2002-04-26 21:22:02Z phk $
10 *
11 * A very simple device driver for PCI cards based on Xilinx 6200 series
12 * FPGA/RPU devices. Current Functionality is to allow you to open and
13 * mmap the entire thing into your program.
14 *
15 * Hardware currently supported:
16 * www.vcc.com HotWorks 1 6216 based card.
17 *
18 */
19
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/conf.h>
23 #include <sys/kernel.h>
24 #include <sys/malloc.h>
25 #include <sys/timetc.h>
26 #include <sys/timepps.h>
27 #include <sys/xrpuio.h>
28 #include <sys/bus.h>
29 #include <machine/bus.h>
30 #include <sys/rman.h>
31 #include <machine/resource.h>
32 #include <pci/pcireg.h>
33 #include <pci/pcivar.h>
34 #include "pci_if.h"
35
36 /*
37 * Device driver initialization stuff
38 */
39
40 static d_open_t xrpu_open;
41 static d_close_t xrpu_close;
42 static d_ioctl_t xrpu_ioctl;
43 static d_mmap_t xrpu_mmap;
44
45 #define CDEV_MAJOR 100
46 static struct cdevsw xrpu_cdevsw = {
47 /* open */ xrpu_open,
48 /* close */ xrpu_close,
49 /* read */ noread,
50 /* write */ nowrite,
51 /* ioctl */ xrpu_ioctl,
52 /* poll */ nopoll,
53 /* mmap */ xrpu_mmap,
54 /* strategy */ nostrategy,
55 /* name */ "xrpu",
56 /* maj */ CDEV_MAJOR,
57 /* dump */ nodump,
58 /* psize */ nopsize,
59 /* flags */ 0,
60 };
61
62 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
63
64 static devclass_t xrpu_devclass;
65
66 #define dev2unit(devt) (minor(devt) & 0xff)
67 #define dev2pps(devt) ((minor(devt) >> 16)-1)
68
69 struct softc {
70 enum { NORMAL, TIMECOUNTER } mode;
71 vm_offset_t virbase, physbase;
72 u_int *virbase62;
73 struct timecounter tc;
74 u_int *trigger, *latch, dummy;
75 struct pps_state pps[XRPU_MAX_PPS];
76 u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS];
77 };
78
79 static unsigned
80 xrpu_get_timecount(struct timecounter *tc)
81 {
82 struct softc *sc = tc->tc_priv;
83
84 sc->dummy += *sc->trigger;
85 return (*sc->latch & tc->tc_counter_mask);
86 }
87
88 static void
89 xrpu_poll_pps(struct timecounter *tc)
90 {
91 struct softc *sc = tc->tc_priv;
92 int i, j;
93 unsigned count1, ppscount;
94
95 for (i = 0; i < XRPU_MAX_PPS; i++) {
96 if (sc->assert[i]) {
97 pps_capture(&sc->pps[i]);
98 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
99 j = 0;
100 do {
101 count1 = ppscount;
102 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
103 } while (ppscount != count1 && ++j < 5);
104 sc->pps[i].capcount = ppscount;
105 pps_event(&sc->pps[i], PPS_CAPTUREASSERT);
106 }
107 if (sc->clear[i]) {
108 pps_capture(&sc->pps[i]);
109 j = 0;
110 ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
111 do {
112 count1 = ppscount;
113 ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
114 } while (ppscount != count1 && ++j < 5);
115 sc->pps[i].capcount = ppscount;
116 pps_event(&sc->pps[i], PPS_CAPTURECLEAR);
117 }
118 }
119 }
120
121 static int
122 xrpu_open(dev_t dev, int flag, int mode, struct thread *td)
123 {
124 struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
125
126 if (!sc)
127 return (ENXIO);
128 dev->si_drv1 = sc;
129 return (0);
130 }
131
132 static int
133 xrpu_close(dev_t dev, int flag, int mode, struct thread *td)
134 {
135 return (0);
136 }
137
138 static int
139 xrpu_mmap(dev_t dev, vm_offset_t offset, int nprot)
140 {
141 struct softc *sc = dev->si_drv1;
142 if (offset >= 0x1000000)
143 return (-1);
144 return (i386_btop(sc->physbase + offset));
145 }
146
147 static int
148 xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr)
149 {
150 struct softc *sc = dev->si_drv1;
151 int i, error;
152
153 if (sc->mode == TIMECOUNTER) {
154 i = dev2pps(dev);
155 if (i < 0 || i >= XRPU_MAX_PPS)
156 return ENODEV;
157 error = pps_ioctl(cmd, arg, &sc->pps[i]);
158 return (error);
159 }
160
161 if (cmd == XRPU_IOC_TIMECOUNTING) {
162 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
163
164 /* Name SHALL be zero terminated */
165 xt->xt_name[sizeof xt->xt_name - 1] = '\0';
166 i = strlen(xt->xt_name);
167 sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK);
168 strcpy(sc->tc.tc_name, xt->xt_name);
169 sc->tc.tc_frequency = xt->xt_frequency;
170 sc->tc.tc_get_timecount = xrpu_get_timecount;
171 sc->tc.tc_poll_pps = xrpu_poll_pps;
172 sc->tc.tc_priv = sc;
173 sc->tc.tc_counter_mask = xt->xt_mask;
174 sc->trigger = sc->virbase62 + xt->xt_addr_trigger;
175 sc->latch = sc->virbase62 + xt->xt_addr_latch;
176
177 for (i = 0; i < XRPU_MAX_PPS; i++) {
178 if (xt->xt_pps[i].xt_addr_assert == 0
179 && xt->xt_pps[i].xt_addr_clear == 0)
180 continue;
181 make_dev(&xrpu_cdevsw, (i+1)<<16,
182 UID_ROOT, GID_WHEEL, 0600, "xpps%d", i);
183 sc->pps[i].ppscap = 0;
184 if (xt->xt_pps[i].xt_addr_assert) {
185 sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
186 sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
187 }
188 if (xt->xt_pps[i].xt_addr_clear) {
189 sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
190 sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
191 }
192 pps_init(&sc->pps[i]);
193 }
194 sc->mode = TIMECOUNTER;
195 tc_init(&sc->tc);
196 return (0);
197 }
198 error = ENOTTY;
199 return (error);
200 }
201
202 /*
203 * PCI initialization stuff
204 */
205
206 static int
207 xrpu_probe(device_t self)
208 {
209 char *desc;
210
211 desc = NULL;
212 switch (pci_get_devid(self)) {
213 case 0x6216133e:
214 desc = "VCC Hotworks-I xc6216";
215 break;
216 }
217 if (desc == NULL)
218 return ENXIO;
219
220 device_set_desc(self, desc);
221 return 0;
222 }
223
224 static int
225 xrpu_attach(device_t self)
226 {
227 struct softc *sc;
228 struct resource *res;
229 int rid, unit;
230
231 unit = device_get_unit(self);
232 sc = device_get_softc(self);
233 sc->mode = NORMAL;
234 rid = PCIR_MAPS;
235 res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
236 0, ~0, 1, RF_ACTIVE);
237 if (res == NULL) {
238 device_printf(self, "Could not map memory\n");
239 return ENXIO;
240 }
241 sc->virbase = (vm_offset_t)rman_get_virtual(res);
242 sc->physbase = rman_get_start(res);
243 sc->virbase62 = (u_int *)(sc->virbase + 0x800000);
244
245 if (bootverbose)
246 printf("Mapped physbase %#lx to virbase %#lx\n",
247 (u_long)sc->physbase, (u_long)sc->virbase);
248
249 make_dev(&xrpu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
250 return 0;
251 }
252
253 static device_method_t xrpu_methods[] = {
254 /* Device interface */
255 DEVMETHOD(device_probe, xrpu_probe),
256 DEVMETHOD(device_attach, xrpu_attach),
257 DEVMETHOD(device_suspend, bus_generic_suspend),
258 DEVMETHOD(device_resume, bus_generic_resume),
259 DEVMETHOD(device_shutdown, bus_generic_shutdown),
260
261 {0, 0}
262 };
263
264 static driver_t xrpu_driver = {
265 "xrpu",
266 xrpu_methods,
267 sizeof(struct softc)
268 };
269
270
271 DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);
Cache object: 544dbacbd04cbf41922f7ff8e4a37d24
|