1 /* $NetBSD: if_ex_cardbus.c,v 1.56 2016/07/07 06:55:41 msaitoh Exp $ */ 2 3 /* 4 * Copyright (c) 1998 and 1999 5 * HAYAKAWA Koichi. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY HAYAKAWA KOICHI ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL TAKESHI OHASHI OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * CardBus specific routines for 3Com 3C575-family CardBus ethernet adapter 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: if_ex_cardbus.c,v 1.56 2016/07/07 06:55:41 msaitoh Exp $"); 35 36 /* #define EX_DEBUG 4 */ /* define to report information for debugging */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/mbuf.h> 41 #include <sys/socket.h> 42 #include <sys/ioctl.h> 43 #include <sys/errno.h> 44 #include <sys/syslog.h> 45 #include <sys/select.h> 46 #include <sys/device.h> 47 48 #include <net/if.h> 49 #include <net/if_dl.h> 50 #include <net/if_ether.h> 51 #include <net/if_media.h> 52 53 #include <sys/cpu.h> 54 #include <sys/bus.h> 55 56 #include <dev/cardbus/cardbusvar.h> 57 #include <dev/pci/pcidevs.h> 58 59 #include <dev/mii/miivar.h> 60 61 #include <dev/ic/elink3var.h> 62 #include <dev/ic/elink3reg.h> 63 #include <dev/ic/elinkxlreg.h> 64 #include <dev/ic/elinkxlvar.h> 65 66 #if defined DEBUG && !defined EX_DEBUG 67 #define EX_DEBUG 68 #endif 69 70 #if defined EX_DEBUG 71 #define DPRINTF(a) printf a 72 #else 73 #define DPRINTF(a) 74 #endif 75 76 #define CARDBUS_3C575BTX_FUNCSTAT_PCIREG PCI_BAR2 /* means 0x18 */ 77 #define EX_CB_INTR 4 /* intr acknowledge reg. CardBus only */ 78 #define EX_CB_INTR_ACK 0x8000 /* intr acknowledge bit */ 79 80 int ex_cardbus_match(device_t, cfdata_t, void *); 81 void ex_cardbus_attach(device_t, device_t, void *); 82 int ex_cardbus_detach(device_t, int); 83 void ex_cardbus_intr_ack(struct ex_softc *); 84 85 int ex_cardbus_enable(struct ex_softc *); 86 void ex_cardbus_disable(struct ex_softc *); 87 88 struct ex_cardbus_softc { 89 struct ex_softc sc_softc; 90 91 cardbus_devfunc_t sc_ct; 92 uint8_t sc_cardbus_flags; 93 #define EX_REATTACH 0x01 94 #define EX_ABSENT 0x02 95 uint8_t sc_cardtype; 96 #define EX_CB_BOOMERANG 1 97 #define EX_CB_CYCLONE 2 98 99 /* CardBus function status space. 575B requests it. */ 100 bus_space_tag_t sc_funct; 101 bus_space_handle_t sc_funch; 102 bus_size_t sc_funcsize; 103 104 bus_size_t sc_mapsize; /* the size of mapped bus space region */ 105 106 pcitag_t sc_tag; 107 108 pcireg_t sc_csr; 109 int sc_bar_reg; /* which BAR to use */ 110 pcireg_t sc_bar_val; /* value of the BAR */ 111 int sc_bar_reg1; /* which BAR to use */ 112 pcireg_t sc_bar_val1; /* value of the BAR */ 113 114 }; 115 116 CFATTACH_DECL3_NEW(ex_cardbus, sizeof(struct ex_cardbus_softc), 117 ex_cardbus_match, ex_cardbus_attach, ex_cardbus_detach, ex_activate, 118 NULL, NULL, DVF_DETACH_SHUTDOWN); 119 120 const struct ex_cardbus_product { 121 uint32_t ecp_prodid; /* CardBus product ID */ 122 int ecp_flags; /* initial softc flags */ 123 pcireg_t ecp_csr; /* PCI CSR flags */ 124 int ecp_cardtype; /* card type */ 125 const char *ecp_name; /* device name */ 126 } ex_cardbus_products[] = { 127 { PCI_PRODUCT_3COM_3C575TX, 128 EX_CONF_MII | EX_CONF_EEPROM_OFF | EX_CONF_EEPROM_8BIT, 129 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE, 130 EX_CB_BOOMERANG, 131 "3c575-TX Ethernet" }, 132 133 { PCI_PRODUCT_3COM_3C575BTX, 134 EX_CONF_90XB|EX_CONF_MII|EX_CONF_INV_LED_POLARITY | 135 EX_CONF_EEPROM_OFF | EX_CONF_EEPROM_8BIT, 136 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | 137 PCI_COMMAND_MASTER_ENABLE, 138 EX_CB_CYCLONE, 139 "3c575B-TX Ethernet" }, 140 141 { PCI_PRODUCT_3COM_3C575CTX, 142 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 143 EX_CONF_EEPROM_8BIT, 144 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | 145 PCI_COMMAND_MASTER_ENABLE, 146 EX_CB_CYCLONE, 147 "3c575CT Ethernet" }, 148 149 { PCI_PRODUCT_3COM_3C656_E, 150 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 151 EX_CONF_EEPROM_8BIT | EX_CONF_INV_LED_POLARITY, 152 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | 153 PCI_COMMAND_MASTER_ENABLE, 154 EX_CB_CYCLONE, 155 "3c656-TX Ethernet" }, 156 157 { PCI_PRODUCT_3COM_3C656B_E, 158 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 159 EX_CONF_EEPROM_8BIT | EX_CONF_INV_LED_POLARITY, 160 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | 161 PCI_COMMAND_MASTER_ENABLE, 162 EX_CB_CYCLONE, 163 "3c656B-TX Ethernet" }, 164 165 { PCI_PRODUCT_3COM_3C656C_E, 166 EX_CONF_90XB | EX_CONF_PHY_POWER | EX_CONF_EEPROM_OFF | 167 EX_CONF_EEPROM_8BIT, 168 PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | 169 PCI_COMMAND_MASTER_ENABLE, 170 EX_CB_CYCLONE, 171 "3c656C-TX Ethernet" }, 172 173 { 0, 174 0, 175 0, 176 0, 177 NULL }, 178 }; 179 180 181 void ex_cardbus_setup(struct ex_cardbus_softc *); 182 183 const struct ex_cardbus_product *ex_cardbus_lookup 184 (const struct cardbus_attach_args *); 185 186 const struct ex_cardbus_product * 187 ex_cardbus_lookup(const struct cardbus_attach_args *ca) 188 { 189 const struct ex_cardbus_product *ecp; 190 191 if (PCI_VENDOR(ca->ca_id) != PCI_VENDOR_3COM) 192 return (NULL); 193 194 for (ecp = ex_cardbus_products; ecp->ecp_name != NULL; ecp++) 195 if (PCI_PRODUCT(ca->ca_id) == ecp->ecp_prodid) 196 return (ecp); 197 return (NULL); 198 } 199 200 int 201 ex_cardbus_match(device_t parent, cfdata_t cf, void *aux) 202 { 203 struct cardbus_attach_args *ca = aux; 204 205 if (ex_cardbus_lookup(ca) != NULL) 206 return (1); 207 208 return (0); 209 } 210 211 void 212 ex_cardbus_attach(device_t parent, device_t self, void *aux) 213 { 214 struct ex_cardbus_softc *csc = device_private(self); 215 struct ex_softc *sc = &csc->sc_softc; 216 struct cardbus_attach_args *ca = aux; 217 cardbus_devfunc_t ct = ca->ca_ct; 218 const struct ex_cardbus_product *ecp; 219 bus_addr_t adr, adr1; 220 221 sc->sc_dev = self; 222 223 sc->sc_dmat = ca->ca_dmat; 224 csc->sc_ct = ca->ca_ct; 225 csc->sc_tag = ca->ca_tag; 226 227 ecp = ex_cardbus_lookup(ca); 228 if (ecp == NULL) { 229 printf("\n"); 230 panic("ex_cardbus_attach: impossible"); 231 } 232 233 aprint_normal(": 3Com %s\n", ecp->ecp_name); 234 235 sc->ex_conf = ecp->ecp_flags; 236 csc->sc_cardtype = ecp->ecp_cardtype; 237 csc->sc_csr = ecp->ecp_csr; 238 239 if (Cardbus_mapreg_map(ct, PCI_BAR0, PCI_MAPREG_TYPE_IO, 0, 240 &sc->sc_iot, &sc->sc_ioh, &adr, &csc->sc_mapsize) == 0) { 241 csc->sc_bar_reg = PCI_BAR0; 242 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO; 243 244 if (csc->sc_cardtype == EX_CB_CYCLONE) { 245 /* Map CardBus function status window. */ 246 if (Cardbus_mapreg_map(ct, 247 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 248 PCI_MAPREG_TYPE_MEM, 0, 249 &csc->sc_funct, &csc->sc_funch, 250 &adr1, &csc->sc_funcsize) == 0) { 251 252 csc->sc_bar_reg1 = 253 CARDBUS_3C575BTX_FUNCSTAT_PCIREG; 254 csc->sc_bar_val1 = 255 adr1 | PCI_MAPREG_TYPE_MEM; 256 257 } else { 258 aprint_error_dev(self, 259 "unable to map function status window\n"); 260 return; 261 } 262 263 /* Setup interrupt acknowledge hook */ 264 sc->intr_ack = ex_cardbus_intr_ack; 265 } 266 } else { 267 aprint_naive(": can't map i/o space\n"); 268 return; 269 } 270 271 /* Power management hooks. */ 272 sc->enable = ex_cardbus_enable; 273 sc->disable = ex_cardbus_disable; 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(struct ex_softc *sc) 292 { 293 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 294 295 bus_space_write_4(csc->sc_funct, csc->sc_funch, EX_CB_INTR, 296 EX_CB_INTR_ACK); 297 } 298 299 int 300 ex_cardbus_detach(device_t self, int flags) 301 { 302 struct ex_cardbus_softc *csc = device_private(self); 303 struct ex_softc *sc = &csc->sc_softc; 304 struct cardbus_devfunc *ct = csc->sc_ct; 305 int rv; 306 307 #if defined(DIAGNOSTIC) 308 if (ct == NULL) { 309 panic("%s: data structure lacks", device_xname(self)); 310 } 311 #endif 312 313 if ((rv = ex_detach(sc)) != 0) 314 return rv; 315 316 /* 317 * Unhook the interrupt handler. 318 */ 319 Cardbus_intr_disestablish(ct, sc->sc_ih); 320 321 if (csc->sc_cardtype == EX_CB_CYCLONE) { 322 Cardbus_mapreg_unmap(ct, 323 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 324 csc->sc_funct, csc->sc_funch, csc->sc_funcsize); 325 } 326 327 Cardbus_mapreg_unmap(ct, PCI_BAR0, sc->sc_iot, 328 sc->sc_ioh, csc->sc_mapsize); 329 return 0; 330 } 331 332 int 333 ex_cardbus_enable(struct ex_softc *sc) 334 { 335 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 336 337 Cardbus_function_enable(csc->sc_ct); 338 ex_cardbus_setup(csc); 339 340 sc->sc_ih = Cardbus_intr_establish(csc->sc_ct, IPL_NET, ex_intr, sc); 341 if (NULL == sc->sc_ih) { 342 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n"); 343 return (1); 344 } 345 346 return (0); 347 } 348 349 void 350 ex_cardbus_disable(struct ex_softc *sc) 351 { 352 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 353 354 if (sc->sc_ih != NULL) { 355 Cardbus_intr_disestablish(csc->sc_ct, sc->sc_ih); 356 sc->sc_ih = NULL; 357 } 358 359 Cardbus_function_disable(csc->sc_ct); 360 361 } 362 363 void 364 ex_cardbus_setup(struct ex_cardbus_softc *csc) 365 { 366 cardbus_devfunc_t ct = csc->sc_ct; 367 pcireg_t reg; 368 369 (void)cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0); 370 371 /* Program the BAR */ 372 Cardbus_conf_write(ct, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val); 373 /* Make sure the right access type is on the CardBus bridge. */ 374 if (csc->sc_cardtype == EX_CB_CYCLONE) { 375 /* Program the BAR */ 376 Cardbus_conf_write(ct, csc->sc_tag, 377 csc->sc_bar_reg1, csc->sc_bar_val1); 378 /* 379 * Make sure CardBus brigde can access memory space. Usually 380 * memory access is enabled by BIOS, but some BIOSes do not 381 * enable it. 382 */ 383 } 384 385 /* Enable the appropriate bits in the CARDBUS CSR. */ 386 reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG); 387 reg |= csc->sc_csr; 388 Cardbus_conf_write(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); 389 390 /* 391 * set latency timer 392 */ 393 reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_BHLC_REG); 394 if (PCI_LATTIMER(reg) < 0x20) { 395 /* at least the value of latency timer should 0x20. */ 396 DPRINTF(("if_ex_cardbus: lattimer 0x%x -> 0x20\n", 397 PCI_LATTIMER(reg))); 398 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 399 reg |= (0x20 << PCI_LATTIMER_SHIFT); 400 Cardbus_conf_write(ct, csc->sc_tag, PCI_BHLC_REG, reg); 401 } 402 } 403