summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/files.pci9
-rw-r--r--sys/dev/pci/if_che.c364
2 files changed, 372 insertions, 1 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 1876ec0897a..920c5573dbf 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.234 2007/05/15 01:00:15 dlg Exp $
+# $OpenBSD: files.pci,v 1.235 2007/05/26 17:39:53 claudio Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -358,6 +358,13 @@ device tht: ether, ifnet, ifmedia, firmload
attach tht at thtc
file dev/pci/if_tht.c thtc | tht
+# Chelsio 10Gb Ethernet
+device cheg {}
+attach cheg at pci
+device che: ether, ifnet, ifmedia, firmload
+attach che at cheg
+file dev/pci/if_che.c cheg | che
+
# DEC/Intel 21143 and "tulip" clone ethernet
attach dc at pci with dc_pci
file dev/pci/if_dc_pci.c dc_pci
diff --git a/sys/dev/pci/if_che.c b/sys/dev/pci/if_che.c
new file mode 100644
index 00000000000..1e9263ed751
--- /dev/null
+++ b/sys/dev/pci/if_che.c
@@ -0,0 +1,364 @@
+/* $OpenBSD: if_che.c,v 1.1 2007/05/26 17:39:53 claudio Exp $ */
+
+/*
+ * Copyright (c) 2007 Claudio Jeker <claudio@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
+
+
+struct cheg_softc {
+ struct device sc_dev;
+
+ bus_dma_tag_t sc_dmat;
+
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_memh;
+ bus_size_t sc_mems;
+
+ u_int32_t sc_rev; /* card revision */
+};
+
+struct che_softc {
+ struct device sc_dev;
+ struct arpcom sc_ac;
+ struct ifmedia sc_media;
+
+ void *sc_if;
+};
+
+/* function protos */
+int cheg_match(struct device *, void *, void *);
+void cheg_attach(struct device *, struct device *, void *);
+int cheg_print(void *, const char *);
+int che_match(struct device *, void *, void *);
+void che_attach(struct device *, struct device *, void *);
+u_int32_t che_read(struct cheg_softc *, bus_size_t);
+void che_write(struct cheg_softc *, bus_size_t, u_int32_t);
+int che_waitfor(struct cheg_softc *, bus_size_t, u_int32_t, int);
+int che_write_flash_reg(struct cheg_softc *, size_t, int,
+ u_int32_t);
+int che_read_flash_reg(struct cheg_softc *, size_t, int,
+ u_int32_t *);
+int che_read_flash_multi4(struct cheg_softc *, u_int, u_int32_t *,
+ size_t);
+void che_reset(struct cheg_softc *);
+
+/* registers & defines */
+#define CHE_PCI_BAR 0x10
+
+#define CHE_REG_PL_RST 0x6f0
+#define CHE_RST_F_CRSTWRM 0x2
+#define CHE_RST_F_CRSTWRMMODE 0x1
+#define CHE_REG_PL_REV 0x6f4
+
+/* serial flash and firmware definitions */
+#define CHE_REG_SF_DATA 0x6d8
+#define CHE_REG_SF_OP 0x6dc
+#define CHE_SF_SEC_SIZE (64 * 1024) /* serial flash sector size */
+#define CHE_SF_SIZE (8 * CHE_SF_SEC_SIZE) /* serial flash size */
+#define CHE_SF_PROG_PAGE 2
+#define CHE_SF_WR_DISABLE 4
+#define CHE_SF_RD_STATUS 5 /* read status register */
+#define CHE_SF_WR_ENABLE 6
+#define CHE_SF_RD_DATA 11
+#define CHE_SF_SEC_ERASE 216
+#define CHE_SF_F_BUSY (1U << 31)
+#define CHE_SF_F_OP 0x1
+#define CHE_SF_CONT(_x) ((_x) << 3)
+#define CHE_SF_BYTECNT_MASK 0x3
+#define CHE_SF_BYTECNT(_x) (((_x) & CHE_SF_BYTECNT_MASK) << 1)
+
+#define FW_FLASH_BOOT_ADDR 0x70000 /* start address of FW in flash */
+#define FW_VERS_ADDR 0x77ffc /* flash address holding FW version */
+#define FW_VERS_TYPE_N3 0
+#define FW_VERS_TYPE_T3 1
+#define FW_VERS_TYPE(_x) (((_x) >> 28) & 0xf)
+#define FW_VERS_MAJOR(_x) (((_x) >> 16) & 0xfff)
+#define FW_VERS_MINOR(_x) (((_x) >> 8) & 0xff)
+#define FW_VERS_MICRO(_x) ((_x) & 0xff)
+
+struct cfattach cheg_ca = {
+ sizeof(struct cheg_softc), cheg_match, cheg_attach
+};
+
+struct cfdriver cheg_cd = {
+ NULL, "cheg", DV_DULL
+};
+
+/* glue between the controller and the port */
+struct che_attach_args {
+ struct pci_attach_args *caa_pa;
+ pci_intr_handle_t caa_ih;
+ int caa_port;
+};
+
+struct cfattach che_ca = {
+ sizeof(struct che_softc), che_match, che_attach
+};
+
+struct cfdriver che_cd = {
+ NULL, "che", DV_IFNET
+};
+
+struct cheg_device {
+ pci_vendor_id_t cd_vendor;
+ pci_vendor_id_t cd_product;
+ u_int cd_nports;
+};
+
+const struct cheg_device *cheg_lookup(struct pci_attach_args *);
+
+const struct cheg_device che_devices[] = {
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_PE9000, 2 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T302E, 2 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T302X, 2 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T310E, 1 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T310X, 1 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T320E, 2 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T320X, 2 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T3B02, 2 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T3B10, 1 },
+ { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T3B20, 2 }
+};
+
+const struct cheg_device *
+cheg_lookup(struct pci_attach_args *pa)
+{
+ int i;
+ const struct cheg_device *cd;
+
+ for (i = 0; i < sizeof(che_devices)/sizeof(che_devices[0]); i++) {
+ cd = &che_devices[i];
+ if (cd->cd_vendor == PCI_VENDOR(pa->pa_id) &&
+ cd->cd_product == PCI_PRODUCT(pa->pa_id))
+ return (cd);
+ }
+
+ return (NULL);
+}
+
+int
+cheg_match(struct device *parent, void *match, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ if (cheg_lookup(pa) != NULL)
+ return (1);
+
+ return (0);
+}
+
+void
+cheg_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct cheg_softc *sc = (struct cheg_softc *)self;
+ struct pci_attach_args *pa = aux;
+ const struct cheg_device *cd;
+ struct che_attach_args caa;
+ pcireg_t memtype;
+ u_int32_t vers;
+ u_int i;
+
+ bzero(&caa, sizeof(caa));
+ cd = cheg_lookup(pa);
+
+ sc->sc_dmat = pa->pa_dmat;
+
+ memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CHE_PCI_BAR);
+ if (pci_mapreg_map(pa, CHE_PCI_BAR, memtype, 0, &sc->sc_memt,
+ &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) {
+ printf(": unable to map host registers\n");
+ return;
+ }
+
+ if (pci_intr_map(pa, &caa.caa_ih) != 0) {
+ printf(": unable to map interrupt\n");
+ goto unmap;
+ }
+ printf(": %s", pci_intr_string(pa->pa_pc, caa.caa_ih));
+
+ sc->sc_rev = che_read(sc, CHE_REG_PL_REV);
+
+ /* reset the beast */
+ che_reset(sc);
+
+ che_read_flash_multi4(sc, FW_VERS_ADDR, &vers, 1);
+ printf(", rev %d, fw %d-%d.%d.%d\n", sc->sc_rev, FW_VERS_TYPE(vers),
+ FW_VERS_MAJOR(vers), FW_VERS_MINOR(vers), FW_VERS_MICRO(vers));
+
+ caa.caa_pa = pa;
+ for (i = 0; i < cd->cd_nports; i++) {
+ caa.caa_port = i;
+
+ config_found(self, &caa, cheg_print);
+ }
+
+ return;
+
+unmap:
+ bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
+ sc->sc_mems = 0;
+}
+
+int
+cheg_print(void *aux, const char *pnp)
+{
+ struct che_attach_args *caa = aux;
+
+ if (pnp != NULL)
+ printf("\"%s\" at %s", che_cd.cd_name, pnp);
+
+ printf(" port %d", caa->caa_port);
+
+ return (UNCONF);
+}
+
+int
+che_match(struct device *parent, void *match, void *aux)
+{
+ return (1);
+}
+
+void
+che_attach(struct device *parent, struct device *self, void *aux)
+{
+ printf(": not done yet\n");
+ return;
+}
+
+u_int32_t
+che_read(struct cheg_softc *sc, bus_size_t r)
+{
+ bus_space_barrier(sc->sc_memt, sc->sc_memh, r, 4,
+ BUS_SPACE_BARRIER_READ);
+ return (bus_space_read_4(sc->sc_memt, sc->sc_memh, r));
+}
+
+void
+che_write(struct cheg_softc *sc, bus_size_t r, u_int32_t v)
+{
+ bus_space_write_4(sc->sc_memt, sc->sc_memh, r, v);
+ bus_space_barrier(sc->sc_memt, sc->sc_memh, r, 4,
+ BUS_SPACE_BARRIER_WRITE);
+}
+
+int
+che_waitfor(struct cheg_softc *sc, bus_size_t r, u_int32_t mask, int tries)
+{
+ u_int32_t v;
+ int i;
+
+ for (i = 0; i < tries; i++) {
+ v = che_read(sc, r);
+ if ((v & mask) == 0)
+ return (0);
+ delay(10);
+ }
+ return (EAGAIN);
+}
+
+int
+che_write_flash_reg(struct cheg_softc *sc, size_t bcnt, int cont, u_int32_t v)
+{
+ if (che_read(sc, CHE_REG_SF_OP) & CHE_SF_F_BUSY)
+ return (EBUSY);
+
+ che_write(sc, CHE_REG_SF_DATA, v);
+ che_write(sc, CHE_REG_SF_OP, CHE_SF_CONT(cont) |
+ CHE_SF_BYTECNT(bcnt - 1) | CHE_SF_F_OP);
+
+ return (che_waitfor(sc, CHE_REG_SF_OP, CHE_SF_F_BUSY, 5));
+}
+
+int
+che_read_flash_reg(struct cheg_softc *sc, size_t bcnt, int cont, u_int32_t *vp)
+{
+ if (che_read(sc, CHE_REG_SF_OP) & CHE_SF_F_BUSY)
+ return (EBUSY);
+
+ che_write(sc, CHE_REG_SF_OP, CHE_SF_CONT(cont) |
+ CHE_SF_BYTECNT(bcnt - 1));
+
+ if (che_waitfor(sc, CHE_REG_SF_OP, CHE_SF_F_BUSY, 5))
+ return (EAGAIN);
+
+ *vp = che_read(sc, CHE_REG_SF_DATA);
+ return (0);
+}
+
+int
+che_read_flash_multi4(struct cheg_softc *sc, u_int addr, u_int32_t *datap,
+ size_t count)
+{
+ int rv;
+
+ if (addr + count * sizeof(u_int32_t) > CHE_SF_SIZE || (addr & 3))
+ panic("%s: che_read_flash_multi4 bad params\n", DEVNAME(sc));
+
+ addr = swap32(addr) | CHE_SF_RD_DATA;
+
+ if ((rv = che_write_flash_reg(sc, 4, 1, addr)))
+ return (rv);
+ if ((rv = che_read_flash_reg(sc, 1, 1, datap)))
+ return (rv);
+
+ while (count) {
+ if ((rv = che_read_flash_reg(sc, 4, count > 1, datap)))
+ return (rv);
+ count--;
+ datap++;
+ }
+ return (0);
+}
+
+void
+che_reset(struct cheg_softc *sc)
+{
+ che_write(sc, CHE_REG_PL_RST, CHE_RST_F_CRSTWRM |
+ CHE_RST_F_CRSTWRMMODE);
+
+ /* Give the card some time to boot */
+ delay(500);
+}