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