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$
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 "opt_devfs.h"
21
22 #include "xrpu.h"
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/conf.h>
26 #include <sys/kernel.h>
27 #include <sys/malloc.h>
28 #include <sys/timepps.h>
29 #ifdef DEVFS
30 #include <sys/devfsext.h>
31 #endif
32 #include <sys/xrpuio.h>
33 #include <pci/pcireg.h>
34 #include <pci/pcivar.h>
35
36 static const char* xrpu_probe (pcici_t tag, pcidi_t type);
37 static void xrpu_attach (pcici_t tag, int unit);
38 static u_long xrpu_count;
39
40 static void xrpu_poll_pps(struct timecounter *tc);
41
42 /*
43 * Device driver initialization stuff
44 */
45
46 static d_open_t xrpu_open;
47 static d_close_t xrpu_close;
48 static d_ioctl_t xrpu_ioctl;
49 static d_mmap_t xrpu_mmap;
50
51 #define CDEV_MAJOR 100
52 static struct cdevsw xrpudevsw = {
53 xrpu_open, xrpu_close, noread, nowrite,
54 xrpu_ioctl, nullstop, noreset, nodevtotty,
55 seltrue, xrpu_mmap, nostrategy, "xrpu",
56 NULL, -1
57 };
58
59 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
60
61 #define dev2unit(devt) (minor(devt) & 0xff)
62 #define dev2pps(devt) ((minor(devt) >> 16)-1)
63
64 static struct softc {
65 pcici_t tag;
66 enum { NORMAL, TIMECOUNTER } mode;
67 vm_offset_t virbase, physbase;
68 u_int *virbase62;
69 struct timecounter tc;
70 u_int *trigger, *latch, dummy;
71 struct pps_state pps[XRPU_MAX_PPS];
72 u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS];
73 } *softc[NXRPU];
74
75 static unsigned
76 xrpu_get_timecount(struct timecounter *tc)
77 {
78 struct softc *sc = tc->tc_priv;
79
80 sc->dummy += *sc->trigger;
81 return (*sc->latch & tc->tc_counter_mask);
82 }
83
84 void
85 xrpu_poll_pps(struct timecounter *tc)
86 {
87 struct softc *sc = tc->tc_priv;
88 int i;
89 unsigned count1, ppscount;
90
91 for (i = 0; i < XRPU_MAX_PPS; i++) {
92 if (sc->assert[i]) {
93 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
94 do {
95 count1 = ppscount;
96 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
97 } while (ppscount != count1);
98 pps_event(&sc->pps[i], &sc->tc, ppscount, PPS_CAPTUREASSERT);
99 }
100 if (sc->clear[i]) {
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);
106 pps_event(&sc->pps[i], &sc->tc, ppscount, PPS_CAPTURECLEAR);
107 }
108 }
109 }
110
111 static int
112 xrpu_open(dev_t dev, int flag, int mode, struct proc *p)
113 {
114 return (0);
115 }
116
117 static int
118 xrpu_close(dev_t dev, int flag, int mode, struct proc *p)
119 {
120 return (0);
121 }
122
123 static int
124 xrpu_mmap(dev_t dev, vm_offset_t offset, int nprot)
125 {
126 struct softc *sc = softc[dev2unit(dev)];
127 if (offset >= 0x1000000)
128 return (-1);
129 return (i386_btop(sc->physbase + offset));
130 }
131
132 static int
133 xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr)
134 {
135 struct softc *sc = softc[dev2unit(dev)];
136 int i, error;
137
138 if (sc->mode == TIMECOUNTER) {
139 i = dev2pps(dev);
140 if (i < 0 || i >= XRPU_MAX_PPS)
141 return ENODEV;
142 error = pps_ioctl(cmd, arg, &sc->pps[i]);
143 return (error);
144 }
145
146 if (cmd == XRPU_IOC_TIMECOUNTING) {
147 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
148
149 /* Name SHALL be zero terminated */
150 xt->xt_name[sizeof xt->xt_name - 1] = '\0';
151 i = strlen(xt->xt_name);
152 sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK);
153 strcpy(sc->tc.tc_name, xt->xt_name);
154 sc->tc.tc_frequency = xt->xt_frequency;
155 sc->tc.tc_get_timecount = xrpu_get_timecount;
156 sc->tc.tc_poll_pps = xrpu_poll_pps;
157 sc->tc.tc_priv = sc;
158 sc->tc.tc_counter_mask = xt->xt_mask;
159 sc->trigger = sc->virbase62 + xt->xt_addr_trigger;
160 sc->latch = sc->virbase62 + xt->xt_addr_latch;
161
162 for (i = 0; i < XRPU_MAX_PPS; i++) {
163 if (xt->xt_pps[i].xt_addr_assert == 0
164 && xt->xt_pps[i].xt_addr_clear == 0)
165 continue;
166 #ifdef DEVFS
167 devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL,
168 0600, "xpps%d", i);
169 #endif
170 sc->pps[i].ppscap = 0;
171 if (xt->xt_pps[i].xt_addr_assert) {
172 sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
173 sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
174 }
175 if (xt->xt_pps[i].xt_addr_clear) {
176 sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
177 sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
178 }
179 pps_init(&sc->pps[i]);
180 }
181 sc->mode = TIMECOUNTER;
182 init_timecounter(&sc->tc);
183 return (0);
184 }
185 error = ENOTTY;
186 return (error);
187 }
188
189 /*
190 * PCI initialization stuff
191 */
192
193 static struct pci_device xrpu_device = {
194 "xrpu",
195 xrpu_probe,
196 xrpu_attach,
197 &xrpu_count,
198 NULL
199 };
200
201 DATA_SET (pcidevice_set, xrpu_device);
202
203 static const char*
204 xrpu_probe (pcici_t tag, pcidi_t typea)
205 {
206 u_int id;
207 const char *vendor, *chip, *type;
208
209 (void)pci_conf_read(tag, PCI_CLASS_REG);
210 id = pci_conf_read(tag, PCI_ID_REG);
211
212 vendor = chip = type = 0;
213
214 if (id == 0x6216133e) {
215 return "VCC Hotworks-I xc6216";
216 }
217 return 0;
218 }
219
220 static void
221 xrpu_attach (pcici_t tag, int unit)
222 {
223 struct softc *sc;
224 dev_t cdev = makedev(CDEV_MAJOR, unit);
225
226 sc = (struct softc *)malloc(sizeof *sc, M_XRPU, M_WAITOK);
227 softc[unit] = sc;
228 bzero(sc, sizeof *sc);
229
230 sc->tag = tag;
231 sc->mode = NORMAL;
232
233 pci_map_mem(tag, PCI_MAP_REG_START, &sc->virbase, &sc->physbase);
234
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 if (!unit)
242 cdevsw_add(&cdev, &xrpudevsw, NULL);
243
244 #ifdef DEVFS
245 devfs_add_devswf(&xrpudevsw, 0, DV_CHR, UID_ROOT, GID_WHEEL, 0600,
246 "xrpu%d", unit);
247 #endif
248 }
Cache object: c74e7574da9de050f23f21a035badfaf
|