summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordg <dg@FreeBSD.org>1997-09-05 10:23:58 +0000
committerdg <dg@FreeBSD.org>1997-09-05 10:23:58 +0000
commitf2abdbfd233c603d969eed10b50cbeae826026fe (patch)
treea5209960265f96cad4925f195be52fd60f7f620e
parent687ed5fec1ae09e57abdac7a5b5be1fce217350a (diff)
downloadFreeBSD-src-f2abdbfd233c603d969eed10b50cbeae826026fe.zip
FreeBSD-src-f2abdbfd233c603d969eed10b50cbeae826026fe.tar.gz
Changes to support NetBSD and the new ifmedia extensions.
Submitted by: Jason Thorpe <thorpej@netbsd.org>
-rw-r--r--sys/dev/fxp/if_fxp.c943
-rw-r--r--sys/dev/fxp/if_fxpreg.h35
-rw-r--r--sys/dev/fxp/if_fxpvar.h107
-rw-r--r--sys/pci/if_fxp.c943
-rw-r--r--sys/pci/if_fxpreg.h35
-rw-r--r--sys/pci/if_fxpvar.h107
6 files changed, 1684 insertions, 486 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c
index 669bb1f..a4d1fcc 100644
--- a/sys/dev/fxp/if_fxp.c
+++ b/sys/dev/fxp/if_fxp.c
@@ -2,6 +2,9 @@
* Copyright (c) 1995, David Greenman
* All rights reserved.
*
+ * Modifications to support NetBSD and media selection:
+ * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -24,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_fxp.c,v 1.37 1997/07/25 23:41:12 davidg Exp $
+ * $Id$
*/
/*
@@ -35,7 +38,6 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
@@ -43,10 +45,10 @@
#include <sys/syslog.h>
#include <net/if.h>
+#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
-#include <netinet/if_ether.h>
#endif
#ifdef NS
@@ -58,30 +60,78 @@
#include <net/bpf.h>
#endif
+#if defined(__NetBSD__)
+
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+
+#include <netinet/if_inarp.h>
+
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/pci/if_fxpreg.h>
+#include <dev/pci/if_fxpvar.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#ifdef __alpha__ /* XXX */
+/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
+#endif /* __alpha__ */
+
+#else /* __FreeBSD__ */
+
+#include <sys/sockio.h>
+
+#include <netinet/if_ether.h>
+
#include <vm/vm.h> /* for vtophys */
#include <vm/pmap.h> /* for vtophys */
#include <machine/clock.h> /* for DELAY */
#include <pci/pcivar.h>
#include <pci/if_fxpreg.h>
+#include <pci/if_fxpvar.h>
-struct fxp_softc {
- struct arpcom arpcom; /* per-interface network data */
- struct fxp_csr *csr; /* control/status registers */
- struct fxp_cb_tx *cbl_base; /* base of TxCB list */
- struct fxp_cb_tx *cbl_first; /* first active TxCB in list */
- struct fxp_cb_tx *cbl_last; /* last active TxCB in list */
- struct mbuf *rfa_headm; /* first mbuf in receive frame area */
- struct mbuf *rfa_tailm; /* last mbuf in receive frame area */
- struct fxp_stats *fxp_stats; /* Pointer to interface stats */
- int tx_queued; /* # of active TxCB's */
- int promisc_mode; /* promiscuous mode enabled */
- int phy_primary_addr; /* address of primary PHY */
- int phy_primary_device; /* device type of primary PHY */
- int phy_10Mbps_only; /* PHY is 10Mbps-only device */
-};
+#endif /* __NetBSD__ */
-static u_long fxp_count;
+/*
+ * NOTE! On the Alpha, we have an alignment constraint. The
+ * card DMAs the packet immediately following the RFA. However,
+ * the first thing in the packet is a 14-byte Ethernet header.
+ * This means that the packet is misaligned. To compensate,
+ * we actually offset the RFA 2 bytes into the cluster. This
+ * alignes the packet after the Ethernet header at a 32-bit
+ * boundary. HOWEVER! This means that the RFA is misaligned!
+ */
+#define RFA_ALIGNMENT_FUDGE 2
+
+/*
+ * Inline function to copy a 16-bit aligned 32-bit quantity.
+ */
+static __inline void fxp_lwcopy __P((volatile u_int32_t *,
+ volatile u_int32_t *));
+static __inline void
+fxp_lwcopy(src, dst)
+ volatile u_int32_t *src, *dst;
+{
+ volatile u_int16_t *a = (u_int16_t *)src;
+ volatile u_int16_t *b = (u_int16_t *)dst;
+
+ b[0] = a[0];
+ b[1] = a[1];
+}
/*
* Template for default configuration parameters.
@@ -116,32 +166,65 @@ static u_char fxp_cb_config_template[] = {
0x0, 0x0
};
-static inline void fxp_scb_wait __P((struct fxp_csr *));
-static char *fxp_probe __P((pcici_t, pcidi_t));
-static void fxp_attach __P((pcici_t, int));
-static void fxp_intr __P((void *));
+/* Supported media types. */
+struct fxp_supported_media {
+ const int fsm_phy; /* PHY type */
+ const int *fsm_media; /* the media array */
+ const int fsm_nmedia; /* the number of supported media */
+ const int fsm_defmedia; /* default media for this PHY */
+};
+
+const int fxp_media_standard[] = {
+ IFM_ETHER|IFM_10_T,
+ IFM_ETHER|IFM_10_T|IFM_FDX,
+ IFM_ETHER|IFM_100_TX,
+ IFM_ETHER|IFM_100_TX|IFM_FDX,
+ IFM_ETHER|IFM_AUTO,
+};
+#define FXP_MEDIA_STANDARD_DEFMEDIA (IFM_ETHER|IFM_AUTO)
+
+const int fxp_media_default[] = {
+ IFM_ETHER|IFM_MANUAL, /* XXX IFM_AUTO ? */
+};
+#define FXP_MEDIA_DEFAULT_DEFMEDIA (IFM_ETHER|IFM_MANUAL)
+
+const struct fxp_supported_media fxp_media[] = {
+ { FXP_PHY_DP83840, fxp_media_standard,
+ sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]),
+ FXP_MEDIA_STANDARD_DEFMEDIA },
+ { FXP_PHY_DP83840A, fxp_media_standard,
+ sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]),
+ FXP_MEDIA_STANDARD_DEFMEDIA },
+ { FXP_PHY_82555, fxp_media_standard,
+ sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]),
+ FXP_MEDIA_STANDARD_DEFMEDIA },
+ { FXP_PHY_80C24, fxp_media_default,
+ sizeof(fxp_media_default) / sizeof(fxp_media_default[0]),
+ FXP_MEDIA_DEFAULT_DEFMEDIA },
+};
+#define NFXPMEDIA (sizeof(fxp_media) / sizeof(fxp_media[0]))
+
+static int fxp_mediachange __P((struct ifnet *));
+static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
+
+void fxp_set_media __P((struct fxp_softc *, int));
+
+static inline void fxp_scb_wait __P((struct fxp_softc *));
+static FXP_INTR_TYPE fxp_intr __P((void *));
static void fxp_start __P((struct ifnet *));
-static int fxp_ioctl __P((struct ifnet *, int, caddr_t));
+static int fxp_ioctl __P((struct ifnet *,
+ FXP_IOCTLCMD_TYPE, caddr_t));
static void fxp_init __P((void *));
static void fxp_stop __P((struct fxp_softc *));
static void fxp_watchdog __P((struct ifnet *));
static int fxp_add_rfabuf __P((struct fxp_softc *, struct mbuf *));
-static void fxp_shutdown __P((int, void *));
-static int fxp_mdi_read __P((struct fxp_csr *, int, int));
-static void fxp_mdi_write __P((struct fxp_csr *, int, int, int));
-static void fxp_read_eeprom __P((struct fxp_csr *, u_short *, int, int));
-
+static int fxp_mdi_read __P((struct fxp_softc *, int, int));
+static void fxp_mdi_write __P((struct fxp_softc *, int, int, int));
+static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *,
+ int, int));
+static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
-timeout_t fxp_stats_update;
-
-static struct pci_device fxp_device = {
- "fxp",
- fxp_probe,
- fxp_attach,
- &fxp_count,
- NULL
-};
-DATA_SET(pcidevice_set, fxp_device);
+void fxp_stats_update __P((void *));
/*
* Set initial transmit threshold at 64 (512 bytes). This is
@@ -184,14 +267,225 @@ static int tx_threshold = 64;
* completed).
*/
static inline void
-fxp_scb_wait(csr)
- struct fxp_csr *csr;
+fxp_scb_wait(sc)
+ struct fxp_softc *sc;
{
int i = 10000;
- while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i);
+ while ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) & FXP_SCB_COMMAND_MASK)
+ && --i);
}
+/*************************************************************
+ * Operating system-specific autoconfiguration glue
+ *************************************************************/
+
+#if defined(__NetBSD__)
+
+#ifdef __BROKEN_INDIRECT_CONFIG
+static int fxp_match __P((struct device *, void *, void *));
+#else
+static int fxp_match __P((struct device *, struct cfdata *, void *));
+#endif
+static void fxp_attach __P((struct device *, struct device *, void *));
+
+static void fxp_shutdown __P((void *));
+
+/* Compensate for lack of a generic ether_ioctl() */
+static int fxp_ether_ioctl __P((struct ifnet *,
+ FXP_IOCTLCMD_TYPE, caddr_t));
+#define ether_ioctl fxp_ether_ioctl
+
+struct cfattach fxp_ca = {
+ sizeof(struct fxp_softc), fxp_match, fxp_attach
+};
+
+struct cfdriver fxp_cd = {
+ NULL, "fxp", DV_IFNET
+};
+
+/*
+ * Check if a device is an 82557.
+ */
+static int
+fxp_match(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
+ return (0);
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_INTEL_82557:
+ return (1);
+ }
+
+ return (0);
+}
+
+static void
+fxp_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct fxp_softc *sc = (struct fxp_softc *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ u_int8_t enaddr[6];
+ struct ifnet *ifp;
+
+ /*
+ * Map control/status registers.
+ */
+ if (pci_mapreg_map(pa, FXP_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_st, &sc->sc_sh, NULL, NULL)) {
+ printf(": can't map registers\n");
+ return;
+ }
+ printf(": Intel EtherExpress Pro 10/100B Ethernet\n");
+
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt",
+ sc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ /* Do generic parts of attach. */
+ if (fxp_attach_common(sc, enaddr)) {
+ /* Failed! */
+ return;
+ }
+
+ printf("%s: Ethernet address %s%s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(enaddr), sc->phy_10Mbps_only ? ", 10Mbps" : "");
+
+ ifp = &sc->sc_ethercom.ec_if;
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = fxp_ioctl;
+ ifp->if_start = fxp_start;
+ ifp->if_watchdog = fxp_watchdog;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp, enaddr);
+#if NBPFILTER > 0
+ bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
+#endif
+
+ /*
+ * Add shutdown hook so that DMA is disabled prior to reboot. Not
+ * doing do could allow DMA to corrupt kernel memory during the
+ * reboot before the driver initializes.
+ */
+ shutdownhook_establish(fxp_shutdown, sc);
+}
+
+/*
+ * Device shutdown routine. Called at system shutdown after sync. The
+ * main purpose of this routine is to shut off receiver DMA so that
+ * kernel memory doesn't get clobbered during warmboot.
+ */
+static void
+fxp_shutdown(sc)
+ void *sc;
+{
+ fxp_stop((struct fxp_softc *) sc);
+}
+
+static int
+fxp_ether_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ FXP_IOCTLCMD_TYPE cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ struct fxp_softc *sc = ifp->if_softc;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ fxp_init(sc);
+ arp_ifinit(ifp, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host = *(union ns_host *)
+ LLADDR(ifp->if_sadl);
+ else
+ bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
+ ifp->if_addrlen);
+ /* Set new address. */
+ fxp_init(sc);
+ break;
+ }
+#endif
+ default:
+ fxp_init(sc);
+ break;
+ }
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+#else /* __FreeBSD__ */
+
+static u_long fxp_count;
+static char *fxp_probe __P((pcici_t, pcidi_t));
+static void fxp_attach __P((pcici_t, int));
+
+static void fxp_shutdown __P((int, void *));
+
+static struct pci_device fxp_device = {
+ "fxp",
+ fxp_probe,
+ fxp_attach,
+ &fxp_count,
+ NULL
+};
+DATA_SET(pcidevice_set, fxp_device);
+
/*
* Return identification string if this is device is ours.
*/
@@ -207,19 +501,15 @@ fxp_probe(config_id, device_id)
return NULL;
}
-/*
- * Allocate data structures and attach the device.
- */
static void
fxp_attach(config_id, unit)
pcici_t config_id;
int unit;
{
struct fxp_softc *sc;
- struct ifnet *ifp;
vm_offset_t pbase;
- int s, i;
- u_short data;
+ struct ifnet *ifp;
+ int s;
sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT);
if (sc == NULL)
@@ -238,12 +528,6 @@ fxp_attach(config_id, unit)
}
/*
- * Reset to a stable state.
- */
- sc->csr->port = FXP_PORT_SELECTIVE_RESET;
- DELAY(10);
-
- /*
* Allocate our interrupt.
*/
if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) {
@@ -251,14 +535,97 @@ fxp_attach(config_id, unit)
goto fail;
}
+ /* Do generic parts of attach. */
+ if (fxp_attach_common(sc, sc->arpcom.ac_enaddr)) {
+ /* Failed! */
+ (void) pci_unmap_int(config_id);
+ goto fail;
+ }
+
+ printf("fxp%d: Ethernet address %6D%s\n", unit,
+ sc->arpcom.ac_enaddr, ":", sc->phy_10Mbps_only ? ", 10Mbps" : "");
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_unit = unit;
+ ifp->if_name = "fxp";
+ ifp->if_output = ether_output;
+ ifp->if_baudrate = 100000000;
+ ifp->if_init = fxp_init;
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = fxp_ioctl;
+ ifp->if_start = fxp_start;
+ ifp->if_watchdog = fxp_watchdog;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+#if NBPFILTER > 0
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ /*
+ * Add shutdown hook so that DMA is disabled prior to reboot. Not
+ * doing do could allow DMA to corrupt kernel memory during the
+ * reboot before the driver initializes.
+ */
+ at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC);
+
+ splx(s);
+ return;
+
+ fail:
+ free(sc, M_DEVBUF);
+ splx(s);
+}
+
+/*
+ * Device shutdown routine. Called at system shutdown after sync. The
+ * main purpose of this routine is to shut off receiver DMA so that
+ * kernel memory doesn't get clobbered during warmboot.
+ */
+static void
+fxp_shutdown(howto, sc)
+ int howto;
+ void *sc;
+{
+ fxp_stop((struct fxp_softc *) sc);
+}
+
+#endif /* __NetBSD__ */
+
+/*************************************************************
+ * End of operating system-specific autoconfiguration glue
+ *************************************************************/
+
+/*
+ * Do generic parts of attach.
+ */
+static int
+fxp_attach_common(sc, enaddr)
+ struct fxp_softc *sc;
+ u_int8_t *enaddr;
+{
+ u_int16_t data;
+ int i, nmedia, defmedia;
+ const int *media;
+
+ /*
+ * Reset to a stable state.
+ */
+ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+ DELAY(10);
+
sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,
M_DEVBUF, M_NOWAIT);
if (sc->cbl_base == NULL)
- goto malloc_fail;
+ goto fail;
sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT);
if (sc->fxp_stats == NULL)
- goto malloc_fail;
+ goto fail;
bzero(sc->fxp_stats, sizeof(struct fxp_stats));
/*
@@ -266,73 +633,60 @@ fxp_attach(config_id, unit)
*/
for (i = 0; i < FXP_NRFABUFS; i++) {
if (fxp_add_rfabuf(sc, NULL) != 0) {
- goto malloc_fail;
+ goto fail;
}
}
/*
* Get info about the primary PHY
*/
- fxp_read_eeprom(sc->csr, (u_short *)&data, 6, 1);
+ fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);
sc->phy_primary_addr = data & 0xff;
sc->phy_primary_device = (data >> 8) & 0x3f;
sc->phy_10Mbps_only = data >> 15;
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "fxp";
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = fxp_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = fxp_start;
- ifp->if_watchdog = fxp_watchdog;
- ifp->if_baudrate = 100000000;
- ifp->if_init = fxp_init;
-
/*
- * Read MAC address
+ * Read MAC address.
*/
- fxp_read_eeprom(sc->csr, (u_short *)sc->arpcom.ac_enaddr, 0, 3);
- printf("fxp%d: Ethernet address %6D", unit, sc->arpcom.ac_enaddr, ":");
- if (sc->phy_10Mbps_only)
- printf(", 10Mbps");
- printf("\n");
+ fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);
/*
- * Attach the interface.
+ * Initialize the media structures.
*/
- if_attach(ifp);
- ether_ifattach(ifp);
-#if NBPFILTER > 0
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-#endif
+ media = fxp_media_default;
+ nmedia = sizeof(fxp_media_default) / sizeof(fxp_media_default[0]);
+ defmedia = FXP_MEDIA_DEFAULT_DEFMEDIA;
- /*
- * Add shutdown hook so that DMA is disabled prior to reboot. Not
- * doing do could allow DMA to corrupt kernel memory during the
- * reboot before the driver initializes.
- */
- at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC);
+ for (i = 0; i < NFXPMEDIA; i++) {
+ if (sc->phy_primary_device == fxp_media[i].fsm_phy) {
+ media = fxp_media[i].fsm_media;
+ nmedia = fxp_media[i].fsm_nmedia;
+ defmedia = fxp_media[i].fsm_defmedia;
+ }
+ }
- splx(s);
- return;
+ ifmedia_init(&sc->sc_media, 0, fxp_mediachange, fxp_mediastatus);
+ for (i = 0; i < nmedia; i++) {
+ if (IFM_SUBTYPE(media[i]) == IFM_100_TX && sc->phy_10Mbps_only)
+ continue;
+ ifmedia_add(&sc->sc_media, media[i], 0, NULL);
+ }
+ ifmedia_set(&sc->sc_media, defmedia);
-malloc_fail:
- printf("fxp%d: Failed to malloc memory\n", unit);
- (void) pci_unmap_int(config_id);
- if (sc && sc->cbl_base)
+ return (0);
+
+ fail:
+ printf(FXP_FORMAT ": Failed to malloc memory\n", FXP_ARGS(sc));
+ if (sc->cbl_base)
free(sc->cbl_base, M_DEVBUF);
- if (sc && sc->fxp_stats)
+ if (sc->fxp_stats)
free(sc->fxp_stats, M_DEVBUF);
/* frees entire chain */
- if (sc && sc->rfa_headm)
+ if (sc->rfa_headm)
m_freem(sc->rfa_headm);
-fail:
- if (sc)
- free(sc, M_DEVBUF);
- splx(s);
+
+ return (ENOMEM);
}
/*
@@ -343,17 +697,17 @@ fail:
* every 16 bits of data.
*/
static void
-fxp_read_eeprom(csr, data, offset, words)
- struct fxp_csr *csr;
+fxp_read_eeprom(sc, data, offset, words)
+ struct fxp_softc *sc;
u_short *data;
int offset;
int words;
{
- u_short reg;
+ u_int16_t reg;
int i, x;
for (i = 0; i < words; i++) {
- csr->eeprom_control = FXP_EEPROM_EECS;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
/*
* Shift in read opcode.
*/
@@ -363,10 +717,11 @@ fxp_read_eeprom(csr, data, offset, words)
} else {
reg = FXP_EEPROM_EECS;
}
- csr->eeprom_control = reg;
- csr->eeprom_control = reg | FXP_EEPROM_EESK;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
DELAY(1);
- csr->eeprom_control = reg;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
DELAY(1);
}
/*
@@ -378,10 +733,11 @@ fxp_read_eeprom(csr, data, offset, words)
} else {
reg = FXP_EEPROM_EECS;
}
- csr->eeprom_control = reg;
- csr->eeprom_control = reg | FXP_EEPROM_EESK;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
DELAY(1);
- csr->eeprom_control = reg;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
DELAY(1);
}
reg = FXP_EEPROM_EECS;
@@ -390,32 +746,21 @@ fxp_read_eeprom(csr, data, offset, words)
* Shift out data.
*/
for (x = 16; x > 0; x--) {
- csr->eeprom_control = reg | FXP_EEPROM_EESK;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
DELAY(1);
- if (csr->eeprom_control & FXP_EEPROM_EEDO)
+ if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
+ FXP_EEPROM_EEDO)
data[i] |= (1 << (x - 1));
- csr->eeprom_control = reg;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
DELAY(1);
}
- csr->eeprom_control = 0;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
DELAY(1);
}
}
/*
- * Device shutdown routine. Called at system shutdown after sync. The
- * main purpose of this routine is to shut off receiver DMA so that
- * kernel memory doesn't get clobbered during warmboot.
- */
-static void
-fxp_shutdown(howto, sc)
- int howto;
- void *sc;
-{
- fxp_stop((struct fxp_softc *) sc);
-}
-
-/*
* Start packet transmission on the interface.
*/
static void
@@ -423,7 +768,6 @@ fxp_start(ifp)
struct ifnet *ifp;
{
struct fxp_softc *sc = ifp->if_softc;
- struct fxp_csr *csr = sc->csr;
struct fxp_cb_tx *txp;
struct mbuf *m, *mb_head;
int segment, first = 1;
@@ -487,7 +831,8 @@ tbdinit:
return;
}
}
- m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(mn, caddr_t));
+ m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
+ mtod(mn, caddr_t));
mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;
m_freem(mb_head);
mb_head = mn;
@@ -526,20 +871,20 @@ tbdinit:
*/
if (first) {
first--;
- fxp_scb_wait(csr);
+ fxp_scb_wait(sc);
}
/*
* Resume transmission if suspended.
*/
- csr->scb_command = FXP_SCB_COMMAND_CU_RESUME;
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
#if NBPFILTER > 0
/*
* Pass packet to bpf if there is a listener.
*/
if (ifp->if_bpf)
- bpf_mtap(ifp, mb_head);
+ bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head);
#endif
/*
* Set a 5 second timer just in case we don't hear from the
@@ -553,20 +898,25 @@ tbdinit:
/*
* Process interface interrupts.
*/
-static void
+static FXP_INTR_TYPE
fxp_intr(arg)
void *arg;
{
struct fxp_softc *sc = arg;
- struct fxp_csr *csr = sc->csr;
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
u_int8_t statack;
+#if defined(__NetBSD__)
+ int claimed = 0;
+#endif
- while ((statack = csr->scb_statack) != 0) {
+ while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
+#if defined(__NetBSD__)
+ claimed = 1;
+#endif
/*
* First ACK all the interrupts in this pass.
*/
- csr->scb_statack = statack;
+ CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
/*
* Free any finished transmit mbuf chains.
@@ -603,7 +953,8 @@ fxp_intr(arg)
struct fxp_rfa *rfa;
rcvloop:
m = sc->rfa_headm;
- rfa = (struct fxp_rfa *)m->m_ext.ext_buf;
+ rfa = (struct fxp_rfa *)(m->m_ext.ext_buf +
+ RFA_ALIGNMENT_FUDGE);
if (rfa->rfa_status & FXP_RFA_STATUS_C) {
/*
@@ -613,48 +964,65 @@ rcvloop:
m->m_next = NULL;
/*
- * Add a new buffer to the receive chain. If this
- * fails, the old buffer is recycled instead.
+ * Add a new buffer to the receive chain.
+ * If this fails, the old buffer is recycled
+ * instead.
*/
if (fxp_add_rfabuf(sc, m) == 0) {
struct ether_header *eh;
- u_short total_len;
+ u_int16_t total_len;
- total_len = rfa->actual_size & (MCLBYTES - 1);
- if (total_len < sizeof(struct ether_header)) {
+ total_len = rfa->actual_size &
+ (MCLBYTES - 1);
+ if (total_len <
+ sizeof(struct ether_header)) {
m_freem(m);
goto rcvloop;
}
m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len -
+ m->m_pkthdr.len = m->m_len =
+ total_len -
sizeof(struct ether_header);
eh = mtod(m, struct ether_header *);
#if NBPFILTER > 0
if (ifp->if_bpf) {
- bpf_tap(ifp, mtod(m, caddr_t), total_len);
+ bpf_tap(FXP_BPFTAP_ARG(ifp),
+ mtod(m, caddr_t),
+ total_len);
/*
- * Only pass this packet up if it is for us.
+ * Only pass this packet up
+ * if it is for us.
*/
- if ((ifp->if_flags & IFF_PROMISC) &&
- (rfa->rfa_status & FXP_RFA_STATUS_IAMATCH) &&
- (eh->ether_dhost[0] & 1) == 0) {
+ if ((ifp->if_flags &
+ IFF_PROMISC) &&
+ (rfa->rfa_status &
+ FXP_RFA_STATUS_IAMATCH) &&
+ (eh->ether_dhost[0] & 1)
+ == 0) {
m_freem(m);
goto rcvloop;
}
}
-#endif
- m->m_data += sizeof(struct ether_header);
+#endif /* NBPFILTER > 0 */
+ m->m_data +=
+ sizeof(struct ether_header);
ether_input(ifp, eh, m);
}
goto rcvloop;
}
if (statack & FXP_SCB_STATACK_RNR) {
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf);
- csr->scb_command = FXP_SCB_COMMAND_RU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+ vtophys(sc->rfa_headm->m_ext.ext_buf) +
+ RFA_ALIGNMENT_FUDGE);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
+ FXP_SCB_COMMAND_RU_START);
}
}
}
+#if defined(__NetBSD__)
+ return (claimed);
+#endif
}
/*
@@ -673,7 +1041,7 @@ fxp_stats_update(arg)
void *arg;
{
struct fxp_softc *sc = arg;
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
struct fxp_stats *sp = sc->fxp_stats;
ifp->if_opackets += sp->tx_good;
@@ -697,14 +1065,16 @@ fxp_stats_update(arg)
* If there is no pending command, start another stats
* dump. Otherwise punt for now.
*/
- if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) {
+ if ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) &
+ FXP_SCB_COMMAND_MASK) == 0) {
/*
* Start another stats dump. By waiting for it to be
* accepted, we avoid having to do splhigh locking when
* writing scb_command in other parts of the driver.
*/
- sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET;
- fxp_scb_wait(sc->csr);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
+ FXP_SCB_COMMAND_CU_DUMPRESET);
+ fxp_scb_wait(sc);
} else {
/*
* A previous command is still waiting to be accepted.
@@ -735,7 +1105,7 @@ static void
fxp_stop(sc)
struct fxp_softc *sc;
{
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
struct fxp_cb_tx *txp;
int i;
@@ -747,7 +1117,7 @@ fxp_stop(sc)
/*
* Issue software reset
*/
- sc->csr->port = FXP_PORT_SELECTIVE_RESET;
+ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
DELAY(10);
/*
@@ -792,10 +1162,12 @@ static void
fxp_watchdog(ifp)
struct ifnet *ifp;
{
- log(LOG_ERR, "fxp%d: device timeout\n", ifp->if_unit);
+ struct fxp_softc *sc = ifp->if_softc;
+
+ log(LOG_ERR, FXP_FORMAT ": device timeout\n", FXP_ARGS(sc));
ifp->if_oerrors++;
- fxp_init(ifp->if_softc);
+ fxp_init(sc);
}
static void
@@ -803,11 +1175,10 @@ fxp_init(xsc)
void *xsc;
{
struct fxp_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
struct fxp_cb_config *cbp;
struct fxp_cb_ias *cb_ias;
struct fxp_cb_tx *txp;
- struct fxp_csr *csr = sc->csr;
int i, s, mcast, prm;
s = splimp();
@@ -829,18 +1200,18 @@ fxp_init(xsc)
* Initialize base of CBL and RFA memory. Loading with zero
* sets it up for regular linear addressing.
*/
- csr->scb_general = 0;
- csr->scb_command = FXP_SCB_COMMAND_CU_BASE;
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
- fxp_scb_wait(csr);
- csr->scb_command = FXP_SCB_COMMAND_RU_BASE;
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
/*
* Initialize base of dump-stats buffer.
*/
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(sc->fxp_stats);
- csr->scb_command = FXP_SCB_COMMAND_CU_DUMP_ADR;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats));
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR);
/*
* We temporarily use memory that contains the TxCB list to
@@ -893,9 +1264,9 @@ fxp_init(xsc)
/*
* Start the config command/DMA.
*/
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(cbp);
- csr->scb_command = FXP_SCB_COMMAND_CU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(cbp));
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
while (!(cbp->cb_status & FXP_CB_STATUS_C));
@@ -907,14 +1278,18 @@ fxp_init(xsc)
cb_ias->cb_status = 0;
cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
cb_ias->link_addr = -1;
+#if defined(__NetBSD__)
+ bcopy(LLADDR(ifp->if_sadl), (void *)cb_ias->macaddr, 6);
+#else
bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr,
sizeof(sc->arpcom.ac_enaddr));
+#endif /* __NetBSD__ */
/*
* Start the IAS (Individual Address Setup) command/DMA.
*/
- fxp_scb_wait(csr);
- csr->scb_command = FXP_SCB_COMMAND_CU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
@@ -939,51 +1314,66 @@ fxp_init(xsc)
sc->cbl_first = sc->cbl_last = txp;
sc->tx_queued = 0;
- fxp_scb_wait(csr);
- csr->scb_command = FXP_SCB_COMMAND_CU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/*
* Initialize receiver buffer area - RFA.
*/
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf);
- csr->scb_command = FXP_SCB_COMMAND_RU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+ vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
/*
- * Toggle a few bits in the PHY.
+ * Set current media.
*/
+ fxp_set_media(sc, sc->sc_media.ifm_cur->ifm_media);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ splx(s);
+
+ /*
+ * Start stats updater.
+ */
+ timeout(fxp_stats_update, sc, hz);
+}
+
+void
+fxp_set_media(sc, media)
+ struct fxp_softc *sc;
+ int media;
+{
+
switch (sc->phy_primary_device) {
case FXP_PHY_DP83840:
case FXP_PHY_DP83840A:
- fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_DP83840_PCR,
- fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_DP83840_PCR) |
+ fxp_mdi_write(sc, sc->phy_primary_addr, FXP_DP83840_PCR,
+ fxp_mdi_read(sc, sc->phy_primary_addr, FXP_DP83840_PCR) |
FXP_DP83840_PCR_LED4_MODE | /* LED4 always indicates duplex */
FXP_DP83840_PCR_F_CONNECT | /* force link disconnect bypass */
FXP_DP83840_PCR_BIT10); /* XXX I have no idea */
/* fall through */
case FXP_PHY_82555:
- /*
- * If link0 is set, disable auto-negotiation and then:
- * If link1 is unset = 10Mbps
- * If link1 is set = 100Mbps
- * If link2 is unset = half duplex
- * If link2 is set = full duplex
- */
- if (ifp->if_flags & IFF_LINK0) {
+ if (IFM_SUBTYPE(media) != IFM_AUTO) {
int flags;
- flags = (ifp->if_flags & IFF_LINK1) ?
- FXP_PHY_BMCR_SPEED_100M : 0;
- flags |= (ifp->if_flags & IFF_LINK2) ?
- FXP_PHY_BMCR_FULLDUPLEX : 0;
- fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR,
- (fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR) &
+ flags = (IFM_SUBTYPE(media) == IFM_100_TX) ?
+ FXP_PHY_BMCR_SPEED_100M : 0;
+ flags |= (media & IFM_FDX) ?
+ FXP_PHY_BMCR_FULLDUPLEX : 0;
+ fxp_mdi_write(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR,
+ (fxp_mdi_read(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR) &
~(FXP_PHY_BMCR_AUTOEN | FXP_PHY_BMCR_SPEED_100M |
FXP_PHY_BMCR_FULLDUPLEX)) | flags);
} else {
- fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR,
- (fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR) |
- FXP_PHY_BMCR_AUTOEN));
+ fxp_mdi_write(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR,
+ (fxp_mdi_read(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR) | FXP_PHY_BMCR_AUTOEN));
}
break;
/*
@@ -993,18 +1383,64 @@ fxp_init(xsc)
case FXP_PHY_80C24:
break;
default:
- printf("fxp%d: warning: unsupported PHY, type = %d, addr = %d\n",
- ifp->if_unit, sc->phy_primary_device, sc->phy_primary_addr);
+ printf(FXP_FORMAT
+ ": warning: unsupported PHY, type = %d, addr = %d\n",
+ FXP_ARGS(sc), sc->phy_primary_device,
+ sc->phy_primary_addr);
}
+}
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
- splx(s);
+/*
+ * Change media according to request.
+ */
+int
+fxp_mediachange(ifp)
+ struct ifnet *ifp;
+{
+ struct fxp_softc *sc = ifp->if_softc;
+ struct ifmedia *ifm = &sc->sc_media;
- /*
- * Start stats updater.
- */
- timeout(fxp_stats_update, sc, hz);
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return (EINVAL);
+
+ fxp_set_media(sc, ifm->ifm_media);
+ return (0);
+}
+
+/*
+ * Notify the world which media we're using.
+ */
+void
+fxp_mediastatus(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct fxp_softc *sc = ifp->if_softc;
+ int flags;
+
+ switch (sc->phy_primary_device) {
+ case FXP_PHY_DP83840:
+ case FXP_PHY_DP83840A:
+ case FXP_PHY_82555:
+ flags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_BMCR);
+ ifmr->ifm_active = IFM_ETHER;
+ if (flags & FXP_PHY_BMCR_AUTOEN)
+ ifmr->ifm_active |= IFM_AUTO;
+ else {
+ if (flags & FXP_PHY_BMCR_SPEED_100M)
+ ifmr->ifm_active |= IFM_100_TX;
+ else
+ ifmr->ifm_active |= IFM_10_T;
+
+ if (flags & FXP_PHY_BMCR_FULLDUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ }
+ break;
+
+ case FXP_PHY_80C24:
+ default:
+ ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; /* XXX IFM_AUTO ? */
+ }
}
/*
@@ -1020,6 +1456,7 @@ fxp_add_rfabuf(sc, oldm)
struct fxp_softc *sc;
struct mbuf *oldm;
{
+ u_int32_t v;
struct mbuf *m;
struct fxp_rfa *rfa, *p_rfa;
@@ -1039,27 +1476,44 @@ fxp_add_rfabuf(sc, oldm)
m = oldm;
m->m_data = m->m_ext.ext_buf;
}
+
+ /*
+ * Move the data pointer up so that the incoming data packet
+ * will be 32-bit aligned.
+ */
+ m->m_data += RFA_ALIGNMENT_FUDGE;
+
/*
* Get a pointer to the base of the mbuf cluster and move
* data start past it.
*/
rfa = mtod(m, struct fxp_rfa *);
m->m_data += sizeof(struct fxp_rfa);
- rfa->size = MCLBYTES - sizeof(struct fxp_rfa);
+ rfa->size = MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE;
+ /*
+ * Initialize the rest of the RFA. Note that since the RFA
+ * is misaligned, we cannot store values directly. Instead,
+ * we use an optimized, inline copy.
+ */
rfa->rfa_status = 0;
rfa->rfa_control = FXP_RFA_CONTROL_EL;
- rfa->link_addr = -1;
- rfa->rbd_addr = -1;
rfa->actual_size = 0;
+
+ v = -1;
+ fxp_lwcopy(&v, &rfa->link_addr);
+ fxp_lwcopy(&v, &rfa->rbd_addr);
+
/*
* If there are other buffers already on the list, attach this
* one to the end by fixing up the tail to point to this one.
*/
if (sc->rfa_headm != NULL) {
- p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf;
+ p_rfa = (struct fxp_rfa *) (sc->rfa_tailm->m_ext.ext_buf +
+ RFA_ALIGNMENT_FUDGE);
sc->rfa_tailm->m_next = m;
- p_rfa->link_addr = vtophys(rfa);
+ v = vtophys(rfa);
+ fxp_lwcopy(&v, &p_rfa->link_addr);
p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL;
} else {
sc->rfa_headm = m;
@@ -1070,53 +1524,58 @@ fxp_add_rfabuf(sc, oldm)
}
static volatile int
-fxp_mdi_read(csr, phy, reg)
- struct fxp_csr *csr;
+fxp_mdi_read(sc, phy, reg)
+ struct fxp_softc *sc;
int phy;
int reg;
{
int count = 10000;
int value;
- csr->mdi_control = (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21);
+ CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+ (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
- while (((value = csr->mdi_control) & 0x10000000) == 0 && count--)
+ while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0
+ && count--)
DELAY(10);
if (count <= 0)
- printf("fxp_mdi_read: timed out\n");
+ printf(FXP_FORMAT ": fxp_mdi_read: timed out\n",
+ FXP_ARGS(sc));
return (value & 0xffff);
}
static void
-fxp_mdi_write(csr, phy, reg, value)
- struct fxp_csr *csr;
+fxp_mdi_write(sc, phy, reg, value)
+ struct fxp_softc *sc;
int phy;
int reg;
int value;
{
int count = 10000;
- csr->mdi_control = (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21)
- | (value & 0xffff);
+ CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+ (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) |
+ (value & 0xffff));
- while ((csr->mdi_control & 0x10000000) == 0 && count--)
+ while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 &&
+ count--)
DELAY(10);
if (count <= 0)
- printf("fxp_mdi_write: timed out\n");
+ printf(FXP_FORMAT ": fxp_mdi_write: timed out\n",
+ FXP_ARGS(sc));
}
static int
fxp_ioctl(ifp, command, data)
struct ifnet *ifp;
- int command;
+ FXP_IOCTLCMD_TYPE command;
caddr_t data;
{
- struct ifaddr *ifa = (struct ifaddr *) data;
struct fxp_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *) data;
+ struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
s = splimp();
@@ -1124,8 +1583,10 @@ fxp_ioctl(ifp, command, data)
switch (command) {
case SIOCSIFADDR:
+#if !defined(__NetBSD__)
case SIOCGIFADDR:
case SIOCSIFMTU:
+#endif
error = ether_ioctl(ifp, command, data);
break;
@@ -1147,12 +1608,36 @@ fxp_ioctl(ifp, command, data)
case SIOCADDMULTI:
case SIOCDELMULTI:
+#if defined(__NetBSD__)
+ {
+ struct ifreq *ifr = (struct ifreq *) data;
+
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_ethercom) :
+ ether_delmulti(ifr, &sc->sc_ethercom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly.
+ */
+ fxp_init(sc);
+ error = 0;
+ }
+ }
+#else /* __FreeBSD__ */
/*
* Multicast list has changed; set the hardware filter
* accordingly.
*/
fxp_init(sc);
error = 0;
+#endif /* __NetBSD__ */
+ break;
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
break;
default:
diff --git a/sys/dev/fxp/if_fxpreg.h b/sys/dev/fxp/if_fxpreg.h
index 0708dff..e2835ca 100644
--- a/sys/dev/fxp/if_fxpreg.h
+++ b/sys/dev/fxp/if_fxpreg.h
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_fxpreg.h,v 1.8 1997/03/21 08:00:13 davidg Exp $
+ * $Id$
*/
#define FXP_VENDORID_INTEL 0x8086
@@ -33,19 +33,26 @@
#define FXP_PCI_MMBA 0x10
#define FXP_PCI_IOBA 0x14
-struct fxp_csr {
- volatile u_int8_t :2,
- scb_rus:4,
- scb_cus:2;
- volatile u_int8_t scb_statack;
- volatile u_int8_t scb_command;
- volatile u_int8_t scb_intrcntl;
- volatile u_int32_t scb_general;
- volatile u_int32_t port;
- volatile u_int16_t flash_control;
- volatile u_int16_t eeprom_control;
- volatile u_int32_t mdi_control;
-};
+/*
+ * Control/status registers.
+ */
+#define FXP_CSR_SCB_RUSCUS 0 /* scb_rus/scb_cus (1 byte) */
+#define FXP_CSR_SCB_STATACK 1 /* scb_statack (1 byte) */
+#define FXP_CSR_SCB_COMMAND 2 /* scb_command (1 byte) */
+#define FXP_CSR_SCB_INTRCNTL 3 /* scb_intrcntl (1 byte) */
+#define FXP_CSR_SCB_GENERAL 4 /* scb_general (4 bytes) */
+#define FXP_CSR_PORT 8 /* port (4 bytes) */
+#define FXP_CSR_FLASHCONTROL 12 /* flash control (2 bytes) */
+#define FXP_CSR_EEPROMCONTROL 14 /* eeprom control (2 bytes) */
+#define FXP_CSR_MDICONTROL 16 /* mdi control (4 bytes) */
+
+/*
+ * FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS:
+ *
+ * volatile u_int8_t :2,
+ * scb_rus:4,
+ * scb_cus:2;
+ */
#define FXP_PORT_SOFTWARE_RESET 0
#define FXP_PORT_SELFTEST 1
diff --git a/sys/dev/fxp/if_fxpvar.h b/sys/dev/fxp/if_fxpvar.h
new file mode 100644
index 0000000..9c7e310
--- /dev/null
+++ b/sys/dev/fxp/if_fxpvar.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1995, David Greenman
+ * All rights reserved.
+ *
+ * Modifications to support NetBSD:
+ * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * Misc. defintions for the Intel EtherExpress Pro/100B PCI Fast
+ * Ethernet driver
+ */
+
+struct fxp_softc {
+#if defined(__NetBSD__)
+ struct device sc_dev; /* generic device structures */
+ void *sc_ih; /* interrupt handler cookie */
+ bus_space_tag_t sc_st; /* bus space tag */
+ bus_space_handle_t sc_sh; /* bus space handle */
+ struct ethercom sc_ethercom; /* ethernet common part */
+#else
+ struct arpcom arpcom; /* per-interface network data */
+ caddr_t csr; /* control/status registers */
+#endif /* __NetBSD__ */
+ struct ifmedia sc_media; /* media information */
+ struct fxp_cb_tx *cbl_base; /* base of TxCB list */
+ struct fxp_cb_tx *cbl_first; /* first active TxCB in list */
+ struct fxp_cb_tx *cbl_last; /* last active TxCB in list */
+ struct mbuf *rfa_headm; /* first mbuf in receive frame area */
+ struct mbuf *rfa_tailm; /* last mbuf in receive frame area */
+ struct fxp_stats *fxp_stats; /* Pointer to interface stats */
+ int tx_queued; /* # of active TxCB's */
+ int promisc_mode; /* promiscuous mode enabled */
+ int phy_primary_addr; /* address of primary PHY */
+ int phy_primary_device; /* device type of primary PHY */
+ int phy_10Mbps_only; /* PHY is 10Mbps-only device */
+};
+
+/* Macros to ease CSR access. */
+#if defined(__NetBSD__)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2((sc)->sc_st, (sc)->sc_sh, (reg))
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#else
+#define CSR_READ_1(sc, reg) \
+ (*((u_int8_t *)((sc)->csr + (reg))))
+#define CSR_READ_2(sc, reg) \
+ (*((u_int16_t *)((sc)->csr + (reg))))
+#define CSR_READ_4(sc, reg) \
+ (*((u_int32_t *)((sc)->csr + (reg))))
+#define CSR_WRITE_1(sc, reg, val) \
+ (*((u_int8_t *)((sc)->csr + (reg)))) = (val)
+#define CSR_WRITE_2(sc, reg, val) \
+ (*((u_int16_t *)((sc)->csr + (reg)))) = (val)
+#define CSR_WRITE_4(sc, reg, val) \
+ (*((u_int32_t *)((sc)->csr + (reg)))) = (val)
+#endif /* __NetBSD__ */
+
+/* Deal with slight differences in software interfaces. */
+#if defined(__NetBSD__)
+#define sc_if sc_ethercom.ec_if
+#define FXP_FORMAT "%s"
+#define FXP_ARGS(sc) (sc)->sc_dev.dv_xname
+#define FXP_INTR_TYPE int
+#define FXP_IOCTLCMD_TYPE u_long
+#define FXP_BPFTAP_ARG(ifp) (ifp)->if_bpf
+#else /* __FreeBSD__ */
+#define sc_if arpcom.ac_if
+#define FXP_FORMAT "fxp%d"
+#define FXP_ARGS(sc) (sc)->arpcom.ac_if.if_unit
+#define FXP_INTR_TYPE void
+#define FXP_IOCTLCMD_TYPE int
+#define FXP_BPFTAP_ARG(ifp) ifp
+#endif /* __NetBSD__ */
diff --git a/sys/pci/if_fxp.c b/sys/pci/if_fxp.c
index 669bb1f..a4d1fcc 100644
--- a/sys/pci/if_fxp.c
+++ b/sys/pci/if_fxp.c
@@ -2,6 +2,9 @@
* Copyright (c) 1995, David Greenman
* All rights reserved.
*
+ * Modifications to support NetBSD and media selection:
+ * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -24,7 +27,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_fxp.c,v 1.37 1997/07/25 23:41:12 davidg Exp $
+ * $Id$
*/
/*
@@ -35,7 +38,6 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
@@ -43,10 +45,10 @@
#include <sys/syslog.h>
#include <net/if.h>
+#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
-#include <netinet/if_ether.h>
#endif
#ifdef NS
@@ -58,30 +60,78 @@
#include <net/bpf.h>
#endif
+#if defined(__NetBSD__)
+
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+
+#include <netinet/if_inarp.h>
+
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/pci/if_fxpreg.h>
+#include <dev/pci/if_fxpvar.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#ifdef __alpha__ /* XXX */
+/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
+#endif /* __alpha__ */
+
+#else /* __FreeBSD__ */
+
+#include <sys/sockio.h>
+
+#include <netinet/if_ether.h>
+
#include <vm/vm.h> /* for vtophys */
#include <vm/pmap.h> /* for vtophys */
#include <machine/clock.h> /* for DELAY */
#include <pci/pcivar.h>
#include <pci/if_fxpreg.h>
+#include <pci/if_fxpvar.h>
-struct fxp_softc {
- struct arpcom arpcom; /* per-interface network data */
- struct fxp_csr *csr; /* control/status registers */
- struct fxp_cb_tx *cbl_base; /* base of TxCB list */
- struct fxp_cb_tx *cbl_first; /* first active TxCB in list */
- struct fxp_cb_tx *cbl_last; /* last active TxCB in list */
- struct mbuf *rfa_headm; /* first mbuf in receive frame area */
- struct mbuf *rfa_tailm; /* last mbuf in receive frame area */
- struct fxp_stats *fxp_stats; /* Pointer to interface stats */
- int tx_queued; /* # of active TxCB's */
- int promisc_mode; /* promiscuous mode enabled */
- int phy_primary_addr; /* address of primary PHY */
- int phy_primary_device; /* device type of primary PHY */
- int phy_10Mbps_only; /* PHY is 10Mbps-only device */
-};
+#endif /* __NetBSD__ */
-static u_long fxp_count;
+/*
+ * NOTE! On the Alpha, we have an alignment constraint. The
+ * card DMAs the packet immediately following the RFA. However,
+ * the first thing in the packet is a 14-byte Ethernet header.
+ * This means that the packet is misaligned. To compensate,
+ * we actually offset the RFA 2 bytes into the cluster. This
+ * alignes the packet after the Ethernet header at a 32-bit
+ * boundary. HOWEVER! This means that the RFA is misaligned!
+ */
+#define RFA_ALIGNMENT_FUDGE 2
+
+/*
+ * Inline function to copy a 16-bit aligned 32-bit quantity.
+ */
+static __inline void fxp_lwcopy __P((volatile u_int32_t *,
+ volatile u_int32_t *));
+static __inline void
+fxp_lwcopy(src, dst)
+ volatile u_int32_t *src, *dst;
+{
+ volatile u_int16_t *a = (u_int16_t *)src;
+ volatile u_int16_t *b = (u_int16_t *)dst;
+
+ b[0] = a[0];
+ b[1] = a[1];
+}
/*
* Template for default configuration parameters.
@@ -116,32 +166,65 @@ static u_char fxp_cb_config_template[] = {
0x0, 0x0
};
-static inline void fxp_scb_wait __P((struct fxp_csr *));
-static char *fxp_probe __P((pcici_t, pcidi_t));
-static void fxp_attach __P((pcici_t, int));
-static void fxp_intr __P((void *));
+/* Supported media types. */
+struct fxp_supported_media {
+ const int fsm_phy; /* PHY type */
+ const int *fsm_media; /* the media array */
+ const int fsm_nmedia; /* the number of supported media */
+ const int fsm_defmedia; /* default media for this PHY */
+};
+
+const int fxp_media_standard[] = {
+ IFM_ETHER|IFM_10_T,
+ IFM_ETHER|IFM_10_T|IFM_FDX,
+ IFM_ETHER|IFM_100_TX,
+ IFM_ETHER|IFM_100_TX|IFM_FDX,
+ IFM_ETHER|IFM_AUTO,
+};
+#define FXP_MEDIA_STANDARD_DEFMEDIA (IFM_ETHER|IFM_AUTO)
+
+const int fxp_media_default[] = {
+ IFM_ETHER|IFM_MANUAL, /* XXX IFM_AUTO ? */
+};
+#define FXP_MEDIA_DEFAULT_DEFMEDIA (IFM_ETHER|IFM_MANUAL)
+
+const struct fxp_supported_media fxp_media[] = {
+ { FXP_PHY_DP83840, fxp_media_standard,
+ sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]),
+ FXP_MEDIA_STANDARD_DEFMEDIA },
+ { FXP_PHY_DP83840A, fxp_media_standard,
+ sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]),
+ FXP_MEDIA_STANDARD_DEFMEDIA },
+ { FXP_PHY_82555, fxp_media_standard,
+ sizeof(fxp_media_standard) / sizeof(fxp_media_standard[0]),
+ FXP_MEDIA_STANDARD_DEFMEDIA },
+ { FXP_PHY_80C24, fxp_media_default,
+ sizeof(fxp_media_default) / sizeof(fxp_media_default[0]),
+ FXP_MEDIA_DEFAULT_DEFMEDIA },
+};
+#define NFXPMEDIA (sizeof(fxp_media) / sizeof(fxp_media[0]))
+
+static int fxp_mediachange __P((struct ifnet *));
+static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
+
+void fxp_set_media __P((struct fxp_softc *, int));
+
+static inline void fxp_scb_wait __P((struct fxp_softc *));
+static FXP_INTR_TYPE fxp_intr __P((void *));
static void fxp_start __P((struct ifnet *));
-static int fxp_ioctl __P((struct ifnet *, int, caddr_t));
+static int fxp_ioctl __P((struct ifnet *,
+ FXP_IOCTLCMD_TYPE, caddr_t));
static void fxp_init __P((void *));
static void fxp_stop __P((struct fxp_softc *));
static void fxp_watchdog __P((struct ifnet *));
static int fxp_add_rfabuf __P((struct fxp_softc *, struct mbuf *));
-static void fxp_shutdown __P((int, void *));
-static int fxp_mdi_read __P((struct fxp_csr *, int, int));
-static void fxp_mdi_write __P((struct fxp_csr *, int, int, int));
-static void fxp_read_eeprom __P((struct fxp_csr *, u_short *, int, int));
-
+static int fxp_mdi_read __P((struct fxp_softc *, int, int));
+static void fxp_mdi_write __P((struct fxp_softc *, int, int, int));
+static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *,
+ int, int));
+static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
-timeout_t fxp_stats_update;
-
-static struct pci_device fxp_device = {
- "fxp",
- fxp_probe,
- fxp_attach,
- &fxp_count,
- NULL
-};
-DATA_SET(pcidevice_set, fxp_device);
+void fxp_stats_update __P((void *));
/*
* Set initial transmit threshold at 64 (512 bytes). This is
@@ -184,14 +267,225 @@ static int tx_threshold = 64;
* completed).
*/
static inline void
-fxp_scb_wait(csr)
- struct fxp_csr *csr;
+fxp_scb_wait(sc)
+ struct fxp_softc *sc;
{
int i = 10000;
- while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i);
+ while ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) & FXP_SCB_COMMAND_MASK)
+ && --i);
}
+/*************************************************************
+ * Operating system-specific autoconfiguration glue
+ *************************************************************/
+
+#if defined(__NetBSD__)
+
+#ifdef __BROKEN_INDIRECT_CONFIG
+static int fxp_match __P((struct device *, void *, void *));
+#else
+static int fxp_match __P((struct device *, struct cfdata *, void *));
+#endif
+static void fxp_attach __P((struct device *, struct device *, void *));
+
+static void fxp_shutdown __P((void *));
+
+/* Compensate for lack of a generic ether_ioctl() */
+static int fxp_ether_ioctl __P((struct ifnet *,
+ FXP_IOCTLCMD_TYPE, caddr_t));
+#define ether_ioctl fxp_ether_ioctl
+
+struct cfattach fxp_ca = {
+ sizeof(struct fxp_softc), fxp_match, fxp_attach
+};
+
+struct cfdriver fxp_cd = {
+ NULL, "fxp", DV_IFNET
+};
+
+/*
+ * Check if a device is an 82557.
+ */
+static int
+fxp_match(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
+ return (0);
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_INTEL_82557:
+ return (1);
+ }
+
+ return (0);
+}
+
+static void
+fxp_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct fxp_softc *sc = (struct fxp_softc *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ u_int8_t enaddr[6];
+ struct ifnet *ifp;
+
+ /*
+ * Map control/status registers.
+ */
+ if (pci_mapreg_map(pa, FXP_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_st, &sc->sc_sh, NULL, NULL)) {
+ printf(": can't map registers\n");
+ return;
+ }
+ printf(": Intel EtherExpress Pro 10/100B Ethernet\n");
+
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt",
+ sc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ /* Do generic parts of attach. */
+ if (fxp_attach_common(sc, enaddr)) {
+ /* Failed! */
+ return;
+ }
+
+ printf("%s: Ethernet address %s%s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(enaddr), sc->phy_10Mbps_only ? ", 10Mbps" : "");
+
+ ifp = &sc->sc_ethercom.ec_if;
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = fxp_ioctl;
+ ifp->if_start = fxp_start;
+ ifp->if_watchdog = fxp_watchdog;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp, enaddr);
+#if NBPFILTER > 0
+ bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
+#endif
+
+ /*
+ * Add shutdown hook so that DMA is disabled prior to reboot. Not
+ * doing do could allow DMA to corrupt kernel memory during the
+ * reboot before the driver initializes.
+ */
+ shutdownhook_establish(fxp_shutdown, sc);
+}
+
+/*
+ * Device shutdown routine. Called at system shutdown after sync. The
+ * main purpose of this routine is to shut off receiver DMA so that
+ * kernel memory doesn't get clobbered during warmboot.
+ */
+static void
+fxp_shutdown(sc)
+ void *sc;
+{
+ fxp_stop((struct fxp_softc *) sc);
+}
+
+static int
+fxp_ether_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ FXP_IOCTLCMD_TYPE cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ struct fxp_softc *sc = ifp->if_softc;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ fxp_init(sc);
+ arp_ifinit(ifp, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host = *(union ns_host *)
+ LLADDR(ifp->if_sadl);
+ else
+ bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
+ ifp->if_addrlen);
+ /* Set new address. */
+ fxp_init(sc);
+ break;
+ }
+#endif
+ default:
+ fxp_init(sc);
+ break;
+ }
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+#else /* __FreeBSD__ */
+
+static u_long fxp_count;
+static char *fxp_probe __P((pcici_t, pcidi_t));
+static void fxp_attach __P((pcici_t, int));
+
+static void fxp_shutdown __P((int, void *));
+
+static struct pci_device fxp_device = {
+ "fxp",
+ fxp_probe,
+ fxp_attach,
+ &fxp_count,
+ NULL
+};
+DATA_SET(pcidevice_set, fxp_device);
+
/*
* Return identification string if this is device is ours.
*/
@@ -207,19 +501,15 @@ fxp_probe(config_id, device_id)
return NULL;
}
-/*
- * Allocate data structures and attach the device.
- */
static void
fxp_attach(config_id, unit)
pcici_t config_id;
int unit;
{
struct fxp_softc *sc;
- struct ifnet *ifp;
vm_offset_t pbase;
- int s, i;
- u_short data;
+ struct ifnet *ifp;
+ int s;
sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT);
if (sc == NULL)
@@ -238,12 +528,6 @@ fxp_attach(config_id, unit)
}
/*
- * Reset to a stable state.
- */
- sc->csr->port = FXP_PORT_SELECTIVE_RESET;
- DELAY(10);
-
- /*
* Allocate our interrupt.
*/
if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) {
@@ -251,14 +535,97 @@ fxp_attach(config_id, unit)
goto fail;
}
+ /* Do generic parts of attach. */
+ if (fxp_attach_common(sc, sc->arpcom.ac_enaddr)) {
+ /* Failed! */
+ (void) pci_unmap_int(config_id);
+ goto fail;
+ }
+
+ printf("fxp%d: Ethernet address %6D%s\n", unit,
+ sc->arpcom.ac_enaddr, ":", sc->phy_10Mbps_only ? ", 10Mbps" : "");
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_unit = unit;
+ ifp->if_name = "fxp";
+ ifp->if_output = ether_output;
+ ifp->if_baudrate = 100000000;
+ ifp->if_init = fxp_init;
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = fxp_ioctl;
+ ifp->if_start = fxp_start;
+ ifp->if_watchdog = fxp_watchdog;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+#if NBPFILTER > 0
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ /*
+ * Add shutdown hook so that DMA is disabled prior to reboot. Not
+ * doing do could allow DMA to corrupt kernel memory during the
+ * reboot before the driver initializes.
+ */
+ at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC);
+
+ splx(s);
+ return;
+
+ fail:
+ free(sc, M_DEVBUF);
+ splx(s);
+}
+
+/*
+ * Device shutdown routine. Called at system shutdown after sync. The
+ * main purpose of this routine is to shut off receiver DMA so that
+ * kernel memory doesn't get clobbered during warmboot.
+ */
+static void
+fxp_shutdown(howto, sc)
+ int howto;
+ void *sc;
+{
+ fxp_stop((struct fxp_softc *) sc);
+}
+
+#endif /* __NetBSD__ */
+
+/*************************************************************
+ * End of operating system-specific autoconfiguration glue
+ *************************************************************/
+
+/*
+ * Do generic parts of attach.
+ */
+static int
+fxp_attach_common(sc, enaddr)
+ struct fxp_softc *sc;
+ u_int8_t *enaddr;
+{
+ u_int16_t data;
+ int i, nmedia, defmedia;
+ const int *media;
+
+ /*
+ * Reset to a stable state.
+ */
+ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+ DELAY(10);
+
sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,
M_DEVBUF, M_NOWAIT);
if (sc->cbl_base == NULL)
- goto malloc_fail;
+ goto fail;
sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT);
if (sc->fxp_stats == NULL)
- goto malloc_fail;
+ goto fail;
bzero(sc->fxp_stats, sizeof(struct fxp_stats));
/*
@@ -266,73 +633,60 @@ fxp_attach(config_id, unit)
*/
for (i = 0; i < FXP_NRFABUFS; i++) {
if (fxp_add_rfabuf(sc, NULL) != 0) {
- goto malloc_fail;
+ goto fail;
}
}
/*
* Get info about the primary PHY
*/
- fxp_read_eeprom(sc->csr, (u_short *)&data, 6, 1);
+ fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);
sc->phy_primary_addr = data & 0xff;
sc->phy_primary_device = (data >> 8) & 0x3f;
sc->phy_10Mbps_only = data >> 15;
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "fxp";
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = fxp_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = fxp_start;
- ifp->if_watchdog = fxp_watchdog;
- ifp->if_baudrate = 100000000;
- ifp->if_init = fxp_init;
-
/*
- * Read MAC address
+ * Read MAC address.
*/
- fxp_read_eeprom(sc->csr, (u_short *)sc->arpcom.ac_enaddr, 0, 3);
- printf("fxp%d: Ethernet address %6D", unit, sc->arpcom.ac_enaddr, ":");
- if (sc->phy_10Mbps_only)
- printf(", 10Mbps");
- printf("\n");
+ fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);
/*
- * Attach the interface.
+ * Initialize the media structures.
*/
- if_attach(ifp);
- ether_ifattach(ifp);
-#if NBPFILTER > 0
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-#endif
+ media = fxp_media_default;
+ nmedia = sizeof(fxp_media_default) / sizeof(fxp_media_default[0]);
+ defmedia = FXP_MEDIA_DEFAULT_DEFMEDIA;
- /*
- * Add shutdown hook so that DMA is disabled prior to reboot. Not
- * doing do could allow DMA to corrupt kernel memory during the
- * reboot before the driver initializes.
- */
- at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC);
+ for (i = 0; i < NFXPMEDIA; i++) {
+ if (sc->phy_primary_device == fxp_media[i].fsm_phy) {
+ media = fxp_media[i].fsm_media;
+ nmedia = fxp_media[i].fsm_nmedia;
+ defmedia = fxp_media[i].fsm_defmedia;
+ }
+ }
- splx(s);
- return;
+ ifmedia_init(&sc->sc_media, 0, fxp_mediachange, fxp_mediastatus);
+ for (i = 0; i < nmedia; i++) {
+ if (IFM_SUBTYPE(media[i]) == IFM_100_TX && sc->phy_10Mbps_only)
+ continue;
+ ifmedia_add(&sc->sc_media, media[i], 0, NULL);
+ }
+ ifmedia_set(&sc->sc_media, defmedia);
-malloc_fail:
- printf("fxp%d: Failed to malloc memory\n", unit);
- (void) pci_unmap_int(config_id);
- if (sc && sc->cbl_base)
+ return (0);
+
+ fail:
+ printf(FXP_FORMAT ": Failed to malloc memory\n", FXP_ARGS(sc));
+ if (sc->cbl_base)
free(sc->cbl_base, M_DEVBUF);
- if (sc && sc->fxp_stats)
+ if (sc->fxp_stats)
free(sc->fxp_stats, M_DEVBUF);
/* frees entire chain */
- if (sc && sc->rfa_headm)
+ if (sc->rfa_headm)
m_freem(sc->rfa_headm);
-fail:
- if (sc)
- free(sc, M_DEVBUF);
- splx(s);
+
+ return (ENOMEM);
}
/*
@@ -343,17 +697,17 @@ fail:
* every 16 bits of data.
*/
static void
-fxp_read_eeprom(csr, data, offset, words)
- struct fxp_csr *csr;
+fxp_read_eeprom(sc, data, offset, words)
+ struct fxp_softc *sc;
u_short *data;
int offset;
int words;
{
- u_short reg;
+ u_int16_t reg;
int i, x;
for (i = 0; i < words; i++) {
- csr->eeprom_control = FXP_EEPROM_EECS;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
/*
* Shift in read opcode.
*/
@@ -363,10 +717,11 @@ fxp_read_eeprom(csr, data, offset, words)
} else {
reg = FXP_EEPROM_EECS;
}
- csr->eeprom_control = reg;
- csr->eeprom_control = reg | FXP_EEPROM_EESK;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
DELAY(1);
- csr->eeprom_control = reg;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
DELAY(1);
}
/*
@@ -378,10 +733,11 @@ fxp_read_eeprom(csr, data, offset, words)
} else {
reg = FXP_EEPROM_EECS;
}
- csr->eeprom_control = reg;
- csr->eeprom_control = reg | FXP_EEPROM_EESK;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
DELAY(1);
- csr->eeprom_control = reg;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
DELAY(1);
}
reg = FXP_EEPROM_EECS;
@@ -390,32 +746,21 @@ fxp_read_eeprom(csr, data, offset, words)
* Shift out data.
*/
for (x = 16; x > 0; x--) {
- csr->eeprom_control = reg | FXP_EEPROM_EESK;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ reg | FXP_EEPROM_EESK);
DELAY(1);
- if (csr->eeprom_control & FXP_EEPROM_EEDO)
+ if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
+ FXP_EEPROM_EEDO)
data[i] |= (1 << (x - 1));
- csr->eeprom_control = reg;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
DELAY(1);
}
- csr->eeprom_control = 0;
+ CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
DELAY(1);
}
}
/*
- * Device shutdown routine. Called at system shutdown after sync. The
- * main purpose of this routine is to shut off receiver DMA so that
- * kernel memory doesn't get clobbered during warmboot.
- */
-static void
-fxp_shutdown(howto, sc)
- int howto;
- void *sc;
-{
- fxp_stop((struct fxp_softc *) sc);
-}
-
-/*
* Start packet transmission on the interface.
*/
static void
@@ -423,7 +768,6 @@ fxp_start(ifp)
struct ifnet *ifp;
{
struct fxp_softc *sc = ifp->if_softc;
- struct fxp_csr *csr = sc->csr;
struct fxp_cb_tx *txp;
struct mbuf *m, *mb_head;
int segment, first = 1;
@@ -487,7 +831,8 @@ tbdinit:
return;
}
}
- m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(mn, caddr_t));
+ m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
+ mtod(mn, caddr_t));
mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;
m_freem(mb_head);
mb_head = mn;
@@ -526,20 +871,20 @@ tbdinit:
*/
if (first) {
first--;
- fxp_scb_wait(csr);
+ fxp_scb_wait(sc);
}
/*
* Resume transmission if suspended.
*/
- csr->scb_command = FXP_SCB_COMMAND_CU_RESUME;
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
#if NBPFILTER > 0
/*
* Pass packet to bpf if there is a listener.
*/
if (ifp->if_bpf)
- bpf_mtap(ifp, mb_head);
+ bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head);
#endif
/*
* Set a 5 second timer just in case we don't hear from the
@@ -553,20 +898,25 @@ tbdinit:
/*
* Process interface interrupts.
*/
-static void
+static FXP_INTR_TYPE
fxp_intr(arg)
void *arg;
{
struct fxp_softc *sc = arg;
- struct fxp_csr *csr = sc->csr;
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
u_int8_t statack;
+#if defined(__NetBSD__)
+ int claimed = 0;
+#endif
- while ((statack = csr->scb_statack) != 0) {
+ while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
+#if defined(__NetBSD__)
+ claimed = 1;
+#endif
/*
* First ACK all the interrupts in this pass.
*/
- csr->scb_statack = statack;
+ CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
/*
* Free any finished transmit mbuf chains.
@@ -603,7 +953,8 @@ fxp_intr(arg)
struct fxp_rfa *rfa;
rcvloop:
m = sc->rfa_headm;
- rfa = (struct fxp_rfa *)m->m_ext.ext_buf;
+ rfa = (struct fxp_rfa *)(m->m_ext.ext_buf +
+ RFA_ALIGNMENT_FUDGE);
if (rfa->rfa_status & FXP_RFA_STATUS_C) {
/*
@@ -613,48 +964,65 @@ rcvloop:
m->m_next = NULL;
/*
- * Add a new buffer to the receive chain. If this
- * fails, the old buffer is recycled instead.
+ * Add a new buffer to the receive chain.
+ * If this fails, the old buffer is recycled
+ * instead.
*/
if (fxp_add_rfabuf(sc, m) == 0) {
struct ether_header *eh;
- u_short total_len;
+ u_int16_t total_len;
- total_len = rfa->actual_size & (MCLBYTES - 1);
- if (total_len < sizeof(struct ether_header)) {
+ total_len = rfa->actual_size &
+ (MCLBYTES - 1);
+ if (total_len <
+ sizeof(struct ether_header)) {
m_freem(m);
goto rcvloop;
}
m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len -
+ m->m_pkthdr.len = m->m_len =
+ total_len -
sizeof(struct ether_header);
eh = mtod(m, struct ether_header *);
#if NBPFILTER > 0
if (ifp->if_bpf) {
- bpf_tap(ifp, mtod(m, caddr_t), total_len);
+ bpf_tap(FXP_BPFTAP_ARG(ifp),
+ mtod(m, caddr_t),
+ total_len);
/*
- * Only pass this packet up if it is for us.
+ * Only pass this packet up
+ * if it is for us.
*/
- if ((ifp->if_flags & IFF_PROMISC) &&
- (rfa->rfa_status & FXP_RFA_STATUS_IAMATCH) &&
- (eh->ether_dhost[0] & 1) == 0) {
+ if ((ifp->if_flags &
+ IFF_PROMISC) &&
+ (rfa->rfa_status &
+ FXP_RFA_STATUS_IAMATCH) &&
+ (eh->ether_dhost[0] & 1)
+ == 0) {
m_freem(m);
goto rcvloop;
}
}
-#endif
- m->m_data += sizeof(struct ether_header);
+#endif /* NBPFILTER > 0 */
+ m->m_data +=
+ sizeof(struct ether_header);
ether_input(ifp, eh, m);
}
goto rcvloop;
}
if (statack & FXP_SCB_STATACK_RNR) {
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf);
- csr->scb_command = FXP_SCB_COMMAND_RU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+ vtophys(sc->rfa_headm->m_ext.ext_buf) +
+ RFA_ALIGNMENT_FUDGE);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
+ FXP_SCB_COMMAND_RU_START);
}
}
}
+#if defined(__NetBSD__)
+ return (claimed);
+#endif
}
/*
@@ -673,7 +1041,7 @@ fxp_stats_update(arg)
void *arg;
{
struct fxp_softc *sc = arg;
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
struct fxp_stats *sp = sc->fxp_stats;
ifp->if_opackets += sp->tx_good;
@@ -697,14 +1065,16 @@ fxp_stats_update(arg)
* If there is no pending command, start another stats
* dump. Otherwise punt for now.
*/
- if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) {
+ if ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) &
+ FXP_SCB_COMMAND_MASK) == 0) {
/*
* Start another stats dump. By waiting for it to be
* accepted, we avoid having to do splhigh locking when
* writing scb_command in other parts of the driver.
*/
- sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET;
- fxp_scb_wait(sc->csr);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
+ FXP_SCB_COMMAND_CU_DUMPRESET);
+ fxp_scb_wait(sc);
} else {
/*
* A previous command is still waiting to be accepted.
@@ -735,7 +1105,7 @@ static void
fxp_stop(sc)
struct fxp_softc *sc;
{
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
struct fxp_cb_tx *txp;
int i;
@@ -747,7 +1117,7 @@ fxp_stop(sc)
/*
* Issue software reset
*/
- sc->csr->port = FXP_PORT_SELECTIVE_RESET;
+ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
DELAY(10);
/*
@@ -792,10 +1162,12 @@ static void
fxp_watchdog(ifp)
struct ifnet *ifp;
{
- log(LOG_ERR, "fxp%d: device timeout\n", ifp->if_unit);
+ struct fxp_softc *sc = ifp->if_softc;
+
+ log(LOG_ERR, FXP_FORMAT ": device timeout\n", FXP_ARGS(sc));
ifp->if_oerrors++;
- fxp_init(ifp->if_softc);
+ fxp_init(sc);
}
static void
@@ -803,11 +1175,10 @@ fxp_init(xsc)
void *xsc;
{
struct fxp_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifnet *ifp = &sc->sc_if;
struct fxp_cb_config *cbp;
struct fxp_cb_ias *cb_ias;
struct fxp_cb_tx *txp;
- struct fxp_csr *csr = sc->csr;
int i, s, mcast, prm;
s = splimp();
@@ -829,18 +1200,18 @@ fxp_init(xsc)
* Initialize base of CBL and RFA memory. Loading with zero
* sets it up for regular linear addressing.
*/
- csr->scb_general = 0;
- csr->scb_command = FXP_SCB_COMMAND_CU_BASE;
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
- fxp_scb_wait(csr);
- csr->scb_command = FXP_SCB_COMMAND_RU_BASE;
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
/*
* Initialize base of dump-stats buffer.
*/
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(sc->fxp_stats);
- csr->scb_command = FXP_SCB_COMMAND_CU_DUMP_ADR;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats));
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR);
/*
* We temporarily use memory that contains the TxCB list to
@@ -893,9 +1264,9 @@ fxp_init(xsc)
/*
* Start the config command/DMA.
*/
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(cbp);
- csr->scb_command = FXP_SCB_COMMAND_CU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(cbp));
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
while (!(cbp->cb_status & FXP_CB_STATUS_C));
@@ -907,14 +1278,18 @@ fxp_init(xsc)
cb_ias->cb_status = 0;
cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
cb_ias->link_addr = -1;
+#if defined(__NetBSD__)
+ bcopy(LLADDR(ifp->if_sadl), (void *)cb_ias->macaddr, 6);
+#else
bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr,
sizeof(sc->arpcom.ac_enaddr));
+#endif /* __NetBSD__ */
/*
* Start the IAS (Individual Address Setup) command/DMA.
*/
- fxp_scb_wait(csr);
- csr->scb_command = FXP_SCB_COMMAND_CU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
@@ -939,51 +1314,66 @@ fxp_init(xsc)
sc->cbl_first = sc->cbl_last = txp;
sc->tx_queued = 0;
- fxp_scb_wait(csr);
- csr->scb_command = FXP_SCB_COMMAND_CU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/*
* Initialize receiver buffer area - RFA.
*/
- fxp_scb_wait(csr);
- csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf);
- csr->scb_command = FXP_SCB_COMMAND_RU_START;
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+ vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
/*
- * Toggle a few bits in the PHY.
+ * Set current media.
*/
+ fxp_set_media(sc, sc->sc_media.ifm_cur->ifm_media);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ splx(s);
+
+ /*
+ * Start stats updater.
+ */
+ timeout(fxp_stats_update, sc, hz);
+}
+
+void
+fxp_set_media(sc, media)
+ struct fxp_softc *sc;
+ int media;
+{
+
switch (sc->phy_primary_device) {
case FXP_PHY_DP83840:
case FXP_PHY_DP83840A:
- fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_DP83840_PCR,
- fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_DP83840_PCR) |
+ fxp_mdi_write(sc, sc->phy_primary_addr, FXP_DP83840_PCR,
+ fxp_mdi_read(sc, sc->phy_primary_addr, FXP_DP83840_PCR) |
FXP_DP83840_PCR_LED4_MODE | /* LED4 always indicates duplex */
FXP_DP83840_PCR_F_CONNECT | /* force link disconnect bypass */
FXP_DP83840_PCR_BIT10); /* XXX I have no idea */
/* fall through */
case FXP_PHY_82555:
- /*
- * If link0 is set, disable auto-negotiation and then:
- * If link1 is unset = 10Mbps
- * If link1 is set = 100Mbps
- * If link2 is unset = half duplex
- * If link2 is set = full duplex
- */
- if (ifp->if_flags & IFF_LINK0) {
+ if (IFM_SUBTYPE(media) != IFM_AUTO) {
int flags;
- flags = (ifp->if_flags & IFF_LINK1) ?
- FXP_PHY_BMCR_SPEED_100M : 0;
- flags |= (ifp->if_flags & IFF_LINK2) ?
- FXP_PHY_BMCR_FULLDUPLEX : 0;
- fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR,
- (fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR) &
+ flags = (IFM_SUBTYPE(media) == IFM_100_TX) ?
+ FXP_PHY_BMCR_SPEED_100M : 0;
+ flags |= (media & IFM_FDX) ?
+ FXP_PHY_BMCR_FULLDUPLEX : 0;
+ fxp_mdi_write(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR,
+ (fxp_mdi_read(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR) &
~(FXP_PHY_BMCR_AUTOEN | FXP_PHY_BMCR_SPEED_100M |
FXP_PHY_BMCR_FULLDUPLEX)) | flags);
} else {
- fxp_mdi_write(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR,
- (fxp_mdi_read(sc->csr, sc->phy_primary_addr, FXP_PHY_BMCR) |
- FXP_PHY_BMCR_AUTOEN));
+ fxp_mdi_write(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR,
+ (fxp_mdi_read(sc, sc->phy_primary_addr,
+ FXP_PHY_BMCR) | FXP_PHY_BMCR_AUTOEN));
}
break;
/*
@@ -993,18 +1383,64 @@ fxp_init(xsc)
case FXP_PHY_80C24:
break;
default:
- printf("fxp%d: warning: unsupported PHY, type = %d, addr = %d\n",
- ifp->if_unit, sc->phy_primary_device, sc->phy_primary_addr);
+ printf(FXP_FORMAT
+ ": warning: unsupported PHY, type = %d, addr = %d\n",
+ FXP_ARGS(sc), sc->phy_primary_device,
+ sc->phy_primary_addr);
}
+}
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
- splx(s);
+/*
+ * Change media according to request.
+ */
+int
+fxp_mediachange(ifp)
+ struct ifnet *ifp;
+{
+ struct fxp_softc *sc = ifp->if_softc;
+ struct ifmedia *ifm = &sc->sc_media;
- /*
- * Start stats updater.
- */
- timeout(fxp_stats_update, sc, hz);
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return (EINVAL);
+
+ fxp_set_media(sc, ifm->ifm_media);
+ return (0);
+}
+
+/*
+ * Notify the world which media we're using.
+ */
+void
+fxp_mediastatus(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct fxp_softc *sc = ifp->if_softc;
+ int flags;
+
+ switch (sc->phy_primary_device) {
+ case FXP_PHY_DP83840:
+ case FXP_PHY_DP83840A:
+ case FXP_PHY_82555:
+ flags = fxp_mdi_read(sc, sc->phy_primary_addr, FXP_PHY_BMCR);
+ ifmr->ifm_active = IFM_ETHER;
+ if (flags & FXP_PHY_BMCR_AUTOEN)
+ ifmr->ifm_active |= IFM_AUTO;
+ else {
+ if (flags & FXP_PHY_BMCR_SPEED_100M)
+ ifmr->ifm_active |= IFM_100_TX;
+ else
+ ifmr->ifm_active |= IFM_10_T;
+
+ if (flags & FXP_PHY_BMCR_FULLDUPLEX)
+ ifmr->ifm_active |= IFM_FDX;
+ }
+ break;
+
+ case FXP_PHY_80C24:
+ default:
+ ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; /* XXX IFM_AUTO ? */
+ }
}
/*
@@ -1020,6 +1456,7 @@ fxp_add_rfabuf(sc, oldm)
struct fxp_softc *sc;
struct mbuf *oldm;
{
+ u_int32_t v;
struct mbuf *m;
struct fxp_rfa *rfa, *p_rfa;
@@ -1039,27 +1476,44 @@ fxp_add_rfabuf(sc, oldm)
m = oldm;
m->m_data = m->m_ext.ext_buf;
}
+
+ /*
+ * Move the data pointer up so that the incoming data packet
+ * will be 32-bit aligned.
+ */
+ m->m_data += RFA_ALIGNMENT_FUDGE;
+
/*
* Get a pointer to the base of the mbuf cluster and move
* data start past it.
*/
rfa = mtod(m, struct fxp_rfa *);
m->m_data += sizeof(struct fxp_rfa);
- rfa->size = MCLBYTES - sizeof(struct fxp_rfa);
+ rfa->size = MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE;
+ /*
+ * Initialize the rest of the RFA. Note that since the RFA
+ * is misaligned, we cannot store values directly. Instead,
+ * we use an optimized, inline copy.
+ */
rfa->rfa_status = 0;
rfa->rfa_control = FXP_RFA_CONTROL_EL;
- rfa->link_addr = -1;
- rfa->rbd_addr = -1;
rfa->actual_size = 0;
+
+ v = -1;
+ fxp_lwcopy(&v, &rfa->link_addr);
+ fxp_lwcopy(&v, &rfa->rbd_addr);
+
/*
* If there are other buffers already on the list, attach this
* one to the end by fixing up the tail to point to this one.
*/
if (sc->rfa_headm != NULL) {
- p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf;
+ p_rfa = (struct fxp_rfa *) (sc->rfa_tailm->m_ext.ext_buf +
+ RFA_ALIGNMENT_FUDGE);
sc->rfa_tailm->m_next = m;
- p_rfa->link_addr = vtophys(rfa);
+ v = vtophys(rfa);
+ fxp_lwcopy(&v, &p_rfa->link_addr);
p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL;
} else {
sc->rfa_headm = m;
@@ -1070,53 +1524,58 @@ fxp_add_rfabuf(sc, oldm)
}
static volatile int
-fxp_mdi_read(csr, phy, reg)
- struct fxp_csr *csr;
+fxp_mdi_read(sc, phy, reg)
+ struct fxp_softc *sc;
int phy;
int reg;
{
int count = 10000;
int value;
- csr->mdi_control = (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21);
+ CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+ (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
- while (((value = csr->mdi_control) & 0x10000000) == 0 && count--)
+ while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0
+ && count--)
DELAY(10);
if (count <= 0)
- printf("fxp_mdi_read: timed out\n");
+ printf(FXP_FORMAT ": fxp_mdi_read: timed out\n",
+ FXP_ARGS(sc));
return (value & 0xffff);
}
static void
-fxp_mdi_write(csr, phy, reg, value)
- struct fxp_csr *csr;
+fxp_mdi_write(sc, phy, reg, value)
+ struct fxp_softc *sc;
int phy;
int reg;
int value;
{
int count = 10000;
- csr->mdi_control = (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21)
- | (value & 0xffff);
+ CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+ (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) |
+ (value & 0xffff));
- while ((csr->mdi_control & 0x10000000) == 0 && count--)
+ while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 &&
+ count--)
DELAY(10);
if (count <= 0)
- printf("fxp_mdi_write: timed out\n");
+ printf(FXP_FORMAT ": fxp_mdi_write: timed out\n",
+ FXP_ARGS(sc));
}
static int
fxp_ioctl(ifp, command, data)
struct ifnet *ifp;
- int command;
+ FXP_IOCTLCMD_TYPE command;
caddr_t data;
{
- struct ifaddr *ifa = (struct ifaddr *) data;
struct fxp_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *) data;
+ struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
s = splimp();
@@ -1124,8 +1583,10 @@ fxp_ioctl(ifp, command, data)
switch (command) {
case SIOCSIFADDR:
+#if !defined(__NetBSD__)
case SIOCGIFADDR:
case SIOCSIFMTU:
+#endif
error = ether_ioctl(ifp, command, data);
break;
@@ -1147,12 +1608,36 @@ fxp_ioctl(ifp, command, data)
case SIOCADDMULTI:
case SIOCDELMULTI:
+#if defined(__NetBSD__)
+ {
+ struct ifreq *ifr = (struct ifreq *) data;
+
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_ethercom) :
+ ether_delmulti(ifr, &sc->sc_ethercom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly.
+ */
+ fxp_init(sc);
+ error = 0;
+ }
+ }
+#else /* __FreeBSD__ */
/*
* Multicast list has changed; set the hardware filter
* accordingly.
*/
fxp_init(sc);
error = 0;
+#endif /* __NetBSD__ */
+ break;
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
break;
default:
diff --git a/sys/pci/if_fxpreg.h b/sys/pci/if_fxpreg.h
index 0708dff..e2835ca 100644
--- a/sys/pci/if_fxpreg.h
+++ b/sys/pci/if_fxpreg.h
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_fxpreg.h,v 1.8 1997/03/21 08:00:13 davidg Exp $
+ * $Id$
*/
#define FXP_VENDORID_INTEL 0x8086
@@ -33,19 +33,26 @@
#define FXP_PCI_MMBA 0x10
#define FXP_PCI_IOBA 0x14
-struct fxp_csr {
- volatile u_int8_t :2,
- scb_rus:4,
- scb_cus:2;
- volatile u_int8_t scb_statack;
- volatile u_int8_t scb_command;
- volatile u_int8_t scb_intrcntl;
- volatile u_int32_t scb_general;
- volatile u_int32_t port;
- volatile u_int16_t flash_control;
- volatile u_int16_t eeprom_control;
- volatile u_int32_t mdi_control;
-};
+/*
+ * Control/status registers.
+ */
+#define FXP_CSR_SCB_RUSCUS 0 /* scb_rus/scb_cus (1 byte) */
+#define FXP_CSR_SCB_STATACK 1 /* scb_statack (1 byte) */
+#define FXP_CSR_SCB_COMMAND 2 /* scb_command (1 byte) */
+#define FXP_CSR_SCB_INTRCNTL 3 /* scb_intrcntl (1 byte) */
+#define FXP_CSR_SCB_GENERAL 4 /* scb_general (4 bytes) */
+#define FXP_CSR_PORT 8 /* port (4 bytes) */
+#define FXP_CSR_FLASHCONTROL 12 /* flash control (2 bytes) */
+#define FXP_CSR_EEPROMCONTROL 14 /* eeprom control (2 bytes) */
+#define FXP_CSR_MDICONTROL 16 /* mdi control (4 bytes) */
+
+/*
+ * FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS:
+ *
+ * volatile u_int8_t :2,
+ * scb_rus:4,
+ * scb_cus:2;
+ */
#define FXP_PORT_SOFTWARE_RESET 0
#define FXP_PORT_SELFTEST 1
diff --git a/sys/pci/if_fxpvar.h b/sys/pci/if_fxpvar.h
new file mode 100644
index 0000000..9c7e310
--- /dev/null
+++ b/sys/pci/if_fxpvar.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1995, David Greenman
+ * All rights reserved.
+ *
+ * Modifications to support NetBSD:
+ * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * Misc. defintions for the Intel EtherExpress Pro/100B PCI Fast
+ * Ethernet driver
+ */
+
+struct fxp_softc {
+#if defined(__NetBSD__)
+ struct device sc_dev; /* generic device structures */
+ void *sc_ih; /* interrupt handler cookie */
+ bus_space_tag_t sc_st; /* bus space tag */
+ bus_space_handle_t sc_sh; /* bus space handle */
+ struct ethercom sc_ethercom; /* ethernet common part */
+#else
+ struct arpcom arpcom; /* per-interface network data */
+ caddr_t csr; /* control/status registers */
+#endif /* __NetBSD__ */
+ struct ifmedia sc_media; /* media information */
+ struct fxp_cb_tx *cbl_base; /* base of TxCB list */
+ struct fxp_cb_tx *cbl_first; /* first active TxCB in list */
+ struct fxp_cb_tx *cbl_last; /* last active TxCB in list */
+ struct mbuf *rfa_headm; /* first mbuf in receive frame area */
+ struct mbuf *rfa_tailm; /* last mbuf in receive frame area */
+ struct fxp_stats *fxp_stats; /* Pointer to interface stats */
+ int tx_queued; /* # of active TxCB's */
+ int promisc_mode; /* promiscuous mode enabled */
+ int phy_primary_addr; /* address of primary PHY */
+ int phy_primary_device; /* device type of primary PHY */
+ int phy_10Mbps_only; /* PHY is 10Mbps-only device */
+};
+
+/* Macros to ease CSR access. */
+#if defined(__NetBSD__)
+#define CSR_READ_1(sc, reg) \
+ bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))
+#define CSR_READ_2(sc, reg) \
+ bus_space_read_2((sc)->sc_st, (sc)->sc_sh, (reg))
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define CSR_WRITE_2(sc, reg, val) \
+ bus_space_write_2((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#else
+#define CSR_READ_1(sc, reg) \
+ (*((u_int8_t *)((sc)->csr + (reg))))
+#define CSR_READ_2(sc, reg) \
+ (*((u_int16_t *)((sc)->csr + (reg))))
+#define CSR_READ_4(sc, reg) \
+ (*((u_int32_t *)((sc)->csr + (reg))))
+#define CSR_WRITE_1(sc, reg, val) \
+ (*((u_int8_t *)((sc)->csr + (reg)))) = (val)
+#define CSR_WRITE_2(sc, reg, val) \
+ (*((u_int16_t *)((sc)->csr + (reg)))) = (val)
+#define CSR_WRITE_4(sc, reg, val) \
+ (*((u_int32_t *)((sc)->csr + (reg)))) = (val)
+#endif /* __NetBSD__ */
+
+/* Deal with slight differences in software interfaces. */
+#if defined(__NetBSD__)
+#define sc_if sc_ethercom.ec_if
+#define FXP_FORMAT "%s"
+#define FXP_ARGS(sc) (sc)->sc_dev.dv_xname
+#define FXP_INTR_TYPE int
+#define FXP_IOCTLCMD_TYPE u_long
+#define FXP_BPFTAP_ARG(ifp) (ifp)->if_bpf
+#else /* __FreeBSD__ */
+#define sc_if arpcom.ac_if
+#define FXP_FORMAT "fxp%d"
+#define FXP_ARGS(sc) (sc)->arpcom.ac_if.if_unit
+#define FXP_INTR_TYPE void
+#define FXP_IOCTLCMD_TYPE int
+#define FXP_BPFTAP_ARG(ifp) ifp
+#endif /* __NetBSD__ */
OpenPOWER on IntegriCloud