intpm.c revision 43288
1/*- 2 * Copyright (c) 1998, 1999 Takanori Watanabe 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: intpm.c,v 1.1 1999/01/24 18:13:31 nsouch Exp $ 27 */ 28 29#include "pci.h" 30#include "intpm.h" 31 32#if NPCI > 0 33#if NINTPM >0 34/* I don't think the chip is used in other architecture. :-)*/ 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38 39#include <machine/bus_pio.h> 40#include <machine/bus_memio.h> 41#include <machine/bus.h> 42 43#include <machine/clock.h> 44#include <sys/uio.h> 45#include <sys/module.h> 46#include <sys/bus.h> 47#include <sys/conf.h> 48#include <sys/malloc.h> 49#include <sys/buf.h> 50 51#include <dev/smbus/smbconf.h> 52 53#include "smbus_if.h" 54 55/*This should be removed if force_pci_map_int supported*/ 56#include <sys/interrupt.h> 57 58#include <pci/pcireg.h> 59#include <pci/pcivar.h> 60#include <pci/intpmreg.h> 61 62#include "opt_intpm.h" 63 64static struct _pcsid 65{ 66 pcidi_t type; 67 char *desc; 68} pci_ids[] = 69{ 70 { 0x71138086,"Intel 82371AB Power management controller"}, 71 72 { 0x00000000, NULL } 73}; 74static int intsmb_probe(device_t); 75static int intsmb_attach(device_t); 76static void intsmb_print_child(device_t, device_t); 77 78static int intsmb_intr(device_t dev); 79static int intsmb_slvintr(device_t dev); 80static void intsmb_alrintr(device_t dev); 81static int intsmb_callback(device_t dev, int index, caddr_t data); 82static int intsmb_quick(device_t dev, u_char slave, int how); 83static int intsmb_sendb(device_t dev, u_char slave, char byte); 84static int intsmb_recvb(device_t dev, u_char slave, char *byte); 85static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 86static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 87static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 88static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 89static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 90static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 91static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 92static void intsmb_start(device_t dev,u_char cmd,int nointr); 93static int intsmb_stop(device_t dev); 94static int intsmb_stop_poll(device_t dev); 95static int intsmb_free(device_t dev); 96static struct intpm_pci_softc *intpm_alloc(int unit); 97static const char* intpm_probe __P((pcici_t tag, pcidi_t type)); 98static void intpm_attach __P((pcici_t config_id, int unit)); 99static devclass_t intsmb_devclass; 100 101static device_method_t intpm_methods[]={ 102 DEVMETHOD(device_probe,intsmb_probe), 103 DEVMETHOD(device_attach,intsmb_attach), 104 105 DEVMETHOD(bus_print_child, intsmb_print_child), 106 107 DEVMETHOD(smbus_callback,intsmb_callback), 108 DEVMETHOD(smbus_quick,intsmb_quick), 109 DEVMETHOD(smbus_sendb,intsmb_sendb), 110 DEVMETHOD(smbus_recvb,intsmb_recvb), 111 DEVMETHOD(smbus_writeb,intsmb_writeb), 112 DEVMETHOD(smbus_writew,intsmb_writew), 113 DEVMETHOD(smbus_readb,intsmb_readb), 114 DEVMETHOD(smbus_readw,intsmb_readw), 115 DEVMETHOD(smbus_pcall,intsmb_pcall), 116 DEVMETHOD(smbus_bwrite,intsmb_bwrite), 117 DEVMETHOD(smbus_bread,intsmb_bread), 118 {0,0} 119}; 120 121static struct intpm_pci_softc{ 122 bus_space_tag_t smbst; 123 bus_space_handle_t smbsh; 124 bus_space_tag_t pmst; 125 bus_space_handle_t pmsh; 126 pcici_t cfg; 127 device_t smbus; 128}intpm_pci[NINTPM]; 129 130 131struct intsmb_softc{ 132 struct intpm_pci_softc *pci_sc; 133 bus_space_tag_t st; 134 bus_space_handle_t sh; 135 device_t smbus; 136 int isbusy; 137}; 138static driver_t intpm_driver = { 139 "intsmb", 140 intpm_methods, 141 DRIVER_TYPE_MISC, 142 sizeof(struct intsmb_softc), 143}; 144static u_long intpm_count ; 145 146static struct pci_device intpm_device = { 147 "intpm", 148 intpm_probe, 149 intpm_attach, 150 &intpm_count 151}; 152 153DATA_SET (pcidevice_set, intpm_device); 154 155static int 156intsmb_probe(device_t dev) 157{ 158 struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); 159 sc->smbus=smbus_alloc_bus(dev); 160 if (!sc->smbus) 161 return (EINVAL); /* XXX don't know what to return else */ 162 device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); 163 164 return (0); /* XXX don't know what to return else */ 165} 166static int 167intsmb_attach(device_t dev) 168{ 169 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 170 sc->pci_sc=&intpm_pci[device_get_unit(dev)]; 171 sc->isbusy=0; 172 sc->sh=sc->pci_sc->smbsh; 173 sc->st=sc->pci_sc->smbst; 174 sc->pci_sc->smbus=dev; 175 device_probe_and_attach(sc->smbus); 176#ifdef ENABLE_ALART 177 /*Enable Arart*/ 178 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 179 PIIX4_SMBSLVCNT_ALTEN); 180#endif 181 return (0); 182} 183 184static void 185intsmb_print_child(device_t bus, device_t dev) 186{ 187 printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 188 return; 189} 190static int 191intsmb_callback(device_t dev, int index, caddr_t data) 192{ 193 int error = 0; 194 intrmask_t s; 195 s=splnet(); 196 switch (index) { 197 case SMB_REQUEST_BUS: 198 break; 199 case SMB_RELEASE_BUS: 200 break; 201 default: 202 error = EINVAL; 203 } 204 splx(s); 205 return (error); 206} 207/*counterpart of smbtx_smb_free*/ 208static int 209intsmb_free(device_t dev){ 210 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 211 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& 212 PIIX4_SMBHSTSTAT_BUSY) 213#ifdef ENABLE_ALART 214 ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& 215 PIIX4_SMBSLVSTS_BUSY) 216#endif 217 || sc->isbusy) 218 return EBUSY; 219 sc->isbusy=1; 220 /*Disable Intrrupt in slave part*/ 221#ifndef ENABLE_ALART 222 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); 223#endif 224 /*Reset INTR Flag to prepare INTR*/ 225 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, 226 (PIIX4_SMBHSTSTAT_INTR| 227 PIIX4_SMBHSTSTAT_ERR| 228 PIIX4_SMBHSTSTAT_BUSC| 229 PIIX4_SMBHSTSTAT_FAIL) 230 ); 231 return 0; 232} 233 234static int 235intsmb_intr(device_t dev) 236{ 237 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 238 int status; 239 intrmask_t s; 240 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 241 if(status&PIIX4_SMBHSTSTAT_BUSY){ 242 return 1; 243 244 } 245 s=splhigh(); 246 if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR| 247 PIIX4_SMBHSTSTAT_ERR| 248 PIIX4_SMBHSTSTAT_BUSC| 249 PIIX4_SMBHSTSTAT_FAIL))){ 250 int tmp; 251 sc->isbusy=0; 252 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 253 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, 254 tmp&~PIIX4_SMBHSTCNT_INTREN); 255 splx(s); 256 wakeup(sc); 257 return 0; 258 } 259 splx(s); 260 return 1;/* Not Completed*/ 261} 262static int 263intsmb_slvintr(device_t dev) 264{ 265 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 266 int status,retval; 267 retval=1; 268 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); 269 if(status&PIIX4_SMBSLVSTS_BUSY) 270 return retval; 271 if(status&PIIX4_SMBSLVSTS_ALART){ 272 intsmb_alrintr(dev); 273 retval=0; 274 }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 275 |PIIX4_SMBSLVSTS_SDW1)){ 276 retval=0; 277 } 278 /*Reset Status Register*/ 279 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| 280 PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| 281 PIIX4_SMBSLVSTS_SLV); 282 return retval; 283} 284 285static void intsmb_alrintr(device_t dev) 286{ 287 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 288 int slvcnt; 289#ifdef ENABLE_ALART 290 int error; 291#endif 292 293 /*stop generating INTR from ALART*/ 294 slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); 295#ifdef ENABLE_ALART 296 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 297 slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; 298#endif 299 DELAY(5); 300 /*ask bus who assert it and then ask it what's the matter. */ 301#ifdef ENABLE_ALART 302 error=intsmb_free(dev); 303 if(!error){ 304 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP 305 |LSB); 306 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); 307 if(!(error=intsmb_stop_poll(dev))){ 308 volatile u_int8_t *addr; 309 addr=bus_space_read_1(sc->st,sc->sh, 310 PIIX4_SMBHSTDAT0); 311 printf("ALART_RESPONSE: %x\n",(int) addr); 312 } 313 }else{ 314 printf("ERROR\n"); 315 } 316 317 /*Re-enable INTR from ALART*/ 318 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, 319 slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; 320 DELAY(5); 321#endif 322 323 return; 324} 325static void 326intsmb_start(device_t dev,unsigned char cmd,int nointr) 327{ 328 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 329 unsigned char tmp; 330 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 331 tmp&= 0xe0; 332 tmp |= cmd; 333 tmp |=PIIX4_SMBHSTCNT_START; 334 /*While not in autoconfiguration Intrrupt Enabled*/ 335 if(!cold||!nointr) 336 tmp |=PIIX4_SMBHSTCNT_INTREN; 337 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); 338} 339 340/*Polling Code. Polling is not encouraged 341 * because It is required to wait for the device get busy. 342 *(29063505.pdf from Intel) 343 * But during boot,intrrupt cannot be used. 344 * so use polling code while in autoconfiguration. 345 */ 346 347static int 348intsmb_stop_poll(device_t dev){ 349 int error,i; 350 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 351 /* 352 * In smbtx driver ,Simply waiting. 353 * This loops 100-200 times. 354 */ 355 for(i=0;i<0x7fff;i++){ 356 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) 357 &PIIX4_SMBHSTSTAT_BUSY)){ 358 break; 359 } 360 } 361 for(i=0;i<0x7fff;i++){ 362 int status; 363 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 364 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 365 sc->isbusy=0; 366 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 367 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 368 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 369 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 370 printf("unknown cause why?"); 371 } 372 return error; 373 } 374 } 375 sc->isbusy=0; 376 return EIO; 377} 378/* 379 *wait for completion and return result. 380 */ 381static int 382intsmb_stop(device_t dev){ 383 int error; 384 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 385 if(cold){ 386 /*So that it can use device during probing device on SMBus.*/ 387 error=intsmb_stop_poll(dev); 388 return error; 389 }else{ 390 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ 391 int status; 392 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); 393 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ 394 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : 395 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: 396 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; 397 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ 398 printf("intsmb%d:unknown cause why?\n", 399 device_get_unit(dev)); 400 } 401#ifdef ENABLE_ALART 402 bus_space_write_1(sc->st,sc->sh, 403 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 404#endif 405 return error; 406 } 407 } 408 } 409 /*Timeout Procedure*/ 410 sc->isbusy=0; 411 /*Re-enable supressed intrrupt from slave part*/ 412 bus_space_write_1(sc->st,sc->sh, 413 PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); 414 return EIO; 415} 416 417static int 418intsmb_quick(device_t dev, u_char slave, int how) 419{ 420 int error=0; 421 u_char data; 422 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 423 data=slave; 424 /*Quick command is part of Address, I think*/ 425 switch(how){ 426 case SMB_QWRITE: 427 data&=~LSB; 428 break; 429 case SMB_QREAD: 430 data|=LSB; 431 break; 432 default: 433 error=EINVAL; 434 } 435 if(!error){ 436 error=intsmb_free(dev); 437 if(!error){ 438 bus_space_write_1(sc->st,sc->sh, 439 PIIX4_SMBHSTADD,data); 440 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); 441 error=intsmb_stop(dev); 442 } 443 } 444 445 return (error); 446} 447 448static int 449intsmb_sendb(device_t dev, u_char slave, char byte) 450{ 451 int error; 452 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 453 error=intsmb_free(dev); 454 if(!error){ 455 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 456 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); 457 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 458 error=intsmb_stop(dev); 459 } 460 return (error); 461} 462static int 463intsmb_recvb(device_t dev, u_char slave, char *byte) 464{ 465 int error; 466 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 467 error=intsmb_free(dev); 468 if(!error){ 469 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave 470 |LSB); 471 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); 472 if(!(error=intsmb_stop(dev))){ 473#ifdef RECV_IS_IN_CMD 474 /*Linux SMBus stuff also troubles 475 Because Intel's datasheet will not make clear. 476 */ 477 *byte=bus_space_read_1(sc->st,sc->sh, 478 PIIX4_SMBHSTCMD); 479#else 480 *byte=bus_space_read_1(sc->st,sc->sh, 481 PIIX4_SMBHSTDAT0); 482#endif 483 } 484 } 485 return (error); 486} 487static int 488intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 489{ 490 int error; 491 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 492 error=intsmb_free(dev); 493 if(!error){ 494 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 495 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 496 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); 497 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 498 error=intsmb_stop(dev); 499 } 500 return (error); 501} 502static int 503intsmb_writew(device_t dev, u_char slave, char cmd, short word) 504{ 505 int error; 506 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 507 error=intsmb_free(dev); 508 if(!error){ 509 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 510 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 511 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, 512 word&0xff); 513 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, 514 (word>>8)&0xff); 515 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 516 error=intsmb_stop(dev); 517 } 518 return (error); 519} 520 521static int 522intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 523{ 524 int error; 525 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 526 error=intsmb_free(dev); 527 if(!error){ 528 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 529 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 530 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); 531 if(!(error=intsmb_stop(dev))){ 532 *byte=bus_space_read_1(sc->st,sc->sh, 533 PIIX4_SMBHSTDAT0); 534 } 535 } 536 return (error); 537} 538static int 539intsmb_readw(device_t dev, u_char slave, char cmd, short *word) 540{ 541 int error; 542 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 543 error=intsmb_free(dev); 544 if(!error){ 545 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 546 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 547 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 548 if(!(error=intsmb_stop(dev))){ 549 *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 550 *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 551 } 552 } 553 return (error); 554} 555/* 556 * Data sheet claims that it implements all function, but also claims 557 * that it implements 7 function and not mention PCALL. So I don't know 558 * whether it will work. 559 */ 560static int 561intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 562{ 563#ifdef PROCCALL_TEST 564 int error; 565 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 566 error=intsmb_free(dev); 567 if(!error){ 568 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 569 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 570 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); 571 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); 572 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); 573 } 574 if(!(error=intsmb_stop(dev))){ 575 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; 576 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; 577 } 578 return error; 579#else 580 return 0; 581#endif 582} 583static int 584intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 585{ 586 int error,i; 587 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 588 error=intsmb_free(dev); 589 if(count>SMBBLOCKTRANS_MAX||count==0) 590 error=EINVAL; 591 if(!error){ 592 /*Reset internal array index*/ 593 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 594 595 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); 596 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 597 for(i=0;i<count;i++){ 598 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); 599 } 600 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 601 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 602 error=intsmb_stop(dev); 603 } 604 return (error); 605} 606 607static int 608intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 609{ 610 int error,i; 611 struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); 612 error=intsmb_free(dev); 613 if(count>SMBBLOCKTRANS_MAX||count==0) 614 error=EINVAL; 615 if(!error){ 616 /*Reset internal array index*/ 617 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); 618 619 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); 620 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); 621 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); 622 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); 623 error=intsmb_stop(dev); 624 if(!error){ 625 bzero(buf,count);/*Is it needed?*/ 626 count= bus_space_read_1(sc->st,sc->sh, 627 PIIX4_SMBHSTDAT0); 628 if(count!=0&&count<=SMBBLOCKTRANS_MAX){ 629 for(i=0;i<count;i++){ 630 buf[i]=bus_space_read_1(sc->st, 631 sc->sh, 632 PIIX4_SMBBLKDAT); 633 } 634 } 635 else{ 636 error=EIO; 637 } 638 } 639 } 640 return (error); 641} 642 643DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0); 644 645 646static void intpm_intr __P((void *arg)); 647 648static const char* 649intpm_probe (pcici_t tag, pcidi_t type) 650{ 651 struct _pcsid *ep =pci_ids; 652 while (ep->type && ep->type != type) 653 ++ep; 654 return (ep->desc); 655} 656 657static struct intpm_pci_softc *intpm_alloc(int unit){ 658 if(unit<NINTPM) 659 return &intpm_pci[unit]; 660 else 661 return NULL; 662} 663 664/*Same as pci_map_int but this ignores INTPIN*/ 665static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr) 666{ 667 int error; 668#ifdef APIC_IO 669 int nextpin, muxcnt; 670#endif 671 /* Spec sheet claims that it use IRQ 9*/ 672 int irq = 9; 673 void *dev_instance = (void *)-1; /* XXX use cfg->devdata */ 674 void *idesc; 675 676 idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); 677 error = intr_connect(idesc); 678 if (error != 0) 679 return 0; 680#ifdef APIC_IO 681 nextpin = next_apic_irq(irq); 682 683 if (nextpin < 0) 684 return 1; 685 686 /* 687 * Attempt handling of some broken mp tables. 688 * 689 * It's OK to yell (since the mp tables are broken). 690 * 691 * Hanging in the boot is not OK 692 */ 693 694 muxcnt = 2; 695 nextpin = next_apic_irq(nextpin); 696 while (muxcnt < 5 && nextpin >= 0) { 697 muxcnt++; 698 nextpin = next_apic_irq(nextpin); 699 } 700 if (muxcnt >= 5) { 701 printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); 702 return 0; 703 } 704 705 printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt); 706 707 nextpin = next_apic_irq(irq); 708 while (nextpin >= 0) { 709 idesc = intr_create(dev_instance, nextpin, func, arg, 710 maskptr, 0); 711 error = intr_connect(idesc); 712 if (error != 0) 713 return 0; 714 printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); 715 nextpin = next_apic_irq(nextpin); 716 } 717#endif 718 return 1; 719} 720static void 721intpm_attach(config_id, unit) 722 pcici_t config_id; 723 int unit; 724{ 725 int value; 726 727 char * str; 728 { 729 struct intpm_pci_softc *sciic; 730 device_t smbinterface; 731 value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4); 732 sciic=intpm_alloc(unit); 733 if(sciic==NULL){ 734 return; 735 } 736 737 sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM; 738 739 /*Calling pci_map_port is better.But bus_space_handle_t != 740 * pci_port_t, so I don't call support routine while 741 * bus_space_??? support routine will be appear. 742 */ 743 sciic->smbsh=value&(~1); 744 if(sciic->smbsh==I386_BUS_SPACE_MEM){ 745 /*According to the spec, this will not occur*/ 746 int dummy; 747 pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy); 748 } 749 printf("intpm%d: %s %x ",unit, 750 (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory", 751 sciic->smbsh); 752#ifndef NO_CHANGE_PCICONF 753 pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1); 754 pci_cfgwrite(config_id,PCI_HST_CFG_SMB, 755 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 756#endif 757 config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1); 758 printf("ALLOCED IRQ %d ",config_id->intline); 759 value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1); 760 switch(value&0xe){ 761 case PCI_INTR_SMB_SMI: 762 str="SMI"; 763 break; 764 case PCI_INTR_SMB_IRQ9: 765 str="IRQ 9"; 766 break; 767 default: 768 str="BOGUS"; 769 } 770 printf("intr %s %s ",str,((value&1)? "enabled":"disabled")); 771 value=pci_cfgread(config_id,PCI_REVID_SMB,1); 772 printf("revision %d\n",value); 773 /* 774 * Install intr HANDLER here 775 */ 776 if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){ 777 printf("intpm%d: Failed to map intr\n",unit); 778 } 779 smbinterface=device_add_child(root_bus,"intsmb",unit,NULL); 780 device_probe_and_attach(smbinterface); 781 } 782 value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4); 783 printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 784 return; 785} 786static void intpm_intr(void *arg) 787{ 788 struct intpm_pci_softc *sc; 789 sc=(struct intpm_pci_softc *)arg; 790 intsmb_intr(sc->smbus); 791 intsmb_slvintr(sc->smbus); 792} 793#endif /* NPCI > 0 */ 794#endif 795