Author: avg
Date: Sat Sep 12 18:24:31 2009
New Revision: 197128
URL: http://svn.freebsd.org/changeset/base/197128

Log:
  intpm: add support for smbus controller found in AMD SB700
  
  According to the specifications AMD/ATI SMBus controller is very
  similar to SMBus controller found in PIIX4.
  Some notable differences:
   o different bit for enabling/signalling regular interrupt mode
   o in practice seems to support only polling mode
  Thus, intpm driver is modified to support polling-only mode
  and to recognize SB700 PCI ID and differences.
  
  Tested on:    SB700 and PIIX4E platforms
  Reviewed by:  jhb
  MFC after:    2 weeks
  X-Perhaps-ToDo:       rename the driver to reflect its function
                and supported hardware

Modified:
  head/sys/pci/intpm.c
  head/sys/pci/intpmreg.h

Modified: head/sys/pci/intpm.c
==============================================================================
--- head/sys/pci/intpm.c        Sat Sep 12 18:16:46 2009        (r197127)
+++ head/sys/pci/intpm.c        Sat Sep 12 18:24:31 2009        (r197128)
@@ -53,6 +53,8 @@ struct intsmb_softc {
        void                    *irq_hand;
        device_t                smbus;
        int                     isbusy;
+       int                     cfg_irq9;
+       int                     poll;
        struct mtx              lock;
 };
 
@@ -96,6 +98,10 @@ intsmb_probe(device_t dev)
 #endif
                device_set_desc(dev, "Intel PIIX4 SMBUS Interface");
                break;
+       case 0x43851002:
+               device_set_desc(dev, "AMD SB600/700/710/750 SMBus Controller");
+               /* XXX Maybe force polling right here? */
+               break;
        default:
                return (ENXIO);
        }
@@ -108,12 +114,24 @@ intsmb_attach(device_t dev)
 {
        struct intsmb_softc *sc = device_get_softc(dev);
        int error, rid, value;
+       int intr;
        char *str;
 
        sc->dev = dev;
 
        mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
 
+       sc->cfg_irq9 = 0;
+#ifndef NO_CHANGE_PCICONF
+       switch (pci_get_devid(dev)) {
+       case 0x71138086:        /* Intel 82371AB */
+       case 0x719b8086:        /* Intel 82443MX */
+               /* Changing configuration is allowed. */
+               sc->cfg_irq9 = 1;
+               break;
+       }
+#endif
+
        rid = PCI_BASE_ADDR_SMB;
        sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
            RF_ACTIVE);
@@ -123,27 +141,36 @@ intsmb_attach(device_t dev)
                goto fail;
        }
 
-#ifndef NO_CHANGE_PCICONF
-       pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
-       pci_write_config(dev, PCI_HST_CFG_SMB,
-           PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
-#endif
+       if (sc->cfg_irq9) {
+               pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
+               pci_write_config(dev, PCI_HST_CFG_SMB,
+                   PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
+       }
        value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
-       switch (value & 0xe) {
+       sc->poll = (value & PCI_INTR_SMB_ENABLE) == 0;
+       intr = value & PCI_INTR_SMB_MASK;
+       switch (intr) {
        case PCI_INTR_SMB_SMI:
                str = "SMI";
                break;
        case PCI_INTR_SMB_IRQ9:
                str = "IRQ 9";
                break;
+       case PCI_INTR_SMB_IRQ_PCI:
+               str = "PCI IRQ";
+               break;
        default:
                str = "BOGUS";
        }
+
        device_printf(dev, "intr %s %s ", str,
-           (value & 1) ? "enabled" : "disabled");
+           sc->poll == 0 ? "enabled" : "disabled");
        printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1));
 
-       if ((value & 0xe) != PCI_INTR_SMB_IRQ9) {
+       if (sc->poll)
+           goto no_intr;
+
+       if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) {
                device_printf(dev, "Unsupported interrupt mode\n");
                error = ENXIO;
                goto fail;
@@ -151,7 +178,9 @@ intsmb_attach(device_t dev)
 
        /* Force IRQ 9. */
        rid = 0;
-       bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
+       if (sc->cfg_irq9)
+               bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
+
        sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
            RF_SHAREABLE | RF_ACTIVE);
        if (sc->irq_res == NULL) {
@@ -167,6 +196,7 @@ intsmb_attach(device_t dev)
                goto fail;
        }
 
+no_intr:
        sc->isbusy = 0;
        sc->smbus = device_add_child(dev, "smbus", -1);
        if (sc->smbus == NULL) {
@@ -361,7 +391,7 @@ intsmb_start(struct intsmb_softc *sc, un
        tmp |= PIIX4_SMBHSTCNT_START;
 
        /* While not in autoconfiguration enable interrupts. */
-       if (!cold && !nointr)
+       if (!sc->poll && !cold && !nointr)
                tmp |= PIIX4_SMBHSTCNT_INTREN;
        bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp);
 }
@@ -411,8 +441,6 @@ intsmb_stop_poll(struct intsmb_softc *sc
                if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
                        sc->isbusy = 0;
                        error = intsmb_error(sc->dev, status);
-                       if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
-                               device_printf(sc->dev, "unknown cause why?\n");
                        return (error);
                }
        }
@@ -434,7 +462,7 @@ intsmb_stop(struct intsmb_softc *sc)
 
        INTSMB_LOCK_ASSERT(sc);
 
-       if (cold)
+       if (sc->poll || cold)
                /* So that it can use device during device probe on SMBus. */
                return (intsmb_stop_poll(sc));
 

Modified: head/sys/pci/intpmreg.h
==============================================================================
--- head/sys/pci/intpmreg.h     Sat Sep 12 18:16:46 2009        (r197127)
+++ head/sys/pci/intpmreg.h     Sat Sep 12 18:24:31 2009        (r197128)
@@ -35,7 +35,9 @@
 #define        PCI_BASE_ADDR_SMB       0x90    /* IO BAR. */
 #define        PCI_BASE_ADDR_PM        0x40
 #define        PCI_HST_CFG_SMB         0xd2    /* Host Configuration */
+#define        PCI_INTR_SMB_MASK       0xe
 #define        PCI_INTR_SMB_SMI        0
+#define        PCI_INTR_SMB_IRQ_PCI    2
 #define        PCI_INTR_SMB_IRQ9       8
 #define        PCI_INTR_SMB_ENABLE     1
 #define        PCI_SLV_CMD_SMB         0xd3 /*SLAVE COMMAND*/
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to