1/* $OpenBSD: if_re_cardbus.c,v 1.32 2024/05/24 06:26:47 jsg 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/systm.h> 25#include <sys/mbuf.h> 26#include <sys/device.h> 27#include <sys/timeout.h> 28 29#include <net/if.h> 30#include <net/if_media.h> 31 32#include <netinet/in.h> 33#include <netinet/if_ether.h> 34 35#include <dev/mii/miivar.h> 36 37#include <dev/pci/pcidevs.h> 38 39#include <dev/cardbus/cardbusvar.h> 40 41#include <dev/ic/rtl81x9reg.h> 42#include <dev/ic/revar.h> 43 44struct re_cardbus_softc { 45 /* General */ 46 struct rl_softc sc_rl; 47 48 /* Cardbus-specific data */ 49 cardbus_devfunc_t ct; 50 pcitag_t sc_tag; 51 pci_chipset_tag_t sc_pc; 52 int sc_csr; 53 int sc_cben; 54 int sc_bar_reg; 55 pcireg_t sc_bar_val; 56 int sc_intrline; 57 58 bus_size_t sc_mapsize; 59}; 60 61int re_cardbus_probe(struct device *, void *, void *); 62void re_cardbus_attach(struct device *, struct device *, void *); 63int re_cardbus_detach(struct device *, int); 64void re_cardbus_setup(struct rl_softc *); 65 66/* 67 * Cardbus autoconfig definitions 68 */ 69const struct cfattach re_cardbus_ca = { 70 sizeof(struct re_cardbus_softc), 71 re_cardbus_probe, 72 re_cardbus_attach, 73 re_cardbus_detach 74}; 75 76const struct pci_matchid re_cardbus_devices[] = { 77 { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 }, 78}; 79 80/* 81 * Probe for a Realtek 8169/8110 chip. Check the PCI vendor and device 82 * IDs against our list and return a device name if we find a match. 83 */ 84int 85re_cardbus_probe(struct device *parent, void *match, void *aux) 86{ 87 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 88 re_cardbus_devices, nitems(re_cardbus_devices))); 89} 90 91/* 92 * Attach the interface. Allocate softc structures, do ifmedia 93 * setup and ethernet/BPF attach. 94 */ 95void 96re_cardbus_attach(struct device *parent, struct device *self, void *aux) 97{ 98 struct re_cardbus_softc *csc = (struct re_cardbus_softc *)self; 99 struct rl_softc *sc = &csc->sc_rl; 100 struct cardbus_attach_args *ca = aux; 101 struct cardbus_softc *psc = 102 (struct cardbus_softc *)sc->sc_dev.dv_parent; 103 cardbus_chipset_tag_t cc = psc->sc_cc; 104 cardbus_function_tag_t cf = psc->sc_cf; 105 cardbus_devfunc_t ct = ca->ca_ct; 106 bus_addr_t adr; 107 char intrstr[16]; 108 109 sc->sc_dmat = ca->ca_dmat; 110 csc->ct = ct; 111 csc->sc_tag = ca->ca_tag; 112 csc->sc_pc = ca->ca_pc; 113 csc->sc_intrline = ca->ca_intrline; 114 115 /* 116 * Map control/status registers. 117 */ 118 if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0, 119 &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) { 120 csc->sc_cben = CARDBUS_MEM_ENABLE; 121 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; 122 csc->sc_bar_reg = RL_PCI_LOMEM; 123 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; 124 } else { 125 printf(": can't map mem space\n"); 126 return; 127 } 128 129 /* Enable power */ 130 Cardbus_function_enable(ct); 131 132 /* Get chip out of powersave mode (if applicable), initialize 133 * config registers */ 134 re_cardbus_setup(sc); 135 136 /* Allocate interrupt */ 137 sc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, 138 IPL_NET, re_intr, sc, sc->sc_dev.dv_xname); 139 if (sc->sc_ih == NULL) { 140 printf(": couldn't establish interrupt at %d", 141 ca->ca_intrline); 142 Cardbus_function_disable(csc->ct); 143 return; 144 } 145 snprintf(intrstr, sizeof(intrstr), "irq %d", ca->ca_intrline); 146 147 sc->sc_product = PCI_PRODUCT(ca->ca_id); 148 149 /* Call bus-independent (common) attach routine */ 150 if (re_attach(sc, intrstr)) { 151 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, sc->sc_ih); 152 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, 153 sc->rl_bhandle, csc->sc_mapsize); 154 } 155} 156 157/* 158 * Get chip out of power-saving mode, init registers 159 */ 160void 161re_cardbus_setup(struct rl_softc *sc) 162{ 163 struct re_cardbus_softc *csc = (struct re_cardbus_softc *)sc; 164 cardbus_devfunc_t ct = csc->ct; 165 cardbus_chipset_tag_t cc = ct->ct_cc; 166 pci_chipset_tag_t pc = csc->sc_pc; 167 pcireg_t reg, command; 168 int pmreg; 169 170 /* Handle power management nonsense */ 171 if (pci_get_capability(pc, csc->sc_tag, 172 PCI_CAP_PWRMGMT, &pmreg, 0)) { 173 command = pci_conf_read(pc, csc->sc_tag, 174 pmreg + PCI_PMCSR); 175 176 if (command & RL_PSTATE_MASK) { 177 pcireg_t iobase, membase, irq; 178 179 /* Save important PCI config data */ 180 iobase = pci_conf_read(pc, csc->sc_tag, RL_PCI_LOIO); 181 membase = pci_conf_read(pc, csc->sc_tag, RL_PCI_LOMEM); 182 irq = pci_conf_read(pc, csc->sc_tag, RL_PCI_INTLINE); 183 184 /* Reset the power state */ 185 printf("%s: chip is in D%d power mode " 186 "-- setting to D0\n", sc->sc_dev.dv_xname, 187 command & RL_PSTATE_MASK); 188 command &= RL_PSTATE_MASK; 189 pci_conf_write(pc, csc->sc_tag, pmreg + PCI_PMCSR, 190 command); 191 192 /* Restore PCI config data */ 193 pci_conf_write(pc, csc->sc_tag, RL_PCI_LOIO, iobase); 194 pci_conf_write(pc, csc->sc_tag, RL_PCI_LOMEM, membase); 195 pci_conf_write(pc, csc->sc_tag, RL_PCI_INTLINE, irq); 196 } 197 } 198 199 /* Make sure the right access type is on the Cardbus bridge */ 200 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); 201 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 202 203 /* Program the BAR */ 204 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val); 205 206 /* Enable proper bits in CARDBUS CSR */ 207 reg = pci_conf_read(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG); 208 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); 209 reg |= csc->sc_csr; 210 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); 211 212 /* Make sure the latency timer is set to some reasonable value */ 213 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG); 214 if (PCI_LATTIMER(reg) < 0x20) { 215 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 216 reg |= (0x20 << PCI_LATTIMER_SHIFT); 217 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg); 218 } 219} 220 221/* 222 * Cardbus detach function: deallocate all resources 223 */ 224int 225re_cardbus_detach(struct device *self, int flags) 226{ 227 struct re_cardbus_softc *csc = (void *)self; 228 struct rl_softc *sc = &csc->sc_rl; 229 struct cardbus_devfunc *ct = csc->ct; 230 231 re_detach(sc); 232 233 /* Disable interrupts */ 234 if (sc->sc_ih != NULL) 235 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, sc->sc_ih); 236 237 /* Free cardbus resources */ 238 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, sc->rl_bhandle, 239 csc->sc_mapsize); 240 241 return (0); 242} 243