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 * A very simple device driver for PCI cards based on Xilinx 6200 series
10 * FPGA/RPU devices. Current Functionality is to allow you to open and
11 * mmap the entire thing into your program.
12 *
13 * Hardware currently supported:
14 * www.vcc.com HotWorks 1 6216 based card.
15 */
16
17 #include <sys/cdefs.h>
18 __FBSDID("$FreeBSD: releng/5.2/sys/pci/xrpu.c 121942 2003-11-03 10:19:33Z phk $");
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 <dev/pci/pcireg.h>
33 #include <dev/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 static struct cdevsw xrpu_cdevsw = {
46 .d_open = xrpu_open,
47 .d_close = xrpu_close,
48 .d_ioctl = xrpu_ioctl,
49 .d_mmap = xrpu_mmap,
50 .d_name = "xrpu",
51 };
52
53 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
54
55 static devclass_t xrpu_devclass;
56
57 #define dev2unit(devt) (minor(devt) & 0xff)
58 #define dev2pps(devt) ((minor(devt) >> 16)-1)
59
60 struct softc {
61 enum { NORMAL, TIMECOUNTER } mode;
62 vm_offset_t virbase, physbase;
63 u_int *virbase62;
64 struct timecounter tc;
65 u_int *trigger, *latch, dummy;
66 struct pps_state pps[XRPU_MAX_PPS];
67 u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS];
68 };
69
70 static unsigned
71 xrpu_get_timecount(struct timecounter *tc)
72 {
73 struct softc *sc = tc->tc_priv;
74
75 sc->dummy += *sc->trigger;
76 return (*sc->latch & tc->tc_counter_mask);
77 }
78
79 static void
80 xrpu_poll_pps(struct timecounter *tc)
81 {
82 struct softc *sc = tc->tc_priv;
83 int i, j;
84 unsigned count1, ppscount;
85
86 for (i = 0; i < XRPU_MAX_PPS; i++) {
87 if (sc->assert[i]) {
88 pps_capture(&sc->pps[i]);
89 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
90 j = 0;
91 do {
92 count1 = ppscount;
93 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
94 } while (ppscount != count1 && ++j < 5);
95 sc->pps[i].capcount = ppscount;
96 pps_event(&sc->pps[i], PPS_CAPTUREASSERT);
97 }
98 if (sc->clear[i]) {
99 pps_capture(&sc->pps[i]);
100 j = 0;
101 ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
102 do {
103 count1 = ppscount;
104 ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
105 } while (ppscount != count1 && ++j < 5);
106 sc->pps[i].capcount = ppscount;
107 pps_event(&sc->pps[i], PPS_CAPTURECLEAR);
108 }
109 }
110 }
111
112 static int
113 xrpu_open(dev_t dev, int flag, int mode, struct thread *td)
114 {
115 struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
116
117 if (!sc)
118 return (ENXIO);
119 dev->si_drv1 = sc;
120 return (0);
121 }
122
123 static int
124 xrpu_close(dev_t dev, int flag, int mode, struct thread *td)
125 {
126 return (0);
127 }
128
129 static int
130 xrpu_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
131 {
132 struct softc *sc = dev->si_drv1;
133 if (offset >= 0x1000000)
134 return (-1);
135 *paddr = sc->physbase + offset;
136 return (0);
137 }
138
139 static int
140 xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr)
141 {
142 struct softc *sc = dev->si_drv1;
143 int i, error;
144
145 if (sc->mode == TIMECOUNTER) {
146 i = dev2pps(dev);
147 if (i < 0 || i >= XRPU_MAX_PPS)
148 return ENODEV;
149 error = pps_ioctl(cmd, arg, &sc->pps[i]);
150 return (error);
151 }
152
153 if (cmd == XRPU_IOC_TIMECOUNTING) {
154 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
155
156 /* Name SHALL be zero terminated */
157 xt->xt_name[sizeof xt->xt_name - 1] = '\0';
158 i = strlen(xt->xt_name);
159 sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK);
160 strcpy(sc->tc.tc_name, xt->xt_name);
161 sc->tc.tc_frequency = xt->xt_frequency;
162 sc->tc.tc_get_timecount = xrpu_get_timecount;
163 sc->tc.tc_poll_pps = xrpu_poll_pps;
164 sc->tc.tc_priv = sc;
165 sc->tc.tc_counter_mask = xt->xt_mask;
166 sc->trigger = sc->virbase62 + xt->xt_addr_trigger;
167 sc->latch = sc->virbase62 + xt->xt_addr_latch;
168
169 for (i = 0; i < XRPU_MAX_PPS; i++) {
170 if (xt->xt_pps[i].xt_addr_assert == 0
171 && xt->xt_pps[i].xt_addr_clear == 0)
172 continue;
173 make_dev(&xrpu_cdevsw, (i+1)<<16,
174 UID_ROOT, GID_WHEEL, 0600, "xpps%d", i);
175 sc->pps[i].ppscap = 0;
176 if (xt->xt_pps[i].xt_addr_assert) {
177 sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
178 sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
179 }
180 if (xt->xt_pps[i].xt_addr_clear) {
181 sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
182 sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
183 }
184 pps_init(&sc->pps[i]);
185 }
186 sc->mode = TIMECOUNTER;
187 tc_init(&sc->tc);
188 return (0);
189 }
190 error = ENOTTY;
191 return (error);
192 }
193
194 /*
195 * PCI initialization stuff
196 */
197
198 static int
199 xrpu_probe(device_t self)
200 {
201 char *desc;
202
203 desc = NULL;
204 switch (pci_get_devid(self)) {
205 case 0x6216133e:
206 desc = "VCC Hotworks-I xc6216";
207 break;
208 }
209 if (desc == NULL)
210 return ENXIO;
211
212 device_set_desc(self, desc);
213 return 0;
214 }
215
216 static int
217 xrpu_attach(device_t self)
218 {
219 struct softc *sc;
220 struct resource *res;
221 int rid, unit;
222
223 unit = device_get_unit(self);
224 sc = device_get_softc(self);
225 sc->mode = NORMAL;
226 rid = PCIR_BAR(0);
227 res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
228 0, ~0, 1, RF_ACTIVE);
229 if (res == NULL) {
230 device_printf(self, "Could not map memory\n");
231 return ENXIO;
232 }
233 sc->virbase = (vm_offset_t)rman_get_virtual(res);
234 sc->physbase = rman_get_start(res);
235 sc->virbase62 = (u_int *)(sc->virbase + 0x800000);
236
237 if (bootverbose)
238 printf("Mapped physbase %#lx to virbase %#lx\n",
239 (u_long)sc->physbase, (u_long)sc->virbase);
240
241 make_dev(&xrpu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
242 return 0;
243 }
244
245 static device_method_t xrpu_methods[] = {
246 /* Device interface */
247 DEVMETHOD(device_probe, xrpu_probe),
248 DEVMETHOD(device_attach, xrpu_attach),
249 DEVMETHOD(device_suspend, bus_generic_suspend),
250 DEVMETHOD(device_resume, bus_generic_resume),
251 DEVMETHOD(device_shutdown, bus_generic_shutdown),
252
253 {0, 0}
254 };
255
256 static driver_t xrpu_driver = {
257 "xrpu",
258 xrpu_methods,
259 sizeof(struct softc)
260 };
261
262
263 DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);
264 MODULE_DEPEND(xrpu, pci, 1, 1, 1);
Cache object: da6bb9862c09a63c558a0bd9e960ec41
|