Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Jan 1999 19:22:20 +0100
From:      Nicolas Souchu <nsouch@teaser.fr>
To:        cvs-committers@FreeBSD.ORG
Subject:   pci power-management code review
Message-ID:  <19990123192220.18873@breizh.prism.uvsq.fr>

next in thread | raw e-mail | index | archive | help

--DocE+STaALJfprDB
Content-Type: text/plain; charset=us-ascii

Hi committers,

I have some new code for the SMBus management of the PIIX4 to commit.

Who may review the attach sequence of the driver? I'm not sure all is
permitted..

Nicholas.

-- 
nsouch@teaser.fr / nsouch@freebsd.org
FreeBSD - Turning PCs into workstations - http://www.FreeBSD.org

--DocE+STaALJfprDB
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="intpm.c"

/*-
 * Copyright (c) 1998, 1999 Takanori Watanabe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	$Id$
 */

#include "pci.h"
#include "intpm.h"

#if NPCI > 0
#if NINTPM >0
/* I don't think the chip is used in other architecture. :-)*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>

#include <machine/bus_pio.h>
#include <machine/bus_memio.h>
#include <machine/bus.h>

#include <machine/clock.h>
#include <sys/uio.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/buf.h>

#include <dev/smbus/smbconf.h>

#include "smbus_if.h"

/*This should be removed if force_pci_map_int supported*/
#include <sys/interrupt.h>

#include <pci/pcireg.h>
#include <pci/pcivar.h>
#include <pci/intpmreg.h>

#include "opt_intpm.h"

static struct _pcsid
{
        pcidi_t type;
	char	*desc;
} pci_ids[] =
{
	{ 0x71138086,"Intel 82371AB Power management controller"},
	
	{ 0x00000000,	NULL					}
};
static int intsmb_probe(device_t);
static int intsmb_attach(device_t);
static void intsmb_print_child(device_t, device_t);

static int intsmb_intr(device_t dev);
static int intsmb_slvintr(device_t dev);
static void  intsmb_alrintr(device_t dev);
static int intsmb_callback(device_t dev, int index, caddr_t data);
static int intsmb_quick(device_t dev, u_char slave, int how);
static int intsmb_sendb(device_t dev, u_char slave, char byte);
static int intsmb_recvb(device_t dev, u_char slave, char *byte);
static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
static void intsmb_start(device_t dev,u_char cmd,int nointr);
static int intsmb_stop(device_t dev);
static int intsmb_stop_poll(device_t dev);
static int intsmb_free(device_t dev);
static struct intpm_pci_softc *intpm_alloc(int unit);
static const char* intpm_probe __P((pcici_t tag, pcidi_t type));
static void intpm_attach __P((pcici_t config_id, int unit));
static devclass_t intsmb_devclass;

static device_method_t intpm_methods[]={
        DEVMETHOD(device_probe,intsmb_probe),
        DEVMETHOD(device_attach,intsmb_attach),

        DEVMETHOD(bus_print_child, intsmb_print_child),
        
        DEVMETHOD(smbus_callback,intsmb_callback),
        DEVMETHOD(smbus_quick,intsmb_quick),
        DEVMETHOD(smbus_sendb,intsmb_sendb),
        DEVMETHOD(smbus_recvb,intsmb_recvb),
        DEVMETHOD(smbus_writeb,intsmb_writeb),
        DEVMETHOD(smbus_writew,intsmb_writew),
        DEVMETHOD(smbus_readb,intsmb_readb),
        DEVMETHOD(smbus_readw,intsmb_readw),
        DEVMETHOD(smbus_pcall,intsmb_pcall),
        DEVMETHOD(smbus_bwrite,intsmb_bwrite),
        DEVMETHOD(smbus_bread,intsmb_bread),
        {0,0}
};

static struct intpm_pci_softc{
        bus_space_tag_t smbst;
        bus_space_handle_t smbsh;
	bus_space_tag_t pmst;
	bus_space_handle_t pmsh;
        pcici_t cfg;
	device_t  smbus;
}intpm_pci[NINTPM];


struct intsmb_softc{
        struct intpm_pci_softc *pci_sc;
        bus_space_tag_t st;
        bus_space_handle_t sh;
        device_t smbus;
        int isbusy;
};
static driver_t intpm_driver = {
        "intsmb",
        intpm_methods,
        DRIVER_TYPE_MISC,
        sizeof(struct intsmb_softc),
};
static u_long intpm_count ;

static struct	pci_device intpm_device = {
	"intpm",
 	intpm_probe,
	intpm_attach,
	&intpm_count
};

DATA_SET (pcidevice_set, intpm_device);

static int 
intsmb_probe(device_t dev)
{
        struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
        sc->smbus=smbus_alloc_bus(dev);
        if (!sc->smbus)
                return (EINVAL);    /* XXX don't know what to return else */
        device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
        
        return (0);          /* XXX don't know what to return else */
}
static int
intsmb_attach(device_t dev)
{
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        sc->pci_sc=&intpm_pci[device_get_unit(dev)];
        sc->isbusy=0;
	sc->sh=sc->pci_sc->smbsh;
	sc->st=sc->pci_sc->smbst;
	sc->pci_sc->smbus=dev;
        device_probe_and_attach(sc->smbus);
#ifdef ENABLE_ALART
	/*Enable Arart*/
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
			  PIIX4_SMBSLVCNT_ALTEN);
#endif 
        return (0);
}

static void
intsmb_print_child(device_t bus, device_t dev)
{
	printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
	return;
}
static int 
intsmb_callback(device_t dev, int index, caddr_t data)
{
	int error = 0;
	intrmask_t s;
	s=splnet();
	switch (index) {
	case SMB_REQUEST_BUS:
		break;
	case SMB_RELEASE_BUS:
		break;
	default:
		error = EINVAL;
	}
	splx(s);
	return (error);
}
/*counterpart of smbtx_smb_free*/
static        int
intsmb_free(device_t dev){
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
	    PIIX4_SMBHSTSTAT_BUSY)
#ifdef ENABLE_ALART
	   ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
	      PIIX4_SMBSLVSTS_BUSY)
#endif
	   || sc->isbusy)
                return EBUSY;
        sc->isbusy=1;
	/*Disable Intrrupt in slave part*/
#ifndef ENABLE_ALART
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
#endif
        /*Reset INTR Flag to prepare INTR*/
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
			  (PIIX4_SMBHSTSTAT_INTR|
			   PIIX4_SMBHSTSTAT_ERR|
			   PIIX4_SMBHSTSTAT_BUSC|
			   PIIX4_SMBHSTSTAT_FAIL)
		);
        return 0;
}

static int
intsmb_intr(device_t dev)
{
	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
	int status;
	intrmask_t s;
	status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
	if(status&PIIX4_SMBHSTSTAT_BUSY){
		return 1;
		
	}
	s=splhigh();
	if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR|
				PIIX4_SMBHSTSTAT_ERR|
				PIIX4_SMBHSTSTAT_BUSC|
				PIIX4_SMBHSTSTAT_FAIL))){
		int tmp;
		sc->isbusy=0;
		tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
		bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
				  tmp&~PIIX4_SMBHSTCNT_INTREN);
		splx(s);
		wakeup(sc);
		return 0;
	}
	splx(s);
	return 1;/* Not Completed*/
}
static int
intsmb_slvintr(device_t dev)
{
	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        int status,retval;
	retval=1;
        status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
	if(status&PIIX4_SMBSLVSTS_BUSY)
		return retval;
	if(status&PIIX4_SMBSLVSTS_ALART){
		intsmb_alrintr(dev);
		retval=0;
	}else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
			  |PIIX4_SMBSLVSTS_SDW1)){
		retval=0;
	}
	/*Reset Status Register*/
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
			  PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
			  PIIX4_SMBSLVSTS_SLV);
	return retval;
}

static void intsmb_alrintr(device_t dev)
{
	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
	int slvcnt;
	/*stop generating INTR from ALART*/
	slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
#ifdef ENABLE_ALART
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
			  slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
#endif
	DELAY(5);
	/*ask bus who assert it and then ask it what's the matter. */	
#ifdef ENABLE_ALART
	error=intsmb_free(dev);
	if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
                                  |LSB);
		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
		if(!(error=intsmb_stop_poll(dev))){
			addr=bus_space_read_1(sc->st,sc->sh,
					      PIIX4_SMBHSTDAT0);
			printf("ALART_RESPONSE: %x\n",(int) addr);
		}
	}else{
	        printf("ERROR\n");
	}

	/*Re-enable INTR from ALART*/
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
			  slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
	DELAY(5);
#endif

	return;
}
static void
intsmb_start(device_t dev,unsigned char cmd,int nointr)
{
	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
	unsigned char tmp;
	tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
	tmp&= 0xe0;
	tmp |= cmd;
	tmp |=PIIX4_SMBHSTCNT_START;
	/*While not in autoconfiguration Intrrupt Enabled*/
	if(!cold||!nointr)
		tmp |=PIIX4_SMBHSTCNT_INTREN;
	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
}

/*Polling Code. Polling is not encouraged 
 * because It is required to wait for the device get busy.
 *(29063505.pdf from Intel)
 * But during boot,intrrupt cannot be used.
 * so use polling code while in autoconfiguration.
 */

static        int
intsmb_stop_poll(device_t dev){
        int error,i;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
	/*
	 *  In smbtx driver ,Simply waiting.
	 *  This loops 100-200 times.
	 */
	for(i=0;i<0x7fff;i++){
                if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
		    &PIIX4_SMBHSTSTAT_BUSY)){
                        break;
                }
	}
	for(i=0;i<0x7fff;i++){
		int status;
		status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
		if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
			sc->isbusy=0;
			error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
				(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
				(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
			if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
				printf("unknown cause why?");
			}
			return error;
		}
	}
	sc->isbusy=0;
	return EIO;
}
/*
 *wait for completion and return result.
 */
static        int
intsmb_stop(device_t dev){
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
	if(cold){
		/*So that it can use device during probing device on SMBus.*/
		error=intsmb_stop_poll(dev);
		return error;
	}else{
		if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
			int status;
			status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
			if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
				error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
					(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
					(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
				if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
					printf("intsmb%d:unknown cause why?\n",
					       device_get_unit(dev));
				}
#ifdef ENABLE_ALART
				bus_space_write_1(sc->st,sc->sh,
						  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
#endif
				return error;
			}
		}
	}
	/*Timeout Procedure*/
	sc->isbusy=0;
	/*Re-enable supressed intrrupt from slave part*/
	bus_space_write_1(sc->st,sc->sh,
			  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
        return EIO;
}

static int
intsmb_quick(device_t dev, u_char slave, int how)
{
        int error=0;
        u_char data;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        data=slave;
	/*Quick command is part of Address, I think*/
        switch(how){
        case SMB_QWRITE:
                data&=~LSB;
		break;
        case SMB_QREAD:
                data|=LSB;
                break;
        default:
                error=EINVAL;
        }
        if(!error){
	        error=intsmb_free(dev);
                if(!error){
                        bus_space_write_1(sc->st,sc->sh,
					  PIIX4_SMBHSTADD,data);
			intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
                        error=intsmb_stop(dev);
                }
        }

        return (error);
}

static int
intsmb_sendb(device_t dev, u_char slave, char byte)
{
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
                error=intsmb_stop(dev);
        }
        return (error);
}
static int
intsmb_recvb(device_t dev, u_char slave, char *byte)
{
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
				  |LSB);
                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
                if(!(error=intsmb_stop(dev))){
#ifdef RECV_IS_IN_CMD
		        /*Linux SMBus stuff also troubles
			  Because Intel's datasheet will not make clear.
			 */
                        *byte=bus_space_read_1(sc->st,sc->sh,
					       PIIX4_SMBHSTCMD);
#else
                        *byte=bus_space_read_1(sc->st,sc->sh,
					       PIIX4_SMBHSTDAT0);
#endif
                }
        }
        return (error);
}
static int
intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
{
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
                error=intsmb_stop(dev);
        }
        return (error);
}
static int
intsmb_writew(device_t dev, u_char slave, char cmd, short word)
{
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
				  word&0xff);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
				  (word>>8)&0xff);
		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
                error=intsmb_stop(dev);
        }
        return (error);
}

static int
intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
{
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
                if(!(error=intsmb_stop(dev))){
		        *byte=bus_space_read_1(sc->st,sc->sh,
					       PIIX4_SMBHSTDAT0);
                }
        }
        return (error);
}
static int
intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
{
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
                if(!(error=intsmb_stop(dev))){
                        *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
                        *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
                }
        }
        return (error);
}
/*
 * Data sheet claims that it implements all function, but also claims
 * that it implements 7 function and not mention PCALL. So I don't know
 * whether it will work.
 */
static int
intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
{
#ifdef PROCCALL_TEST
        int error;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(!error){
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
        }
        if(!(error=intsmb_stop(dev))){
                *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
                *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
        }
        return error;
#else
	return 0;
#endif
}
static int
intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
{
        int error,i;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(count>SMBBLOCKTRANS_MAX||count==0)
                error=EINVAL;
        if(!error){
                /*Reset internal array index*/
                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
		
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
                for(i=0;i<count;i++){
                        bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
                }
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
                error=intsmb_stop(dev);
        }
        return (error);
}

static int
intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
{
        int error,i;
        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
        error=intsmb_free(dev);
        if(count>SMBBLOCKTRANS_MAX||count==0)
                error=EINVAL;
        if(!error){
                /*Reset internal array index*/
                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
		
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
                error=intsmb_stop(dev);
                if(!error){
                        bzero(buf,count);/*Is it needed?*/
                        count= bus_space_read_1(sc->st,sc->sh,
						PIIX4_SMBHSTDAT0);
                        if(count!=0&&count<=SMBBLOCKTRANS_MAX){
			        for(i=0;i<count;i++){
				        buf[i]=bus_space_read_1(sc->st,
								sc->sh,
								PIIX4_SMBBLKDAT);
				}
			}
                        else{
				error=EIO;
                        }
		}
	}
        return (error);
}

DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0);


static void intpm_intr __P((void *arg));

static const char*
intpm_probe (pcici_t tag, pcidi_t type)
{
        struct _pcsid	*ep =pci_ids;
        while (ep->type && ep->type != type)
                ++ep;
        return (ep->desc);
}

static struct intpm_pci_softc *intpm_alloc(int unit){
        if(unit<NINTPM)
                return &intpm_pci[unit];
        else
                return NULL;
}

/*Same as pci_map_int but this ignores INTPIN*/
static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr)
{
        int error;
#ifdef APIC_IO
        int nextpin, muxcnt;
#endif
	/* Spec sheet claims that it use IRQ 9*/
        int irq = 9;
        void *dev_instance = (void *)-1; /* XXX use cfg->devdata        */
        void *idesc;
        
        idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0);
        error = intr_connect(idesc);
        if (error != 0)
                return 0;
#ifdef APIC_IO
        nextpin = next_apic_irq(irq);
        
        if (nextpin < 0)
                return 1;
        
        /* 
         * Attempt handling of some broken mp tables.
         *
         * It's OK to yell (since the mp tables are broken).
         * 
         * Hanging in the boot is not OK
         */
        
        muxcnt = 2;
        nextpin = next_apic_irq(nextpin);
        while (muxcnt < 5 && nextpin >= 0) {
                muxcnt++;
                nextpin = next_apic_irq(nextpin);
        }
        if (muxcnt >= 5) {
                printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
                return 0;
        }
        
        printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt);
        
        nextpin = next_apic_irq(irq);
        while (nextpin >= 0) {
                idesc = intr_create(dev_instance, nextpin, func, arg,
				    maskptr, 0);
                error = intr_connect(idesc);
                if (error != 0)
                        return 0;
                printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq);
                nextpin = next_apic_irq(nextpin);
        }
#endif
        return 1;
}
static void
intpm_attach(config_id, unit)
     pcici_t config_id;
     int	unit;
{
        int value;
        
        char * str;
        {
                struct intpm_pci_softc *sciic;
                device_t smbinterface;
                value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4);
                sciic=intpm_alloc(unit);
                if(sciic==NULL){
                        return;
                }

		sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM;

		/*Calling pci_map_port is better.But bus_space_handle_t != 
		 * pci_port_t, so I don't call support routine while 
		 * bus_space_??? support routine will be appear.
		 */
                sciic->smbsh=value&(~1);
		if(sciic->smbsh==I386_BUS_SPACE_MEM){
		       /*According to the spec, this will not occur*/
                       int dummy;
		       pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy);
		}
                printf("intpm%d: %s %x ",unit,
		       (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory",
		       sciic->smbsh);
#ifndef NO_CHANGE_PCICONF
		pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1);
                pci_cfgwrite(config_id,PCI_HST_CFG_SMB, 
			     PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
#endif
		config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1);
		printf("ALLOCED IRQ %d ",config_id->intline);
                value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1);
                switch(value&0xe){
                case PCI_INTR_SMB_SMI:
                        str="SMI";
                        break;
                case PCI_INTR_SMB_IRQ9:
                        str="IRQ 9";
                        break;
                default:
                        str="BOGUS";
                }
                printf("intr %s %s ",str,((value&1)? "enabled":"disabled"));
                value=pci_cfgread(config_id,PCI_REVID_SMB,1);
                printf("revision %d\n",value);                
                /*
                 * Install intr HANDLER here
                 */
                if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){
                        printf("intpm%d: Failed to map intr\n",unit);
                }
                smbinterface=device_add_child(root_bus,"intsmb",unit,NULL);
                device_probe_and_attach(smbinterface);
        }
        value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4);
        printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
        return;
}
static void intpm_intr(void *arg)
{
        struct intpm_pci_softc *sc;
        sc=(struct intpm_pci_softc *)arg;
	intsmb_intr(sc->smbus);
	intsmb_slvintr(sc->smbus);
}
#endif /* NPCI > 0 */
#endif

--DocE+STaALJfprDB--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe cvs-all" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19990123192220.18873>