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