intpm.c revision 46590
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1998, 1999 Takanori Watanabe 31573Srgrimes * All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 141573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241573Srgrimes * SUCH DAMAGE. 251573Srgrimes * 261573Srgrimes * $Id: intpm.c,v 1.6 1999/04/24 20:14:02 peter Exp $ 271573Srgrimes */ 281573Srgrimes 291573Srgrimes#include "pci.h" 301573Srgrimes#include "intpm.h" 311573Srgrimes 321573Srgrimes#if NPCI > 0 331573Srgrimes#if NINTPM >0 341573Srgrimes/* I don't think the chip is used in other architecture. :-)*/ 351573Srgrimes#include <sys/param.h> 361573Srgrimes#include <sys/systm.h> 371573Srgrimes#include <sys/kernel.h> 381573Srgrimes 391573Srgrimes#include <machine/bus_pio.h> 401573Srgrimes#include <machine/bus_memio.h> 411573Srgrimes#include <machine/bus.h> 421573Srgrimes 431573Srgrimes#include <machine/clock.h> 441573Srgrimes#include <sys/uio.h> 451573Srgrimes#include <sys/module.h> 4611659Sphk#include <sys/bus.h> 471573Srgrimes#include <sys/conf.h> 481573Srgrimes#include <sys/malloc.h> 491573Srgrimes#include <sys/buf.h> 501573Srgrimes 511573Srgrimes#include <dev/smbus/smbconf.h> 521573Srgrimes 531573Srgrimes#include "smbus_if.h" 541573Srgrimes 551573Srgrimes/*This should be removed if force_pci_map_int supported*/ 561573Srgrimes#include <sys/interrupt.h> 571573Srgrimes 581573Srgrimes#include <pci/pcireg.h> 591573Srgrimes#include <pci/pcivar.h> 601573Srgrimes#include <pci/intpmreg.h> 611573Srgrimes 621573Srgrimes#include "opt_intpm.h" 631573Srgrimes 641573Srgrimesstatic struct _pcsid 651573Srgrimes{ 661573Srgrimes pcidi_t type; 671573Srgrimes char *desc; 681573Srgrimes} pci_ids[] = 6942353Sdes{ 7042353Sdes { 0x71138086,"Intel 82371AB Power management controller"}, 7142353Sdes 7242353Sdes { 0x00000000, NULL } 731573Srgrimes}; 741573Srgrimesstatic int intsmb_probe(device_t); 751573Srgrimesstatic int intsmb_attach(device_t); 761573Srgrimesstatic void intsmb_print_child(device_t, device_t); 771573Srgrimes 781573Srgrimesstatic int intsmb_intr(device_t dev); 7942353Sdesstatic int intsmb_slvintr(device_t dev); 8042353Sdesstatic void intsmb_alrintr(device_t dev); 8142353Sdesstatic int intsmb_callback(device_t dev, int index, caddr_t data); 8242353Sdesstatic int intsmb_quick(device_t dev, u_char slave, int how); 831573Srgrimesstatic int intsmb_sendb(device_t dev, u_char slave, char byte); 841573Srgrimesstatic int intsmb_recvb(device_t dev, u_char slave, char *byte); 851573Srgrimesstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 861573Srgrimesstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 871573Srgrimesstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 881573Srgrimesstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 891573Srgrimesstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 901573Srgrimesstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 911573Srgrimesstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 921573Srgrimesstatic void intsmb_start(device_t dev,u_char cmd,int nointr); 931573Srgrimesstatic int intsmb_stop(device_t dev); 941573Srgrimesstatic int intsmb_stop_poll(device_t dev); 951573Srgrimesstatic int intsmb_free(device_t dev); 961573Srgrimesstatic struct intpm_pci_softc *intpm_alloc(int unit); 971573Srgrimesstatic const char* intpm_probe __P((pcici_t tag, pcidi_t type)); 981573Srgrimesstatic void intpm_attach __P((pcici_t config_id, int unit)); 991573Srgrimesstatic devclass_t intsmb_devclass; 1001573Srgrimes 1011573Srgrimesstatic device_method_t intpm_methods[]={ 1021573Srgrimes DEVMETHOD(device_probe,intsmb_probe), 1031573Srgrimes DEVMETHOD(device_attach,intsmb_attach), 1041573Srgrimes 1051573Srgrimes DEVMETHOD(bus_print_child, intsmb_print_child), 1061573Srgrimes 1071573Srgrimes DEVMETHOD(smbus_callback,intsmb_callback), 1081573Srgrimes DEVMETHOD(smbus_quick,intsmb_quick), 1091573Srgrimes DEVMETHOD(smbus_sendb,intsmb_sendb), 1101573Srgrimes DEVMETHOD(smbus_recvb,intsmb_recvb), 1111573Srgrimes DEVMETHOD(smbus_writeb,intsmb_writeb), 1121573Srgrimes DEVMETHOD(smbus_writew,intsmb_writew), 1131573Srgrimes DEVMETHOD(smbus_readb,intsmb_readb), 1141573Srgrimes DEVMETHOD(smbus_readw,intsmb_readw), 1151573Srgrimes DEVMETHOD(smbus_pcall,intsmb_pcall), 1161573Srgrimes DEVMETHOD(smbus_bwrite,intsmb_bwrite), 1171573Srgrimes DEVMETHOD(smbus_bread,intsmb_bread), 1181573Srgrimes {0,0} 1191573Srgrimes}; 1201573Srgrimes 1211573Srgrimesstatic struct intpm_pci_softc{ 1221573Srgrimes bus_space_tag_t smbst; 1231573Srgrimes bus_space_handle_t smbsh; 1241573Srgrimes bus_space_tag_t pmst; 1251573Srgrimes bus_space_handle_t pmsh; 1261573Srgrimes pcici_t cfg; 1271573Srgrimes device_t smbus; 1281573Srgrimes}intpm_pci[NINTPM]; 1291573Srgrimes 1301573Srgrimes 1311573Srgrimesstruct intsmb_softc{ 1321573Srgrimes struct intpm_pci_softc *pci_sc; 1331573Srgrimes bus_space_tag_t st; 1341573Srgrimes bus_space_handle_t sh; 1351573Srgrimes device_t smbus; 1361573Srgrimes int isbusy; 1371573Srgrimes}; 1381573Srgrimesstatic driver_t intpm_driver = { 1391573Srgrimes "intsmb", 1401573Srgrimes intpm_methods, 1411573Srgrimes DRIVER_TYPE_MISC, 1421573Srgrimes sizeof(struct intsmb_softc), 1431573Srgrimes}; 1441573Srgrimesstatic u_long intpm_count ; 1451573Srgrimes 1461573Srgrimesstatic struct pci_device intpm_device = { 1471573Srgrimes "intpm", 1481573Srgrimes intpm_probe, 1491573Srgrimes intpm_attach, 1501573Srgrimes &intpm_count 1511573Srgrimes}; 1521573Srgrimes 1531573Srgrimes#ifdef COMPAT_PCI_DRIVER 1541573SrgrimesCOMPAT_PCI_DRIVER (intpm, intpm_device); 1551573Srgrimes#else 1561573SrgrimesDATA_SET (pcidevice_set, intpm_device); 1571573Srgrimes#endif /* COMPAT_PCI_DRIVER */ 1581573Srgrimes 1591573Srgrimesstatic int 1601573Srgrimesintsmb_probe(device_t dev) 1611573Srgrimes{ 1621573Srgrimes struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 1631573Srgrimes sc->smbus=smbus_alloc_bus(dev); 1641573Srgrimes if (!sc->smbus) 1651573Srgrimes return (EINVAL); /* XXX don't know what to return else */ 1661573Srgrimes device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 1671573Srgrimes 1681573Srgrimes return (0); /* XXX don't know what to return else */ 1691573Srgrimes} 1701573Srgrimesstatic int 1711573Srgrimesintsmb_attach(device_t dev) 1721573Srgrimes{ 1731573Srgrimes struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 1741573Srgrimes sc->pci_sc=&intpm_pci[device_get_unit(dev)]; 1751573Srgrimes sc->isbusy=0; 1761573Srgrimes sc->sh=sc->pci_sc->smbsh; 1771573Srgrimes sc->st=sc->pci_sc->smbst; 1781573Srgrimes sc->pci_sc->smbus=dev; 1791573Srgrimes device_probe_and_attach(sc->smbus); 1801573Srgrimes#ifdef ENABLE_ALART 1811573Srgrimes /*Enable Arart*/ 1821573Srgrimes bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 183 PIIX4_SMBSLVCNT_ALTEN); 184#endif 185 return (0); 186} 187 188static void 189intsmb_print_child(device_t bus, device_t dev) 190{ 191 printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 192 return; 193} 194static int 195intsmb_callback(device_t dev, int index, caddr_t data) 196{ 197 int error = 0; 198 intrmask_t s; 199 s=splnet(); 200 switch (index) { 201 case SMB_REQUEST_BUS: 202 break; 203 case SMB_RELEASE_BUS: 204 break; 205 default: 206 error = EINVAL; 207 } 208 splx(s); 209 return (error); 210} 211/*counterpart of smbtx_smb_free*/ 212static int 213intsmb_free(device_t dev){ 214 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 215 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 216 PIIX4_SMBHSTSTAT_BUSY) 217#ifdef ENABLE_ALART 218 ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 219 PIIX4_SMBSLVSTS_BUSY) 220#endif 221 || sc->isbusy) 222 return EBUSY; 223 sc->isbusy=1; 224 /*Disable Intrrupt in slave part*/ 225#ifndef ENABLE_ALART 226 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 227#endif 228 /*Reset INTR Flag to prepare INTR*/ 229 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 230 (PIIX4_SMBHSTSTAT_INTR| 231 PIIX4_SMBHSTSTAT_ERR| 232 PIIX4_SMBHSTSTAT_BUSC| 233 PIIX4_SMBHSTSTAT_FAIL) 234 ); 235 return 0; 236} 237 238static int 239intsmb_intr(device_t dev) 240{ 241 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 242 int status; 243 intrmask_t s; 244 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 245 if(status&PIIX4_SMBHSTSTAT_BUSY){ 246 return 1; 247 248 } 249 s=splhigh(); 250 if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR| 251 PIIX4_SMBHSTSTAT_ERR| 252 PIIX4_SMBHSTSTAT_BUSC| 253 PIIX4_SMBHSTSTAT_FAIL))){ 254 int tmp; 255 sc->isbusy=0; 256 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 257 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 258 tmp&~PIIX4_SMBHSTCNT_INTREN); 259 splx(s); 260 wakeup(sc); 261 return 0; 262 } 263 splx(s); 264 return 1;/* Not Completed*/ 265} 266static int 267intsmb_slvintr(device_t dev) 268{ 269 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 270 int status,retval; 271 retval=1; 272 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 273 if(status&PIIX4_SMBSLVSTS_BUSY) 274 return retval; 275 if(status&PIIX4_SMBSLVSTS_ALART){ 276 intsmb_alrintr(dev); 277 retval=0; 278 }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 279 |PIIX4_SMBSLVSTS_SDW1)){ 280 retval=0; 281 } 282 /*Reset Status Register*/ 283 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 284 PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 285 PIIX4_SMBSLVSTS_SLV); 286 return retval; 287} 288 289static void intsmb_alrintr(device_t dev) 290{ 291 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 292 int slvcnt; 293#ifdef ENABLE_ALART 294 int error; 295#endif 296 297 /*stop generating INTR from ALART*/ 298 slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 299#ifdef ENABLE_ALART 300 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 301 slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 302#endif 303 DELAY(5); 304 /*ask bus who assert it and then ask it what's the matter. */ 305#ifdef ENABLE_ALART 306 error=intsmb_free(dev); 307 if(!error){ 308 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 309 |LSB); 310 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 311 if(!(error=intsmb_stop_poll(dev))){ 312 volatile u_int8_t *addr; 313 addr=bus_space_read_1(sc->st,sc->sh, 314 PIIX4_SMBHSTDAT0); 315 printf("ALART_RESPONSE: %p\n", addr); 316 } 317 }else{ 318 printf("ERROR\n"); 319 } 320 321 /*Re-enable INTR from ALART*/ 322 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 323 slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 324 DELAY(5); 325#endif 326 327 return; 328} 329static void 330intsmb_start(device_t dev,unsigned char cmd,int nointr) 331{ 332 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 333 unsigned char tmp; 334 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 335 tmp&= 0xe0; 336 tmp |= cmd; 337 tmp |=PIIX4_SMBHSTCNT_START; 338 /*While not in autoconfiguration Intrrupt Enabled*/ 339 if(!cold||!nointr) 340 tmp |=PIIX4_SMBHSTCNT_INTREN; 341 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 342} 343 344/*Polling Code. Polling is not encouraged 345 * because It is required to wait for the device get busy. 346 *(29063505.pdf from Intel) 347 * But during boot,intrrupt cannot be used. 348 * so use polling code while in autoconfiguration. 349 */ 350 351static int 352intsmb_stop_poll(device_t dev){ 353 int error,i; 354 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 355 /* 356 * In smbtx driver ,Simply waiting. 357 * This loops 100-200 times. 358 */ 359 for(i=0;i<0x7fff;i++){ 360 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 361 &PIIX4_SMBHSTSTAT_BUSY)){ 362 break; 363 } 364 } 365 for(i=0;i<0x7fff;i++){ 366 int status; 367 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 368 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 369 sc->isbusy=0; 370 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 371 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 372 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 373 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 374 printf("unknown cause why?"); 375 } 376 return error; 377 } 378 } 379 sc->isbusy=0; 380 return EIO; 381} 382/* 383 *wait for completion and return result. 384 */ 385static int 386intsmb_stop(device_t dev){ 387 int error; 388 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 389 if(cold){ 390 /*So that it can use device during probing device on SMBus.*/ 391 error=intsmb_stop_poll(dev); 392 return error; 393 }else{ 394 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 395 int status; 396 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 397 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 398 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 399 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 400 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 401 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 402 printf("intsmb%d:unknown cause why?\n", 403 device_get_unit(dev)); 404 } 405#ifdef ENABLE_ALART 406 bus_space_write_1(sc->st,sc->sh, 407 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 408#endif 409 return error; 410 } 411 } 412 } 413 /*Timeout Procedure*/ 414 sc->isbusy=0; 415 /*Re-enable supressed intrrupt from slave part*/ 416 bus_space_write_1(sc->st,sc->sh, 417 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 418 return EIO; 419} 420 421static int 422intsmb_quick(device_t dev, u_char slave, int how) 423{ 424 int error=0; 425 u_char data; 426 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 427 data=slave; 428 /*Quick command is part of Address, I think*/ 429 switch(how){ 430 case SMB_QWRITE: 431 data&=~LSB; 432 break; 433 case SMB_QREAD: 434 data|=LSB; 435 break; 436 default: 437 error=EINVAL; 438 } 439 if(!error){ 440 error=intsmb_free(dev); 441 if(!error){ 442 bus_space_write_1(sc->st,sc->sh, 443 PIIX4_SMBHSTADD,data); 444 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 445 error=intsmb_stop(dev); 446 } 447 } 448 449 return (error); 450} 451 452static int 453intsmb_sendb(device_t dev, u_char slave, char byte) 454{ 455 int error; 456 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 457 error=intsmb_free(dev); 458 if(!error){ 459 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 460 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 461 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 462 error=intsmb_stop(dev); 463 } 464 return (error); 465} 466static int 467intsmb_recvb(device_t dev, u_char slave, char *byte) 468{ 469 int error; 470 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 471 error=intsmb_free(dev); 472 if(!error){ 473 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 474 |LSB); 475 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 476 if(!(error=intsmb_stop(dev))){ 477#ifdef RECV_IS_IN_CMD 478 /*Linux SMBus stuff also troubles 479 Because Intel's datasheet will not make clear. 480 */ 481 *byte=bus_space_read_1(sc->st,sc->sh, 482 PIIX4_SMBHSTCMD); 483#else 484 *byte=bus_space_read_1(sc->st,sc->sh, 485 PIIX4_SMBHSTDAT0); 486#endif 487 } 488 } 489 return (error); 490} 491static int 492intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 493{ 494 int error; 495 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 496 error=intsmb_free(dev); 497 if(!error){ 498 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 499 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 500 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 501 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 502 error=intsmb_stop(dev); 503 } 504 return (error); 505} 506static int 507intsmb_writew(device_t dev, u_char slave, char cmd, short word) 508{ 509 int error; 510 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 511 error=intsmb_free(dev); 512 if(!error){ 513 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 514 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 515 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 516 word&0xff); 517 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 518 (word>>8)&0xff); 519 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 520 error=intsmb_stop(dev); 521 } 522 return (error); 523} 524 525static int 526intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 527{ 528 int error; 529 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 530 error=intsmb_free(dev); 531 if(!error){ 532 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 533 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 534 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 535 if(!(error=intsmb_stop(dev))){ 536 *byte=bus_space_read_1(sc->st,sc->sh, 537 PIIX4_SMBHSTDAT0); 538 } 539 } 540 return (error); 541} 542static int 543intsmb_readw(device_t dev, u_char slave, char cmd, short *word) 544{ 545 int error; 546 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 547 error=intsmb_free(dev); 548 if(!error){ 549 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 550 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 551 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 552 if(!(error=intsmb_stop(dev))){ 553 *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 554 *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 555 } 556 } 557 return (error); 558} 559/* 560 * Data sheet claims that it implements all function, but also claims 561 * that it implements 7 function and not mention PCALL. So I don't know 562 * whether it will work. 563 */ 564static int 565intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 566{ 567#ifdef PROCCALL_TEST 568 int error; 569 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 570 error=intsmb_free(dev); 571 if(!error){ 572 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 573 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 574 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 575 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 576 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 577 } 578 if(!(error=intsmb_stop(dev))){ 579 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 580 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 581 } 582 return error; 583#else 584 return 0; 585#endif 586} 587static int 588intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 589{ 590 int error,i; 591 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 592 error=intsmb_free(dev); 593 if(count>SMBBLOCKTRANS_MAX||count==0) 594 error=EINVAL; 595 if(!error){ 596 /*Reset internal array index*/ 597 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 598 599 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 600 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 601 for(i=0;i<count;i++){ 602 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 603 } 604 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 605 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 606 error=intsmb_stop(dev); 607 } 608 return (error); 609} 610 611static int 612intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 613{ 614 int error,i; 615 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 616 error=intsmb_free(dev); 617 if(count>SMBBLOCKTRANS_MAX||count==0) 618 error=EINVAL; 619 if(!error){ 620 /*Reset internal array index*/ 621 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 622 623 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 624 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 625 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 626 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 627 error=intsmb_stop(dev); 628 if(!error){ 629 bzero(buf,count);/*Is it needed?*/ 630 count= bus_space_read_1(sc->st,sc->sh, 631 PIIX4_SMBHSTDAT0); 632 if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 633 for(i=0;i<count;i++){ 634 buf[i]=bus_space_read_1(sc->st, 635 sc->sh, 636 PIIX4_SMBBLKDAT); 637 } 638 } 639 else{ 640 error=EIO; 641 } 642 } 643 } 644 return (error); 645} 646 647DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0); 648 649 650static void intpm_intr __P((void *arg)); 651 652static const char* 653intpm_probe (pcici_t tag, pcidi_t type) 654{ 655 struct _pcsid *ep =pci_ids; 656 while (ep->type && ep->type != type) 657 ++ep; 658 return (ep->desc); 659} 660 661static struct intpm_pci_softc *intpm_alloc(int unit){ 662 if(unit<NINTPM) 663 return &intpm_pci[unit]; 664 else 665 return NULL; 666} 667 668/*Same as pci_map_int but this ignores INTPIN*/ 669static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr) 670{ 671#ifdef APIC_IO 672 int nextpin, muxcnt; 673#endif 674 /* Spec sheet claims that it use IRQ 9*/ 675 int irq = 9; 676 void *idesc; 677 678 idesc = inthand_add(NULL, irq, func, arg, maskptr, 0); 679 if (idesc == 0) 680 return 0; 681#ifdef APIC_IO 682 nextpin = next_apic_irq(irq); 683 684 if (nextpin < 0) 685 return 1; 686 687 /* 688 * Attempt handling of some broken mp tables. 689 * 690 * It's OK to yell (since the mp tables are broken). 691 * 692 * Hanging in the boot is not OK 693 */ 694 695 muxcnt = 2; 696 nextpin = next_apic_irq(nextpin); 697 while (muxcnt < 5 && nextpin >= 0) { 698 muxcnt++; 699 nextpin = next_apic_irq(nextpin); 700 } 701 if (muxcnt >= 5) { 702 printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); 703 return 0; 704 } 705 706 printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt); 707 708 nextpin = next_apic_irq(irq); 709 while (nextpin >= 0) { 710 idesc = inthand_add(NULL, nextpin, func, arg, maskptr, 0); 711 if (idesc == 0) 712 return 0; 713 printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); 714 nextpin = next_apic_irq(nextpin); 715 } 716#endif 717 return 1; 718} 719static void 720intpm_attach(config_id, unit) 721 pcici_t config_id; 722 int unit; 723{ 724 int value; 725 726 char * str; 727 { 728 struct intpm_pci_softc *sciic; 729 device_t smbinterface; 730 value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4); 731 sciic=intpm_alloc(unit); 732 if(sciic==NULL){ 733 return; 734 } 735 736 sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM; 737 738 /*Calling pci_map_port is better.But bus_space_handle_t != 739 * pci_port_t, so I don't call support routine while 740 * bus_space_??? support routine will be appear. 741 */ 742 sciic->smbsh=value&(~1); 743 if(sciic->smbsh==I386_BUS_SPACE_MEM){ 744 /*According to the spec, this will not occur*/ 745 int dummy; 746 pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy); 747 } 748 printf("intpm%d: %s %x ",unit, 749 (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory", 750 sciic->smbsh); 751#ifndef NO_CHANGE_PCICONF 752 pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1); 753 pci_cfgwrite(config_id,PCI_HST_CFG_SMB, 754 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 755#endif 756 config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1); 757 printf("ALLOCED IRQ %d ",config_id->intline); 758 value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1); 759 switch(value&0xe){ 760 case PCI_INTR_SMB_SMI: 761 str="SMI"; 762 break; 763 case PCI_INTR_SMB_IRQ9: 764 str="IRQ 9"; 765 break; 766 default: 767 str="BOGUS"; 768 } 769 printf("intr %s %s ",str,((value&1)? "enabled":"disabled")); 770 value=pci_cfgread(config_id,PCI_REVID_SMB,1); 771 printf("revision %d\n",value); 772 /* 773 * Install intr HANDLER here 774 */ 775 if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){ 776 printf("intpm%d: Failed to map intr\n",unit); 777 } 778 smbinterface=device_add_child(root_bus,"intsmb",unit,NULL); 779 device_probe_and_attach(smbinterface); 780 } 781 value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4); 782 printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 783 return; 784} 785static void intpm_intr(void *arg) 786{ 787 struct intpm_pci_softc *sc; 788 sc=(struct intpm_pci_softc *)arg; 789 intsmb_intr(sc->smbus); 790 intsmb_slvintr(sc->smbus); 791} 792#endif /* NPCI > 0 */ 793#endif 794