1 /* $NetBSD: if_ex_cardbus.c,v 1.45 2008/06/24 19:44:52 drochner 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.45 2008/06/24 19:44:52 drochner 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(device_t, cfdata_t, void *); 87 void ex_cardbus_attach(device_t, device_t, void *); 88 int ex_cardbus_detach(device_t, 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 94 struct ex_cardbus_softc { 95 struct ex_softc sc_softc; 96 97 cardbus_devfunc_t sc_ct; 98 cardbus_intr_line_t sc_intrline; 99 uint8_t sc_cardbus_flags; 100 #define EX_REATTACH 0x01 101 #define EX_ABSENT 0x02 102 uint8_t sc_cardtype; 103 #define EX_CB_BOOMERANG 1 104 #define EX_CB_CYCLONE 2 105 106 /* CardBus function status space. 575B requests it. */ 107 bus_space_tag_t sc_funct; 108 bus_space_handle_t sc_funch; 109 bus_size_t sc_funcsize; 110 111 bus_size_t sc_mapsize; /* the size of mapped bus space region */ 112 113 cardbustag_t sc_tag; 114 115 int sc_csr; /* CSR bits */ 116 int sc_bar_reg; /* which BAR to use */ 117 pcireg_t sc_bar_val; /* value of the BAR */ 118 int sc_bar_reg1; /* which BAR to use */ 119 pcireg_t sc_bar_val1; /* value of the BAR */ 120 121 }; 122 123 CFATTACH_DECL_NEW(ex_cardbus, sizeof(struct ex_cardbus_softc), 124 ex_cardbus_match, ex_cardbus_attach, ex_cardbus_detach, ex_activate); 125 126 const struct ex_cardbus_product { 127 uint32_t ecp_prodid; /* CardBus product ID */ 128 int ecp_flags; /* initial softc flags */ 129 pcireg_t ecp_csr; /* PCI CSR flags */ 130 int ecp_cardtype; /* card type */ 131 const char *ecp_name; /* device name */ 132 } ex_cardbus_products[] = { 133 { PCI_PRODUCT_3COM_3C575TX, 134 EX_CONF_MII | EX_CONF_EEPROM_OFF | EX_CONF_EEPROM_8BIT, 135 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MASTER_ENABLE, 136 EX_CB_BOOMERANG, 137 "3c575-TX Ethernet" }, 138 139 { PCI_PRODUCT_3COM_3C575BTX, 140 EX_CONF_90XB|EX_CONF_MII|EX_CONF_INV_LED_POLARITY | 141 EX_CONF_EEPROM_OFF | EX_CONF_EEPROM_8BIT, 142 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 143 CARDBUS_COMMAND_MASTER_ENABLE, 144 EX_CB_CYCLONE, 145 "3c575B-TX Ethernet" }, 146 147 { PCI_PRODUCT_3COM_3C575CTX, 148 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 149 EX_CONF_EEPROM_8BIT, 150 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 151 CARDBUS_COMMAND_MASTER_ENABLE, 152 EX_CB_CYCLONE, 153 "3c575CT Ethernet" }, 154 155 { PCI_PRODUCT_3COM_3C656_E, 156 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 157 EX_CONF_EEPROM_8BIT | EX_CONF_INV_LED_POLARITY, 158 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 159 CARDBUS_COMMAND_MASTER_ENABLE, 160 EX_CB_CYCLONE, 161 "3c656-TX Ethernet" }, 162 163 { PCI_PRODUCT_3COM_3C656B_E, 164 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 165 EX_CONF_EEPROM_8BIT | EX_CONF_INV_LED_POLARITY, 166 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 167 CARDBUS_COMMAND_MASTER_ENABLE, 168 EX_CB_CYCLONE, 169 "3c656B-TX Ethernet" }, 170 171 { PCI_PRODUCT_3COM_3C656C_E, 172 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 173 EX_CONF_EEPROM_8BIT, 174 CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE | 175 CARDBUS_COMMAND_MASTER_ENABLE, 176 EX_CB_CYCLONE, 177 "3c656C-TX Ethernet" }, 178 179 { 0, 180 0, 181 0, 182 0, 183 NULL }, 184 }; 185 186 187 void ex_cardbus_setup(struct ex_cardbus_softc *); 188 189 const struct ex_cardbus_product *ex_cardbus_lookup 190 (const struct cardbus_attach_args *); 191 192 const struct ex_cardbus_product * 193 ex_cardbus_lookup(const struct cardbus_attach_args *ca) 194 { 195 const struct ex_cardbus_product *ecp; 196 197 if (CARDBUS_VENDOR(ca->ca_id) != PCI_VENDOR_3COM) 198 return (NULL); 199 200 for (ecp = ex_cardbus_products; ecp->ecp_name != NULL; ecp++) 201 if (CARDBUS_PRODUCT(ca->ca_id) == ecp->ecp_prodid) 202 return (ecp); 203 return (NULL); 204 } 205 206 int 207 ex_cardbus_match(device_t parent, cfdata_t cf, void *aux) 208 { 209 struct cardbus_attach_args *ca = aux; 210 211 if (ex_cardbus_lookup(ca) != NULL) 212 return (1); 213 214 return (0); 215 } 216 217 void 218 ex_cardbus_attach(device_t parent, device_t self, void *aux) 219 { 220 struct ex_cardbus_softc *csc = device_private(self); 221 struct ex_softc *sc = &csc->sc_softc; 222 struct cardbus_attach_args *ca = aux; 223 cardbus_devfunc_t ct = ca->ca_ct; 224 #if rbus 225 #else 226 cardbus_chipset_tag_t cc = ct->ct_cc; 227 #endif 228 const struct ex_cardbus_product *ecp; 229 bus_addr_t adr, adr1; 230 231 sc->sc_dev = self; 232 233 sc->ex_bustype = EX_BUS_CARDBUS; 234 sc->sc_dmat = ca->ca_dmat; 235 csc->sc_ct = ca->ca_ct; 236 csc->sc_intrline = ca->ca_intrline; 237 csc->sc_tag = ca->ca_tag; 238 239 ecp = ex_cardbus_lookup(ca); 240 if (ecp == NULL) { 241 printf("\n"); 242 panic("ex_cardbus_attach: impossible"); 243 } 244 245 aprint_normal(": 3Com %s\n", ecp->ecp_name); 246 247 sc->ex_conf = ecp->ecp_flags; 248 csc->sc_cardtype = ecp->ecp_cardtype; 249 csc->sc_csr = ecp->ecp_csr; 250 251 if (Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, 0, 252 &sc->sc_iot, &sc->sc_ioh, &adr, &csc->sc_mapsize) == 0) { 253 #if rbus 254 #else 255 (*ct->ct_cf->cardbus_io_open)(cc, 0, adr, adr + csc->sc_mapsize); 256 #endif 257 csc->sc_bar_reg = CARDBUS_BASE0_REG; 258 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_IO; 259 260 if (csc->sc_cardtype == EX_CB_CYCLONE) { 261 /* Map CardBus function status window. */ 262 if (Cardbus_mapreg_map(ct, 263 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 264 CARDBUS_MAPREG_TYPE_MEM, 0, 265 &csc->sc_funct, &csc->sc_funch, 266 &adr1, &csc->sc_funcsize) == 0) { 267 268 csc->sc_bar_reg1 = 269 CARDBUS_3C575BTX_FUNCSTAT_PCIREG; 270 csc->sc_bar_val1 = 271 adr1 | CARDBUS_MAPREG_TYPE_MEM; 272 273 } else { 274 aprint_error_dev(self, "unable to map function " 275 "status window\n"); 276 return; 277 } 278 279 /* Setup interrupt acknowledge hook */ 280 sc->intr_ack = ex_cardbus_intr_ack; 281 } 282 } 283 else { 284 aprint_naive(": can't map i/o space\n"); 285 return; 286 } 287 288 /* Power management hooks. */ 289 sc->enable = ex_cardbus_enable; 290 sc->disable = ex_cardbus_disable; 291 292 /* 293 * Handle power management nonsense and 294 * initialize the configuration registers. 295 */ 296 ex_cardbus_setup(csc); 297 298 ex_config(sc); 299 300 if (csc->sc_cardtype == EX_CB_CYCLONE) 301 bus_space_write_4(csc->sc_funct, csc->sc_funch, 302 EX_CB_INTR, EX_CB_INTR_ACK); 303 304 Cardbus_function_disable(csc->sc_ct); 305 } 306 307 void 308 ex_cardbus_intr_ack(struct ex_softc *sc) 309 { 310 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 311 312 bus_space_write_4(csc->sc_funct, csc->sc_funch, EX_CB_INTR, 313 EX_CB_INTR_ACK); 314 } 315 316 int 317 ex_cardbus_detach(device_t self, int arg) 318 { 319 struct ex_cardbus_softc *csc = device_private(self); 320 struct ex_softc *sc = &csc->sc_softc; 321 struct cardbus_devfunc *ct = csc->sc_ct; 322 int rv; 323 324 #if defined(DIAGNOSTIC) 325 if (ct == NULL) { 326 panic("%s: data structure lacks", device_xname(self)); 327 } 328 #endif 329 330 rv = ex_detach(sc); 331 if (rv == 0) { 332 /* 333 * Unhook the interrupt handler. 334 */ 335 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, sc->sc_ih); 336 337 if (csc->sc_cardtype == EX_CB_CYCLONE) { 338 Cardbus_mapreg_unmap(ct, 339 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 340 csc->sc_funct, csc->sc_funch, csc->sc_funcsize); 341 } 342 343 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_iot, 344 sc->sc_ioh, csc->sc_mapsize); 345 } 346 return (rv); 347 } 348 349 int 350 ex_cardbus_enable(struct ex_softc *sc) 351 { 352 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 353 cardbus_function_tag_t cf = csc->sc_ct->ct_cf; 354 cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc; 355 356 Cardbus_function_enable(csc->sc_ct); 357 ex_cardbus_setup(csc); 358 359 sc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, 360 IPL_NET, ex_intr, sc); 361 if (NULL == sc->sc_ih) { 362 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n"); 363 return (1); 364 } 365 366 return (0); 367 } 368 369 void 370 ex_cardbus_disable(struct ex_softc *sc) 371 { 372 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 373 cardbus_function_tag_t cf = csc->sc_ct->ct_cf; 374 cardbus_chipset_tag_t cc = csc->sc_ct->ct_cc; 375 376 cardbus_intr_disestablish(cc, cf, sc->sc_ih); 377 sc->sc_ih = NULL; 378 379 Cardbus_function_disable(csc->sc_ct); 380 381 } 382 383 void 384 ex_cardbus_setup(struct ex_cardbus_softc *csc) 385 { 386 cardbus_devfunc_t ct = csc->sc_ct; 387 cardbus_chipset_tag_t cc = ct->ct_cc; 388 cardbus_function_tag_t cf = ct->ct_cf; 389 cardbusreg_t reg; 390 391 (void)cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0); 392 393 /* Program the BAR */ 394 cardbus_conf_write(cc, cf, csc->sc_tag, 395 csc->sc_bar_reg, csc->sc_bar_val); 396 /* Make sure the right access type is on the CardBus bridge. */ 397 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); 398 if (csc->sc_cardtype == EX_CB_CYCLONE) { 399 /* Program the BAR */ 400 cardbus_conf_write(cc, cf, csc->sc_tag, 401 csc->sc_bar_reg1, csc->sc_bar_val1); 402 /* 403 * Make sure CardBus brigde can access memory space. Usually 404 * memory access is enabled by BIOS, but some BIOSes do not 405 * enable it. 406 */ 407 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 408 } 409 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 410 411 /* Enable the appropriate bits in the CARDBUS CSR. */ 412 reg = cardbus_conf_read(cc, cf, csc->sc_tag, 413 CARDBUS_COMMAND_STATUS_REG); 414 reg |= csc->sc_csr; 415 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, 416 reg); 417 418 /* 419 * set latency timer 420 */ 421 reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG); 422 if (CARDBUS_LATTIMER(reg) < 0x20) { 423 /* at least the value of latency timer should 0x20. */ 424 DPRINTF(("if_ex_cardbus: lattimer 0x%x -> 0x20\n", 425 CARDBUS_LATTIMER(reg))); 426 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 427 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 428 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg); 429 } 430 } 431