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