summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorgmcgarry <gmcgarry@NetBSD.org>2001-07-01 01:57:29 +0000
committergmcgarry <gmcgarry@NetBSD.org>2001-07-01 01:57:29 +0000
commit52f5073f289aaf65c5a3f862dd73f37071a3cbb6 (patch)
treea92b916b223a64f0dcdb244c3f64f37f74c9d0ce /sys/dev
parenta48df4b3553874890a91a088fca0e0e7119430a6 (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.c261
-rw-r--r--sys/dev/pcmcia/if_xireg.h12
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 */