summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_xl.c
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2000-08-28 20:40:03 +0000
committerwpaul <wpaul@FreeBSD.org>2000-08-28 20:40:03 +0000
commite86657bc59909662a6f245c7d1651597a47ae9c4 (patch)
tree17113dd4f4b529d362b83a8898fc581d5f5353e8 /sys/pci/if_xl.c
parente543d870bc1d0006fc920d88df1ba0b9f144930c (diff)
downloadFreeBSD-src-e86657bc59909662a6f245c7d1651597a47ae9c4.zip
FreeBSD-src-e86657bc59909662a6f245c7d1651597a47ae9c4.tar.gz
Add support for the 3Com 556 and 556B mini-pci adapters used on some
laptops. I've checked that this still works with the other cards and it works with the 3c556 that I have access to, but I want to check that it works with the 556B mentioned in PR #20878 before I close out the PR and merge to -stable.
Diffstat (limited to 'sys/pci/if_xl.c')
-rw-r--r--sys/pci/if_xl.c85
1 files changed, 76 insertions, 9 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
index dc9d319..8f72467 100644
--- a/sys/pci/if_xl.c
+++ b/sys/pci/if_xl.c
@@ -55,6 +55,8 @@
* 3Com 3c980C-TX 10/100Mbps server adapter (Tornado ASIC)
* 3Com 3cSOHO100-TX 10/100Mbps/RJ-45 (Hurricane ASIC)
* 3Com 3c450-TX 10/100Mbps/RJ-45 (Tornado ASIC)
+ * 3Com 3c556 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC)
+ * 3Com 3c556B 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC)
* Dell Optiplex GX1 on-board 3c918 10/100Mbps/RJ-45
* Dell on-board 3c920 10/100Mbps/RJ-45
* Dell Precision on-board 3c905B 10/100Mbps/RJ-45
@@ -186,6 +188,10 @@ static struct xl_type xl_devs[] = {
"3Com 3cSOHO100-TX OfficeConnect" },
{ TC_VENDORID, TC_DEVICEID_TORNADO_HOMECONNECT,
"3Com 3c450-TX HomeConnect" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_556,
+ "3Com 3c556 Fast Etherlink XL" },
+ { TC_VENDORID, TC_DEVICEID_HURRICANE_556B,
+ "3Com 3c556B Fast Etherlink XL" },
{ 0, 0, NULL }
};
@@ -532,6 +538,8 @@ static int xl_miibus_readreg(dev, phy, reg)
struct xl_softc *sc;
struct xl_mii_frame frame;
+ sc = device_get_softc(dev);
+
/*
* Pretend that PHYs are only available at MII address 24.
* This is to guard against problems with certain 3Com ASIC
@@ -539,11 +547,9 @@ static int xl_miibus_readreg(dev, phy, reg)
* control registers at all MII addresses. This can cause
* the miibus code to attach the same PHY several times over.
*/
- if (phy != 24)
+ if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24)
return(0);
- sc = device_get_softc(dev);
-
bzero((char *)&frame, sizeof(frame));
frame.mii_phyaddr = phy;
@@ -560,11 +566,11 @@ static int xl_miibus_writereg(dev, phy, reg, data)
struct xl_softc *sc;
struct xl_mii_frame frame;
- if (phy != 24)
- return(0);
-
sc = device_get_softc(dev);
+ if ((!(sc->xl_flags & XL_FLAG_PHYOK)) && phy != 24)
+ return(0);
+
bzero((char *)&frame, sizeof(frame));
frame.mii_phyaddr = phy;
@@ -686,14 +692,25 @@ static int xl_read_eeprom(sc, dest, off, cnt, swap)
{
int err = 0, i;
u_int16_t word = 0, *ptr;
-
+#define EEPROM_5BIT_OFFSET(A) ((((A) << 2) & 0x7F00) | ((A) & 0x003F))
+ /* WARNING! DANGER!
+ * It's easy to accidentally overwrite the rom content!
+ * Note: the 3c575 uses 8bit EEPROM offsets.
+ */
XL_SEL_WIN(0);
if (xl_eeprom_wait(sc))
return(1);
+ if (sc->xl_flags & XL_FLAG_EEPROM_OFFSET_30)
+ off += 0x30;
+
for (i = 0; i < cnt; i++) {
- CSR_WRITE_2(sc, XL_W0_EE_CMD, XL_EE_READ | (off + i));
+ if (sc->xl_flags & XL_FLAG_8BITROM)
+ CSR_WRITE_2(sc, XL_W0_EE_CMD, (2<<8) | (off + i));
+ else
+ CSR_WRITE_2(sc, XL_W0_EE_CMD,
+ XL_EE_READ | EEPROM_5BIT_OFFSET(off + i));
err = xl_eeprom_wait(sc);
if (err)
break;
@@ -984,7 +1001,8 @@ static void xl_reset(sc)
register int i;
XL_SEL_WIN(0);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET |
+ ((sc->xl_flags & XL_FLAG_WEIRDRESET)?0xFF:0));
for (i = 0; i < XL_TIMEOUT; i++) {
DELAY(10);
@@ -1003,6 +1021,12 @@ static void xl_reset(sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
xl_wait(sc);
+ if (sc->xl_flags & XL_FLAG_WEIRDRESET) {
+ XL_SEL_WIN(2);
+ CSR_WRITE_2(sc, XL_W2_RESET_OPTIONS, CSR_READ_2(sc,
+ XL_W2_RESET_OPTIONS) | 0x4010);
+ }
+
/* Wait a little while for the chip to get its brains in order. */
DELAY(100000);
return;
@@ -1126,6 +1150,8 @@ static void xl_choose_xcvr(sc, verbose)
printf("xl%d: guessing 10baseFL\n", sc->xl_unit);
break;
case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */
+ case TC_DEVICEID_HURRICANE_556: /* 3c556 */
+ case TC_DEVICEID_HURRICANE_556B: /* 3c556B */
sc->xl_media = XL_MEDIAOPT_MII;
sc->xl_xcvr = XL_XCVR_MII;
if (verbose)
@@ -1186,6 +1212,14 @@ static int xl_attach(dev)
sc = device_get_softc(dev);
unit = device_get_unit(dev);
+ sc->xl_flags = 0;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_556 ||
+ pci_get_device(dev) == TC_DEVICEID_HURRICANE_556B)
+ sc->xl_flags |= XL_FLAG_FUNCREG | XL_FLAG_PHYOK |
+ XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_WEIRDRESET;
+ if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_556)
+ sc->xl_flags |= XL_FLAG_8BITROM;
+
/*
* If this is a 3c905B, we have to check one extra thing.
* The 905B supports power management and may be placed in
@@ -1264,12 +1298,31 @@ static int xl_attach(dev)
sc->xl_btag = rman_get_bustag(sc->xl_res);
sc->xl_bhandle = rman_get_bushandle(sc->xl_res);
+ if (sc->xl_flags & XL_FLAG_FUNCREG) {
+ rid = XL_PCI_FUNCMEM;
+ sc->xl_fres = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->xl_fres == NULL) {
+ printf ("xl%d: couldn't map ports/memory\n", unit);
+ bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->xl_ftag = rman_get_bustag(sc->xl_fres);
+ sc->xl_fhandle = rman_get_bushandle(sc->xl_fres);
+ }
+
rid = 0;
sc->xl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (sc->xl_irq == NULL) {
printf("xl%d: couldn't map interrupt\n", unit);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
error = ENXIO;
goto fail;
@@ -1280,6 +1333,9 @@ static int xl_attach(dev)
if (error) {
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
printf("xl%d: couldn't set up irq\n", unit);
goto fail;
@@ -1295,6 +1351,9 @@ static int xl_attach(dev)
printf("xl%d: failed to read station address\n", sc->xl_unit);
bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
error = ENXIO;
goto fail;
@@ -1316,6 +1375,9 @@ static int xl_attach(dev)
printf("xl%d: no memory for list buffers!\n", unit);
bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
error = ENXIO;
goto fail;
@@ -1524,6 +1586,9 @@ static int xl_detach(dev)
bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
+ if (sc->xl_fres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ XL_PCI_FUNCMEM, sc->xl_fres);
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
ifmedia_removeall(&sc->ifmedia);
@@ -2545,6 +2610,7 @@ static void xl_init(xsc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
+ if (sc->xl_flags & XL_FLAG_FUNCREG) bus_space_write_4 (sc->xl_ftag, sc->xl_fhandle, 4, 0x8000);
/* Set the RX early threshold */
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2));
@@ -2814,6 +2880,7 @@ static void xl_stop(sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
+ if (sc->xl_flags & XL_FLAG_FUNCREG) bus_space_write_4 (sc->xl_ftag, sc->xl_fhandle, 4, 0x8000);
/* Stop the stats updater. */
untimeout(xl_stats_update, sc, sc->xl_stat_ch);
OpenPOWER on IntegriCloud