summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_sis.c
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 /sys/pci/if_sis.c
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.
Diffstat (limited to 'sys/pci/if_sis.c')
-rw-r--r--sys/pci/if_sis.c99
1 files changed, 98 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;
}
OpenPOWER on IntegriCloud