summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2001-02-09 00:45:29 +0000
committerwpaul <wpaul@FreeBSD.org>2001-02-09 00:45:29 +0000
commit363bdddf694863339f6629340cfb324771b8ffe7 (patch)
tree1a737128a945d29ccc8893ad9ca9cecab5b2fade
parentf565cff4f149afb29f553dce0077233e2f021145 (diff)
downloadFreeBSD-src-363bdddf694863339f6629340cfb324771b8ffe7.zip
FreeBSD-src-363bdddf694863339f6629340cfb324771b8ffe7.tar.gz
Apply patch to add support for the intergrated ethernet in the SiS630E
chipset. The MAC address is stored in the APC CMOS RAM and we have to commit trememdous evil in order to read it. The code to do this is only activated on the i386 platform. Thanks to Cameron Grant for providing access to a test box for me to tinker with. This will fix the problem where the sis driver ends up with a station address of 00:00:00:00:00:00 on boards that use the 630E chipset.
-rw-r--r--sys/pci/if_sis.c99
-rw-r--r--sys/pci/if_sisreg.h7
2 files changed, 105 insertions, 1 deletions
diff --git a/sys/pci/if_sis.c b/sys/pci/if_sis.c
index ce4b097..b5b96ce 100644
--- a/sys/pci/if_sis.c
+++ b/sys/pci/if_sis.c
@@ -142,6 +142,12 @@ static void sis_eeprom_putbyte __P((struct sis_softc *, int));
static void sis_eeprom_getword __P((struct sis_softc *, int, u_int16_t *));
static void sis_read_eeprom __P((struct sis_softc *, caddr_t, int,
int, int));
+#ifdef __i386__
+static void sis_read_cmos __P((struct sis_softc *, device_t, caddr_t,
+ int, int));
+static device_t sis_find_bridge __P((device_t));
+#endif
+
static int sis_miibus_readreg __P((device_t, int, int));
static int sis_miibus_writereg __P((device_t, int, int, int));
static void sis_miibus_statchg __P((device_t));
@@ -359,6 +365,73 @@ static void sis_read_eeprom(sc, dest, off, cnt, swap)
return;
}
+#ifdef __i386__
+static device_t sis_find_bridge(dev)
+ device_t dev;
+{
+ devclass_t pci_devclass;
+ device_t *pci_devices;
+ int pci_count = 0;
+ device_t *pci_children;
+ int pci_childcount = 0;
+ device_t *busp, *childp;
+ int i, j;
+
+ if ((pci_devclass = devclass_find("pci")) == NULL)
+ return(NULL);
+
+ devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
+
+ for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
+ pci_childcount = 0;
+ device_get_children(*busp, &pci_children, &pci_childcount);
+ for (j = 0, childp = pci_children;
+ j < pci_childcount; j++, childp++) {
+ if (pci_get_vendor(*childp) == SIS_VENDORID &&
+ pci_get_device(*childp) == 0x0008) {
+ free(pci_devices, M_TEMP);
+ free(pci_children, M_TEMP);
+ return(*childp);
+ }
+ }
+ }
+
+ free(pci_devices, M_TEMP);
+ free(pci_children, M_TEMP);
+ return(NULL);
+}
+
+static void sis_read_cmos(sc, dev, dest, off, cnt)
+ struct sis_softc *sc;
+ device_t dev;
+ caddr_t dest;
+ int off;
+ int cnt;
+{
+ device_t bridge;
+ u_int8_t reg;
+ int i;
+ bus_space_tag_t btag;
+
+ bridge = sis_find_bridge(dev);
+ if (bridge == NULL)
+ return;
+ reg = pci_read_config(bridge, 0x48, 1);
+ pci_write_config(bridge, 0x48, reg|0x40, 1);
+
+ /* XXX */
+ btag = I386_BUS_SPACE_IO;
+
+ for (i = 0; i < cnt; i++) {
+ bus_space_write_1(btag, 0x0, 0x70, i + off);
+ *(dest + i) = bus_space_read_1(btag, 0x0, 0x71);
+ }
+
+ pci_write_config(bridge, 0x48, reg & ~0x40, 1);
+ return;
+}
+#endif
+
static int sis_miibus_readreg(dev, phy, reg)
device_t dev;
int phy, reg;
@@ -776,7 +849,31 @@ static int sis_attach(dev)
break;
case SIS_VENDORID:
default:
- sis_read_eeprom(sc, (caddr_t)&eaddr, SIS_EE_NODEADDR, 3, 0);
+#ifdef __i386__
+ /*
+ * If this is a SiS 630E chipset with an embedded
+ * SiS 900 controller, we have to read the MAC address
+ * from the APC CMOS RAM. Our method for doing this
+ * is very ugly since we have to reach out and grab
+ * ahold of hardware for which we cannot properly
+ * allocate resources. This code is only compiled on
+ * the i386 architecture since the SiS 630E chipset
+ * is for x86 motherboards only. Note that there are
+ * a lot of magic numbers in this hack. These are
+ * taken from SiS's Linux driver. I'd like to replace
+ * them with proper symbolic definitions, but that
+ * requires some datasheets that I don't have access
+ * to at the moment.
+ */
+ command = pci_read_config(dev, PCIR_REVID, 1);
+ if (command == SIS_REV_630S ||
+ command == SIS_REV_630E ||
+ command == SIS_REV_630EA1)
+ sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6);
+ else
+#endif
+ sis_read_eeprom(sc, (caddr_t)&eaddr,
+ SIS_EE_NODEADDR, 3, 0);
break;
}
diff --git a/sys/pci/if_sisreg.h b/sys/pci/if_sisreg.h
index d1781b7..96bbd6d 100644
--- a/sys/pci/if_sisreg.h
+++ b/sys/pci/if_sisreg.h
@@ -356,6 +356,13 @@ struct sis_ring_data {
#define SIS_DEVICEID_7016 0x7016
/*
+ * SiS 900 PCI revision codes.
+ */
+#define SIS_REV_630E 0x0081
+#define SIS_REV_630S 0x0082
+#define SIS_REV_630EA1 0x0083
+
+/*
* NatSemi vendor ID
*/
#define NS_VENDORID 0x100B
OpenPOWER on IntegriCloud