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