Annotation of sys/dev/cardbus/if_rl_cardbus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_rl_cardbus.c,v 1.16 2007/05/08 18:49:32 deraadt Exp $ */
! 2: /* $NetBSD: if_rl_cardbus.c,v 1.3.8.3 2001/11/14 19:14:02 nathanw Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000 Masanori Kanaoka
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. The name of the author may not be used to endorse or promote products
! 17: * derived from this software without specific prior written permission.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 21: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 22: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 23: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 24: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 25: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 26: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 27: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 28: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 29: */
! 30:
! 31: /*
! 32: * if_rl_cardbus.c:
! 33: * Cardbus specific routines for RealTek 8139 ethernet adapter.
! 34: * Tested for
! 35: * - elecom-Laneed LD-10/100CBA (Accton MPX5030)
! 36: * - MELCO LPC3-TX-CB (RealTek 8139)
! 37: */
! 38:
! 39: #include "bpfilter.h"
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/mbuf.h>
! 44: #include <sys/socket.h>
! 45: #include <sys/ioctl.h>
! 46: #include <sys/errno.h>
! 47: #include <sys/malloc.h>
! 48: #include <sys/kernel.h>
! 49: #include <sys/timeout.h>
! 50: #include <sys/device.h>
! 51:
! 52: #include <net/if.h>
! 53: #include <net/if_dl.h>
! 54: #include <net/if_types.h>
! 55: #include <net/if_media.h>
! 56:
! 57: #include <machine/endian.h>
! 58:
! 59: #if NBPFILTER > 0
! 60: #include <net/bpf.h>
! 61: #endif
! 62:
! 63: #ifdef INET
! 64: #include <netinet/in.h>
! 65: #include <netinet/in_systm.h>
! 66: #include <netinet/in_var.h>
! 67: #include <netinet/ip.h>
! 68: #include <netinet/if_ether.h>
! 69: #endif
! 70:
! 71: #include <machine/bus.h>
! 72: #include <machine/intr.h>
! 73:
! 74: #include <dev/mii/miivar.h>
! 75:
! 76: #include <dev/pci/pcivar.h>
! 77: #include <dev/pci/pcireg.h>
! 78: #include <dev/pci/pcidevs.h>
! 79:
! 80: #include <dev/cardbus/cardbusvar.h>
! 81:
! 82: /*
! 83: * Default to using PIO access for this driver. On SMP systems,
! 84: * there appear to be problems with memory mapped mode: it looks like
! 85: * doing too many memory mapped access back to back in rapid succession
! 86: * can hang the bus. I'm inclined to blame this on crummy design/construction
! 87: * on the part of RealTek. Memory mapped mode does appear to work on
! 88: * uniprocessor systems though.
! 89: */
! 90: #define RL_USEIOSPACE
! 91:
! 92: #include <dev/ic/rtl81x9reg.h>
! 93:
! 94: /*
! 95: * Various supported device vendors/types and their names.
! 96: */
! 97: const struct cardbus_matchid rl_cardbus_devices[] = {
! 98: { PCI_VENDOR_ACCTON, PCI_PRODUCT_ACCTON_5030 },
! 99: { PCI_VENDOR_ABOCOM, PCI_PRODUCT_ABOCOM_FE2000VX },
! 100: { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8138 },
! 101: { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8139 },
! 102: { PCI_VENDOR_COREGA, PCI_PRODUCT_COREGA_CB_TXD },
! 103: { PCI_VENDOR_COREGA, PCI_PRODUCT_COREGA_2CB_TXD },
! 104: { PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DFE690TXD },
! 105: { PCI_VENDOR_PLANEX, PCI_PRODUCT_PLANEX_FNW_3603_TX },
! 106: { PCI_VENDOR_PLANEX, PCI_PRODUCT_PLANEX_FNW_3800_TX },
! 107: };
! 108:
! 109: struct rl_cardbus_softc {
! 110: struct rl_softc sc_rl; /* real rtk softc */
! 111:
! 112: /* CardBus-specific goo. */
! 113: void *sc_ih;
! 114: cardbus_devfunc_t sc_ct;
! 115: cardbustag_t sc_tag;
! 116: int sc_csr;
! 117: int sc_cben;
! 118: int sc_bar_reg;
! 119: pcireg_t sc_bar_val;
! 120: bus_size_t sc_mapsize;
! 121: int sc_intrline;
! 122: };
! 123:
! 124: static int rl_cardbus_match(struct device *, void *, void *);
! 125: static void rl_cardbus_attach(struct device *, struct device *, void *);
! 126: static int rl_cardbus_detach(struct device *, int);
! 127: void rl_cardbus_setup(struct rl_cardbus_softc *);
! 128:
! 129: struct cfattach rl_cardbus_ca = {
! 130: sizeof(struct rl_cardbus_softc), rl_cardbus_match, rl_cardbus_attach,
! 131: rl_cardbus_detach
! 132: };
! 133:
! 134: int
! 135: rl_cardbus_match(parent, match, aux)
! 136: struct device *parent;
! 137: void *match;
! 138: void *aux;
! 139: {
! 140: return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
! 141: rl_cardbus_devices,
! 142: sizeof(rl_cardbus_devices)/sizeof(rl_cardbus_devices[0])));
! 143: }
! 144:
! 145:
! 146: void
! 147: rl_cardbus_attach(parent, self, aux)
! 148: struct device *parent, *self;
! 149: void *aux;
! 150: {
! 151: struct rl_cardbus_softc *csc = (struct rl_cardbus_softc *)self;
! 152: struct rl_softc *sc = &csc->sc_rl;
! 153: struct cardbus_attach_args *ca = aux;
! 154: struct cardbus_softc *psc =
! 155: (struct cardbus_softc *)sc->sc_dev.dv_parent;
! 156: cardbus_chipset_tag_t cc = psc->sc_cc;
! 157: cardbus_function_tag_t cf = psc->sc_cf;
! 158: cardbus_devfunc_t ct = ca->ca_ct;
! 159: bus_addr_t adr;
! 160:
! 161: sc->sc_dmat = ca->ca_dmat;
! 162: csc->sc_ct = ct;
! 163: csc->sc_tag = ca->ca_tag;
! 164: csc->sc_intrline = ca->ca_intrline;
! 165:
! 166: /*
! 167: * Map control/status registers.
! 168: */
! 169: csc->sc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
! 170: #ifdef RL_USEIOSPACE
! 171: if (Cardbus_mapreg_map(ct, RL_PCI_LOIO, CARDBUS_MAPREG_TYPE_IO, 0,
! 172: &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) {
! 173: csc->sc_cben = CARDBUS_IO_ENABLE;
! 174: csc->sc_csr |= CARDBUS_COMMAND_IO_ENABLE;
! 175: csc->sc_bar_reg = RL_PCI_LOIO;
! 176: csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_IO;
! 177: }
! 178: #else
! 179: if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, CARDBUS_MAPREG_TYPE_MEM, 0,
! 180: &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) {
! 181: csc->sc_cben = CARDBUS_MEM_ENABLE;
! 182: csc->sc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
! 183: csc->sc_bar_reg = RL_PCI_LOMEM;
! 184: csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM;
! 185: }
! 186: #endif
! 187: else {
! 188: printf("%s: unable to map deviceregisters\n",
! 189: sc->sc_dev.dv_xname);
! 190: return;
! 191: }
! 192:
! 193: Cardbus_function_enable(ct);
! 194:
! 195: rl_cardbus_setup(csc);
! 196:
! 197: /*
! 198: * Map and establish the interrupt.
! 199: */
! 200: csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
! 201: rl_intr, sc, sc->sc_dev.dv_xname);
! 202: if (csc->sc_ih == NULL) {
! 203: printf(": couldn't establish interrupt\n");
! 204: Cardbus_function_disable(csc->sc_ct);
! 205: return;
! 206: }
! 207: printf(": irq %d", csc->sc_intrline);
! 208:
! 209: /* XXX - hardcode this, for now */
! 210: sc->rl_type = RL_8139;
! 211:
! 212: rl_attach(sc);
! 213: }
! 214:
! 215: extern int rl_detach(struct rl_softc *);
! 216:
! 217: int
! 218: rl_detach(sc)
! 219: struct rl_softc *sc;
! 220: {
! 221: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 222:
! 223: /* Unhook our tick handler. */
! 224: timeout_del(&sc->sc_tick_tmo);
! 225:
! 226: /* Detach any PHYs we might have. */
! 227: if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL)
! 228: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
! 229:
! 230: /* Delete any remaining media. */
! 231: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
! 232:
! 233: ether_ifdetach(ifp);
! 234: if_detach(ifp);
! 235:
! 236: if (sc->sc_sdhook != NULL)
! 237: shutdownhook_disestablish(sc->sc_sdhook);
! 238: if (sc->sc_pwrhook != NULL)
! 239: powerhook_disestablish(sc->sc_pwrhook);
! 240:
! 241: return (0);
! 242: }
! 243:
! 244: int
! 245: rl_cardbus_detach(self, flags)
! 246: struct device *self;
! 247: int flags;
! 248: {
! 249: struct rl_cardbus_softc *csc = (void *) self;
! 250: struct rl_softc *sc = &csc->sc_rl;
! 251: struct cardbus_devfunc *ct = csc->sc_ct;
! 252: int rv;
! 253:
! 254: #ifdef DIAGNOSTIC
! 255: if (ct == NULL)
! 256: panic("%s: data structure lacks", sc->sc_dev.dv_xname);
! 257: #endif
! 258: rv = rl_detach(sc);
! 259: if (rv)
! 260: return (rv);
! 261: /*
! 262: * Unhook the interrupt handler.
! 263: */
! 264: if (csc->sc_ih != NULL)
! 265: cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
! 266:
! 267: /*
! 268: * Release bus space and close window.
! 269: */
! 270: if (csc->sc_bar_reg != 0)
! 271: Cardbus_mapreg_unmap(ct, csc->sc_bar_reg,
! 272: sc->rl_btag, sc->rl_bhandle, csc->sc_mapsize);
! 273:
! 274: return (0);
! 275: }
! 276:
! 277: void
! 278: rl_cardbus_setup(csc)
! 279: struct rl_cardbus_softc *csc;
! 280: {
! 281: struct rl_softc *sc = &csc->sc_rl;
! 282: cardbus_devfunc_t ct = csc->sc_ct;
! 283: cardbus_chipset_tag_t cc = ct->ct_cc;
! 284: cardbus_function_tag_t cf = ct->ct_cf;
! 285: pcireg_t reg, command;
! 286: int pmreg;
! 287:
! 288: /*
! 289: * Handle power management nonsense.
! 290: */
! 291: if (cardbus_get_capability(cc, cf, csc->sc_tag,
! 292: PCI_CAP_PWRMGMT, &pmreg, 0)) {
! 293: command = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4);
! 294: if (command & RL_PSTATE_MASK) {
! 295: pcireg_t iobase, membase, irq;
! 296:
! 297: /* Save important PCI config data. */
! 298: iobase = cardbus_conf_read(cc, cf, csc->sc_tag,
! 299: RL_PCI_LOIO);
! 300: membase = cardbus_conf_read(cc, cf,csc->sc_tag,
! 301: RL_PCI_LOMEM);
! 302: irq = cardbus_conf_read(cc, cf,csc->sc_tag,
! 303: PCI_PRODUCT_DELTA_8139);
! 304:
! 305: /* Reset the power state. */
! 306: printf("%s: chip is in D%d power mode "
! 307: "-- setting to D0\n", sc->sc_dev.dv_xname,
! 308: command & RL_PSTATE_MASK);
! 309: command &= 0xFFFFFFFC;
! 310: cardbus_conf_write(cc, cf, csc->sc_tag,
! 311: pmreg + 4, command);
! 312:
! 313: /* Restore PCI config data. */
! 314: cardbus_conf_write(cc, cf, csc->sc_tag,
! 315: RL_PCI_LOIO, iobase);
! 316: cardbus_conf_write(cc, cf, csc->sc_tag,
! 317: RL_PCI_LOMEM, membase);
! 318: cardbus_conf_write(cc, cf, csc->sc_tag,
! 319: PCI_PRODUCT_DELTA_8139, irq);
! 320: }
! 321: }
! 322:
! 323: /* Make sure the right access type is on the CardBus bridge. */
! 324: (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
! 325: (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
! 326:
! 327: /* Program the BAR */
! 328: cardbus_conf_write(cc, cf, csc->sc_tag,
! 329: csc->sc_bar_reg, csc->sc_bar_val);
! 330:
! 331: /* Enable the appropriate bits in the CARDBUS CSR. */
! 332: reg = cardbus_conf_read(cc, cf, csc->sc_tag,
! 333: CARDBUS_COMMAND_STATUS_REG);
! 334: reg &= ~(CARDBUS_COMMAND_IO_ENABLE|CARDBUS_COMMAND_MEM_ENABLE);
! 335: reg |= csc->sc_csr;
! 336: cardbus_conf_write(cc, cf, csc->sc_tag,
! 337: CARDBUS_COMMAND_STATUS_REG, reg);
! 338:
! 339: /*
! 340: * Make sure the latency timer is set to some reasonable
! 341: * value.
! 342: */
! 343: reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG);
! 344: if (CARDBUS_LATTIMER(reg) < 0x20) {
! 345: reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
! 346: reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
! 347: cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg);
! 348: }
! 349: }
! 350:
CVSweb