]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pci/nfsmb.c
This commit was generated by cvs2svn to compensate for changes in r161653,
[FreeBSD/FreeBSD.git] / sys / pci / nfsmb.c
1 #include <sys/cdefs.h>
2 __FBSDID("$FreeBSD$");
3
4 #include <sys/param.h>
5 #include <sys/kernel.h>
6 #include <sys/systm.h>
7 #include <sys/module.h>
8 #include <sys/bus.h>
9 #include <sys/uio.h>
10
11 #include <machine/bus.h>
12 #include <machine/resource.h>
13 #include <sys/rman.h>
14
15 #include <dev/pci/pcivar.h>
16 #include <dev/pci/pcireg.h>
17
18 #include <dev/iicbus/iiconf.h>
19 #include <dev/smbus/smbconf.h>
20 #include "smbus_if.h"
21
22 #define NFSMB_DEBUG(x)  if (nfsmb_debug) (x)
23
24 #ifdef DEBUG
25 static int nfsmb_debug = 1;
26 #else
27 static int nfsmb_debug = 0;
28 #endif
29
30 /* NVIDIA nForce2/3/4 MCP */
31 #define NFSMB_VENDORID_NVIDIA           0x10de
32 #define NFSMB_DEVICEID_NF2_SMB          0x0064
33 #define NFSMB_DEVICEID_NF2_ULTRA_SMB    0x0084
34 #define NFSMB_DEVICEID_NF3_PRO150_SMB   0x00d4
35 #define NFSMB_DEVICEID_NF3_250GB_SMB    0x00e4
36 #define NFSMB_DEVICEID_NF4_SMB          0x0052
37 #define NFSMB_DEVICEID_NF4_04_SMB       0x0034
38 #define NFSMB_DEVICEID_NF4_51_SMB       0x0264
39 #define NFSMB_DEVICEID_NF4_55_SMB       0x0368
40
41 /* PCI Configuration space registers */
42 #define NF2PCI_SMBASE_1         PCIR_BAR(4)
43 #define NF2PCI_SMBASE_2         PCIR_BAR(5)
44
45 /*
46  * ACPI 3.0, Chapter 12, SMBus Host Controller Interface.
47  */
48 #define SMB_PRTCL               0x00    /* protocol */
49 #define SMB_STS                 0x01    /* status */
50 #define SMB_ADDR                0x02    /* address */
51 #define SMB_CMD                 0x03    /* command */
52 #define SMB_DATA                0x04    /* 32 data registers */
53 #define SMB_BCNT                0x24    /* number of data bytes */
54 #define SMB_ALRM_A              0x25    /* alarm address */
55 #define SMB_ALRM_D              0x26    /* 2 bytes alarm data */
56
57 #define SMB_STS_DONE            0x80
58 #define SMB_STS_ALRM            0x40
59 #define SMB_STS_RES             0x20
60 #define SMB_STS_STATUS          0x1f
61 #define SMB_STS_OK              0x00    /* OK */
62 #define SMB_STS_UF              0x07    /* Unknown Failure */
63 #define SMB_STS_DANA            0x10    /* Device Address Not Acknowledged */
64 #define SMB_STS_DED             0x11    /* Device Error Detected */
65 #define SMB_STS_DCAD            0x12    /* Device Command Access Denied */
66 #define SMB_STS_UE              0x13    /* Unknown Error */
67 #define SMB_STS_DAD             0x17    /* Device Access Denied */
68 #define SMB_STS_T               0x18    /* Timeout */
69 #define SMB_STS_HUP             0x19    /* Host Unsupported Protocol */
70 #define SMB_STS_B               0x1A    /* Busy */
71 #define SMB_STS_PEC             0x1F    /* PEC (CRC-8) Error */
72
73 #define SMB_PRTCL_WRITE         0x00
74 #define SMB_PRTCL_READ          0x01
75 #define SMB_PRTCL_QUICK         0x02
76 #define SMB_PRTCL_BYTE          0x04
77 #define SMB_PRTCL_BYTE_DATA     0x06
78 #define SMB_PRTCL_WORD_DATA     0x08
79 #define SMB_PRTCL_BLOCK_DATA    0x0a
80 #define SMB_PRTCL_PROC_CALL     0x0c
81 #define SMB_PRTCL_BLOCK_PROC_CALL 0x0d
82 #define SMB_PRTCL_PEC           0x80
83
84 struct nfsmb_softc {
85         int rid;
86         struct resource *res;
87         bus_space_tag_t smbst;
88         bus_space_handle_t smbsh;
89
90         device_t smbus;
91         device_t subdev;
92 };
93
94 #define NFSMB_SMBINB(nfsmb, register) \
95         (bus_space_read_1(nfsmb->smbst, nfsmb->smbsh, register))
96 #define NFSMB_SMBOUTB(nfsmb, register, value) \
97         (bus_space_write_1(nfsmb->smbst, nfsmb->smbsh, register, value))
98
99 static int
100 nfsmbsub_probe(device_t dev)
101 {
102
103         device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
104         return (BUS_PROBE_DEFAULT);
105 }
106
107 static int
108 nfsmb_probe(device_t dev)
109 {
110         u_int16_t vid;
111         u_int16_t did;
112
113         vid = pci_get_vendor(dev);
114         did = pci_get_device(dev);
115
116         if (vid == NFSMB_VENDORID_NVIDIA) {
117                 switch(did) {
118                 case NFSMB_DEVICEID_NF2_SMB:
119                 case NFSMB_DEVICEID_NF2_ULTRA_SMB:
120                 case NFSMB_DEVICEID_NF3_PRO150_SMB:
121                 case NFSMB_DEVICEID_NF3_250GB_SMB:
122                 case NFSMB_DEVICEID_NF4_SMB:
123                 case NFSMB_DEVICEID_NF4_04_SMB:
124                 case NFSMB_DEVICEID_NF4_51_SMB:
125                 case NFSMB_DEVICEID_NF4_55_SMB:
126                         device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
127                         return (BUS_PROBE_DEFAULT);
128                 }
129         }
130
131         return (ENXIO);
132 }
133
134 static int
135 nfsmbsub_attach(device_t dev)
136 {
137         device_t parent;
138         struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
139
140         parent = device_get_parent(dev);
141
142         nfsmbsub_sc->rid = NF2PCI_SMBASE_2;
143
144         nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT,
145             &nfsmbsub_sc->rid, RF_ACTIVE);
146         if (nfsmbsub_sc->res == NULL) {
147                 device_printf(dev, "could not map i/o space\n");
148                 return (ENXIO);
149         }
150         nfsmbsub_sc->smbst = rman_get_bustag(nfsmbsub_sc->res);
151         nfsmbsub_sc->smbsh = rman_get_bushandle(nfsmbsub_sc->res);
152
153         nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1);
154         if (nfsmbsub_sc->smbus == NULL)
155                 return (EINVAL);
156
157         bus_generic_attach(dev);
158
159         return (0);
160 }
161
162 static int
163 nfsmb_attach(device_t dev)
164 {
165         struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
166
167         /* Allocate I/O space */
168         nfsmb_sc->rid = NF2PCI_SMBASE_1;
169
170         nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
171                 &nfsmb_sc->rid, RF_ACTIVE);
172
173         if (nfsmb_sc->res == NULL) {
174                 device_printf(dev, "could not map i/o space\n");
175                 return (ENXIO);
176         }
177
178         nfsmb_sc->smbst = rman_get_bustag(nfsmb_sc->res);
179         nfsmb_sc->smbsh = rman_get_bushandle(nfsmb_sc->res);
180
181         /* Allocate a new smbus device */
182         nfsmb_sc->smbus = device_add_child(dev, "smbus", -1);
183         if (!nfsmb_sc->smbus)
184                 return (EINVAL);
185
186         nfsmb_sc->subdev = NULL;
187         switch (pci_get_device(dev)) {
188         case NFSMB_DEVICEID_NF2_SMB:
189         case NFSMB_DEVICEID_NF2_ULTRA_SMB:
190         case NFSMB_DEVICEID_NF3_PRO150_SMB:
191         case NFSMB_DEVICEID_NF3_250GB_SMB:
192         case NFSMB_DEVICEID_NF4_SMB:
193         case NFSMB_DEVICEID_NF4_04_SMB:
194         case NFSMB_DEVICEID_NF4_51_SMB:
195         case NFSMB_DEVICEID_NF4_55_SMB:
196                 /* Trying to add secondary device as slave */
197                 nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1);
198                 if (!nfsmb_sc->subdev)
199                         return (EINVAL);
200                 break;
201         default:
202                 break;
203         }
204
205         bus_generic_attach(dev);
206
207         return (0);
208 }
209
210 static int
211 nfsmbsub_detach(device_t dev)
212 {
213         device_t parent;
214         struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
215
216         parent = device_get_parent(dev);
217
218         if (nfsmbsub_sc->smbus) {
219                 device_delete_child(dev, nfsmbsub_sc->smbus);
220                 nfsmbsub_sc->smbus = NULL;
221         }
222         if (nfsmbsub_sc->res) {
223                 bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid,
224                     nfsmbsub_sc->res);
225                 nfsmbsub_sc->res = NULL;
226         }
227         return (0);
228 }
229
230 static int
231 nfsmb_detach(device_t dev)
232 {
233         struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
234
235         if (nfsmb_sc->subdev) {
236                 device_delete_child(dev, nfsmb_sc->subdev);
237                 nfsmb_sc->subdev = NULL;
238         }
239
240         if (nfsmb_sc->smbus) {
241                 device_delete_child(dev, nfsmb_sc->smbus);
242                 nfsmb_sc->smbus = NULL;
243         }
244
245         if (nfsmb_sc->res) {
246                 bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid,
247                     nfsmb_sc->res);
248                 nfsmb_sc->res = NULL;
249         }
250
251         return (0);
252 }
253
254 static int
255 nfsmb_callback(device_t dev, int index, caddr_t *data)
256 {
257         int error = 0;
258
259         switch (index) {
260         case SMB_REQUEST_BUS:
261         case SMB_RELEASE_BUS:
262                 break;
263         default:
264                 error = EINVAL;
265         }
266
267         return (error);
268 }
269
270 static int
271 nfsmb_wait(struct nfsmb_softc *sc)
272 {
273         u_char sts;
274         int error, count;
275
276         if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0)
277         {
278                 count = 10000;
279                 do {
280                         DELAY(500);
281                 } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--);
282                 if (count == 0)
283                         return (SMB_ETIMEOUT);
284         }
285
286         sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS;
287         NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts));
288
289         switch (sts) {
290         case SMB_STS_OK:
291                 error = SMB_ENOERR;
292                 break;
293         case SMB_STS_DANA:
294                 error = SMB_ENOACK;
295                 break;
296         case SMB_STS_B:
297                 error = SMB_EBUSY;
298                 break;
299         case SMB_STS_T:
300                 error = SMB_ETIMEOUT;
301                 break;
302         case SMB_STS_DCAD:
303         case SMB_STS_DAD:
304         case SMB_STS_HUP:
305                 error = SMB_ENOTSUPP;
306                 break;
307         default:
308                 error = SMB_EBUSERR;
309                 break;
310         }
311
312         return (error);
313 }
314
315 static int
316 nfsmb_quick(device_t dev, u_char slave, int how)
317 {
318         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
319         u_char protocol;
320         int error;
321
322         protocol = SMB_PRTCL_QUICK;
323
324         switch (how) {
325         case SMB_QWRITE:
326                 protocol |= SMB_PRTCL_WRITE;
327                 NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave));
328                 break;
329         case SMB_QREAD:
330                 protocol |= SMB_PRTCL_READ;
331                 NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave));
332                 break;
333         default:
334                 panic("%s: unknown QUICK command (%x)!", __func__, how);
335         }
336
337         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
338         NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol);
339
340         error = nfsmb_wait(sc);
341
342         NFSMB_DEBUG(printf(", error=0x%x\n", error));
343
344         return (error);
345 }
346
347 static int
348 nfsmb_sendb(device_t dev, u_char slave, char byte)
349 {
350         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
351         int error;
352
353         NFSMB_SMBOUTB(sc, SMB_CMD, byte);
354         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
355         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE);
356
357         error = nfsmb_wait(sc);
358
359         NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
360
361         return (error);
362 }
363
364 static int
365 nfsmb_recvb(device_t dev, u_char slave, char *byte)
366 {
367         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
368         int error;
369
370         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
371         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE);
372
373         if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
374                 *byte = NFSMB_SMBINB(sc, SMB_DATA);
375
376         NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
377
378         return (error);
379 }
380
381 static int
382 nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
383 {
384         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
385         int error;
386
387         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
388         NFSMB_SMBOUTB(sc, SMB_DATA, byte);
389         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
390         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA);
391
392         error = nfsmb_wait(sc);
393
394         NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
395
396         return (error);
397 }
398
399 static int
400 nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
401 {
402         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
403         int error;
404
405         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
406         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
407         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA);
408
409         if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
410                 *byte = NFSMB_SMBINB(sc, SMB_DATA);
411
412         NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error));
413
414         return (error);
415 }
416
417 static int
418 nfsmb_writew(device_t dev, u_char slave, char cmd, short word)
419 {
420         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
421         int error;
422
423         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
424         NFSMB_SMBOUTB(sc, SMB_DATA, word);
425         NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8);
426         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
427         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA);
428
429         error = nfsmb_wait(sc);
430
431         NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
432
433         return (error);
434 }
435
436 static int
437 nfsmb_readw(device_t dev, u_char slave, char cmd, short *word)
438 {
439         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
440         int error;
441
442         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
443         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
444         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA);
445
446         if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
447                 *word = NFSMB_SMBINB(sc, SMB_DATA) |
448                     (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8);
449
450         NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error));
451
452         return (error);
453 }
454
455 static int
456 nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
457 {
458         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
459         u_char len, i;
460         int error;
461
462         len = min(count, 32);
463         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
464         NFSMB_SMBOUTB(sc, SMB_BCNT, len);
465         for (i = 0; i < len; i++)
466                 NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]);
467         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
468         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA);
469
470         error = nfsmb_wait(sc);
471
472         NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
473
474         return (error);
475 }
476
477 static int
478 nfsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
479 {
480         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
481         u_char len, i;
482         int error;
483
484         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
485         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
486         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA);
487
488         if ((error = nfsmb_wait(sc)) == SMB_ENOERR) {
489                 len = NFSMB_SMBINB(sc, SMB_BCNT);
490                 len = min(len, 32);
491                 for (i = 0; i < len; i++)
492                         buf[i] = NFSMB_SMBINB(sc, SMB_DATA + i);
493         }
494
495         NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
496
497         return (error);
498 }
499
500 static device_method_t nfsmb_methods[] = {
501         /* Device interface */
502         DEVMETHOD(device_probe,         nfsmb_probe),
503         DEVMETHOD(device_attach,        nfsmb_attach),
504         DEVMETHOD(device_detach,        nfsmb_detach),
505
506         /* SMBus interface */
507         DEVMETHOD(smbus_callback,       nfsmb_callback),
508         DEVMETHOD(smbus_quick,          nfsmb_quick),
509         DEVMETHOD(smbus_sendb,          nfsmb_sendb),
510         DEVMETHOD(smbus_recvb,          nfsmb_recvb),
511         DEVMETHOD(smbus_writeb,         nfsmb_writeb),
512         DEVMETHOD(smbus_readb,          nfsmb_readb),
513         DEVMETHOD(smbus_writew,         nfsmb_writew),
514         DEVMETHOD(smbus_readw,          nfsmb_readw),
515         DEVMETHOD(smbus_bwrite,         nfsmb_bwrite),
516         DEVMETHOD(smbus_bread,          nfsmb_bread),
517
518         { 0, 0 }
519 };
520
521 static device_method_t nfsmbsub_methods[] = {
522         /* Device interface */
523         DEVMETHOD(device_probe,         nfsmbsub_probe),
524         DEVMETHOD(device_attach,        nfsmbsub_attach),
525         DEVMETHOD(device_detach,        nfsmbsub_detach),
526
527         /* SMBus interface */
528         DEVMETHOD(smbus_callback,       nfsmb_callback),
529         DEVMETHOD(smbus_quick,          nfsmb_quick),
530         DEVMETHOD(smbus_sendb,          nfsmb_sendb),
531         DEVMETHOD(smbus_recvb,          nfsmb_recvb),
532         DEVMETHOD(smbus_writeb,         nfsmb_writeb),
533         DEVMETHOD(smbus_readb,          nfsmb_readb),
534         DEVMETHOD(smbus_writew,         nfsmb_writew),
535         DEVMETHOD(smbus_readw,          nfsmb_readw),
536         DEVMETHOD(smbus_bwrite,         nfsmb_bwrite),
537         DEVMETHOD(smbus_bread,          nfsmb_bread),
538
539         { 0, 0 }
540 };
541
542 static devclass_t nfsmb_devclass;
543
544 static driver_t nfsmb_driver = {
545         "nfsmb",
546         nfsmb_methods,
547         sizeof(struct nfsmb_softc),
548 };
549
550 static driver_t nfsmbsub_driver = {
551         "nfsmb",
552         nfsmbsub_methods,
553         sizeof(struct nfsmb_softc),
554 };
555
556 DRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0);
557 DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0);
558
559 MODULE_DEPEND(nfsmb, pci, 1, 1, 1);
560 MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
561 MODULE_VERSION(nfsmb, 1);