Annotation of sys/dev/cardbus/if_re_cardbus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_re_cardbus.c,v 1.11 2006/11/28 20:04:02 brad Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 Peter Valchev <pvalchev@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: /*
! 20: * Cardbus front-end for the Realtek 8169
! 21: */
! 22:
! 23: #include <sys/param.h>
! 24: #include <sys/endian.h>
! 25: #include <sys/systm.h>
! 26: #include <sys/sockio.h>
! 27: #include <sys/mbuf.h>
! 28: #include <sys/malloc.h>
! 29: #include <sys/kernel.h>
! 30: #include <sys/device.h>
! 31: #include <sys/timeout.h>
! 32: #include <sys/socket.h>
! 33:
! 34: #include <net/if.h>
! 35: #include <net/if_dl.h>
! 36: #include <net/if_media.h>
! 37:
! 38: #ifdef INET
! 39: #include <netinet/in.h>
! 40: #include <netinet/in_systm.h>
! 41: #include <netinet/in_var.h>
! 42: #include <netinet/ip.h>
! 43: #include <netinet/if_ether.h>
! 44: #endif
! 45:
! 46: #include <dev/mii/mii.h>
! 47: #include <dev/mii/miivar.h>
! 48:
! 49: #include <dev/pci/pcidevs.h>
! 50:
! 51: #include <dev/cardbus/cardbusvar.h>
! 52:
! 53: #include <dev/ic/rtl81x9reg.h>
! 54: #include <dev/ic/revar.h>
! 55:
! 56: struct re_cardbus_softc {
! 57: /* General */
! 58: struct rl_softc sc_rl;
! 59:
! 60: /* Cardbus-specific data */
! 61: void *sc_ih;
! 62: cardbus_devfunc_t ct;
! 63: cardbustag_t sc_tag;
! 64: int sc_csr;
! 65: int sc_cben;
! 66: int sc_bar_reg;
! 67: pcireg_t sc_bar_val;
! 68: int sc_intrline;
! 69:
! 70: bus_size_t sc_mapsize;
! 71: };
! 72:
! 73: int re_cardbus_probe(struct device *, void *, void *);
! 74: void re_cardbus_attach(struct device *, struct device *, void *);
! 75: int re_cardbus_detach(struct device *, int);
! 76: void re_cardbus_setup(struct rl_softc *);
! 77:
! 78: void re_cardbus_shutdown(void *);
! 79: void re_cardbus_powerhook(int, void *);
! 80:
! 81: /*
! 82: * Cardbus autoconfig definitions
! 83: */
! 84: struct cfattach re_cardbus_ca = {
! 85: sizeof(struct re_cardbus_softc),
! 86: re_cardbus_probe,
! 87: re_cardbus_attach,
! 88: re_cardbus_detach
! 89: };
! 90:
! 91: const struct cardbus_matchid re_cardbus_devices[] = {
! 92: { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 },
! 93: };
! 94:
! 95: /*
! 96: * Probe for a RealTek 8169/8110 chip. Check the PCI vendor and device
! 97: * IDs against our list and return a device name if we find a match.
! 98: */
! 99: int
! 100: re_cardbus_probe(struct device *parent, void *match, void *aux)
! 101: {
! 102: return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
! 103: re_cardbus_devices,
! 104: sizeof(re_cardbus_devices)/sizeof(re_cardbus_devices[0])));
! 105: }
! 106:
! 107: /*
! 108: * Attach the interface. Allocate softc structures, do ifmedia
! 109: * setup and ethernet/BPF attach.
! 110: */
! 111: void
! 112: re_cardbus_attach(struct device *parent, struct device *self, void *aux)
! 113: {
! 114: struct re_cardbus_softc *csc = (struct re_cardbus_softc *)self;
! 115: struct rl_softc *sc = &csc->sc_rl;
! 116: struct cardbus_attach_args *ca = aux;
! 117: struct cardbus_softc *psc =
! 118: (struct cardbus_softc *)sc->sc_dev.dv_parent;
! 119: cardbus_chipset_tag_t cc = psc->sc_cc;
! 120: cardbus_function_tag_t cf = psc->sc_cf;
! 121: cardbus_devfunc_t ct = ca->ca_ct;
! 122: bus_addr_t adr;
! 123: char intrstr[16];
! 124:
! 125: sc->sc_dmat = ca->ca_dmat;
! 126: csc->ct = ct;
! 127: csc->sc_tag = ca->ca_tag;
! 128: csc->sc_intrline = ca->ca_intrline;
! 129:
! 130: /*
! 131: * Map control/status registers.
! 132: */
! 133: if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, CARDBUS_MAPREG_TYPE_MEM, 0,
! 134: &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) {
! 135: csc->sc_cben = CARDBUS_MEM_ENABLE;
! 136: csc->sc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
! 137: csc->sc_bar_reg = RL_PCI_LOMEM;
! 138: csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM;
! 139: } else {
! 140: printf(": can't map mem space\n");
! 141: return;
! 142: }
! 143:
! 144: /* Enable power */
! 145: Cardbus_function_enable(ct);
! 146:
! 147: /* Get chip out of powersave mode (if applicable), initialize
! 148: * config registers */
! 149: re_cardbus_setup(sc);
! 150:
! 151: /* Allocate interrupt */
! 152: csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline,
! 153: IPL_NET, re_intr, sc, sc->sc_dev.dv_xname);
! 154: if (csc->sc_ih == NULL) {
! 155: printf(": couldn't establish interrupt at %s",
! 156: ca->ca_intrline);
! 157: Cardbus_function_disable(csc->ct);
! 158: return;
! 159: }
! 160: snprintf(intrstr, sizeof(intrstr), "irq %d", ca->ca_intrline);
! 161:
! 162: sc->sc_flags |= RL_ENABLED;
! 163: sc->rl_type = RL_8169;
! 164:
! 165: sc->sc_sdhook = shutdownhook_establish(re_cardbus_shutdown, sc);
! 166: sc->sc_pwrhook = powerhook_establish(re_cardbus_powerhook, sc);
! 167:
! 168: /* Call bus-independent (common) attach routine */
! 169: re_attach(sc, intrstr);
! 170: }
! 171:
! 172: /*
! 173: * Get chip out of power-saving mode, init registers
! 174: */
! 175: void
! 176: re_cardbus_setup(struct rl_softc *sc)
! 177: {
! 178: struct re_cardbus_softc *csc = (struct re_cardbus_softc *)sc;
! 179: cardbus_devfunc_t ct = csc->ct;
! 180: cardbus_chipset_tag_t cc = ct->ct_cc;
! 181: cardbus_function_tag_t cf = ct->ct_cf;
! 182: pcireg_t reg, command;
! 183: int pmreg;
! 184:
! 185: /* Handle power management nonsense */
! 186: if (cardbus_get_capability(cc, cf, csc->sc_tag,
! 187: PCI_CAP_PWRMGMT, &pmreg, 0)) {
! 188: command = cardbus_conf_read(cc, cf, csc->sc_tag,
! 189: pmreg + PCI_PMCSR);
! 190:
! 191: if (command & RL_PSTATE_MASK) {
! 192: pcireg_t iobase, membase, irq;
! 193:
! 194: /* Save important PCI config data */
! 195: iobase = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_LOIO);
! 196: membase = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_LOMEM);
! 197: irq = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_INTLINE);
! 198:
! 199: /* Reset the power state */
! 200: printf("%s: chip is in D%d power mode "
! 201: "-- setting to D0\n", sc->sc_dev.dv_xname,
! 202: command & RL_PSTATE_MASK);
! 203: command &= RL_PSTATE_MASK;
! 204: cardbus_conf_write(cc, cf, csc->sc_tag, pmreg + PCI_PMCSR,
! 205: command);
! 206:
! 207: /* Restore PCI config data */
! 208: cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_LOIO, iobase);
! 209: cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_LOMEM, membase);
! 210: cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_INTLINE, irq);
! 211: }
! 212: }
! 213:
! 214: /* Make sure the right access type is on the Cardbus bridge */
! 215: (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
! 216: (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
! 217:
! 218: /* Program the BAR */
! 219: cardbus_conf_write(cc, cf, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val);
! 220:
! 221: /* Enable proper bits in CARDBUS CSR */
! 222: reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG);
! 223: reg &= ~(CARDBUS_COMMAND_IO_ENABLE|CARDBUS_COMMAND_MEM_ENABLE);
! 224: reg |= csc->sc_csr;
! 225: cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
! 226:
! 227: /* Make sure the latency timer is set to some reasonable value */
! 228: reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG);
! 229: if (CARDBUS_LATTIMER(reg) < 0x20) {
! 230: reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
! 231: reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
! 232: cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg);
! 233: }
! 234: }
! 235:
! 236: /*
! 237: * Cardbus detach function: deallocate all resources
! 238: */
! 239: int
! 240: re_cardbus_detach(struct device *self, int flags)
! 241: {
! 242: struct re_cardbus_softc *csc = (void *)self;
! 243: struct rl_softc *sc = &csc->sc_rl;
! 244: struct cardbus_devfunc *ct = csc->ct;
! 245: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 246:
! 247: /* Remove timeout handler */
! 248: timeout_del(&sc->timer_handle);
! 249:
! 250: /* Detach PHY */
! 251: if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL)
! 252: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
! 253:
! 254: /* Delete media stuff */
! 255: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
! 256: ether_ifdetach(ifp);
! 257: if_detach(ifp);
! 258:
! 259: /* No more hooks */
! 260: if (sc->sc_sdhook != NULL)
! 261: shutdownhook_disestablish(sc->sc_sdhook);
! 262: if (sc->sc_pwrhook != NULL)
! 263: powerhook_disestablish(sc->sc_pwrhook);
! 264:
! 265: /* Disable interrupts */
! 266: if (csc->sc_ih != NULL)
! 267: cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
! 268:
! 269: /* Free cardbus resources */
! 270: Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, sc->rl_bhandle,
! 271: csc->sc_mapsize);
! 272:
! 273: return (0);
! 274: }
! 275:
! 276: void
! 277: re_cardbus_shutdown(void *arg)
! 278: {
! 279: struct rl_softc *sc = arg;
! 280: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 281:
! 282: re_stop(ifp, 1);
! 283: }
! 284:
! 285: void
! 286: re_cardbus_powerhook(int why, void *arg)
! 287: {
! 288: struct rl_softc *sc = arg;
! 289: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 290:
! 291: if (why == PWR_RESUME)
! 292: re_init(ifp);
! 293: }
CVSweb