diff options
| author | gmcgarry <gmcgarry@NetBSD.org> | 2001-07-01 01:57:29 +0000 |
|---|---|---|
| committer | gmcgarry <gmcgarry@NetBSD.org> | 2001-07-01 01:57:29 +0000 |
| commit | 52f5073f289aaf65c5a3f862dd73f37071a3cbb6 (patch) | |
| tree | a92b916b223a64f0dcdb244c3f64f37f74c9d0ce /sys/dev | |
| parent | a48df4b3553874890a91a088fca0e0e7119430a6 (diff) | |
Jumbo patch:
- data alignment fix
- kludge around broken multicast by using promisc mode
(IPv6 router solicitation now works)
- add support as random source
- support device power-up and power-down
- vlan support
- misc. comment and style fixes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/pcmcia/if_xi.c | 261 | ||||
| -rw-r--r-- | sys/dev/pcmcia/if_xireg.h | 12 |
2 files changed, 201 insertions, 72 deletions
diff --git a/sys/dev/pcmcia/if_xi.c b/sys/dev/pcmcia/if_xi.c index d34769f6bbe..89f732f7df7 100644 --- a/sys/dev/pcmcia/if_xi.c +++ b/sys/dev/pcmcia/if_xi.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_xi.c,v 1.10 2001/06/10 21:53:08 gmcgarry Exp $ */ +/* $NetBSD: if_xi.c,v 1.11 2001/07/01 01:57:29 gmcgarry Exp $ */ /* OpenBSD: if_xe.c,v 1.9 1999/09/16 11:28:42 niklas Exp */ /* @@ -59,6 +59,11 @@ #include <sys/malloc.h> #include <sys/socket.h> +#include "rnd.h" +#if NRND > 0 +#include <sys/rnd.h> +#endif + #include <net/if.h> #include <net/if_dl.h> #include <net/if_media.h> @@ -105,8 +110,6 @@ #include <dev/pcmcia/pcmciavar.h> #include <dev/pcmcia/pcmciadevs.h> -#define XI_IOSIZ 16 - #include <dev/pcmcia/if_xireg.h> #ifdef __GNUC__ @@ -155,6 +158,9 @@ struct xi_softc { u_int32_t sc_flags; /* Misc. flags */ int sc_all_mcasts; /* Receive all multicasts */ u_int8_t sc_enaddr[ETHER_ADDR_LEN]; +#if NRND > 0 + rndsource_element_t sc_rnd_source; +#endif }; struct xi_pcmcia_softc { @@ -165,16 +171,20 @@ struct xi_pcmcia_softc { struct pcmcia_io_handle sc_pcioh; /* iospace info */ int sc_io_window; /* io window info */ void *sc_ih; /* Interrupt handler */ - + void *sc_powerhook; /* power hook descriptor */ int sc_resource; /* resource allocated */ #define XI_RES_PCIC 1 -#define XI_RES_IO 2 +#define XI_RES_IO_ALLOC 2 +#define XI_RES_IO_MAP 4 #define XI_RES_MI 8 }; struct cfattach xi_pcmcia_ca = { - sizeof(struct xi_pcmcia_softc), xi_pcmcia_match, xi_pcmcia_attach, - xi_pcmcia_detach, xi_pcmcia_activate + sizeof(struct xi_pcmcia_softc), + xi_pcmcia_match, + xi_pcmcia_attach, + xi_pcmcia_detach, + xi_pcmcia_activate }; static int xi_pcmcia_cis_quirks __P((struct pcmcia_function *)); @@ -200,6 +210,9 @@ static void xi_stop __P((struct xi_softc *)); static void xi_watchdog __P((struct ifnet *)); const struct xi_pcmcia_product *xi_pcmcia_identify __P((struct device *, struct pcmcia_attach_args *)); +static int xi_pcmcia_enable __P((struct xi_pcmcia_softc *)); +static void xi_pcmcia_disable __P((struct xi_pcmcia_softc *)); +static void xi_pcmcia_power __P((int, void *)); /* flags */ #define XIFLAGS_MOHAWK 0x001 /* 100Mb capabilities (has phy) */ @@ -292,9 +305,8 @@ xi_pcmcia_identify(dev, pa) } /* - * If someone can determine which manufacturers/products require cis_quirks, - * then the proper infrastucture can be used. Until then... - * This also becomes a pain with detaching. + * The quirks are done here instead of the traditional framework because + * of the difficulty in identifying the devices. */ static int xi_pcmcia_cis_quirks(pf) @@ -382,32 +394,26 @@ xi_pcmcia_attach(parent, self, aux) psc->sc_resource |= XI_RES_PCIC; /* allocate/map ISA I/O space */ - if (pcmcia_io_alloc(psc->sc_pf, 0, XI_IOSIZ, XI_IOSIZ, + if (pcmcia_io_alloc(psc->sc_pf, 0, XI_IOSIZE, XI_IOSIZE, &psc->sc_pcioh) != 0) { - printf(": i/o allocation failed\n"); - goto fail; - } - if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_IO16, 0, XI_IOSIZ, - &psc->sc_pcioh, &psc->sc_io_window)) { - printf(": can't map i/o space\n"); + printf(": I/O allocation failed\n"); goto fail; } + psc->sc_resource |= XI_RES_IO_ALLOC; + sc->sc_bst = psc->sc_pcioh.iot; sc->sc_bsh = psc->sc_pcioh.ioh; sc->sc_offset = 0; - psc->sc_resource |= XI_RES_IO; - xpp = xi_pcmcia_identify(parent,pa); - if (xpp == NULL) { - printf(": unrecognised model\n"); - return; + if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_AUTO, 0, XI_IOSIZE, + &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map I/O space\n"); + goto fail; } - sc->sc_flags = xpp->xpp_flags; - - printf(": %s\n", xpp->xpp_name); + psc->sc_resource |= XI_RES_IO_MAP; /* - * Configuration as adviced by DINGO documentation. + * Configuration as advised by DINGO documentation. * Dingo has some extra configuration registers in the CCR space. */ if (sc->sc_flags & XIFLAGS_DINGO) { @@ -415,12 +421,12 @@ xi_pcmcia_attach(parent, self, aux) int ccr_window; bus_addr_t ccr_offset; + /* get access to the DINGO CCR space */ if (pcmcia_mem_alloc(psc->sc_pf, PCMCIA_CCR_SIZE_DINGO, &pcmh)) { DPRINTF(XID_CONFIG, ("xi: bad mem alloc\n")); goto fail; } - if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, psc->sc_pf->ccr_base, PCMCIA_CCR_SIZE_DINGO, &pcmh, &ccr_offset, &ccr_window)) { @@ -429,6 +435,7 @@ xi_pcmcia_attach(parent, self, aux) goto fail; } + /* enable the second function - usually modem */ bus_space_write_1(pcmh.memt, pcmh.memh, ccr_offset + PCMCIA_CCR_DCOR0, PCMCIA_CCR_DCOR0_SFINT); bus_space_write_1(pcmh.memt, pcmh.memh, @@ -446,8 +453,17 @@ xi_pcmcia_attach(parent, self, aux) pcmcia_mem_free(psc->sc_pf, &pcmh); } + xpp = xi_pcmcia_identify(parent,pa); + if (xpp == NULL) { + printf(": unrecognised model\n"); + return; + } + sc->sc_flags = xpp->xpp_flags; + + printf(": %s\n", xpp->xpp_name); + /* - * Try to get the ethernet address from FUNCE/LAN_NID tuple. + * Get the ethernet address from FUNCE/LAN_NID tuple. */ xi_pcmcia_funce_enaddr(parent, sc->sc_enaddr); if (!sc->sc_enaddr) { @@ -490,13 +506,18 @@ xi_pcmcia_attach(parent, self, aux) NULL); ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO); - /* - * Attach the interface. - */ + /* 802.1q capability */ + sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; + /* Attach the interface. */ if_attach(ifp); ether_ifattach(ifp, sc->sc_enaddr); psc->sc_resource |= XI_RES_MI; +#if NRND > 0 + rnd_attach_source(&sc->sc_rnd_source, sc->sc_dev.dv_xname, + RND_TYPE_NET, 0); +#endif + /* * Reset and initialize the card again for DINGO (as found in Linux * driver). Without this Dingo will get a watchdog timeout the first @@ -511,23 +532,22 @@ xi_pcmcia_attach(parent, self, aux) xi_stop(sc); } - /* Establish the interrupt. */ - psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, xi_intr, sc); - if (psc->sc_ih == NULL) { - printf("%s: couldn't establish interrupt\n", - sc->sc_dev.dv_xname); - goto fail; - } + psc->sc_powerhook = powerhook_establish(xi_pcmcia_power, sc); + + pcmcia_function_disable(psc->sc_pf); + psc->sc_resource &= ~XI_RES_PCIC; return; fail: - if ((psc->sc_resource & XI_RES_IO) != 0) { - /* Unmap our i/o windows. */ + if ((psc->sc_resource & XI_RES_IO_MAP) != 0) { pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); - pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); + psc->sc_resource &= ~XI_RES_IO_MAP; + } + if ((psc->sc_resource & XI_RES_IO_ALLOC) != 0) { + pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); + psc->sc_resource &= ~XI_RES_IO_ALLOC; } - psc->sc_resource &= ~XI_RES_IO; if (psc->sc_resource & XI_RES_PCIC) { pcmcia_function_disable(pa->pf); psc->sc_resource &= ~XI_RES_PCIC; @@ -546,34 +566,32 @@ xi_pcmcia_detach(self, flags) DPRINTF(XID_CONFIG, ("xi_pcmcia_detach()\n")); - if ((ifp->if_flags & IFF_RUNNING) == 0) { - xi_stop(sc); - } + if (psc->sc_powerhook != NULL) + powerhook_disestablish(psc->sc_powerhook); - pcmcia_function_disable(psc->sc_pf); - psc->sc_resource &= ~XI_RES_PCIC; - pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_timer = 0; +#if NRND > 0 + rnd_detach_source(&sc->sc_rnd_source); +#endif if ((psc->sc_resource & XI_RES_MI) != 0) { - mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY); - ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY); - ether_ifdetach(ifp); if_detach(ifp); psc->sc_resource &= ~XI_RES_MI; } - - if ((psc->sc_resource & XI_RES_IO) != 0) { - /* Unmap our i/o windows. */ + if (psc->sc_resource & XI_RES_IO_MAP) { pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); + psc->sc_resource &= ~XI_RES_IO_MAP; + } + if ((psc->sc_resource & XI_RES_IO_ALLOC) != 0) { pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); + psc->sc_resource &= ~XI_RES_IO_ALLOC; } + + xi_pcmcia_disable(psc); + free(SIMPLEQ_FIRST(&psc->sc_pf->cfe_head), M_DEVBUF); - psc->sc_resource &= ~XI_RES_IO; return 0; } @@ -603,6 +621,85 @@ xi_pcmcia_activate(self, act) return (rv); } +static int +xi_pcmcia_enable(psc) + struct xi_pcmcia_softc *psc; +{ + struct xi_softc *sc = &psc->sc_xi; + + DPRINTF(XID_CONFIG,("xi_pcmcia_enable()\n")); + + /* establish the interrupt. */ + psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, xi_intr, sc); + if (psc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + return (1); + } + + if (pcmcia_function_enable(psc->sc_pf)) { + pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); + return (1); + } + psc->sc_resource |= XI_RES_PCIC; + + xi_full_reset(sc); + + return (0); +} + + +static void +xi_pcmcia_disable(psc) + struct xi_pcmcia_softc *psc; +{ + DPRINTF(XID_CONFIG,("xi_pcmcia_disable()\n")); + + if (psc->sc_resource & XI_RES_PCIC) { + pcmcia_function_disable(psc->sc_pf); + pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); + psc->sc_resource &= ~XI_RES_PCIC; + } +} + + +static void +xi_pcmcia_power(why, arg) + int why; + void *arg; +{ + struct xi_pcmcia_softc *psc = arg; + struct xi_softc *sc = &psc->sc_xi; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + int s; + + DPRINTF(XID_CONFIG,("xi_pcmcia_power()\n")); + + s = splnet(); + + switch (why) { + case PWR_SUSPEND: + case PWR_STANDBY: + if (ifp->if_flags & IFF_RUNNING) { + xi_stop(sc); + } + ifp->if_flags &= ~IFF_RUNNING; + ifp->if_timer = 0; + break; + case PWR_RESUME: + if ((ifp->if_flags & IFF_RUNNING) == 0) { + xi_init(sc); + } + ifp->if_flags |= IFF_RUNNING; + break; + case PWR_SOFTSUSPEND: + case PWR_SOFTSTANDBY: + case PWR_SOFTRESUME: + break; + } + splx(s); +} + /* * XXX These two functions might be OK to factor out into pcmcia.c since * if_sm_pcmcia.c uses similar ones. @@ -683,8 +780,6 @@ xi_pcmcia_manfid_ciscallback(tuple, arg) return (1); } - - static int xi_intr(arg) void *arg; @@ -729,7 +824,7 @@ xi_intr(arg) rx_status = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RXST0); tx_status = - bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0); + bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0); /* * XXX Linux writes to RXST0 and TXST* here. My CE2 works just fine @@ -805,6 +900,11 @@ end: bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR, ENABLE_INT); + /* have handled the interrupt */ +#if NRND > 0 + rnd_add_uint32(&sc->sc_rnd_source, tx_status); +#endif + return (1); } @@ -1141,11 +1241,15 @@ static void xi_init(sc) struct xi_softc *sc; { + struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)sc; struct ifnet *ifp = &sc->sc_ethercom.ec_if; int s; DPRINTF(XID_CONFIG, ("xi_init()\n")); + if ((psc->sc_resource & XI_RES_PCIC) == 0) + xi_pcmcia_enable(psc); + s = splnet(); xi_set_address(sc); @@ -1307,7 +1411,8 @@ xi_ioctl(ifp, command, data) u_long command; caddr_t data; { - struct xi_softc *sc = ifp->if_softc; + struct xi_pcmcia_softc *psc = ifp->if_softc; + struct xi_softc *sc = &psc->sc_xi; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; @@ -1343,6 +1448,7 @@ xi_ioctl(ifp, command, data) xi_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { + xi_pcmcia_disable(psc); xi_stop(sc); ifp->if_flags &= ~IFF_RUNNING; } @@ -1396,21 +1502,30 @@ xi_set_address(sc) bus_space_handle_t bsh = sc->sc_bsh; bus_addr_t offset = sc->sc_offset; struct ethercom *ether = &sc->sc_ethercom; - struct ether_multi *enm; - struct ether_multistep step; +#if 0 struct ifnet *ifp = &sc->sc_ethercom.ec_if; - int i, page, pos, num; +#endif +#if WORKING_MULTICAST + struct ether_multistep step; + struct ether_multi *enm; + int page, pos, num; +#endif + int i; DPRINTF(XID_CONFIG, ("xi_set_address()\n")); PAGE(sc, 0x50); - for (i = 0; i < 6; i++) { + for (i = 0; i < ETHER_ADDR_LEN; i++) { bus_space_write_1(bst, bsh, offset + IA + i, sc->sc_enaddr[(sc->sc_flags & XIFLAGS_MOHAWK) ? 5-i : i]); } - + if (ether->ec_multicnt > 0) { +#ifdef WORKING_MULTICAST if (ether->ec_multicnt > 9) { +#else + { +#endif PAGE(sc, 0x42); bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + SWC1, @@ -1418,6 +1533,8 @@ xi_set_address(sc) return; } +#ifdef WORKING_MULTICAST + ETHER_FIRST_MULTI(step, ether, enm); pos = IA + 6; @@ -1430,12 +1547,15 @@ xi_set_address(sc) * it's easier just to accept all multicasts. * XXX should we be setting IFF_ALLMULTI here? */ +#if 0 ifp->if_flags |= IFF_ALLMULTI; +#endif sc->sc_all_mcasts=1; break; } - for (i = 0; i < 6; i++) { + for (i = 0; i < ETHER_ADDR_LEN; i++) { + printf("%x:", enm->enm_addrlo[i]); bus_space_write_1(bst, bsh, offset + pos, enm->enm_addrlo[ (sc->sc_flags & XIFLAGS_MOHAWK) ? 5-i : i]); @@ -1446,7 +1566,10 @@ xi_set_address(sc) PAGE(sc, page); } } + printf("\n"); + ETHER_NEXT_MULTI(step, enm); } +#endif } } @@ -1516,14 +1639,16 @@ xi_full_reset(sc) /* Setup the ethernet interrupt mask. */ PAGE(sc, 1); +#if 1 bus_space_write_1(bst, bsh, offset + IMR0, ISR_TX_OFLOW | ISR_PKT_TX | ISR_MAC_INT | /* ISR_RX_EARLY | */ ISR_RX_FULL | ISR_RX_PKT_REJ | ISR_FORCED_INT); -#if 0 +#else bus_space_write_1(bst, bsh, offset + IMR0, 0xff); #endif if (!(sc->sc_flags & XIFLAGS_DINGO)) { /* XXX What is this? Not for Dingo at least. */ + /* Unmask TX underrun detection */ bus_space_write_1(bst, bsh, offset + IMR1, 1); } diff --git a/sys/dev/pcmcia/if_xireg.h b/sys/dev/pcmcia/if_xireg.h index 13bb1f07a76..932eb2a446a 100644 --- a/sys/dev/pcmcia/if_xireg.h +++ b/sys/dev/pcmcia/if_xireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_xireg.h,v 1.2 2001/06/12 15:17:26 wiz Exp $ */ +/* $NetBSD: if_xireg.h,v 1.3 2001/07/01 01:57:29 gmcgarry Exp $ */ /* OpenBSD: if_xereg.h,v 1.1 1999/05/18 19:18:21 niklas Exp */ /* @@ -32,7 +32,9 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Additional Card Configuration Registers on Dingo */ +#define PCMCIA_CCR_ECOR + +/* Additional Card Configuration Registers (CCR) on Dingo */ #define PCMCIA_CCR_DCOR0 0x20 #define PCMCIA_CCR_DCOR0_MRST_SFRST 0x80 @@ -75,13 +77,15 @@ #define PCMCIA_CCR_SIZE_DINGO 0x54 +#define XI_IOSIZE 16 + /* All pages */ #define CR 0x0 /* W - Command register */ #define ESR 0x0 /* R - Ethernet status register */ #define PR 0x1 /* RW - Page register select */ #define EDP 0x2 /* RW - Ethernet data port, 4 registers */ #define ISR0 0x6 /* R - Etherenet interrupt status register */ -#define GIR 0x7 /* RW - Global interrupt register */ +#define GIR 0x7 /* RW - Global interrupt register - dingo only */ #define PTR 0xd /* R - Packets Transmitted register */ /* Page 0 */ @@ -248,7 +252,7 @@ /* CMD0 register bits */ #define ONLINE 0x04 /* Online */ #define OFFLINE 0x08 /* Online */ -#define ENABLE_RX 0x20 /* Enable receiver */ +#define ENABLE_RX 0x20 /* Enable reciever */ #define DISABLE_RX 0x80 /* Disable receiver */ /* RX0Msk register bits */ |
