]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/pci/xrpu.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / 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
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 #include <sys/cdefs.h>
20 __FBSDID("$FreeBSD$");
21
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/conf.h>
25 #include <sys/kernel.h>
26 #include <sys/malloc.h>
27 #include <sys/module.h>
28 #include <sys/timetc.h>
29 #include <sys/timepps.h>
30 #include <sys/xrpuio.h>
31 #include <sys/bus.h>
32 #include <machine/bus.h>
33 #include <sys/rman.h>
34 #include <machine/resource.h>
35 #include <dev/pci/pcireg.h>
36 #include <dev/pci/pcivar.h>
37 #include "pci_if.h"
38
39 /*
40  * Device driver initialization stuff
41  */
42
43 static d_open_t xrpu_open;
44 static d_close_t xrpu_close;
45 static d_ioctl_t xrpu_ioctl;
46 static d_mmap_t xrpu_mmap;
47
48 static struct cdevsw xrpu_cdevsw = {
49         .d_version =    D_VERSION,
50         .d_flags =      D_NEEDGIANT,
51         .d_open =       xrpu_open,
52         .d_close =      xrpu_close,
53         .d_ioctl =      xrpu_ioctl,
54         .d_mmap =       xrpu_mmap,
55         .d_name =       "xrpu",
56 };
57
58 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
59
60 static devclass_t xrpu_devclass;
61
62 #define dev2unit(devt) (minor(devt) & 0xff)
63 #define dev2pps(devt) ((minor(devt) >> 16)-1)
64
65 struct softc {
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 };
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 static void            
85 xrpu_poll_pps(struct timecounter *tc)
86 {               
87         struct softc *sc = tc->tc_priv;
88         int i, j;
89         unsigned count1, ppscount; 
90                 
91         for (i = 0; i < XRPU_MAX_PPS; i++) {
92                 if (sc->assert[i]) {
93                         pps_capture(&sc->pps[i]);
94                         ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
95                         j = 0;
96                         do {
97                                 count1 = ppscount;
98                                 ppscount =  *(sc->assert[i]) & tc->tc_counter_mask;
99                         } while (ppscount != count1 && ++j < 5);
100                         sc->pps[i].capcount = ppscount;
101                         pps_event(&sc->pps[i], PPS_CAPTUREASSERT);
102                 }
103                 if (sc->clear[i]) {
104                         pps_capture(&sc->pps[i]);
105                         j = 0;
106                         ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
107                         do {
108                                 count1 = ppscount;
109                                 ppscount =  *(sc->clear[i]) & tc->tc_counter_mask;
110                         } while (ppscount != count1 && ++j < 5);
111                         sc->pps[i].capcount = ppscount;
112                         pps_event(&sc->pps[i], PPS_CAPTURECLEAR);
113                 }
114         }
115 }
116
117 static int
118 xrpu_open(struct cdev *dev, int flag, int mode, struct  thread *td)
119 {
120         struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
121
122         if (!sc)
123                 return (ENXIO);
124         dev->si_drv1 = sc;
125         return (0);
126 }
127
128 static int
129 xrpu_close(struct cdev *dev, int flag, int mode, struct  thread *td)
130
131         return (0);
132 }
133
134 static int
135 xrpu_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
136 {
137         struct softc *sc = dev->si_drv1;
138         if (offset >= 0x1000000) 
139                 return (-1);
140         *paddr = sc->physbase + offset;
141         return (0);
142 }
143
144 static int
145 xrpu_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
146 {
147         struct softc *sc = dev->si_drv1;
148         int i, error;
149
150         if (sc->mode == TIMECOUNTER) {
151                 i = dev2pps(dev);
152                 if (i < 0 || i >= XRPU_MAX_PPS)
153                         return ENODEV;
154                 error =  pps_ioctl(cmd, arg, &sc->pps[i]);
155                 return (error);
156         }
157                 
158         if (cmd == XRPU_IOC_TIMECOUNTING) {
159                 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
160
161                 /* Name SHALL be zero terminated */
162                 xt->xt_name[sizeof xt->xt_name - 1] = '\0';
163                 i = strlen(xt->xt_name);
164                 sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK);
165                 strcpy(sc->tc.tc_name, xt->xt_name);
166                 sc->tc.tc_frequency = xt->xt_frequency;
167                 sc->tc.tc_get_timecount = xrpu_get_timecount;
168                 sc->tc.tc_poll_pps = xrpu_poll_pps;
169                 sc->tc.tc_priv = sc;
170                 sc->tc.tc_counter_mask = xt->xt_mask;
171                 sc->trigger = sc->virbase62 + xt->xt_addr_trigger;
172                 sc->latch = sc->virbase62 + xt->xt_addr_latch;
173
174                 for (i = 0; i < XRPU_MAX_PPS; i++) {
175                         if (xt->xt_pps[i].xt_addr_assert == 0
176                             && xt->xt_pps[i].xt_addr_clear == 0)
177                                 continue;
178                         make_dev(&xrpu_cdevsw, (i+1)<<16, 
179                             UID_ROOT, GID_WHEEL, 0600, "xpps%d", i);
180                         sc->pps[i].ppscap = 0;
181                         if (xt->xt_pps[i].xt_addr_assert) {
182                                 sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
183                                 sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
184                         }
185                         if (xt->xt_pps[i].xt_addr_clear) {
186                                 sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
187                                 sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
188                         }
189                         pps_init(&sc->pps[i]);
190                 }
191                 sc->mode = TIMECOUNTER;
192                 tc_init(&sc->tc);
193                 return (0);
194         }
195         error = ENOTTY;
196         return (error);
197 }
198
199 /*
200  * PCI initialization stuff
201  */
202
203 static int
204 xrpu_probe(device_t self)
205 {
206         char *desc;
207
208         desc = NULL;
209         switch (pci_get_devid(self)) {
210         case 0x6216133e:
211                 desc = "VCC Hotworks-I xc6216";
212                 break;
213         }
214         if (desc == NULL)
215                 return ENXIO;
216
217         device_set_desc(self, desc);
218         return (BUS_PROBE_DEFAULT);
219 }
220
221 static int
222 xrpu_attach(device_t self)
223 {
224         struct softc *sc;
225         struct resource *res;
226         int rid, unit;
227
228         unit = device_get_unit(self);
229         sc = device_get_softc(self);
230         sc->mode = NORMAL;
231         rid = PCIR_BAR(0);
232         res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
233         if (res == NULL) {
234                 device_printf(self, "Could not map memory\n");
235                 return ENXIO;
236         }
237         sc->virbase = (vm_offset_t)rman_get_virtual(res);
238         sc->physbase = rman_get_start(res);
239         sc->virbase62 = (u_int *)(sc->virbase + 0x800000);
240
241         if (bootverbose)
242                 printf("Mapped physbase %#lx to virbase %#lx\n",
243                     (u_long)sc->physbase, (u_long)sc->virbase);
244
245         make_dev(&xrpu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
246         return 0;
247 }
248
249 static device_method_t xrpu_methods[] = {
250         /* Device interface */
251         DEVMETHOD(device_probe,         xrpu_probe),
252         DEVMETHOD(device_attach,        xrpu_attach),
253         DEVMETHOD(device_suspend,       bus_generic_suspend),
254         DEVMETHOD(device_resume,        bus_generic_resume),
255         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
256
257         {0, 0}
258 };
259  
260 static driver_t xrpu_driver = {
261         "xrpu",
262         xrpu_methods,
263         sizeof(struct softc)
264 };
265  
266  
267 DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);
268 MODULE_DEPEND(xrpu, pci, 1, 1, 1);