1 /* $NetBSD: if_ex_cardbus.c,v 1.41 2007/12/09 20:27:56 jmcneill 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.41 2007/12/09 20:27:56 jmcneill 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 <sys/cpu.h> 60 #include <sys/bus.h> 61 62 #include <dev/cardbus/cardbusvar.h> 63 #include <dev/pci/pcidevs.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(struct device *, struct cfdata *, void *); 87 void ex_cardbus_attach(struct device *, struct device *,void *); 88 int ex_cardbus_detach(struct device *, int); 89 void ex_cardbus_intr_ack(struct ex_softc *); 90 91 int ex_cardbus_enable(struct ex_softc *); 92 void ex_cardbus_disable(struct ex_softc *); 93 void ex_cardbus_power(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 { PCI_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 { PCI_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 { PCI_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 { PCI_PRODUCT_3COM_3C656_E, 157 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 158 EX_CONF_EEPROM_8BIT | EX_CONF_INV_LED_POLARITY, 159 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 160 CARDBUS_COMMAND_MASTER_ENABLE, 161 EX_CB_CYCLONE, 162 "3c656-TX Ethernet" }, 163 164 { PCI_PRODUCT_3COM_3C656B_E, 165 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 166 EX_CONF_EEPROM_8BIT | EX_CONF_INV_LED_POLARITY, 167 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 168 CARDBUS_COMMAND_MASTER_ENABLE, 169 EX_CB_CYCLONE, 170 "3c656B-TX Ethernet" }, 171 172 { PCI_PRODUCT_3COM_3C656C_E, 173 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 174 EX_CONF_EEPROM_8BIT, 175 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 176 CARDBUS_COMMAND_MASTER_ENABLE, 177 EX_CB_CYCLONE, 178 "3c656C-TX Ethernet" }, 179 180 { 0, 181 0, 182 0, 183 0, 184 NULL }, 185 }; 186 187 188 void ex_cardbus_setup(struct ex_cardbus_softc *); 189 190 const struct ex_cardbus_product *ex_cardbus_lookup 191 (const struct cardbus_attach_args *); 192 193 const struct ex_cardbus_product * 194 ex_cardbus_lookup(ca) 195 const struct cardbus_attach_args *ca; 196 { 197 const struct ex_cardbus_product *ecp; 198 199 if (CARDBUS_VENDOR(ca->ca_id) != PCI_VENDOR_3COM) 200 return (NULL); 201 202 for (ecp = ex_cardbus_products; ecp->ecp_name != NULL; ecp++) 203 if (CARDBUS_PRODUCT(ca->ca_id) == ecp->ecp_prodid) 204 return (ecp); 205 return (NULL); 206 } 207 208 int 209 ex_cardbus_match(struct device *parent, struct cfdata *cf, 210 void *aux) 211 { 212 struct cardbus_attach_args *ca = aux; 213 214 if (ex_cardbus_lookup(ca) != NULL) 215 return (1); 216 217 return (0); 218 } 219 220 void 221 ex_cardbus_attach(struct device *parent, struct device *self, 222 void *aux) 223 { 224 struct ex_cardbus_softc *csc = device_private(self); 225 struct ex_softc *sc = &csc->sc_softc; 226 struct cardbus_attach_args *ca = aux; 227 cardbus_devfunc_t ct = ca->ca_ct; 228 #if rbus 229 #else 230 cardbus_chipset_tag_t cc = ct->ct_cc; 231 #endif 232 const struct ex_cardbus_product *ecp; 233 bus_addr_t adr, adr1; 234 235 sc->ex_bustype = EX_BUS_CARDBUS; 236 sc->sc_dmat = ca->ca_dmat; 237 csc->sc_ct = ca->ca_ct; 238 csc->sc_intrline = ca->ca_intrline; 239 csc->sc_tag = ca->ca_tag; 240 241 ecp = ex_cardbus_lookup(ca); 242 if (ecp == NULL) { 243 printf("\n"); 244 panic("ex_cardbus_attach: impossible"); 245 } 246 247 printf(": 3Com %s\n", ecp->ecp_name); 248 249 sc->ex_conf = ecp->ecp_flags; 250 csc->sc_cardtype = ecp->ecp_cardtype; 251 csc->sc_csr = ecp->ecp_csr; 252 253 if (Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, 0, 254 &sc->sc_iot, &sc->sc_ioh, &adr, &csc->sc_mapsize) == 0) { 255 #if rbus 256 #else 257 (*ct->ct_cf->cardbus_io_open)(cc, 0, adr, adr + csc->sc_mapsize); 258 #endif 259 csc->sc_bar_reg = CARDBUS_BASE0_REG; 260 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_IO; 261 262 if (csc->sc_cardtype == EX_CB_CYCLONE) { 263 /* Map CardBus function status window. */ 264 if (Cardbus_mapreg_map(ct, 265 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 266 CARDBUS_MAPREG_TYPE_MEM, 0, 267 &csc->sc_funct, &csc->sc_funch, 268 &adr1, &csc->sc_funcsize) == 0) { 269 270 csc->sc_bar_reg1 = 271 CARDBUS_3C575BTX_FUNCSTAT_PCIREG; 272 csc->sc_bar_val1 = 273 adr1 | CARDBUS_MAPREG_TYPE_MEM; 274 275 } else { 276 printf("%s: unable to map function " 277 "status window\n", self->dv_xname); 278 return; 279 } 280 281 /* Setup interrupt acknowledge hook */ 282 sc->intr_ack = ex_cardbus_intr_ack; 283 } 284 } 285 else { 286 printf(": can't map i/o space\n"); 287 return; 288 } 289 290 /* Power management hooks. */ 291 sc->enable = ex_cardbus_enable; 292 sc->disable = ex_cardbus_disable; 293 sc->power = ex_cardbus_power; 294 295 /* 296 * Handle power management nonsense and 297 * initialize the configuration registers. 298 */ 299 ex_cardbus_setup(csc); 300 301 ex_config(sc); 302 303 if (csc->sc_cardtype == EX_CB_CYCLONE) 304 bus_space_write_4(csc->sc_funct, csc->sc_funch, 305 EX_CB_INTR, EX_CB_INTR_ACK); 306 307 Cardbus_function_disable(csc->sc_ct); 308 } 309 310 void 311 ex_cardbus_intr_ack(sc) 312 struct ex_softc *sc; 313 { 314 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 315 316 bus_space_write_4(csc->sc_funct, csc->sc_funch, EX_CB_INTR, 317 EX_CB_INTR_ACK); 318 } 319 320 int 321 ex_cardbus_detach(struct device *self, int arg) 322 { 323 struct ex_cardbus_softc *csc = device_private(self); 324 struct ex_softc *sc = &csc->sc_softc; 325 struct cardbus_devfunc *ct = csc->sc_ct; 326 int rv; 327 328 #if defined(DIAGNOSTIC) 329 if (ct == NULL) { 330 panic("%s: data structure lacks", sc->sc_dev.dv_xname); 331 } 332 #endif 333 334 rv = ex_detach(sc); 335 if (rv == 0) { 336 /* 337 * Unhook the interrupt handler. 338 */ 339 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, sc->sc_ih); 340 341 if (csc->sc_cardtype == EX_CB_CYCLONE) { 342 Cardbus_mapreg_unmap(ct, 343 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 344 csc->sc_funct, csc->sc_funch, csc->sc_funcsize); 345 } 346 347 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_iot, 348 sc->sc_ioh, csc->sc_mapsize); 349 } 350 return (rv); 351 } 352 353 int 354 ex_cardbus_enable(sc) 355 struct ex_softc *sc; 356 { 357 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 358 cardbus_function_tag_t cf = csc->sc_ct->ct_cf; 359 cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc; 360 361 Cardbus_function_enable(csc->sc_ct); 362 ex_cardbus_setup(csc); 363 364 sc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, 365 IPL_NET, ex_intr, sc); 366 if (NULL == sc->sc_ih) { 367 printf("%s: couldn't establish interrupt\n", 368 sc->sc_dev.dv_xname); 369 return (1); 370 } 371 printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, 372 csc->sc_intrline); 373 374 return (0); 375 } 376 377 void 378 ex_cardbus_disable(sc) 379 struct ex_softc *sc; 380 { 381 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 382 cardbus_function_tag_t cf = csc->sc_ct->ct_cf; 383 cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc; 384 385 cardbus_intr_disestablish(cc, cf, sc->sc_ih); 386 sc->sc_ih = NULL; 387 388 Cardbus_function_disable(csc->sc_ct); 389 390 } 391 392 void 393 ex_cardbus_power(sc, why) 394 struct ex_softc *sc; 395 int why; 396 { 397 struct ex_cardbus_softc *csc = (void *) sc; 398 399 if (why == PWR_RESUME) { 400 /* 401 * Give the PCI configuration registers a kick 402 * in the head. 403 */ 404 #ifdef DIAGNOSTIC 405 if (sc->enabled == 0) 406 panic("ex_cardbus_power"); 407 #endif 408 ex_cardbus_setup(csc); 409 } 410 } 411 412 void 413 ex_cardbus_setup(csc) 414 struct ex_cardbus_softc *csc; 415 { 416 cardbus_devfunc_t ct = csc->sc_ct; 417 cardbus_chipset_tag_t cc = ct->ct_cc; 418 cardbus_function_tag_t cf = ct->ct_cf; 419 cardbusreg_t reg; 420 421 (void)cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0); 422 423 /* Program the BAR */ 424 cardbus_conf_write(cc, cf, csc->sc_tag, 425 csc->sc_bar_reg, csc->sc_bar_val); 426 /* Make sure the right access type is on the CardBus bridge. */ 427 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); 428 if (csc->sc_cardtype == EX_CB_CYCLONE) { 429 /* Program the BAR */ 430 cardbus_conf_write(cc, cf, csc->sc_tag, 431 csc->sc_bar_reg1, csc->sc_bar_val1); 432 /* 433 * Make sure CardBus brigde can access memory space. Usually 434 * memory access is enabled by BIOS, but some BIOSes do not 435 * enable it. 436 */ 437 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 438 } 439 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 440 441 /* Enable the appropriate bits in the CARDBUS CSR. */ 442 reg = cardbus_conf_read(cc, cf, csc->sc_tag, 443 CARDBUS_COMMAND_STATUS_REG); 444 reg |= csc->sc_csr; 445 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, 446 reg); 447 448 /* 449 * set latency timer 450 */ 451 reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG); 452 if (CARDBUS_LATTIMER(reg) < 0x20) { 453 /* at least the value of latency timer should 0x20. */ 454 DPRINTF(("if_ex_cardbus: lattimer 0x%x -> 0x20\n", 455 CARDBUS_LATTIMER(reg))); 456 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 457 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 458 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg); 459 } 460 } 461