Annotation of sys/dev/pci/if_che.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_che.c,v 1.8 2007/05/30 05:11:53 reyk Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2007 Claudio Jeker <claudio@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include "bpfilter.h"
! 20:
! 21: #include <sys/param.h>
! 22: #include <sys/systm.h>
! 23: #include <sys/sockio.h>
! 24: #include <sys/mbuf.h>
! 25: #include <sys/kernel.h>
! 26: #include <sys/socket.h>
! 27: #include <sys/malloc.h>
! 28: #include <sys/device.h>
! 29:
! 30: #include <machine/bus.h>
! 31:
! 32: #include <dev/pci/pcireg.h>
! 33: #include <dev/pci/pcivar.h>
! 34: #include <dev/pci/pcidevs.h>
! 35:
! 36: #include <net/if.h>
! 37: #include <net/if_dl.h>
! 38: #include <net/if_media.h>
! 39: #include <net/if_types.h>
! 40:
! 41: #if NBPFILTER > 0
! 42: #include <net/bpf.h>
! 43: #endif
! 44:
! 45: #include <netinet/in.h>
! 46: #include <netinet/if_ether.h>
! 47:
! 48: #include <dev/mii/mii.h>
! 49: #include <dev/mii/miivar.h>
! 50:
! 51: /* registers & defines */
! 52:
! 53: #define CHE_PCI_BAR 0x10
! 54: #define CHE_PCI_CAP_ID_VPD 0x03
! 55: #define CHE_PCI_VPD_DATA 0x4
! 56: #define CHE_PCI_F_VPD_ADDR 0x80000000
! 57: #define CHE_PCI_VPD_BASE 0xc00
! 58:
! 59: #define CHE_REG_T3DBG_GPIO_EN 0xd0
! 60: #define CHE_T3DBG_F_GPIO11_OEN 0x08000000
! 61: #define CHE_T3DBG_F_GPIO10_OEN 0x04000000
! 62: #define CHE_T3DBG_F_GPIO9_OEN 0x02000000
! 63: #define CHE_T3DBG_F_GPIO8_OEN 0x01000000
! 64: #define CHE_T3DBG_F_GPIO7_OEN 0x00800000
! 65: #define CHE_T3DBG_F_GPIO6_OEN 0x00400000
! 66: #define CHE_T3DBG_F_GPIO5_OEN 0x00200000
! 67: #define CHE_T3DBG_F_GPIO4_OEN 0x00100000
! 68: #define CHE_T3DBG_F_GPIO3_OEN 0x00080000
! 69: #define CHE_T3DBG_F_GPIO2_OEN 0x00040000
! 70: #define CHE_T3DBG_F_GPIO1_OEN 0x00020000
! 71: #define CHE_T3DBG_F_GPIO0_OEN 0x00010000
! 72: #define CHE_T3DBG_F_GPIO11_OUT_VAL 0x00000800
! 73: #define CHE_T3DBG_F_GPIO10_OUT_VAL 0x00000400
! 74: #define CHE_T3DBG_F_GPIO9_OUT_VAL 0x00000200
! 75: #define CHE_T3DBG_F_GPIO8_OUT_VAL 0x00000100
! 76: #define CHE_T3DBG_F_GPIO7_OUT_VAL 0x00000080
! 77: #define CHE_T3DBG_F_GPIO6_OUT_VAL 0x00000040
! 78: #define CHE_T3DBG_F_GPIO5_OUT_VAL 0x00000020
! 79: #define CHE_T3DBG_F_GPIO4_OUT_VAL 0x00000010
! 80: #define CHE_T3DBG_F_GPIO3_OUT_VAL 0x00000008
! 81: #define CHE_T3DBG_F_GPIO2_OUT_VAL 0x00000004
! 82: #define CHE_T3DBG_F_GPIO1_OUT_VAL 0x00000002
! 83: #define CHE_T3DBG_F_GPIO0_OUT_VAL 0x00000001
! 84: #define CHE_REG_I2C_CFG 0x6a0
! 85: #define CHE_I2C_CLKDIV(_x) ((_x) && 0xfff)
! 86: #define CHE_REG_MI1_CFG 0x6b0
! 87: #define CHE_REG_MI1_ADDR 0x6b4
! 88: #define CHE_REG_MI1_DATA 0x6b8
! 89: #define CHE_REG_MI1_OP 0x6bc
! 90: #define CHE_MI1_F_BUSY (1U << 31)
! 91: #define CHE_MI1_F_ST 0x8
! 92: #define CHE_MI1_F_PREEN 0x4
! 93: #define CHE_MI1_F_MDIINV 0x2
! 94: #define CHE_MI1_F_MDIEN 0x1
! 95: #define CHE_MI1_CLKDIV(_x) ((_x) << 5)
! 96: #define CHE_MI1_PHYADDR(_x) ((_x) << 5)
! 97: #define CHE_MI1_OP(_x) ((_x) & 0x3)
! 98: #define CHE_REG_PL_RST 0x6f0
! 99: #define CHE_RST_F_CRSTWRM 0x2
! 100: #define CHE_RST_F_CRSTWRMMODE 0x1
! 101: #define CHE_REG_PL_REV 0x6f4
! 102: #define CHE_REG_XGM_PORT_CFG 0x8b8
! 103: #define CHE_XGMAC0_0_BASE_ADDR 0x800
! 104: #define CHE_XGMAC0_1_BASE_ADDR 0xa00
! 105: #define CHE_XGM_REG(_r, _i) \
! 106: ((_r) + (_i) * (CHE_XGMAC0_1_BASE_ADDR - CHE_XGMAC0_0_BASE_ADDR))
! 107: #define CHE_XGM_PORTSPEED(_x) ((_x) << 1)
! 108: #define CHE_XGM_F_ENRGMII 0x1
! 109: #define CHE_XGM_F_CLKDIVRESET 0x8
! 110:
! 111: /* serial flash and firmware definitions */
! 112: #define CHE_REG_SF_DATA 0x6d8
! 113: #define CHE_REG_SF_OP 0x6dc
! 114: #define CHE_SF_SEC_SIZE (64 * 1024) /* serial flash sector size */
! 115: #define CHE_SF_SIZE (8 * CHE_SF_SEC_SIZE) /* serial flash size */
! 116: #define CHE_SF_PROG_PAGE 2
! 117: #define CHE_SF_WR_DISABLE 4
! 118: #define CHE_SF_RD_STATUS 5 /* read status register */
! 119: #define CHE_SF_WR_ENABLE 6
! 120: #define CHE_SF_RD_DATA 11
! 121: #define CHE_SF_SEC_ERASE 216
! 122: #define CHE_SF_F_BUSY (1U << 31)
! 123: #define CHE_SF_F_OP 0x1
! 124: #define CHE_SF_CONT(_x) ((_x) << 3)
! 125: #define CHE_SF_BYTECNT_MASK 0x3
! 126: #define CHE_SF_BYTECNT(_x) (((_x) & CHE_SF_BYTECNT_MASK) << 1)
! 127:
! 128: #define FW_FLASH_BOOT_ADDR 0x70000 /* start address of FW in flash */
! 129: #define FW_VERS_ADDR 0x77ffc /* flash address holding FW version */
! 130: #define FW_VERS_TYPE_N3 0
! 131: #define FW_VERS_TYPE_T3 1
! 132: #define FW_VERS_TYPE(_x) (((_x) >> 28) & 0xf)
! 133: #define FW_VERS_MAJOR(_x) (((_x) >> 16) & 0xfff)
! 134: #define FW_VERS_MINOR(_x) (((_x) >> 8) & 0xff)
! 135: #define FW_VERS_MICRO(_x) ((_x) & 0xff)
! 136:
! 137: /* Partial EEPROM Vital Product Data structure. */
! 138: struct che_vpd {
! 139: u_int8_t id_tag;
! 140: u_int8_t id_len[2];
! 141: u_int8_t id_data[16];
! 142: u_int8_t vpdr_tag;
! 143: u_int8_t vpdr_len[2];
! 144: u_int8_t pn_name[2]; /* part number */
! 145: u_int8_t pn_len;
! 146: u_int8_t pn_data[16];
! 147: u_int8_t ec_name[2]; /* EC level */
! 148: u_int8_t ec_len;
! 149: u_int8_t ec_data[16];
! 150: u_int8_t sn_name[2]; /* serial number */
! 151: u_int8_t sn_len;
! 152: u_int8_t sn_data[16];
! 153: u_int8_t na_name[2]; /* MAC address base */
! 154: u_int8_t na_len;
! 155: u_int8_t na_data[12];
! 156: u_int8_t cclk_name[2]; /* core clock */
! 157: u_int8_t cclk_len;
! 158: u_int8_t cclk_data[6];
! 159: u_int8_t mclk_name[2]; /* mem clock */
! 160: u_int8_t mclk_len;
! 161: u_int8_t mclk_data[6];
! 162: u_int8_t uclk_name[2]; /* uP clock */
! 163: u_int8_t uclk_len;
! 164: u_int8_t uclk_data[6];
! 165: u_int8_t mdc_name[2]; /* MDIO clock */
! 166: u_int8_t mdc_len;
! 167: u_int8_t mdc_data[6];
! 168: u_int8_t mt_name[2]; /* mem timing */
! 169: u_int8_t mt_len;
! 170: u_int8_t mt_data[2];
! 171: u_int8_t xaui0cfg_name[2]; /* XAUI0 config */
! 172: u_int8_t xaui0cfg_len;
! 173: u_int8_t xaui0cfg_data[6];
! 174: u_int8_t xaui1cfg_name[2]; /* XAUI1 config */
! 175: u_int8_t xaui1cfg_len;
! 176: u_int8_t xaui1cfg_data[6];
! 177: u_int8_t port0_name[2]; /* PHY0 */
! 178: u_int8_t port0_len;
! 179: u_int8_t port0_data[2];
! 180: u_int8_t port1_name[2]; /* PHY1 */
! 181: u_int8_t port1_len;
! 182: u_int8_t port1_data[2];
! 183: u_int8_t port2_name[2]; /* PHY2 */
! 184: u_int8_t port2_len;
! 185: u_int8_t port2_data[2];
! 186: u_int8_t port3_name[2]; /* PHY3 */
! 187: u_int8_t port3_len;
! 188: u_int8_t port3_data[2];
! 189: u_int8_t rv_name[2]; /* csum */
! 190: u_int8_t rv_len;
! 191: u_int8_t rv_data[1];
! 192: u_int8_t pad[4]; /* for multiple-of-4 sizing */
! 193: } __packed;
! 194:
! 195:
! 196: #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
! 197:
! 198: /* the pci controller */
! 199:
! 200: struct cheg_softc {
! 201: struct device sc_dev;
! 202:
! 203: bus_dma_tag_t sc_dmat;
! 204:
! 205: bus_space_tag_t sc_memt;
! 206: bus_space_handle_t sc_memh;
! 207: bus_size_t sc_mems;
! 208:
! 209: u_int32_t sc_rev; /* card revision */
! 210: u_int32_t sc_cclk; /* core clock */
! 211: u_int32_t sc_mdc; /* mdio clock */
! 212:
! 213: pci_vendor_id_t sc_product;
! 214: };
! 215:
! 216: int cheg_match(struct device *, void *, void *);
! 217: void cheg_attach(struct device *, struct device *, void *);
! 218: int cheg_print(void *, const char *);
! 219:
! 220: struct cfattach cheg_ca = {
! 221: sizeof(struct cheg_softc),
! 222: cheg_match,
! 223: cheg_attach
! 224: };
! 225:
! 226: struct cfdriver cheg_cd = {
! 227: NULL, "cheg", DV_DULL
! 228: };
! 229:
! 230: /* glue between the controller and the port */
! 231:
! 232: struct che_attach_args {
! 233: struct pci_attach_args *caa_pa;
! 234: pci_intr_handle_t caa_ih;
! 235: int caa_port;
! 236: u_int8_t caa_lladdr[ETHER_ADDR_LEN];
! 237: };
! 238:
! 239: /* che itself */
! 240:
! 241: struct che_softc {
! 242: struct device sc_dev;
! 243: struct arpcom sc_ac;
! 244: struct mii_data sc_mii;
! 245:
! 246: struct cheg_softc *sc_cheg;
! 247: void *sc_ih;
! 248: int sc_port;
! 249: };
! 250:
! 251: int che_match(struct device *, void *, void *);
! 252: void che_attach(struct device *, struct device *, void *);
! 253:
! 254: struct cfattach che_ca = {
! 255: sizeof(struct che_softc),
! 256: che_match,
! 257: che_attach
! 258: };
! 259:
! 260: struct cfdriver che_cd = {
! 261: NULL, "che", DV_IFNET
! 262: };
! 263:
! 264: int che_write_flash_reg(struct cheg_softc *, size_t, int,
! 265: u_int32_t);
! 266: int che_read_flash_reg(struct cheg_softc *, size_t, int,
! 267: u_int32_t *);
! 268: int che_read_flash_multi4(struct cheg_softc *, u_int, u_int32_t *,
! 269: size_t);
! 270: int che_read_eeprom(struct cheg_softc *, struct pci_attach_args *,
! 271: pcireg_t, pcireg_t *);
! 272: int che_get_vpd(struct cheg_softc *, struct pci_attach_args *,
! 273: void *, size_t);
! 274: void che_conv_lladdr(char *, u_int8_t *);
! 275: u_int32_t che_conv_num(char *, size_t);
! 276: void che_reset(struct cheg_softc *);
! 277: int che_ioctl(struct ifnet *, u_long, caddr_t);
! 278: void che_watchdog(struct ifnet *);
! 279: void che_start(struct ifnet *);
! 280:
! 281: /* ifmedia & mii helper functions */
! 282: int che_ifmedia_upd(struct ifnet *);
! 283: void che_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 284: int che_miibus_readreg(struct device *, int, int);
! 285: void che_miibus_writereg(struct device *, int, int, int);
! 286: int che_miibus_ind_readreg(struct device *, int, int);
! 287: void che_miibus_ind_writereg(struct device *, int, int, int);
! 288: void che_miibus_statchg(struct device *);
! 289:
! 290: /* bus_space wrappers */
! 291: u_int32_t che_read(struct cheg_softc *, bus_size_t);
! 292: void che_write(struct cheg_softc *, bus_size_t, u_int32_t);
! 293: int che_waitfor(struct cheg_softc *, bus_size_t, u_int32_t, int);
! 294:
! 295: /* HW low-level functions */
! 296: void che_hw_init(struct cheg_softc *);
! 297:
! 298: /* cheg */
! 299: struct cheg_device {
! 300: pci_vendor_id_t cd_vendor;
! 301: pci_vendor_id_t cd_product;
! 302: u_int cd_nports;
! 303: };
! 304:
! 305: const struct cheg_device *cheg_lookup(struct pci_attach_args *);
! 306:
! 307: const struct cheg_device che_devices[] = {
! 308: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_PE9000, 2 },
! 309: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T302E, 2 },
! 310: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T302X, 2 },
! 311: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T310E, 1 },
! 312: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T310X, 1 },
! 313: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T320E, 2 },
! 314: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T320X, 2 },
! 315: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T3B02, 2 },
! 316: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T3B10, 1 },
! 317: { PCI_VENDOR_CHELSIO, PCI_PRODUCT_CHELSIO_T3B20, 2 }
! 318: };
! 319:
! 320: const struct cheg_device *
! 321: cheg_lookup(struct pci_attach_args *pa)
! 322: {
! 323: int i;
! 324: const struct cheg_device *cd;
! 325:
! 326: for (i = 0; i < sizeof(che_devices)/sizeof(che_devices[0]); i++) {
! 327: cd = &che_devices[i];
! 328: if (cd->cd_vendor == PCI_VENDOR(pa->pa_id) &&
! 329: cd->cd_product == PCI_PRODUCT(pa->pa_id))
! 330: return (cd);
! 331: }
! 332:
! 333: return (NULL);
! 334: }
! 335:
! 336: int
! 337: cheg_match(struct device *parent, void *match, void *aux)
! 338: {
! 339: struct pci_attach_args *pa = aux;
! 340:
! 341: if (cheg_lookup(pa) != NULL)
! 342: return (1);
! 343:
! 344: return (0);
! 345: }
! 346:
! 347: void
! 348: cheg_attach(struct device *parent, struct device *self, void *aux)
! 349: {
! 350: struct cheg_softc *sc = (struct cheg_softc *)self;
! 351: struct pci_attach_args *pa = aux;
! 352: const struct cheg_device *cd;
! 353: struct che_attach_args caa;
! 354: struct che_vpd vpd;
! 355: pcireg_t memtype;
! 356: u_int32_t vers;
! 357: u_int i;
! 358:
! 359: bzero(&caa, sizeof(caa));
! 360: cd = cheg_lookup(pa);
! 361:
! 362: sc->sc_dmat = pa->pa_dmat;
! 363:
! 364: memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CHE_PCI_BAR);
! 365: if (pci_mapreg_map(pa, CHE_PCI_BAR, memtype, 0, &sc->sc_memt,
! 366: &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) {
! 367: printf(": unable to map host registers\n");
! 368: return;
! 369: }
! 370:
! 371: if (pci_intr_map(pa, &caa.caa_ih) != 0) {
! 372: printf(": unable to map interrupt\n");
! 373: goto unmap;
! 374: }
! 375:
! 376: sc->sc_rev = che_read(sc, CHE_REG_PL_REV);
! 377:
! 378: /* reset the beast */
! 379: che_reset(sc);
! 380:
! 381: if (che_read_flash_multi4(sc, FW_VERS_ADDR, &vers, 1) != 0) {
! 382: printf(": unable to read flash version\n");
! 383: goto unmap;
! 384: }
! 385:
! 386: if (che_get_vpd(sc, pa, &vpd, sizeof(vpd)/sizeof(u_int32_t)) != 0) {
! 387: printf(": unable to get vital product data\n");
! 388: goto unmap;
! 389: }
! 390:
! 391: printf(": %s revision %d firmware %s-%d.%d.%d\n",
! 392: pci_intr_string(pa->pa_pc, caa.caa_ih), sc->sc_rev,
! 393: FW_VERS_TYPE(vers) ? "T" : "N",
! 394: FW_VERS_MAJOR(vers), FW_VERS_MINOR(vers), FW_VERS_MICRO(vers));
! 395:
! 396: sc->sc_product = PCI_PRODUCT(pa->pa_id);
! 397: sc->sc_cclk = che_conv_num(vpd.cclk_data, sizeof(vpd.cclk_data));
! 398: sc->sc_mdc = che_conv_num(vpd.mdc_data, sizeof(vpd.mdc_data));
! 399:
! 400: che_hw_init(sc);
! 401:
! 402: caa.caa_pa = pa;
! 403: che_conv_lladdr(vpd.na_data, caa.caa_lladdr);
! 404:
! 405: for (i = 0; i < cd->cd_nports; i++) {
! 406: caa.caa_port = i;
! 407:
! 408: config_found(self, &caa, cheg_print);
! 409:
! 410: /*
! 411: * The VPD EEPROM stores only the base Ethernet address for the
! 412: * card. The last octet is increased by one for every additional
! 413: * port.
! 414: */
! 415: caa.caa_lladdr[5] += 1;
! 416: }
! 417:
! 418: return;
! 419:
! 420: unmap:
! 421: bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
! 422: sc->sc_mems = 0;
! 423: }
! 424:
! 425: int
! 426: cheg_print(void *aux, const char *pnp)
! 427: {
! 428: struct che_attach_args *caa = aux;
! 429:
! 430: if (pnp != NULL)
! 431: printf("\"%s\" at %s", che_cd.cd_name, pnp);
! 432:
! 433: printf(" port %d", caa->caa_port);
! 434:
! 435: return (UNCONF);
! 436: }
! 437:
! 438: int
! 439: che_match(struct device *parent, void *match, void *aux)
! 440: {
! 441: return (1);
! 442: }
! 443:
! 444: void
! 445: che_attach(struct device *parent, struct device *self, void *aux)
! 446: {
! 447: struct cheg_softc *gsc = (struct cheg_softc *)parent;
! 448: struct che_softc *sc = (struct che_softc *)self;
! 449: struct che_attach_args *caa = aux;
! 450: struct ifnet *ifp;
! 451:
! 452: sc->sc_cheg = gsc;
! 453:
! 454: sc->sc_port = caa->caa_port;
! 455: bcopy(caa->caa_lladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
! 456:
! 457: printf(": address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
! 458:
! 459: ifp = &sc->sc_ac.ac_if;
! 460: ifp->if_softc = sc;
! 461: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 462: ifp->if_ioctl = che_ioctl;
! 463: ifp->if_start = che_start;
! 464: ifp->if_watchdog = che_watchdog;
! 465: ifp->if_hardmtu = MCLBYTES - ETHER_HDR_LEN - ETHER_CRC_LEN; /* XXX */
! 466: strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
! 467: IFQ_SET_MAXLEN(&ifp->if_snd, 400);
! 468: IFQ_SET_READY(&ifp->if_snd);
! 469:
! 470: ifmedia_init(&sc->sc_mii.mii_media, 0,
! 471: che_ifmedia_upd, che_ifmedia_sts);
! 472:
! 473: sc->sc_mii.mii_ifp = ifp;
! 474: sc->sc_mii.mii_readreg = che_miibus_ind_readreg;
! 475: sc->sc_mii.mii_writereg = che_miibus_ind_writereg;
! 476: sc->sc_mii.mii_statchg = che_miibus_statchg;
! 477:
! 478: mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
! 479: MII_OFFSET_ANY, MIIF_DOPAUSE | MIIF_HAVEFIBER);
! 480:
! 481: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
! 482: printf("%s: no PHY found!\n", sc->sc_dev.dv_xname);
! 483: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL,
! 484: 0, NULL);
! 485: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
! 486: } else
! 487: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
! 488:
! 489: if_attach(ifp);
! 490: ether_ifattach(ifp);
! 491:
! 492: return;
! 493: }
! 494:
! 495: int
! 496: che_write_flash_reg(struct cheg_softc *sc, size_t bcnt, int cont, u_int32_t v)
! 497: {
! 498: if (che_read(sc, CHE_REG_SF_OP) & CHE_SF_F_BUSY)
! 499: return (EBUSY);
! 500:
! 501: che_write(sc, CHE_REG_SF_DATA, v);
! 502: che_write(sc, CHE_REG_SF_OP, CHE_SF_CONT(cont) |
! 503: CHE_SF_BYTECNT(bcnt - 1) | CHE_SF_F_OP);
! 504:
! 505: return (che_waitfor(sc, CHE_REG_SF_OP, CHE_SF_F_BUSY, 5));
! 506: }
! 507:
! 508: int
! 509: che_read_flash_reg(struct cheg_softc *sc, size_t bcnt, int cont, u_int32_t *vp)
! 510: {
! 511: if (che_read(sc, CHE_REG_SF_OP) & CHE_SF_F_BUSY)
! 512: return (EBUSY);
! 513:
! 514: che_write(sc, CHE_REG_SF_OP, CHE_SF_CONT(cont) |
! 515: CHE_SF_BYTECNT(bcnt - 1));
! 516:
! 517: if (che_waitfor(sc, CHE_REG_SF_OP, CHE_SF_F_BUSY, 5))
! 518: return (EAGAIN);
! 519:
! 520: *vp = che_read(sc, CHE_REG_SF_DATA);
! 521: return (0);
! 522: }
! 523:
! 524: int
! 525: che_read_flash_multi4(struct cheg_softc *sc, u_int addr, u_int32_t *datap,
! 526: size_t count)
! 527: {
! 528: int rv;
! 529:
! 530: if (addr + count * sizeof(u_int32_t) > CHE_SF_SIZE || (addr & 3))
! 531: panic("%s: che_read_flash_multi4 bad params\n", DEVNAME(sc));
! 532:
! 533: addr = swap32(addr) | CHE_SF_RD_DATA;
! 534:
! 535: if ((rv = che_write_flash_reg(sc, 4, 1, addr)))
! 536: return (rv);
! 537: if ((rv = che_read_flash_reg(sc, 1, 1, datap)))
! 538: return (rv);
! 539:
! 540: while (count) {
! 541: if ((rv = che_read_flash_reg(sc, 4, count > 1, datap)))
! 542: return (rv);
! 543: count--;
! 544: datap++;
! 545: }
! 546: return (0);
! 547: }
! 548:
! 549: int
! 550: che_read_eeprom(struct cheg_softc *sc, struct pci_attach_args *pa,
! 551: pcireg_t addr, pcireg_t *dp)
! 552: {
! 553: pcireg_t rv, base;
! 554: int i = 4;
! 555:
! 556: if (!pci_get_capability(pa->pa_pc, pa->pa_tag, CHE_PCI_CAP_ID_VPD,
! 557: &base, NULL)) {
! 558: printf("%s: VPD EEPROM not found\n",
! 559: DEVNAME(sc), addr);
! 560: return EIO;
! 561: }
! 562:
! 563: addr <<= 16;
! 564: pci_conf_write(pa->pa_pc, pa->pa_tag, base, addr);
! 565:
! 566: while(i--) {
! 567: delay(10);
! 568: rv = pci_conf_read(pa->pa_pc, pa->pa_tag, base);
! 569: if (rv & CHE_PCI_F_VPD_ADDR)
! 570: break;
! 571: }
! 572: if (!(rv & CHE_PCI_F_VPD_ADDR)) {
! 573: printf("%s: reading EEPROM address 0x%x failed\n",
! 574: DEVNAME(sc), addr);
! 575: return EIO;
! 576: }
! 577:
! 578: *dp = pci_conf_read(pa->pa_pc, pa->pa_tag, base + CHE_PCI_VPD_DATA);
! 579: return (0);
! 580: }
! 581:
! 582: int
! 583: che_get_vpd(struct cheg_softc *sc, struct pci_attach_args *pa,
! 584: void *vpd, size_t dwords)
! 585: {
! 586: pcireg_t dw0, *dw = vpd;
! 587: int i;
! 588: u_int16_t addr;
! 589:
! 590: /*
! 591: * Card information is normally at CHE_PCI_VPD_BASE but some early
! 592: * cards had it at 0.
! 593: */
! 594: if (che_read_eeprom(sc, pa, CHE_PCI_VPD_BASE, &dw0))
! 595: return (1);
! 596:
! 597: /* we compare the id_tag which is least significant byte */
! 598: addr = ((dw0 & 0xff) == 0x82) ? CHE_PCI_VPD_BASE : 0;
! 599:
! 600: for (i = 0; i < dwords; i++) {
! 601: if (che_read_eeprom(sc, pa, addr + i * 4, &dw[i]))
! 602: return (1);
! 603: }
! 604:
! 605: return (0);
! 606: }
! 607:
! 608: /*
! 609: * VPD mac addr is stored as ASCII string so we need to convert it to a
! 610: * sane representation form.
! 611: */
! 612: void
! 613: che_conv_lladdr(char *mac, u_int8_t *lladdr)
! 614: {
! 615: int i;
! 616: u_int8_t digit;
! 617:
! 618: bzero(lladdr, ETHER_ADDR_LEN);
! 619:
! 620: for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
! 621: if (mac[i] >= '0' && mac[i] <= '9')
! 622: digit = mac[i] - '0';
! 623: else if (mac[i] >= 'A' && mac[i] <= 'F')
! 624: digit = mac[i] - 'A' + 10;
! 625: else if (mac[i] >= 'a' && mac[i] <= 'f')
! 626: digit = mac[i] - 'a' + 10;
! 627:
! 628: if ((i & 1) == 0)
! 629: digit <<= 4;
! 630:
! 631: lladdr[i/2] |= digit;
! 632: }
! 633: }
! 634:
! 635: u_int32_t
! 636: che_conv_num(char *num, size_t len)
! 637: {
! 638: size_t i;
! 639: u_int32_t n = 0;
! 640:
! 641: for (i = 0; i < len; i++) {
! 642: if (num[i] >= '0' && num[i] <= '9')
! 643: n = 10 * n + (num[i] - '0');
! 644: else
! 645: break;
! 646: }
! 647: return (n);
! 648: }
! 649:
! 650: void
! 651: che_reset(struct cheg_softc *sc)
! 652: {
! 653: che_write(sc, CHE_REG_PL_RST, CHE_RST_F_CRSTWRM |
! 654: CHE_RST_F_CRSTWRMMODE);
! 655:
! 656: /* Give the card some time to boot */
! 657: delay(500);
! 658: }
! 659:
! 660: int
! 661: che_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
! 662: {
! 663: return (EIO);
! 664: }
! 665:
! 666: void
! 667: che_watchdog(struct ifnet *ifp)
! 668: {
! 669: /* XXX */
! 670: }
! 671:
! 672: void
! 673: che_start(struct ifnet *ifp)
! 674: {
! 675: /* XXX */
! 676: }
! 677:
! 678: int
! 679: che_ifmedia_upd(struct ifnet *ifp)
! 680: {
! 681: struct che_softc *sc = ifp->if_softc;
! 682:
! 683: mii_mediachg(&sc->sc_mii);
! 684: return (0);
! 685: }
! 686:
! 687: void
! 688: che_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
! 689: {
! 690: struct che_softc *sc = ifp->if_softc;
! 691:
! 692: mii_pollstat(&sc->sc_mii);
! 693: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 694: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 695: }
! 696:
! 697: int
! 698: che_miibus_readreg(struct device *dev, int phy, int reg)
! 699: {
! 700: struct che_softc *sc = (struct che_softc *)dev;
! 701: u_int32_t addr = CHE_MI1_PHYADDR(phy) | reg;
! 702:
! 703: che_write(sc->sc_cheg, CHE_REG_MI1_ADDR, addr);
! 704: che_write(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_OP(2));
! 705:
! 706: if (che_waitfor(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_F_BUSY, 20))
! 707: return (0);
! 708:
! 709: return ((int)che_read(sc->sc_cheg, CHE_REG_MI1_DATA));
! 710: }
! 711:
! 712: void
! 713: che_miibus_writereg(struct device *dev, int phy, int reg, int val)
! 714: {
! 715: struct che_softc *sc = (struct che_softc *)dev;
! 716: u_int32_t addr = CHE_MI1_PHYADDR(phy) | reg;
! 717:
! 718: che_write(sc->sc_cheg, CHE_REG_MI1_ADDR, addr);
! 719: che_write(sc->sc_cheg, CHE_REG_MI1_DATA, val);
! 720: che_write(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_OP(1));
! 721: che_waitfor(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_F_BUSY, 20);
! 722: }
! 723:
! 724: int
! 725: che_miibus_ind_readreg(struct device *dev, int phy, int reg)
! 726: {
! 727: struct che_softc *sc = (struct che_softc *)dev;
! 728:
! 729: che_write(sc->sc_cheg, CHE_REG_MI1_ADDR, CHE_MI1_PHYADDR(phy));
! 730: che_write(sc->sc_cheg, CHE_REG_MI1_DATA, reg);
! 731: che_write(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_OP(0));
! 732:
! 733: if (che_waitfor(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_F_BUSY, 20))
! 734: return (0);
! 735:
! 736: che_write(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_OP(3));
! 737:
! 738: if (che_waitfor(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_F_BUSY, 20))
! 739: return (0);
! 740:
! 741: return ((int)che_read(sc->sc_cheg, CHE_REG_MI1_DATA));
! 742: }
! 743:
! 744: void
! 745: che_miibus_ind_writereg(struct device *dev, int phy, int reg, int val)
! 746: {
! 747: struct che_softc *sc = (struct che_softc *)dev;
! 748:
! 749: che_write(sc->sc_cheg, CHE_REG_MI1_ADDR, CHE_MI1_PHYADDR(phy));
! 750: che_write(sc->sc_cheg, CHE_REG_MI1_DATA, reg);
! 751: che_write(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_OP(0));
! 752:
! 753: if (che_waitfor(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_F_BUSY, 20))
! 754: return;
! 755:
! 756: che_write(sc->sc_cheg, CHE_REG_MI1_DATA, val);
! 757: che_write(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_OP(1));
! 758:
! 759: che_waitfor(sc->sc_cheg, CHE_REG_MI1_OP, CHE_MI1_F_BUSY, 20);
! 760: }
! 761:
! 762: void
! 763: che_miibus_statchg(struct device *dev)
! 764: {
! 765: struct che_softc *sc = (struct che_softc *)dev;
! 766: //struct mii_data *mii = &sc->sc_mii;
! 767:
! 768: printf("%s: che_miibus_statchg\n", DEVNAME(sc));
! 769: }
! 770:
! 771: u_int32_t
! 772: che_read(struct cheg_softc *sc, bus_size_t r)
! 773: {
! 774: bus_space_barrier(sc->sc_memt, sc->sc_memh, r, 4,
! 775: BUS_SPACE_BARRIER_READ);
! 776: return (bus_space_read_4(sc->sc_memt, sc->sc_memh, r));
! 777: }
! 778:
! 779: void
! 780: che_write(struct cheg_softc *sc, bus_size_t r, u_int32_t v)
! 781: {
! 782: bus_space_write_4(sc->sc_memt, sc->sc_memh, r, v);
! 783: bus_space_barrier(sc->sc_memt, sc->sc_memh, r, 4,
! 784: BUS_SPACE_BARRIER_WRITE);
! 785: }
! 786:
! 787: int
! 788: che_waitfor(struct cheg_softc *sc, bus_size_t r, u_int32_t mask, int tries)
! 789: {
! 790: u_int32_t v;
! 791: int i;
! 792:
! 793: for (i = 0; i < tries; i++) {
! 794: v = che_read(sc, r);
! 795: if ((v & mask) == 0)
! 796: return (0);
! 797: delay(10);
! 798: }
! 799: return (EAGAIN);
! 800: }
! 801:
! 802: void
! 803: che_hw_init(struct cheg_softc *sc)
! 804: {
! 805: u_int32_t mi1_reg;
! 806: u_int32_t i2c_reg;
! 807: u_int32_t gpio_reg;
! 808: u_int32_t port_reg;
! 809:
! 810: mi1_reg = CHE_MI1_F_PREEN |
! 811: CHE_MI1_CLKDIV(sc->sc_cclk / (2 * sc->sc_mdc) - 1);
! 812:
! 813: i2c_reg = CHE_I2C_CLKDIV(sc->sc_cclk / 80 - 1); /* 80KHz */
! 814:
! 815: gpio_reg = CHE_T3DBG_F_GPIO0_OEN | CHE_T3DBG_F_GPIO0_OUT_VAL;
! 816:
! 817: switch (sc->sc_product) {
! 818: case PCI_PRODUCT_CHELSIO_PE9000:
! 819: gpio_reg |= CHE_T3DBG_F_GPIO2_OEN | CHE_T3DBG_F_GPIO2_OUT_VAL |
! 820: CHE_T3DBG_F_GPIO4_OEN | CHE_T3DBG_F_GPIO4_OUT_VAL;
! 821: port_reg = CHE_XGM_PORTSPEED(2);
! 822: break;
! 823: case PCI_PRODUCT_CHELSIO_T302E:
! 824: case PCI_PRODUCT_CHELSIO_T302X:
! 825: case PCI_PRODUCT_CHELSIO_T3B02:
! 826: gpio_reg |= CHE_T3DBG_F_GPIO2_OEN | CHE_T3DBG_F_GPIO2_OUT_VAL |
! 827: CHE_T3DBG_F_GPIO4_OEN | CHE_T3DBG_F_GPIO4_OUT_VAL;
! 828: port_reg = CHE_XGM_PORTSPEED(2);
! 829: break;
! 830: case PCI_PRODUCT_CHELSIO_T310E:
! 831: case PCI_PRODUCT_CHELSIO_T310X:
! 832: case PCI_PRODUCT_CHELSIO_T3B10:
! 833: mi1_reg |= CHE_MI1_F_ST;
! 834: gpio_reg |= CHE_T3DBG_F_GPIO1_OEN | CHE_T3DBG_F_GPIO1_OUT_VAL |
! 835: CHE_T3DBG_F_GPIO6_OEN | CHE_T3DBG_F_GPIO6_OUT_VAL |
! 836: CHE_T3DBG_F_GPIO7_OEN |
! 837: CHE_T3DBG_F_GPIO10_OEN | CHE_T3DBG_F_GPIO10_OUT_VAL;
! 838: port_reg = CHE_XGM_PORTSPEED(3);
! 839: port_reg |= CHE_XGM_F_ENRGMII;
! 840: break;
! 841: case PCI_PRODUCT_CHELSIO_T320X:
! 842: case PCI_PRODUCT_CHELSIO_T320E:
! 843: case PCI_PRODUCT_CHELSIO_T3B20:
! 844: mi1_reg |= CHE_MI1_F_ST;
! 845: gpio_reg |= CHE_T3DBG_F_GPIO1_OEN | CHE_T3DBG_F_GPIO1_OUT_VAL |
! 846: CHE_T3DBG_F_GPIO2_OEN |
! 847: CHE_T3DBG_F_GPIO4_OEN |
! 848: CHE_T3DBG_F_GPIO5_OEN | CHE_T3DBG_F_GPIO5_OUT_VAL |
! 849: CHE_T3DBG_F_GPIO6_OEN | CHE_T3DBG_F_GPIO6_OUT_VAL |
! 850: CHE_T3DBG_F_GPIO7_OEN |
! 851: CHE_T3DBG_F_GPIO10_OEN | CHE_T3DBG_F_GPIO10_OUT_VAL |
! 852: CHE_T3DBG_F_GPIO11_OEN;
! 853: port_reg = CHE_XGM_PORTSPEED(3);
! 854: port_reg |= CHE_XGM_F_ENRGMII;
! 855: break;
! 856: }
! 857:
! 858: if (sc->sc_rev == 0)
! 859: port_reg |= CHE_XGM_F_ENRGMII;
! 860:
! 861: /* write all registers */
! 862: che_write(sc, CHE_REG_MI1_CFG, mi1_reg);
! 863: che_write(sc, CHE_REG_I2C_CFG, i2c_reg);
! 864: che_write(sc, CHE_REG_T3DBG_GPIO_EN, gpio_reg);
! 865:
! 866: che_write(sc, CHE_REG_XGM_PORT_CFG, port_reg);
! 867: (void)che_read(sc, CHE_REG_XGM_PORT_CFG);
! 868:
! 869: port_reg |= CHE_XGM_F_CLKDIVRESET;
! 870:
! 871: che_write(sc, CHE_REG_XGM_PORT_CFG, port_reg);
! 872: (void)che_read(sc, CHE_REG_XGM_PORT_CFG);
! 873: che_write(sc, CHE_XGM_REG(CHE_REG_XGM_PORT_CFG, 1), port_reg);
! 874: (void)che_read(sc, CHE_REG_XGM_PORT_CFG);
! 875: }
CVSweb