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