1 /* $NetBSD: if_ex_cardbus.c,v 1.27 2002/10/02 16:33:42 thorpej Exp $ */ 2 3 /* 4 * CardBus specific routines for 3Com 3C575-family CardBus ethernet adapter 5 * 6 * Copyright (c) 1998 and 1999 7 * HAYAKAWA Koichi. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the author. 20 * 4. Neither the name of the author nor the names of any co-contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY HAYAKAWA KOICHI ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL TAKESHI OHASHI OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: if_ex_cardbus.c,v 1.27 2002/10/02 16:33:42 thorpej Exp $"); 41 42 /* #define EX_DEBUG 4 */ /* define to report information for debugging */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/mbuf.h> 47 #include <sys/socket.h> 48 #include <sys/ioctl.h> 49 #include <sys/errno.h> 50 #include <sys/syslog.h> 51 #include <sys/select.h> 52 #include <sys/device.h> 53 54 #include <net/if.h> 55 #include <net/if_dl.h> 56 #include <net/if_ether.h> 57 #include <net/if_media.h> 58 59 #include <machine/cpu.h> 60 #include <machine/bus.h> 61 62 #include <dev/cardbus/cardbusvar.h> 63 #include <dev/cardbus/cardbusdevs.h> 64 65 #include <dev/mii/miivar.h> 66 67 #include <dev/ic/elink3var.h> 68 #include <dev/ic/elink3reg.h> 69 #include <dev/ic/elinkxlreg.h> 70 #include <dev/ic/elinkxlvar.h> 71 72 #if defined DEBUG && !defined EX_DEBUG 73 #define EX_DEBUG 74 #endif 75 76 #if defined EX_DEBUG 77 #define DPRINTF(a) printf a 78 #else 79 #define DPRINTF(a) 80 #endif 81 82 #define CARDBUS_3C575BTX_FUNCSTAT_PCIREG CARDBUS_BASE2_REG /* means 0x18 */ 83 #define EX_CB_INTR 4 /* intr acknowledge reg. CardBus only */ 84 #define EX_CB_INTR_ACK 0x8000 /* intr acknowledge bit */ 85 86 int ex_cardbus_match __P((struct device *, struct cfdata *, void *)); 87 void ex_cardbus_attach __P((struct device *, struct device *,void *)); 88 int ex_cardbus_detach __P((struct device *, int)); 89 void ex_cardbus_intr_ack __P((struct ex_softc *)); 90 91 int ex_cardbus_enable __P((struct ex_softc *)); 92 void ex_cardbus_disable __P((struct ex_softc *)); 93 void ex_cardbus_power __P((struct ex_softc *, int)); 94 95 struct ex_cardbus_softc { 96 struct ex_softc sc_softc; 97 98 cardbus_devfunc_t sc_ct; 99 int sc_intrline; 100 u_int8_t sc_cardbus_flags; 101 #define EX_REATTACH 0x01 102 #define EX_ABSENT 0x02 103 u_int8_t sc_cardtype; 104 #define EX_CB_BOOMERANG 1 105 #define EX_CB_CYCLONE 2 106 107 /* CardBus function status space. 575B requests it. */ 108 bus_space_tag_t sc_funct; 109 bus_space_handle_t sc_funch; 110 bus_size_t sc_funcsize; 111 112 bus_size_t sc_mapsize; /* the size of mapped bus space region */ 113 114 cardbustag_t sc_tag; 115 116 int sc_csr; /* CSR bits */ 117 int sc_bar_reg; /* which BAR to use */ 118 pcireg_t sc_bar_val; /* value of the BAR */ 119 int sc_bar_reg1; /* which BAR to use */ 120 pcireg_t sc_bar_val1; /* value of the BAR */ 121 122 }; 123 124 CFATTACH_DECL(ex_cardbus, sizeof(struct ex_cardbus_softc), 125 ex_cardbus_match, ex_cardbus_attach, ex_cardbus_detach, ex_activate); 126 127 const struct ex_cardbus_product { 128 u_int32_t ecp_prodid; /* CardBus product ID */ 129 int ecp_flags; /* initial softc flags */ 130 pcireg_t ecp_csr; /* PCI CSR flags */ 131 int ecp_cardtype; /* card type */ 132 const char *ecp_name; /* device name */ 133 } ex_cardbus_products[] = { 134 { CARDBUS_PRODUCT_3COM_3C575TX, 135 EX_CONF_MII | EX_CONF_EEPROM_OFF | EX_CONF_EEPROM_8BIT, 136 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MASTER_ENABLE, 137 EX_CB_BOOMERANG, 138 "3c575-TX Ethernet" }, 139 140 { CARDBUS_PRODUCT_3COM_3C575BTX, 141 EX_CONF_90XB|EX_CONF_MII|EX_CONF_INV_LED_POLARITY | 142 EX_CONF_EEPROM_OFF | EX_CONF_EEPROM_8BIT, 143 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 144 CARDBUS_COMMAND_MASTER_ENABLE, 145 EX_CB_CYCLONE, 146 "3c575B-TX Ethernet" }, 147 148 { CARDBUS_PRODUCT_3COM_3C575CTX, 149 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 150 EX_CONF_EEPROM_8BIT, 151 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 152 CARDBUS_COMMAND_MASTER_ENABLE, 153 EX_CB_CYCLONE, 154 "3c575CT Ethernet" }, 155 156 { 0, 157 0, 158 0, 159 0, 160 NULL }, 161 }; 162 163 164 void ex_cardbus_setup __P((struct ex_cardbus_softc *)); 165 166 const struct ex_cardbus_product *ex_cardbus_lookup 167 __P((const struct cardbus_attach_args *)); 168 169 const struct ex_cardbus_product * 170 ex_cardbus_lookup(ca) 171 const struct cardbus_attach_args *ca; 172 { 173 const struct ex_cardbus_product *ecp; 174 175 if (CARDBUS_VENDOR(ca->ca_id) != CARDBUS_VENDOR_3COM) 176 return (NULL); 177 178 for (ecp = ex_cardbus_products; ecp->ecp_name != NULL; ecp++) 179 if (CARDBUS_PRODUCT(ca->ca_id) == ecp->ecp_prodid) 180 return (ecp); 181 return (NULL); 182 } 183 184 int 185 ex_cardbus_match(parent, cf, aux) 186 struct device *parent; 187 struct cfdata *cf; 188 void *aux; 189 { 190 struct cardbus_attach_args *ca = aux; 191 192 if (ex_cardbus_lookup(ca) != NULL) 193 return (1); 194 195 return (0); 196 } 197 198 void 199 ex_cardbus_attach(parent, self, aux) 200 struct device *parent; 201 struct device *self; 202 void *aux; 203 { 204 struct ex_cardbus_softc *csc = (void *)self; 205 struct ex_softc *sc = &csc->sc_softc; 206 struct cardbus_attach_args *ca = aux; 207 cardbus_devfunc_t ct = ca->ca_ct; 208 #if rbus 209 #else 210 cardbus_chipset_tag_t cc = ct->ct_cc; 211 #endif 212 const struct ex_cardbus_product *ecp; 213 bus_addr_t adr, adr1; 214 215 sc->ex_bustype = EX_BUS_CARDBUS; 216 sc->sc_dmat = ca->ca_dmat; 217 csc->sc_ct = ca->ca_ct; 218 csc->sc_intrline = ca->ca_intrline; 219 csc->sc_tag = ca->ca_tag; 220 221 ecp = ex_cardbus_lookup(ca); 222 if (ecp == NULL) { 223 printf("\n"); 224 panic("ex_cardbus_attach: impossible"); 225 } 226 227 printf(": 3Com %s\n", ecp->ecp_name); 228 229 sc->ex_conf = ecp->ecp_flags; 230 csc->sc_cardtype = ecp->ecp_cardtype; 231 csc->sc_csr = ecp->ecp_csr; 232 233 if (Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, 0, 234 &sc->sc_iot, &sc->sc_ioh, &adr, &csc->sc_mapsize) == 0) { 235 #if rbus 236 #else 237 (*ct->ct_cf->cardbus_io_open)(cc, 0, adr, adr + csc->sc_mapsize); 238 #endif 239 csc->sc_bar_reg = CARDBUS_BASE0_REG; 240 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_IO; 241 242 if (csc->sc_cardtype == EX_CB_CYCLONE) { 243 /* Map CardBus function status window. */ 244 if (Cardbus_mapreg_map(ct, 245 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 246 CARDBUS_MAPREG_TYPE_MEM, 0, 247 &csc->sc_funct, &csc->sc_funch, 248 &adr1, &csc->sc_funcsize) == 0) { 249 250 csc->sc_bar_reg1 = 251 CARDBUS_3C575BTX_FUNCSTAT_PCIREG; 252 csc->sc_bar_val1 = 253 adr1 | CARDBUS_MAPREG_TYPE_MEM; 254 255 } else { 256 printf("%s: unable to map function " 257 "status window\n", self->dv_xname); 258 return; 259 } 260 261 /* Setup interrupt acknowledge hook */ 262 sc->intr_ack = ex_cardbus_intr_ack; 263 } 264 } 265 else { 266 printf(": can't map i/o space\n"); 267 return; 268 } 269 270 /* Power management hooks. */ 271 sc->enable = ex_cardbus_enable; 272 sc->disable = ex_cardbus_disable; 273 sc->power = ex_cardbus_power; 274 275 /* 276 * Handle power management nonsense and 277 * initialize the configuration registers. 278 */ 279 ex_cardbus_setup(csc); 280 281 ex_config(sc); 282 283 if (csc->sc_cardtype == EX_CB_CYCLONE) 284 bus_space_write_4(csc->sc_funct, csc->sc_funch, 285 EX_CB_INTR, EX_CB_INTR_ACK); 286 287 Cardbus_function_disable(csc->sc_ct); 288 } 289 290 void 291 ex_cardbus_intr_ack(sc) 292 struct ex_softc *sc; 293 { 294 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 295 296 bus_space_write_4(csc->sc_funct, csc->sc_funch, EX_CB_INTR, 297 EX_CB_INTR_ACK); 298 } 299 300 int 301 ex_cardbus_detach(self, arg) 302 struct device *self; 303 int arg; 304 { 305 struct ex_cardbus_softc *csc = (void *)self; 306 struct ex_softc *sc = &csc->sc_softc; 307 struct cardbus_devfunc *ct = csc->sc_ct; 308 int rv; 309 310 #if defined(DIAGNOSTIC) 311 if (ct == NULL) { 312 panic("%s: data structure lacks", sc->sc_dev.dv_xname); 313 } 314 #endif 315 316 rv = ex_detach(sc); 317 if (rv == 0) { 318 /* 319 * Unhook the interrupt handler. 320 */ 321 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, sc->sc_ih); 322 323 if (csc->sc_cardtype == EX_CB_CYCLONE) { 324 Cardbus_mapreg_unmap(ct, 325 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 326 csc->sc_funct, csc->sc_funch, csc->sc_funcsize); 327 } 328 329 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_iot, 330 sc->sc_ioh, csc->sc_mapsize); 331 } 332 return (rv); 333 } 334 335 int 336 ex_cardbus_enable(sc) 337 struct ex_softc *sc; 338 { 339 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 340 cardbus_function_tag_t cf = csc->sc_ct->ct_cf; 341 cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc; 342 343 Cardbus_function_enable(csc->sc_ct); 344 ex_cardbus_setup(csc); 345 346 sc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, 347 IPL_NET, ex_intr, sc); 348 if (NULL == sc->sc_ih) { 349 printf("%s: couldn't establish interrupt\n", 350 sc->sc_dev.dv_xname); 351 return (1); 352 } 353 printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, 354 csc->sc_intrline); 355 356 return (0); 357 } 358 359 void 360 ex_cardbus_disable(sc) 361 struct ex_softc *sc; 362 { 363 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 364 cardbus_function_tag_t cf = csc->sc_ct->ct_cf; 365 cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc; 366 367 cardbus_intr_disestablish(cc, cf, sc->sc_ih); 368 sc->sc_ih = NULL; 369 370 Cardbus_function_disable(csc->sc_ct); 371 372 } 373 374 void 375 ex_cardbus_power(sc, why) 376 struct ex_softc *sc; 377 int why; 378 { 379 struct ex_cardbus_softc *csc = (void *) sc; 380 381 if (why == PWR_RESUME) { 382 /* 383 * Give the PCI configuration registers a kick 384 * in the head. 385 */ 386 #ifdef DIAGNOSTIC 387 if (sc->enabled == 0) 388 panic("ex_cardbus_power"); 389 #endif 390 ex_cardbus_setup(csc); 391 } 392 } 393 394 void 395 ex_cardbus_setup(csc) 396 struct ex_cardbus_softc *csc; 397 { 398 struct ex_softc *sc = &csc->sc_softc; 399 cardbus_devfunc_t ct = csc->sc_ct; 400 cardbus_chipset_tag_t cc = ct->ct_cc; 401 cardbus_function_tag_t cf = ct->ct_cf; 402 cardbusreg_t reg; 403 int pmreg; 404 405 /* Get it out of power save mode if needed (BIOS bugs). */ 406 if (cardbus_get_capability(cc, cf, csc->sc_tag, 407 PCI_CAP_PWRMGMT, &pmreg, 0)) { 408 reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4) & 0x03; 409 #if 1 /* XXX Probably not right for CardBus. */ 410 if (reg == 3) { 411 /* 412 * The card has lost all configuration data in 413 * this state, so punt. 414 */ 415 printf("%s: unable to wake up from power state D3\n", 416 sc->sc_dev.dv_xname); 417 return; 418 } 419 #endif 420 if (reg != 0) { 421 printf("%s: waking up from power state D%d\n", 422 sc->sc_dev.dv_xname, reg); 423 cardbus_conf_write(cc, cf, csc->sc_tag, 424 pmreg + 4, 0); 425 } 426 } 427 428 /* Make sure the right access type is on the CardBus bridge. */ 429 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); 430 if (csc->sc_cardtype == EX_CB_CYCLONE) { 431 /* 432 * Make sure CardBus brigde can access memory space. Usually 433 * memory access is enabled by BIOS, but some BIOSes do not 434 * enable it. 435 */ 436 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 437 438 /* Program the BAR */ 439 cardbus_conf_write(cc, cf, csc->sc_tag, 440 csc->sc_bar_reg1, csc->sc_bar_val1); 441 } 442 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 443 444 445 /* Program the BAR */ 446 cardbus_conf_write(cc, cf, csc->sc_tag, 447 csc->sc_bar_reg, csc->sc_bar_val); 448 449 /* Enable the appropriate bits in the CARDBUS CSR. */ 450 reg = cardbus_conf_read(cc, cf, csc->sc_tag, 451 CARDBUS_COMMAND_STATUS_REG); 452 reg |= csc->sc_csr; 453 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, 454 reg); 455 456 /* 457 * set latency timmer 458 */ 459 reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG); 460 if (CARDBUS_LATTIMER(reg) < 0x20) { 461 /* at least the value of latency timer should 0x20. */ 462 DPRINTF(("if_ex_cardbus: lattimer 0x%x -> 0x20\n", 463 CARDBUS_LATTIMER(reg))); 464 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 465 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 466 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg); 467 } 468 } 469