The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/piix4smbus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "io.h"
    7 
    8 /*
    9  *      SMBus support for the PIIX4
   10  */
   11 enum
   12 {
   13         IntelVendID=    0x8086,
   14         Piix4PMID=      0x7113,         /* PIIX4 power management function */
   15 
   16         /* SMBus configuration registers (function 3) */
   17         SMBbase=        0x90, /* 4 byte base address (bit 0 == 1, bit 3:1 == 0) */
   18         SMBconfig=      0xd2,
   19         SMBintrselect=  (7<<1),
   20         SMIenable=      (0<<1),         /* interrupts sent to SMI# */
   21         IRQ9enable=     (4<<1),         /* interrupts sent to IRQ9 */
   22         SMBenable=      (1<<0),         /* 1 enables */
   23 
   24         /* SMBus IO space registers */
   25         Hoststatus=     0x0,    /* (writing 1 bits reset the interrupt bits) */
   26         Failed=         (1<<4),         /* transaction terminated by KILL */
   27         Bus_error=      (1<<3),         /* transaction collision */
   28         Dev_error=      (1<<2),         /* device error interrupt */
   29         Host_complete=  (1<<1),         /* host command completion interrupt */
   30         Host_busy=      (1<<0),         /*  */
   31         Slavestatus=    0x1,    /* (writing 1 bits reset) */
   32         Alert_sts=      (1<<5),         /* someone asserted SMBALERT# */
   33         Shdw2_sts=      (1<<4),         /* slave accessed shadow 2 port */
   34         Shdw1_sts=      (1<<3),         /* slave accessed shadow 1 port */
   35         Slv_sts=        (1<<2),         /* slave accessed shadow 1 port */
   36         Slv_bsy=        (1<<0),
   37         Hostcontrol=    0x2,
   38         Start=          (1<<6),         /* start execution */
   39         Cmd_prot=       (7<<2),         /* command protocol mask */
   40         Quick=          (0<<2),         /*  address only */
   41         Byte=           (1<<2),         /*  address + cmd */
   42         ByteData=       (2<<2),         /*  address + cmd + data */
   43         WordData=       (3<<2),         /*  address + cmd + data + data */
   44         Kill=           (1<<1),         /* abort in progress command */
   45         Ienable=        (1<<0),         /* enable completion interrupts */
   46         Hostcommand=    0x3,
   47         Hostaddress=    0x4,
   48         AddressMask=    (0x7f<<1),      /* target address */
   49         Read=           (1<<0),         /* 1 == read, 0 == write */
   50         Hostdata0=      0x5,
   51         Hostdata1=      0x6,
   52         Blockdata=      0x7,
   53         Slavecontrol=   0x8,
   54         Alert_en=       (1<<3), /* enable inter on SMBALERT# */
   55         Shdw2_en=       (1<<2), /* enable inter on external shadow 2 access */
   56         Shdw1_en=       (1<<1), /* enable inter on external shadow 1 access */
   57         Slv_en=         (1<<0), /* enable inter on access of host ctlr slave port */
   58         Shadowcommand=  0x9,
   59         Slaveevent=     0xa,
   60         Slavedata=      0xc,
   61 };
   62 
   63 static struct
   64 {
   65         int     rw;
   66         int     cmd;
   67         int     len;
   68         int     proto;
   69 } proto[] =
   70 {
   71         [SMBquick]      { 0,    0,      0,      Quick },
   72         [SMBsend]       { 0,    1,      0,      Byte },
   73         [SMBbytewrite]  { 0,    1,      1,      ByteData },
   74         [SMBwordwrite]  { 0,    1,      2,      WordData },
   75         [SMBrecv]       { Read, 0,      1,      Byte },
   76         [SMBbyteread]   { Read, 1,      1,      ByteData },
   77         [SMBwordread]   { Read, 1,      2,      WordData },
   78 };
   79 
   80 static void
   81 transact(SMBus *s, int type, int addr, int cmd, uchar *data)
   82 {
   83         int tries, status;
   84         char err[256];
   85 
   86         if(type < 0 || type > nelem(proto))
   87                 panic("piix4smbus: illegal transaction type %d", type);
   88 
   89         if(waserror()){
   90                 qunlock(s);
   91                 nexterror();
   92         }
   93         qlock(s);
   94 
   95         /* wait a while for the host interface to be available */
   96         for(tries = 0; tries < 1000000; tries++){
   97                 if((inb(s->base+Hoststatus) & Host_busy) == 0)
   98                         break;
   99                 sched();
  100         }
  101         if(tries >= 1000000){
  102                 /* try aborting current transaction */
  103                 outb(s->base+Hostcontrol, Kill);
  104                 for(tries = 0; tries < 1000000; tries++){
  105                         if((inb(s->base+Hoststatus) & Host_busy) == 0)
  106                                 break;
  107                         sched();
  108                 }
  109                 if(tries >= 1000000){
  110                         snprint(err, sizeof(err), "SMBus jammed: %2.2ux", inb(s->base+Hoststatus));
  111                         error(err);
  112                 }
  113         }
  114 
  115         /* set up for transaction */
  116         outb(s->base+Hostaddress, (addr<<1)|proto[type].rw);
  117         if(proto[type].cmd)
  118                 outb(s->base+Hostcommand, cmd);
  119         if(proto[type].rw != Read){
  120                 switch(proto[type].len){
  121                 case 2:
  122                         outb(s->base+Hostdata1, data[1]);
  123                         /* fall through */
  124                 case 1:
  125                         outb(s->base+Hostdata0, data[0]);
  126                         break;
  127                 }
  128         }
  129 
  130 
  131         /* reset the completion/error bits and start transaction */
  132         outb(s->base+Hoststatus, Failed|Bus_error|Dev_error|Host_complete);
  133         outb(s->base+Hostcontrol, Start|proto[type].proto);
  134 
  135         /* wait for completion */
  136         status = 0;
  137         for(tries = 0; tries < 1000000; tries++){
  138                 status = inb(s->base+Hoststatus);
  139                 if(status & (Failed|Bus_error|Dev_error|Host_complete))
  140                         break;
  141                 sched();
  142         }
  143         if((status & Host_complete) == 0){
  144                 snprint(err, sizeof(err), "SMBus request failed: %2.2ux", status);
  145                 error(err);
  146         }
  147 
  148         /* get results */
  149         if(proto[type].rw == Read){
  150                 switch(proto[type].len){
  151                 case 2:
  152                         data[1] = inb(s->base+Hostdata1);
  153                         /* fall through */
  154                 case 1:
  155                         data[0] = inb(s->base+Hostdata0);
  156                         break;
  157                 }
  158         }
  159         qunlock(s);
  160         poperror();
  161 }
  162 
  163 static SMBus smbusproto =
  164 {
  165         .transact = transact,
  166 };
  167 
  168 /*
  169  *  return 0 if this is a piix4 with an smbus interface
  170  */
  171 SMBus*
  172 piix4smbus(void)
  173 {
  174         Pcidev *p;
  175         static SMBus *s;
  176 
  177         if(s != nil)
  178                 return s;
  179 
  180         p = pcimatch(nil, IntelVendID, Piix4PMID);
  181         if(p == nil)
  182                 return nil;
  183 
  184         s = smalloc(sizeof(*s));
  185         memmove(s, &smbusproto, sizeof(*s));
  186         s->arg = p;
  187 
  188         /* disable the smbus */
  189         pcicfgw8(p, SMBconfig, IRQ9enable|0);
  190 
  191         /* see if bios gave us a viable port space */
  192         s->base = pcicfgr32(p, SMBbase) & ~1;
  193 print("SMB base from bios is 0x%lux\n", s->base);
  194         if(ioalloc(s->base, 0xd, 0, "piix4smbus") < 0){
  195                 s->base = ioalloc(-1, 0xd, 2, "piix4smbus");
  196                 if(s->base < 0){
  197                         free(s);
  198                         print("piix4smbus: can't allocate io port\n");
  199                         return nil;
  200                 }
  201 print("SMB base ialloc is 0x%lux\n", s->base);
  202                 pcicfgw32(p, SMBbase, s->base|1);
  203         }
  204 
  205         /* disable SMBus interrupts, abort any transaction in progress */
  206         outb(s->base+Hostcontrol, Kill);
  207         outb(s->base+Slavecontrol, 0);
  208 
  209         /* enable the smbus */
  210         pcicfgw8(p, SMBconfig, IRQ9enable|SMBenable);
  211 
  212         return s;
  213 }

Cache object: 2c3044dddfffb55a1a432faeeed65653


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.