Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci Driver for Sun Cassini/Cassini+ (GigaSwift) Ethe...
details: https://anonhg.NetBSD.org/src/rev/565b4269fe7b
branches: trunk
changeset: 750569:565b4269fe7b
user: jdc <jdc%NetBSD.org@localhost>
date: Thu Jan 07 09:19:55 2010 +0000
description:
Driver for Sun Cassini/Cassini+ (GigaSwift) Ethernet (also known as
National Semiconductor Saturn).
Based on the OpenBSD driver written by Mark Kettenis:
detach support added
MAC address lookup modified (only tested on sparc64)
Tested on single GigaSwift (UTP and MMF) and quad GigaSwift PCI cards.
diffstat:
sys/dev/pci/if_cas.c | 2090 +++++++++++++++++++++++++++++++++++++++++++++++
sys/dev/pci/if_casreg.h | 617 +++++++++++++
sys/dev/pci/if_casvar.h | 261 +++++
3 files changed, 2968 insertions(+), 0 deletions(-)
diffs (truncated from 2980 to 300 lines):
diff -r a200b55eae98 -r 565b4269fe7b sys/dev/pci/if_cas.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/pci/if_cas.c Thu Jan 07 09:19:55 2010 +0000
@@ -0,0 +1,2090 @@
+/* $NetBSD: if_cas.c,v 1.1 2010/01/07 09:19:55 jdc Exp $ */
+/* $OpenBSD: if_cas.c,v 1.29 2009/11/29 16:19:38 kettenis Exp $ */
+
+/*
+ *
+ * Copyright (C) 2007 Mark Kettenis.
+ * Copyright (C) 2001 Eduardo Horvath.
+ * 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, 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 ``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 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.
+ *
+ */
+
+/*
+ * Driver for Sun Cassini ethernet controllers.
+ *
+ * There are basically two variants of this chip: Cassini and
+ * Cassini+. We can distinguish between the two by revision: 0x10 and
+ * up are Cassini+. The most important difference is that Cassini+
+ * has a second RX descriptor ring. Cassini+ will not work without
+ * configuring that second ring. However, since we don't use it we
+ * don't actually fill the descriptors, and only hand off the first
+ * four to the chip.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_cas.c,v 1.1 2010/01/07 09:19:55 jdc Exp $");
+
+#include "opt_inet.h"
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/callout.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <machine/endian.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <sys/bus.h>
+#include <sys/intr.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/mii_bitbang.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/pci/if_casreg.h>
+#include <dev/pci/if_casvar.h>
+
+/* XXX Should use Properties when that's fleshed out. */
+#ifdef macppc
+#include <dev/ofw/openfirm.h>
+#endif /* macppc */
+#ifdef __sparc__
+#include <machine/promlib.h>
+#endif
+
+#ifndef CAS_USE_LOCAL_MAC_ADDRESS
+#if defined (macppc) || defined (__sparc__)
+#define CAS_USE_LOCAL_MAC_ADDRESS 0 /* use system-wide address */
+#else
+#define CAS_USE_LOCAL_MAC_ADDRESS 1
+#endif
+#endif
+
+#define TRIES 10000
+
+static bool cas_estintr(struct cas_softc *sc);
+bool cas_shutdown(device_t, int);
+static bool cas_suspend(device_t PMF_FN_PROTO);
+static bool cas_resume(device_t PMF_FN_PROTO);
+static int cas_detach(device_t, int);
+static void cas_partial_detach(struct cas_softc *, enum cas_attach_stage);
+
+int cas_match(device_t, cfdata_t, void *);
+void cas_attach(device_t, device_t, void *);
+
+
+CFATTACH_DECL3_NEW(cas, sizeof(struct cas_softc),
+ cas_match, cas_attach, cas_detach, NULL, NULL, NULL,
+ DVF_DETACH_SHUTDOWN);
+
+#if CAS_USE_LOCAL_MAC_ADDRESS
+int cas_pci_enaddr(struct cas_softc *, struct pci_attach_args *, uint8_t *);
+#endif
+
+void cas_config(struct cas_softc *, const uint8_t *);
+void cas_start(struct ifnet *);
+void cas_stop(struct ifnet *, int);
+int cas_ioctl(struct ifnet *, u_long, void *);
+void cas_tick(void *);
+void cas_watchdog(struct ifnet *);
+int cas_init(struct ifnet *);
+void cas_init_regs(struct cas_softc *);
+int cas_ringsize(int);
+int cas_cringsize(int);
+int cas_meminit(struct cas_softc *);
+void cas_mifinit(struct cas_softc *);
+int cas_bitwait(struct cas_softc *, bus_space_handle_t, int,
+ u_int32_t, u_int32_t);
+void cas_reset(struct cas_softc *);
+int cas_reset_rx(struct cas_softc *);
+int cas_reset_tx(struct cas_softc *);
+int cas_disable_rx(struct cas_softc *);
+int cas_disable_tx(struct cas_softc *);
+void cas_rxdrain(struct cas_softc *);
+int cas_add_rxbuf(struct cas_softc *, int idx);
+void cas_iff(struct cas_softc *);
+int cas_encap(struct cas_softc *, struct mbuf *, u_int32_t *);
+
+/* MII methods & callbacks */
+int cas_mii_readreg(device_t, int, int);
+void cas_mii_writereg(device_t, int, int, int);
+void cas_mii_statchg(device_t);
+int cas_pcs_readreg(device_t, int, int);
+void cas_pcs_writereg(device_t, int, int, int);
+
+int cas_mediachange(struct ifnet *);
+void cas_mediastatus(struct ifnet *, struct ifmediareq *);
+
+int cas_eint(struct cas_softc *, u_int);
+int cas_rint(struct cas_softc *);
+int cas_tint(struct cas_softc *, u_int32_t);
+int cas_pint(struct cas_softc *);
+int cas_intr(void *);
+
+#ifdef CAS_DEBUG
+#define DPRINTF(sc, x) if ((sc)->sc_ethercom.ec_if.if_flags & IFF_DEBUG) \
+ printf x
+#else
+#define DPRINTF(sc, x) /* nothing */
+#endif
+
+int
+cas_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
+ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_CASSINI))
+ return 1;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS &&
+ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SATURN))
+ return 1;
+
+ return 0;
+}
+
+#if CAS_USE_LOCAL_MAC_ADDRESS
+#define PROMHDR_PTR_DATA 0x18
+#define PROMDATA_PTR_VPD 0x08
+#define PROMDATA_DATA2 0x0a
+
+static const u_int8_t cas_promhdr[] = { 0x55, 0xaa };
+static const u_int8_t cas_promdat[] = {
+ 'P', 'C', 'I', 'R',
+ PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
+ PCI_PRODUCT_SUN_CASSINI & 0xff, PCI_PRODUCT_SUN_CASSINI >> 8
+};
+
+static const u_int8_t cas_promdat2[] = {
+ 0x18, 0x00, /* structure length */
+ 0x00, /* structure revision */
+ 0x00, /* interface revision */
+ PCI_SUBCLASS_NETWORK_ETHERNET, /* subclass code */
+ PCI_CLASS_NETWORK /* class code */
+};
+
+int
+cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa,
+ uint8_t *enaddr)
+{
+ struct pci_vpd_largeres *res;
+ struct pci_vpd *vpd;
+ bus_space_handle_t romh;
+ bus_space_tag_t romt;
+ bus_size_t romsize = 0;
+ u_int8_t buf[32], *desc;
+ pcireg_t address;
+ int dataoff, vpdoff, len;
+ int rv = -1;
+
+ if (pci_mapreg_map(pa, PCI_MAPREG_ROM, PCI_MAPREG_TYPE_MEM, 0,
+ &romt, &romh, NULL, &romsize))
+ return (-1);
+
+ address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
+ address |= PCI_MAPREG_ROM_ENABLE;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START, address);
+
+ bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
+ if (bcmp(buf, cas_promhdr, sizeof(cas_promhdr)))
+ goto fail;
+
+ dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8);
+ if (dataoff < 0x1c)
+ goto fail;
+
+ bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
+ if (bcmp(buf, cas_promdat, sizeof(cas_promdat)) ||
+ bcmp(buf + PROMDATA_DATA2, cas_promdat2, sizeof(cas_promdat2)))
+ goto fail;
+
+ vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8);
+ if (vpdoff < 0x1c)
+ goto fail;
+
+next:
+ bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));
+ if (!PCI_VPDRES_ISLARGE(buf[0]))
+ goto fail;
+
+ res = (struct pci_vpd_largeres *)buf;
+ vpdoff += sizeof(*res);
+
+ len = ((res->vpdres_len_msb << 8) + res->vpdres_len_lsb);
+ switch(PCI_VPDRES_LARGE_NAME(res->vpdres_byte0)) {
+ case PCI_VPDRES_TYPE_IDENTIFIER_STRING:
+ /* Skip identifier string. */
+ vpdoff += len;
+ goto next;
+
+ case PCI_VPDRES_TYPE_VPD:
+ while (len > 0) {
+ bus_space_read_region_1(romt, romh, vpdoff,
+ buf, sizeof(buf));
+
+ vpd = (struct pci_vpd *)buf;
+ vpdoff += sizeof(*vpd) + vpd->vpd_len;
+ len -= sizeof(*vpd) + vpd->vpd_len;
+
+ /*
+ * We're looking for an "Enhanced" VPD...
+ */
+ if (vpd->vpd_key0 != 'Z')
+ continue;
+
+ desc = buf + sizeof(*vpd);
+
+ /*
+ * ...which is an instance property...
+ */
+ if (desc[0] != 'I')
+ continue;
+ desc += 3;
Home |
Main Index |
Thread Index |
Old Index