X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/c992016af420c18fd3582d99b446c40398a2462d..78195a764d5e70464a6d4f49bc08332a2a8bb4d0:/sys/dev/netif/rl/if_rl.c diff --git a/sys/dev/netif/rl/if_rl.c b/sys/dev/netif/rl/if_rl.c index 102402fe9c..fe4fd63e45 100644 --- a/sys/dev/netif/rl/if_rl.c +++ b/sys/dev/netif/rl/if_rl.c @@ -30,9 +30,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/pci/if_rl.c,v 1.38.2.16 2003/03/05 18:42:33 njl Exp $ - * $DragonFly: src/sys/dev/netif/rl/if_rl.c,v 1.14 2004/07/23 07:16:28 joerg Exp $ - * - * $FreeBSD: src/sys/pci/if_rl.c,v 1.38.2.16 2003/03/05 18:42:33 njl Exp $ + * $DragonFly: src/sys/dev/netif/rl/if_rl.c,v 1.29 2005/11/28 17:13:43 dillon Exp $ */ /* @@ -86,15 +84,22 @@ * to select which interface to use depending on the chip type. */ +#include "opt_polling.h" + #include +#include #include #include #include #include #include +#include #include +#include +#include #include +#include #include #include #include @@ -102,9 +107,6 @@ #include -#include /* for vtophys */ -#include /* for vtophys */ -#include /* for DELAY */ #include #include #include @@ -112,8 +114,8 @@ #include #include -#include "../mii_layer/mii.h" -#include "../mii_layer/miivar.h" +#include +#include #include #include @@ -131,16 +133,22 @@ */ #define RL_USEIOSPACE -#include "if_rlreg.h" +#include /* * Various supported device vendors/types and their names. */ -static struct rl_type rl_devs[] = { +static struct rl_type { + uint16_t rl_vid; + uint16_t rl_did; + const char *rl_name; +} rl_devs[] = { { RT_VENDORID, RT_DEVICEID_8129, "RealTek 8129 10/100BaseTX" }, { RT_VENDORID, RT_DEVICEID_8139, "RealTek 8139 10/100BaseTX" }, + { RT_VENDORID, RT_DEVICEID_8138, + "RealTek 8139 10/100BaseTX CardBus" }, { ACCTON_VENDORID, ACCTON_DEVICEID_5030, "Accton MPX 5030/5038 10/100BaseTX" }, { DELTA_VENDORID, DELTA_DEVICEID_8139, @@ -149,59 +157,70 @@ static struct rl_type rl_devs[] = { "Addtron Technolgy 8139 10/100BaseTX" }, { DLINK_VENDORID, DLINK_DEVICEID_530TXPLUS, "D-Link DFE-530TX+ 10/100BaseTX" }, + { DLINK_VENDORID, DLINK_DEVICEID_690TXD, + "D-Link DFE-690TX 10/100BaseTX" }, { NORTEL_VENDORID, ACCTON_DEVICEID_5030, "Nortel Networks 10/100BaseTX" }, { PEPPERCON_VENDORID, PEPPERCON_DEVICEID_ROLF, "Peppercon AG ROL/F" }, + { COREGA_VENDORID, COREGA_DEVICEID_FETHERCBTXD, + "Corega FEther CB-TXD" }, + { COREGA_VENDORID, COREGA_DEVICEID_FETHERIICBTXD, + "Corega FEtherII CB-TXD" }, + { PLANEX_VENDORID, PLANEX_DEVICEID_FNW3800TX, + "Planex FNW-3800-TX" }, { 0, 0, NULL } }; -static int rl_probe (device_t); -static int rl_attach (device_t); -static int rl_detach (device_t); - -static int rl_encap (struct rl_softc *, struct mbuf * ); - -static void rl_rxeof (struct rl_softc *); -static void rl_txeof (struct rl_softc *); -static void rl_intr (void *); -static void rl_tick (void *); -static void rl_start (struct ifnet *); -static int rl_ioctl (struct ifnet *, u_long, caddr_t, - struct ucred *); -static void rl_init (void *); -static void rl_stop (struct rl_softc *); -static void rl_watchdog (struct ifnet *); -static int rl_suspend (device_t); -static int rl_resume (device_t); -static void rl_shutdown (device_t); -static int rl_ifmedia_upd (struct ifnet *); -static void rl_ifmedia_sts (struct ifnet *, struct ifmediareq *); - -static void rl_eeprom_putbyte (struct rl_softc *, int); -static void rl_eeprom_getword (struct rl_softc *, int, u_int16_t *); -static void rl_read_eeprom (struct rl_softc *, caddr_t, - int, int, int); -static void rl_mii_sync (struct rl_softc *); -static void rl_mii_send (struct rl_softc *, u_int32_t, int); -static int rl_mii_readreg (struct rl_softc *, struct rl_mii_frame *); -static int rl_mii_writereg (struct rl_softc *, struct rl_mii_frame *); - -static int rl_miibus_readreg (device_t, int, int); -static int rl_miibus_writereg (device_t, int, int, int); -static void rl_miibus_statchg (device_t); - -static u_int8_t rl_calchash (caddr_t); -static void rl_setmulti (struct rl_softc *); -static void rl_reset (struct rl_softc *); -static int rl_list_tx_init (struct rl_softc *); +static int rl_probe(device_t); +static int rl_attach(device_t); +static int rl_detach(device_t); + +static int rl_encap(struct rl_softc *, struct mbuf * ); + +static void rl_rxeof(struct rl_softc *); +static void rl_txeof(struct rl_softc *); +static void rl_intr(void *); +static void rl_tick(void *); +static void rl_start(struct ifnet *); +static int rl_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); +static void rl_init(void *); +static void rl_stop (struct rl_softc *); +static void rl_watchdog(struct ifnet *); +static int rl_suspend(device_t); +static int rl_resume(device_t); +static void rl_shutdown(device_t); +static int rl_ifmedia_upd(struct ifnet *); +static void rl_ifmedia_sts(struct ifnet *, struct ifmediareq *); + +static void rl_eeprom_putbyte(struct rl_softc *, int); +static void rl_eeprom_getword(struct rl_softc *, int, uint16_t *); +static void rl_read_eeprom(struct rl_softc *, caddr_t, int, int, int); +static void rl_mii_sync(struct rl_softc *); +static void rl_mii_send(struct rl_softc *, uint32_t, int); +static int rl_mii_readreg(struct rl_softc *, struct rl_mii_frame *); +static int rl_mii_writereg(struct rl_softc *, struct rl_mii_frame *); + +static int rl_miibus_readreg(device_t, int, int); +static int rl_miibus_writereg(device_t, int, int, int); +static void rl_miibus_statchg(device_t); + +static void rl_setmulti(struct rl_softc *); +static void rl_reset(struct rl_softc *); +static void rl_list_tx_init(struct rl_softc *); + +static void rl_dma_map_rxbuf(void *, bus_dma_segment_t *, int, int); +static void rl_dma_map_txbuf(void *, bus_dma_segment_t *, int, int); +#ifdef DEVICE_POLLING +static poll_handler_t rl_poll; +#endif #ifdef RL_USEIOSPACE -#define RL_RES SYS_RES_IOPORT -#define RL_RID RL_PCI_LOIO +#define RL_RES SYS_RES_IOPORT +#define RL_RID RL_PCI_LOIO #else -#define RL_RES SYS_RES_MEMORY -#define RL_RID RL_PCI_LOMEM +#define RL_RES SYS_RES_MEMORY +#define RL_RID RL_PCI_LOMEM #endif static device_method_t rl_methods[] = { @@ -225,66 +244,71 @@ static device_method_t rl_methods[] = { { 0, 0 } }; -static driver_t rl_driver = { - "rl", - rl_methods, - sizeof(struct rl_softc) -}; - +static DEFINE_CLASS_0(rl, rl_driver, rl_methods, sizeof(struct rl_softc)); static devclass_t rl_devclass; DECLARE_DUMMY_MODULE(if_rl); DRIVER_MODULE(if_rl, pci, rl_driver, rl_devclass, 0, 0); +DRIVER_MODULE(if_rl, cardbus, rl_driver, rl_devclass, 0, 0); DRIVER_MODULE(miibus, rl, miibus_driver, miibus_devclass, 0, 0); +MODULE_DEPEND(if_rl, miibus, 1, 1, 1); #define EE_SET(x) \ - CSR_WRITE_1(sc, RL_EECMD, \ - CSR_READ_1(sc, RL_EECMD) | x) + CSR_WRITE_1(sc, RL_EECMD, CSR_READ_1(sc, RL_EECMD) | (x)) #define EE_CLR(x) \ - CSR_WRITE_1(sc, RL_EECMD, \ - CSR_READ_1(sc, RL_EECMD) & ~x) + CSR_WRITE_1(sc, RL_EECMD, CSR_READ_1(sc, RL_EECMD) & ~(x)) + +static void +rl_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct rl_softc *sc = arg; + + CSR_WRITE_4(sc, RL_RXADDR, segs->ds_addr & 0xFFFFFFFF); +} + +static void +rl_dma_map_txbuf(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct rl_softc *sc = arg; + + CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), segs->ds_addr & 0xFFFFFFFF); +} /* * Send a read command and address to the EEPROM, check for ACK. */ -static void rl_eeprom_putbyte(sc, addr) - struct rl_softc *sc; - int addr; +static void +rl_eeprom_putbyte(struct rl_softc *sc, int addr) { - int d, i; + int d, i; - d = addr | RL_EECMD_READ; + d = addr | sc->rl_eecmd_read; /* * Feed in each bit and strobe the clock. */ for (i = 0x400; i; i >>= 1) { - if (d & i) { + if (d & i) EE_SET(RL_EE_DATAIN); - } else { + else EE_CLR(RL_EE_DATAIN); - } DELAY(100); EE_SET(RL_EE_CLK); DELAY(150); EE_CLR(RL_EE_CLK); DELAY(100); } - - return; } /* * Read a word of data stored in the EEPROM at address 'addr.' */ -static void rl_eeprom_getword(sc, addr, dest) - struct rl_softc *sc; - int addr; - u_int16_t *dest; +static void +rl_eeprom_getword(struct rl_softc *sc, int addr, uint16_t *dest) { - int i; - u_int16_t word = 0; + int i; + uint16_t word = 0; /* Enter EEPROM access mode. */ CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); @@ -312,22 +336,16 @@ static void rl_eeprom_getword(sc, addr, dest) CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); *dest = word; - - return; } /* * Read a sequence of words from the EEPROM. */ -static void rl_read_eeprom(sc, dest, off, cnt, swap) - struct rl_softc *sc; - caddr_t dest; - int off; - int cnt; - int swap; +static void +rl_read_eeprom(struct rl_softc *sc, caddr_t dest, int off, int cnt, int swap) { - int i; - u_int16_t word = 0, *ptr; + int i; + u_int16_t word = 0, *ptr; for (i = 0; i < cnt; i++) { rl_eeprom_getword(sc, off + i, &word); @@ -337,8 +355,6 @@ static void rl_read_eeprom(sc, dest, off, cnt, swap) else *ptr = word; } - - return; } @@ -348,21 +364,19 @@ static void rl_read_eeprom(sc, dest, off, cnt, swap) * up by diverting rl_phy_readreg()/rl_phy_writereg() to the * direct access PHY registers. */ -#define MII_SET(x) \ - CSR_WRITE_1(sc, RL_MII, \ - CSR_READ_1(sc, RL_MII) | x) +#define MII_SET(x) \ + CSR_WRITE_1(sc, RL_MII, CSR_READ_1(sc, RL_MII) | x) -#define MII_CLR(x) \ - CSR_WRITE_1(sc, RL_MII, \ - CSR_READ_1(sc, RL_MII) & ~x) +#define MII_CLR(x) \ + CSR_WRITE_1(sc, RL_MII, CSR_READ_1(sc, RL_MII) & ~x) /* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ -static void rl_mii_sync(sc) - struct rl_softc *sc; +static void +rl_mii_sync(struct rl_softc *sc) { - int i; + int i; MII_SET(RL_MII_DIR|RL_MII_DATAOUT); @@ -372,28 +386,23 @@ static void rl_mii_sync(sc) MII_CLR(RL_MII_CLK); DELAY(1); } - - return; } /* * Clock a series of bits through the MII. */ -static void rl_mii_send(sc, bits, cnt) - struct rl_softc *sc; - u_int32_t bits; - int cnt; +static void +rl_mii_send(struct rl_softc *sc, uint32_t bits, int cnt) { - int i; + int i; MII_CLR(RL_MII_CLK); for (i = (0x1 << (cnt - 1)); i; i >>= 1) { - if (bits & i) { + if (bits & i) MII_SET(RL_MII_DATAOUT); - } else { + else MII_CLR(RL_MII_DATAOUT); - } DELAY(1); MII_CLR(RL_MII_CLK); DELAY(1); @@ -404,14 +413,10 @@ static void rl_mii_send(sc, bits, cnt) /* * Read an PHY register through the MII. */ -static int rl_mii_readreg(sc, frame) - struct rl_softc *sc; - struct rl_mii_frame *frame; - +static int +rl_mii_readreg(struct rl_softc *sc, struct rl_mii_frame *frame) { - int i, ack, s; - - s = splimp(); + int ack, i; /* * Set up frame for RX. @@ -465,50 +470,37 @@ static int rl_mii_readreg(sc, frame) MII_SET(RL_MII_CLK); DELAY(1); } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - MII_CLR(RL_MII_CLK); - DELAY(1); - if (!ack) { - if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) - frame->mii_data |= i; + } else { + for (i = 0x8000; i; i >>= 1) { + MII_CLR(RL_MII_CLK); + DELAY(1); + if (!ack) { + if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) + frame->mii_data |= i; + DELAY(1); + } + MII_SET(RL_MII_CLK); DELAY(1); } - MII_SET(RL_MII_CLK); - DELAY(1); } -fail: - MII_CLR(RL_MII_CLK); DELAY(1); MII_SET(RL_MII_CLK); DELAY(1); - splx(s); - - if (ack) - return(1); - return(0); + return(ack ? 1 : 0); } /* * Write to a PHY register through the MII. */ -static int rl_mii_writereg(sc, frame) - struct rl_softc *sc; - struct rl_mii_frame *frame; - +static int +rl_mii_writereg(struct rl_softc *sc, struct rl_mii_frame *frame) { - int s; - - s = splimp(); /* * Set up frame for TX. */ - frame->mii_stdelim = RL_MII_STARTDELIM; frame->mii_opcode = RL_MII_WRITEOP; frame->mii_turnaround = RL_MII_TURNAROUND; @@ -538,19 +530,16 @@ static int rl_mii_writereg(sc, frame) */ MII_CLR(RL_MII_DIR); - splx(s); - return(0); } -static int rl_miibus_readreg(dev, phy, reg) - device_t dev; - int phy, reg; +static int +rl_miibus_readreg(device_t dev, int phy, int reg) { - struct rl_softc *sc; - struct rl_mii_frame frame; - u_int16_t rval = 0; - u_int16_t rl8139_reg = 0; + struct rl_softc *sc; + struct rl_mii_frame frame; + uint16_t rval = 0; + uint16_t rl8139_reg = 0; sc = device_get_softc(dev); @@ -558,7 +547,7 @@ static int rl_miibus_readreg(dev, phy, reg) /* Pretend the internal PHY is only at address 0 */ if (phy) return(0); - switch(reg) { + switch (reg) { case MII_BMCR: rl8139_reg = RL_BMCR; break; @@ -587,16 +576,15 @@ static int rl_miibus_readreg(dev, phy, reg) case RL_MEDIASTAT: rval = CSR_READ_1(sc, RL_MEDIASTAT); return(rval); - break; default: - printf("rl%d: bad phy register\n", sc->rl_unit); + device_printf(dev, "bad phy register\n"); return(0); } rval = CSR_READ_2(sc, rl8139_reg); return(rval); } - bzero((char *)&frame, sizeof(frame)); + bzero(&frame, sizeof(frame)); frame.mii_phyaddr = phy; frame.mii_regaddr = reg; @@ -605,13 +593,12 @@ static int rl_miibus_readreg(dev, phy, reg) return(frame.mii_data); } -static int rl_miibus_writereg(dev, phy, reg, data) - device_t dev; - int phy, reg, data; +static int +rl_miibus_writereg(device_t dev, int phy, int reg, int data) { - struct rl_softc *sc; - struct rl_mii_frame frame; - u_int16_t rl8139_reg = 0; + struct rl_softc *sc; + struct rl_mii_frame frame; + u_int16_t rl8139_reg = 0; sc = device_get_softc(dev); @@ -619,7 +606,7 @@ static int rl_miibus_writereg(dev, phy, reg, data) /* Pretend the internal PHY is only at address 0 */ if (phy) return(0); - switch(reg) { + switch (reg) { case MII_BMCR: rl8139_reg = RL_BMCR; break; @@ -638,16 +625,15 @@ static int rl_miibus_writereg(dev, phy, reg, data) case MII_PHYIDR1: case MII_PHYIDR2: return(0); - break; default: - printf("rl%d: bad phy register\n", sc->rl_unit); + device_printf(dev, "bad phy register\n"); return(0); } CSR_WRITE_2(sc, rl8139_reg, data); return(0); } - bzero((char *)&frame, sizeof(frame)); + bzero(&frame, sizeof(frame)); frame.mii_phyaddr = phy; frame.mii_regaddr = reg; @@ -658,52 +644,23 @@ static int rl_miibus_writereg(dev, phy, reg, data) return(0); } -static void rl_miibus_statchg(dev) - device_t dev; -{ - return; -} - -/* - * Calculate CRC of a multicast group address, return the upper 6 bits. - */ -static u_int8_t rl_calchash(addr) - caddr_t addr; +static void +rl_miibus_statchg(device_t dev) { - u_int32_t crc, carry; - int i, j; - u_int8_t c; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (i = 0; i < 6; i++) { - c = *(addr + i); - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ 0x04c11db6) | carry; - } - } - - /* return the filter bit position */ - return(crc >> 26); } /* * Program the 64-bit multicast hash filter. */ -static void rl_setmulti(sc) - struct rl_softc *sc; +static void +rl_setmulti(struct rl_softc *sc) { - struct ifnet *ifp; - int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; - u_int32_t rxfilt; - int mcnt = 0; + struct ifnet *ifp; + int h = 0; + uint32_t hashes[2] = { 0, 0 }; + struct ifmultiaddr *ifma; + uint32_t rxfilt; + int mcnt = 0; ifp = &sc->arpcom.ac_if; @@ -722,11 +679,12 @@ static void rl_setmulti(sc) CSR_WRITE_4(sc, RL_MAR4, 0); /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + h = ether_crc32_be( + LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + ETHER_ADDR_LEN) >> 26; if (h < 32) hashes[0] |= (1 << h); else @@ -742,14 +700,12 @@ static void rl_setmulti(sc) CSR_WRITE_4(sc, RL_RXCFG, rxfilt); CSR_WRITE_4(sc, RL_MAR0, hashes[0]); CSR_WRITE_4(sc, RL_MAR4, hashes[1]); - - return; } -static void rl_reset(sc) - struct rl_softc *sc; +static void +rl_reset(struct rl_softc *sc) { - int i; + int i; CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); @@ -759,9 +715,7 @@ static void rl_reset(sc) break; } if (i == RL_TIMEOUT) - printf("rl%d: reset never completed!\n", sc->rl_unit); - - return; + device_printf(sc->rl_dev, "reset never completed!\n"); } /* @@ -770,15 +724,18 @@ static void rl_reset(sc) * * Return with a value < 0 to give re(4) a change to attach. */ -static int rl_probe(dev) - device_t dev; +static int +rl_probe(device_t dev) { - struct rl_type *t; + struct rl_type *t; + uint16_t product = pci_get_device(dev); + uint16_t vendor = pci_get_vendor(dev); for (t = rl_devs; t->rl_name != NULL; t++) { - if ((pci_get_vendor(dev) == t->rl_vid) && - (pci_get_device(dev) == t->rl_did)) + if (vendor == t->rl_vid && product == t->rl_did) { + device_set_desc(dev, t->rl_name); return(-100); + } } return(ENXIO); @@ -788,89 +745,49 @@ static int rl_probe(dev) * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */ -static int rl_attach(dev) - device_t dev; +static int +rl_attach(device_t dev) { - int s; - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct rl_softc *sc; - struct ifnet *ifp; - u_int16_t rl_did = 0; - int unit, error = 0, rid; - struct rl_type *t; - - for (t = rl_devs; t->rl_name != NULL; t++) { - if ((pci_get_vendor(dev) == t->rl_vid) && - (pci_get_device(dev) == t->rl_did)) { - device_set_desc(dev, t->rl_name); - break; - } - } - - s = splimp(); + uint8_t eaddr[ETHER_ADDR_LEN]; + uint16_t as[3]; + struct rl_softc *sc; + struct ifnet *ifp; + uint16_t rl_did = 0; + int error = 0, rid, i; sc = device_get_softc(dev); - unit = device_get_unit(dev); - bzero(sc, sizeof(struct rl_softc)); + sc->rl_dev = dev; /* * Handle power management nonsense. */ - command = pci_read_config(dev, RL_PCI_CAPID, 4) & 0x000000FF; - if (command == 0x01) { + if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { + uint32_t iobase, membase, irq; - command = pci_read_config(dev, RL_PCI_PWRMGMTCTRL, 4); - if (command & RL_PSTATE_MASK) { - u_int32_t iobase, membase, irq; + /* Save important PCI config data. */ + iobase = pci_read_config(dev, RL_PCI_LOIO, 4); + membase = pci_read_config(dev, RL_PCI_LOMEM, 4); + irq = pci_read_config(dev, RL_PCI_INTLINE, 4); - /* Save important PCI config data. */ - iobase = pci_read_config(dev, RL_PCI_LOIO, 4); - membase = pci_read_config(dev, RL_PCI_LOMEM, 4); - irq = pci_read_config(dev, RL_PCI_INTLINE, 4); + /* Reset the power state. */ + device_printf(dev, "chip is is in D%d power mode " + "-- setting to D0\n", pci_get_powerstate(dev)); + pci_set_powerstate(dev, PCI_POWERSTATE_D0); - /* Reset the power state. */ - printf("rl%d: chip is is in D%d power mode " - "-- setting to D0\n", unit, command & RL_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_write_config(dev, RL_PCI_PWRMGMTCTRL, command, 4); - - /* Restore PCI config data. */ - pci_write_config(dev, RL_PCI_LOIO, iobase, 4); - pci_write_config(dev, RL_PCI_LOMEM, membase, 4); - pci_write_config(dev, RL_PCI_INTLINE, irq, 4); - } + /* Restore PCI config data. */ + pci_write_config(dev, RL_PCI_LOIO, iobase, 4); + pci_write_config(dev, RL_PCI_LOMEM, membase, 4); + pci_write_config(dev, RL_PCI_INTLINE, irq, 4); } - /* - * Map control/status registers. - */ - command = pci_read_config(dev, PCIR_COMMAND, 4); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_write_config(dev, PCIR_COMMAND, command, 4); - command = pci_read_config(dev, PCIR_COMMAND, 4); - -#ifdef RL_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("rl%d: failed to enable I/O ports!\n", unit); - error = ENXIO; - goto fail; - } -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("rl%d: failed to enable memory mapping!\n", unit); - error = ENXIO; - goto fail; - } -#endif + pci_enable_busmaster(dev); rid = RL_RID; - sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid, - 0, ~0, 1, RF_ACTIVE); + sc->rl_res = bus_alloc_resource_any(dev, RL_RES, &rid, RF_ACTIVE); if (sc->rl_res == NULL) { - printf ("rl%d: couldn't map ports/memory\n", unit); + device_printf(dev, "couldn't map ports/memory\n"); error = ENXIO; goto fail; } @@ -879,37 +796,33 @@ static int rl_attach(dev) sc->rl_bhandle = rman_get_bushandle(sc->rl_res); rid = 0; - sc->rl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, - RF_SHAREABLE | RF_ACTIVE); + sc->rl_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); if (sc->rl_irq == NULL) { - printf("rl%d: couldn't map interrupt\n", unit); - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); + device_printf(dev, "couldn't map interrupt\n"); error = ENXIO; goto fail; } - error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, - rl_intr, sc, &sc->rl_intrhand); - - if (error) { - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); - printf("rl%d: couldn't set up irq\n", unit); - goto fail; - } - - callout_handle_init(&sc->rl_stat_ch); + callout_init(&sc->rl_stat_timer); /* Reset the adapter. */ rl_reset(sc); + sc->rl_eecmd_read = RL_EECMD_READ_6BIT; + rl_read_eeprom(sc, (uint8_t *)&rl_did, 0, 1, 0); + if (rl_did != 0x8129) + sc->rl_eecmd_read = RL_EECMD_READ_8BIT; + /* * Get station address from the EEPROM. */ - rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); - - sc->rl_unit = unit; + rl_read_eeprom(sc, (caddr_t)as, RL_EE_EADDR, 3, 0); + for (i = 0; i < 3; i++) { + eaddr[(i * 2) + 0] = as[i] & 0xff; + eaddr[(i * 2) + 1] = as[i] >> 8; + } /* * Now read the exact device type from the EEPROM to find @@ -919,27 +832,65 @@ static int rl_attach(dev) if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 || rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139 || - rl_did == DLINK_DEVICEID_530TXPLUS) + rl_did == DLINK_DEVICEID_530TXPLUS || rl_did == RT_DEVICEID_8138 || + rl_did == DLINK_DEVICEID_690TXD || + rl_did == COREGA_DEVICEID_FETHERCBTXD || + rl_did == COREGA_DEVICEID_FETHERIICBTXD || + rl_did == PLANEX_DEVICEID_FNW3800TX) sc->rl_type = RL_8139; else if (rl_did == RT_DEVICEID_8129) sc->rl_type = RL_8129; else { - printf("rl%d: unknown device ID: %x\n", unit, rl_did); - bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); + device_printf(dev, "unknown device ID: %x\n", rl_did); error = ENXIO; goto fail; } - sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 1518, M_DEVBUF, - M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); +#define RL_NSEG_NEW 32 + error = bus_dma_tag_create(NULL, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MAXBSIZE, RL_NSEG_NEW, /* maxsize, nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + &sc->rl_parent_tag); - if (sc->rl_cdata.rl_rx_buf == NULL) { - printf("rl%d: no memory for list buffers!\n", unit); - bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); + if (error) { + device_printf(dev, "can't create parent tag\n"); + goto fail; + } + + /* + * Now allocate a tag for the DMA descriptor lists. + * All of our lists are allocated as a contiguous block + * of memory. + */ + error = bus_dma_tag_create(sc->rl_parent_tag, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + RL_RXBUFLEN + 1518, 1, /* maxsize, nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ + 0, /* flags */ + &sc->rl_tag); + + if (error) { + device_printf(dev, "can't create RX tag\n"); + goto fail; + } + + /* + * Now allocate a chunk of DMA-able memory based on the tag + * we just created. + */ + error = bus_dmamem_alloc(sc->rl_tag, (void **)&sc->rl_cdata.rl_rx_buf, + BUS_DMA_WAITOK, &sc->rl_cdata.rl_rx_dmamap); + + if (error) { + device_printf(dev, "can't allocate RX memory!\n"); error = ENXIO; goto fail; } @@ -949,22 +900,16 @@ static int rl_attach(dev) sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t); /* Do MII setup */ - if (mii_phy_probe(dev, &sc->rl_miibus, - rl_ifmedia_upd, rl_ifmedia_sts)) { - printf("rl%d: MII without any phy!\n", sc->rl_unit); - contigfree(sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN + 1518, - M_DEVBUF); - bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); - free(sc->rl_cdata.rl_rx_buf, M_DEVBUF); + if (mii_phy_probe(dev, &sc->rl_miibus, rl_ifmedia_upd, + rl_ifmedia_sts)) { + device_printf(dev, "MII without any phy!\n"); error = ENXIO; goto fail; } ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; - if_initname(ifp, "rl", unit); + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = rl_ioctl; @@ -972,43 +917,73 @@ static int rl_attach(dev) ifp->if_watchdog = rl_watchdog; ifp->if_init = rl_init; ifp->if_baudrate = 10000000; - ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + ifp->if_capabilities = IFCAP_VLAN_MTU; +#ifdef DEVICE_POLLING + ifp->if_poll = rl_poll; +#endif + ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); + ifq_set_ready(&ifp->if_snd); /* * Call MI attach routine. */ - ether_ifattach(ifp, eaddr); + ether_ifattach(ifp, eaddr, NULL); + + error = bus_setup_intr(dev, sc->rl_irq, INTR_NETSAFE, rl_intr, + sc, &sc->rl_intrhand, ifp->if_serializer); + + if (error) { + device_printf(dev, "couldn't set up irq\n"); + ether_ifdetach(ifp); + goto fail; + } + + return(0); fail: - splx(s); + rl_detach(dev); return(error); } -static int rl_detach(dev) - device_t dev; +static int +rl_detach(device_t dev) { - struct rl_softc *sc; - struct ifnet *ifp; - int s; - - s = splimp(); + struct rl_softc *sc; + struct ifnet *ifp; sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; - ether_ifdetach(ifp); - rl_stop(sc); + lwkt_serialize_enter(ifp->if_serializer); + if (device_is_attached(dev)) { + rl_stop(sc); + ether_ifdetach(ifp); + } + + if (sc->rl_miibus) + device_delete_child(dev, sc->rl_miibus); bus_generic_detach(dev); - device_delete_child(dev, sc->rl_miibus); - bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); + if (sc->rl_intrhand) + bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); + + if (sc->rl_irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); + if (sc->rl_res) + bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); - contigfree(sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN + 1518, M_DEVBUF); + if (sc->rl_cdata.rl_rx_buf) { + bus_dmamap_unload(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap); + bus_dmamem_free(sc->rl_tag, sc->rl_cdata.rl_rx_buf, + sc->rl_cdata.rl_rx_dmamap); + } + if (sc->rl_tag) + bus_dma_tag_destroy(sc->rl_tag); + if (sc->rl_parent_tag) + bus_dma_tag_destroy(sc->rl_parent_tag); - splx(s); + lwkt_serialize_exit(ifp->if_serializer); return(0); } @@ -1016,23 +991,21 @@ static int rl_detach(dev) /* * Initialize the transmit descriptors. */ -static int rl_list_tx_init(sc) - struct rl_softc *sc; +static void +rl_list_tx_init(struct rl_softc *sc) { - struct rl_chain_data *cd; - int i; + struct rl_chain_data *cd; + int i; cd = &sc->rl_cdata; for (i = 0; i < RL_TX_LIST_CNT; i++) { cd->rl_tx_chain[i] = NULL; CSR_WRITE_4(sc, - RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000); + RL_TXADDR0 + (i * sizeof(uint32_t)), 0x0000000); } sc->rl_cdata.cur_tx = 0; sc->rl_cdata.last_tx = 0; - - return(0); } /* @@ -1046,7 +1019,7 @@ static int rl_list_tx_init(sc) * attempt to document it here. The driver provides a buffer area and * places its base address in the RX buffer start address register. * The chip then begins copying frames into the RX buffer. Each frame - * is preceeded by a 32-bit RX status word which specifies the length + * is preceded by a 32-bit RX status word which specifies the length * of the frame and certain other status bits. Each frame (starting with * the status word) is also 32-bit aligned. The frame length is in the * first 16 bits of the status word; the lower 15 bits correspond with @@ -1062,21 +1035,22 @@ static int rl_list_tx_init(sc) * bytes of space preceecing it so that it will be safe for us to do the * 2-byte backstep even if reading from the ring at offset 0. */ -static void rl_rxeof(sc) - struct rl_softc *sc; +static void +rl_rxeof(struct rl_softc *sc) { - struct mbuf *m; - struct ifnet *ifp; - int total_len = 0; - u_int32_t rxstat; - caddr_t rxbufpos; - int wrap = 0; - u_int16_t cur_rx; - u_int16_t limit; - u_int16_t rx_bytes = 0, max_bytes; + struct mbuf *m; + struct ifnet *ifp; + int total_len = 0; + uint32_t rxstat; + caddr_t rxbufpos; + int wrap = 0; + uint16_t cur_rx, limit, max_bytes, rx_bytes = 0; ifp = &sc->arpcom.ac_if; + bus_dmamap_sync(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap, + BUS_DMASYNC_POSTREAD); + cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; /* Do not try to read past this point. */ @@ -1096,7 +1070,7 @@ static void rl_rxeof(sc) } #endif /* DEVICE_POLLING */ rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; - rxstat = *(u_int32_t *)rxbufpos; + rxstat = le32toh(*(uint32_t *)rxbufpos); /* * Here's a totally undocumented fact for you. When the @@ -1106,10 +1080,10 @@ static void rl_rxeof(sc) * datasheet makes absolutely no mention of this and * RealTek should be shot for this. */ - if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) + if ((uint16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) break; - if (!(rxstat & RL_RXSTAT_RXOK)) { + if ((rxstat & RL_RXSTAT_RXOK) == 0) { ifp->if_ierrors++; rl_init(sc); return; @@ -1136,7 +1110,7 @@ static void rl_rxeof(sc) break; rxbufpos = sc->rl_cdata.rl_rx_buf + - ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); + ((cur_rx + sizeof(uint32_t)) % RL_RXBUFLEN); if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) rxbufpos = sc->rl_cdata.rl_rx_buf; @@ -1180,21 +1154,19 @@ static void rl_rxeof(sc) ifp->if_ipackets++; - (*ifp->if_input)(ifp, m); + ifp->if_input(ifp, m); } - - return; } /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ -static void rl_txeof(sc) - struct rl_softc *sc; +static void +rl_txeof(struct rl_softc *sc) { - struct ifnet *ifp; - u_int32_t txstat; + struct ifnet *ifp; + uint32_t txstat; ifp = &sc->arpcom.ac_if; @@ -1203,134 +1175,126 @@ static void rl_txeof(sc) * frames that have been uploaded. */ do { + if (RL_LAST_TXMBUF(sc) == NULL) + break; txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc)); - if (!(txstat & (RL_TXSTAT_TX_OK| - RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT))) + if ((txstat & (RL_TXSTAT_TX_OK | RL_TXSTAT_TX_UNDERRUN | + RL_TXSTAT_TXABRT)) == 0) break; ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24; - if (RL_LAST_TXMBUF(sc) != NULL) { - m_freem(RL_LAST_TXMBUF(sc)); - RL_LAST_TXMBUF(sc) = NULL; + bus_dmamap_unload(sc->rl_tag, RL_LAST_DMAMAP(sc)); + bus_dmamap_destroy(sc->rl_tag, RL_LAST_DMAMAP(sc)); + m_freem(RL_LAST_TXMBUF(sc)); + RL_LAST_TXMBUF(sc) = NULL; + RL_INC(sc->rl_cdata.last_tx); + + if (txstat & RL_TXSTAT_TX_UNDERRUN) { + sc->rl_txthresh += 32; + if (sc->rl_txthresh > RL_TX_THRESH_MAX) + sc->rl_txthresh = RL_TX_THRESH_MAX; } - if (txstat & RL_TXSTAT_TX_OK) + + if (txstat & RL_TXSTAT_TX_OK) { ifp->if_opackets++; - else { - int oldthresh; + } else { ifp->if_oerrors++; - if ((txstat & RL_TXSTAT_TXABRT) || - (txstat & RL_TXSTAT_OUTOFWIN)) + if (txstat & (RL_TXSTAT_TXABRT | RL_TXSTAT_OUTOFWIN)) CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); - oldthresh = sc->rl_txthresh; - /* error recovery */ - rl_reset(sc); - rl_init(sc); - /* - * If there was a transmit underrun, - * bump the TX threshold. - */ - if (txstat & RL_TXSTAT_TX_UNDERRUN) - sc->rl_txthresh = oldthresh + 32; - return; } - RL_INC(sc->rl_cdata.last_tx); ifp->if_flags &= ~IFF_OACTIVE; } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx); - ifp->if_timer = - (sc->rl_cdata.last_tx == sc->rl_cdata.cur_tx) ? 0 : 5; - - return; + if (RL_LAST_TXMBUF(sc) == NULL) + ifp->if_timer = 0; + else if (ifp->if_timer == 0) + ifp->if_timer = 5; } -static void rl_tick(xsc) - void *xsc; +static void +rl_tick(void *xsc) { - struct rl_softc *sc; - struct mii_data *mii; - int s; + struct rl_softc *sc = xsc; + struct mii_data *mii; - s = splimp(); + lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); - sc = xsc; mii = device_get_softc(sc->rl_miibus); - mii_tick(mii); - splx(s); + callout_reset(&sc->rl_stat_timer, hz, rl_tick, sc); - sc->rl_stat_ch = timeout(rl_tick, sc, hz); - - return; + lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); } #ifdef DEVICE_POLLING -static poll_handler_t rl_poll; static void -rl_poll (struct ifnet *ifp, enum poll_cmd cmd, int count) +rl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct rl_softc *sc = ifp->if_softc; - if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ - CSR_WRITE_4(sc, RL_IMR, RL_INTRS); - return; - } - - sc->rxcycles = count; - rl_rxeof(sc); - rl_txeof(sc); - if (ifp->if_snd.ifq_head != NULL) - rl_start(ifp); - - if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ - u_int16_t status; - - status = CSR_READ_2(sc, RL_ISR); - if (status) - CSR_WRITE_2(sc, RL_ISR, status); - - /* - * XXX check behaviour on receiver stalls. - */ + switch(cmd) { + case POLL_REGISTER: + /* disable interrupts */ + CSR_WRITE_2(sc, RL_IMR, 0x0000); + break; + case POLL_DEREGISTER: + /* enable interrupts */ + CSR_WRITE_2(sc, RL_IMR, RL_INTRS); + break; + default: + sc->rxcycles = count; + rl_rxeof(sc); + rl_txeof(sc); + if (!ifq_is_empty(&ifp->if_snd)) + rl_start(ifp); + + if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ + uint16_t status; + + status = CSR_READ_2(sc, RL_ISR); + if (status == 0xffff) + return; + if (status) + CSR_WRITE_2(sc, RL_ISR, status); + + /* + * XXX check behaviour on receiver stalls. + */ - if (status & RL_ISR_SYSTEM_ERR) { - rl_reset(sc); - rl_init(sc); + if (status & RL_ISR_SYSTEM_ERR) { + rl_reset(sc); + rl_init(sc); + } } + break; } } #endif /* DEVICE_POLLING */ -static void rl_intr(arg) - void *arg; +static void +rl_intr(void *arg) { - struct rl_softc *sc; - struct ifnet *ifp; - u_int16_t status; + struct rl_softc *sc; + struct ifnet *ifp; + uint16_t status; sc = arg; - if (sc->suspended) { + if (sc->suspended) return; - } ifp = &sc->arpcom.ac_if; -#ifdef DEVICE_POLLING - if (ifp->if_flags & IFF_POLLING) - return; - if (ether_poll_register(rl_poll, ifp)) { /* ok, disable interrupts */ - CSR_WRITE_2(sc, RL_IMR, 0x0000); - rl_poll(ifp, 0, 1); - return; - } -#endif /* DEVICE_POLLING */ for (;;) { - status = CSR_READ_2(sc, RL_ISR); - if (status) + /* If the card has gone away, the read returns 0xffff. */ + if (status == 0xffff) + break; + + if (status != 0) CSR_WRITE_2(sc, RL_ISR, status); if ((status & RL_INTRS) == 0) @@ -1351,41 +1315,31 @@ static void rl_intr(arg) } } - if (ifp->if_snd.ifq_head != NULL) - rl_start(ifp); - return; + if (!ifq_is_empty(&ifp->if_snd)) + rl_start(ifp); } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ -static int rl_encap(sc, m_head) - struct rl_softc *sc; - struct mbuf *m_head; +static int +rl_encap(struct rl_softc *sc, struct mbuf *m_head) { - struct mbuf *m_new = NULL; + struct mbuf *m_new = NULL; /* * The RealTek is brain damaged and wants longword-aligned * TX buffers, plus we can only have one fragment buffer * per packet. We have to copy pretty much all the time. */ + m_new = m_defrag(m_head, MB_DONTWAIT); - MGETHDR(m_new, MB_DONTWAIT, MT_DATA); - if (m_new == NULL) + if (m_new == NULL) { + m_freem(m_head); return(1); - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, MB_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - return(1); - } } - m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); m_head = m_new; /* Pad frames to at least 60 bytes. */ @@ -1412,42 +1366,48 @@ static int rl_encap(sc, m_head) * Main transmit routine. */ -static void rl_start(ifp) - struct ifnet *ifp; +static void +rl_start(struct ifnet *ifp) { - struct rl_softc *sc; - struct mbuf *m_head = NULL; + struct rl_softc *sc; + struct mbuf *m_head = NULL; sc = ifp->if_softc; while(RL_CUR_TXMBUF(sc) == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); + m_head = ifq_dequeue(&ifp->if_snd, NULL); if (m_head == NULL) break; - if (rl_encap(sc, m_head)) { - IF_PREPEND(&ifp->if_snd, m_head); - ifp->if_flags |= IFF_OACTIVE; + if (rl_encap(sc, m_head)) break; - } /* * If there's a BPF listener, bounce a copy of this frame * to him. */ - if (ifp->if_bpf) - bpf_mtap(ifp, RL_CUR_TXMBUF(sc)); + BPF_MTAP(ifp, RL_CUR_TXMBUF(sc)); /* * Transmit the frame. */ - CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), - vtophys(mtod(RL_CUR_TXMBUF(sc), caddr_t))); + bus_dmamap_create(sc->rl_tag, 0, &RL_CUR_DMAMAP(sc)); + bus_dmamap_load(sc->rl_tag, RL_CUR_DMAMAP(sc), + mtod(RL_CUR_TXMBUF(sc), void *), + RL_CUR_TXMBUF(sc)->m_pkthdr.len, + rl_dma_map_txbuf, sc, 0); + bus_dmamap_sync(sc->rl_tag, RL_CUR_DMAMAP(sc), + BUS_DMASYNC_PREREAD); CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc), RL_TXTHRESH(sc->rl_txthresh) | RL_CUR_TXMBUF(sc)->m_pkthdr.len); RL_INC(sc->rl_cdata.cur_tx); + + /* + * Set a timeout in case the chip goes out to lunch. + */ + ifp->if_timer = 5; } /* @@ -1457,25 +1417,15 @@ static void rl_start(ifp) */ if (RL_CUR_TXMBUF(sc) != NULL) ifp->if_flags |= IFF_OACTIVE; - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; } -static void rl_init(xsc) - void *xsc; +static void +rl_init(void *xsc) { - struct rl_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mii_data *mii; - int s, i; - u_int32_t rxcfg = 0; - - s = splimp(); + struct rl_softc *sc = xsc; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mii_data *mii; + uint32_t rxcfg = 0; mii = device_get_softc(sc->rl_miibus); @@ -1484,13 +1434,24 @@ static void rl_init(xsc) */ rl_stop(sc); - /* Init our MAC address */ - for (i = 0; i < ETHER_ADDR_LEN; i++) { - CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); - } + /* + * Init our MAC address. Even though the chipset documentation + * doesn't mention it, we need to enter "Config register write enable" + * mode to modify the ID registers. + */ + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG); + CSR_WRITE_STREAM_4(sc, RL_IDR0, + *(uint32_t *)(&sc->arpcom.ac_enaddr[0])); + CSR_WRITE_STREAM_4(sc, RL_IDR4, + *(uint32_t *)(&sc->arpcom.ac_enaddr[4])); + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); /* Init the RX buffer pointer register. */ - CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); + bus_dmamap_load(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap, + sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN, rl_dma_map_rxbuf, + sc, 0); + bus_dmamap_sync(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap, + BUS_DMASYNC_PREWRITE); /* Init TX descriptors. */ rl_list_tx_init(sc); @@ -1564,21 +1525,17 @@ static void rl_init(xsc) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - (void)splx(s); - - sc->rl_stat_ch = timeout(rl_tick, sc, hz); - - return; + callout_reset(&sc->rl_stat_timer, hz, rl_tick, sc); } /* * Set media options. */ -static int rl_ifmedia_upd(ifp) - struct ifnet *ifp; +static int +rl_ifmedia_upd(struct ifnet *ifp) { - struct rl_softc *sc; - struct mii_data *mii; + struct rl_softc *sc; + struct mii_data *mii; sc = ifp->if_softc; mii = device_get_softc(sc->rl_miibus); @@ -1590,42 +1547,26 @@ static int rl_ifmedia_upd(ifp) /* * Report current media status. */ -static void rl_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; +static void +rl_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { - struct rl_softc *sc; - struct mii_data *mii; - - sc = ifp->if_softc; - mii = device_get_softc(sc->rl_miibus); + struct rl_softc *sc = ifp->if_softc; + struct mii_data *mii = device_get_softc(sc->rl_miibus); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; - - return; } -static int rl_ioctl(ifp, command, data, cr) - struct ifnet *ifp; - u_long command; - caddr_t data; - struct ucred *cr; +static int +rl_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) { - struct rl_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - struct mii_data *mii; - int s, error = 0; - - s = splimp(); + struct rl_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + struct mii_data *mii; + int error = 0; - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; + switch (command) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { rl_init(sc); @@ -1645,84 +1586,83 @@ static int rl_ioctl(ifp, command, data, cr) mii = device_get_softc(sc->rl_miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; + case SIOCSIFCAP: + break; default: - error = EINVAL; + error = ether_ioctl(ifp, command, data); break; } - (void)splx(s); - return(error); } -static void rl_watchdog(ifp) - struct ifnet *ifp; +static void +rl_watchdog(struct ifnet *ifp) { - struct rl_softc *sc; + struct rl_softc *sc = ifp->if_softc; - sc = ifp->if_softc; + device_printf(sc->rl_dev, "watchdog timeout\n"); + + lwkt_serialize_enter(ifp->if_serializer); - printf("rl%d: watchdog timeout\n", sc->rl_unit); ifp->if_oerrors++; rl_txeof(sc); rl_rxeof(sc); rl_init(sc); - return; + lwkt_serialize_exit(ifp->if_serializer); } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ -static void rl_stop(sc) - struct rl_softc *sc; +static void +rl_stop(struct rl_softc *sc) { - int i; - struct ifnet *ifp; + struct ifnet *ifp = &sc->arpcom.ac_if; + int i; - ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; - untimeout(rl_tick, sc, sc->rl_stat_ch); + callout_stop(&sc->rl_stat_timer); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); -#ifdef DEVICE_POLLING - ether_poll_deregister(ifp); -#endif /* DEVICE_POLLING */ CSR_WRITE_1(sc, RL_COMMAND, 0x00); CSR_WRITE_2(sc, RL_IMR, 0x0000); + bus_dmamap_unload(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap); /* * Free the TX list buffers. */ for (i = 0; i < RL_TX_LIST_CNT; i++) { if (sc->rl_cdata.rl_tx_chain[i] != NULL) { + bus_dmamap_unload(sc->rl_tag, + sc->rl_cdata.rl_tx_dmamap[i]); + bus_dmamap_destroy(sc->rl_tag, + sc->rl_cdata.rl_tx_dmamap[i]); m_freem(sc->rl_cdata.rl_tx_chain[i]); sc->rl_cdata.rl_tx_chain[i] = NULL; - CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000); + CSR_WRITE_4(sc, RL_TXADDR0 + (i * sizeof(uint32_t)), + 0x0000000); } } - - - return; } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ -static void rl_shutdown(dev) - device_t dev; +static void +rl_shutdown(device_t dev) { - struct rl_softc *sc; + struct rl_softc *sc; sc = device_get_softc(dev); - + lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); rl_stop(sc); - - return; + lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); } /* @@ -1730,18 +1670,17 @@ static void rl_shutdown(dev) * settings in case the BIOS doesn't restore them properly on * resume. */ -static int rl_suspend(dev) - device_t dev; +static int +rl_suspend(device_t dev) { - int i; - struct rl_softc *sc; - - sc = device_get_softc(dev); + struct rl_softc *sc = device_get_softc(dev); + int i; + lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); rl_stop(sc); for (i = 0; i < 5; i++) - sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4); + sc->saved_maps[i] = pci_read_config(dev, PCIR_BAR(i), 4); sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); @@ -1749,6 +1688,7 @@ static int rl_suspend(dev) sc->suspended = 1; + lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); return (0); } @@ -1757,19 +1697,17 @@ static int rl_suspend(dev) * doesn't, re-enable busmastering, and restart the interface if * appropriate. */ -static int rl_resume(dev) - device_t dev; +static int rl_resume(device_t dev) { + struct rl_softc *sc = device_get_softc(dev); + struct ifnet *ifp = &sc->arpcom.ac_if; int i; - struct rl_softc *sc; - struct ifnet *ifp; - sc = device_get_softc(dev); - ifp = &sc->arpcom.ac_if; + lwkt_serialize_enter(ifp->if_serializer); /* better way to do this? */ for (i = 0; i < 5; i++) - pci_write_config(dev, PCIR_MAPS + i * 4, sc->saved_maps[i], 4); + pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4); pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); @@ -1784,6 +1722,6 @@ static int rl_resume(dev) rl_init(sc); sc->suspended = 0; - + lwkt_serialize_exit(ifp->if_serializer); return (0); }