1/* $NetBSD: if_ex_cardbus.c,v 1.54 2010/03/22 23:03:30 dyoung 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.54 2010/03/22 23:03:30 dyoung 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 80int ex_cardbus_match(device_t, cfdata_t, void *); 81void ex_cardbus_attach(device_t, device_t, void *); 82int ex_cardbus_detach(device_t, int); 83void ex_cardbus_intr_ack(struct ex_softc *); 84 85int ex_cardbus_enable(struct ex_softc *); 86void ex_cardbus_disable(struct ex_softc *); 87 88struct 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 116CFATTACH_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 120const 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 181void ex_cardbus_setup(struct ex_cardbus_softc *); 182 183const struct ex_cardbus_product *ex_cardbus_lookup 184 (const struct cardbus_attach_args *); 185 186const struct ex_cardbus_product * 187ex_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 200int 201ex_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 211void 212ex_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, "unable to map function " 259 "status window\n"); 260 return; 261 } 262 263 /* Setup interrupt acknowledge hook */ 264 sc->intr_ack = ex_cardbus_intr_ack; 265 } 266 } 267 else { 268 aprint_naive(": can't map i/o space\n"); 269 return; 270 } 271 272 /* Power management hooks. */ 273 sc->enable = ex_cardbus_enable; 274 sc->disable = ex_cardbus_disable; 275 276 /* 277 * Handle power management nonsense and 278 * initialize the configuration registers. 279 */ 280 ex_cardbus_setup(csc); 281 282 ex_config(sc); 283 284 if (csc->sc_cardtype == EX_CB_CYCLONE) 285 bus_space_write_4(csc->sc_funct, csc->sc_funch, 286 EX_CB_INTR, EX_CB_INTR_ACK); 287 288 Cardbus_function_disable(csc->sc_ct); 289} 290 291void 292ex_cardbus_intr_ack(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 300int 301ex_cardbus_detach(device_t self, int flags) 302{ 303 struct ex_cardbus_softc *csc = device_private(self); 304 struct ex_softc *sc = &csc->sc_softc; 305 struct cardbus_devfunc *ct = csc->sc_ct; 306 int rv; 307 308#if defined(DIAGNOSTIC) 309 if (ct == NULL) { 310 panic("%s: data structure lacks", device_xname(self)); 311 } 312#endif 313 314 if ((rv = ex_detach(sc)) != 0) 315 return rv; 316 317 /* 318 * Unhook the interrupt handler. 319 */ 320 Cardbus_intr_disestablish(ct, sc->sc_ih); 321 322 if (csc->sc_cardtype == EX_CB_CYCLONE) { 323 Cardbus_mapreg_unmap(ct, 324 CARDBUS_3C575BTX_FUNCSTAT_PCIREG, 325 csc->sc_funct, csc->sc_funch, csc->sc_funcsize); 326 } 327 328 Cardbus_mapreg_unmap(ct, PCI_BAR0, sc->sc_iot, 329 sc->sc_ioh, csc->sc_mapsize); 330 return 0; 331} 332 333int 334ex_cardbus_enable(struct ex_softc *sc) 335{ 336 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 337 338 Cardbus_function_enable(csc->sc_ct); 339 ex_cardbus_setup(csc); 340 341 sc->sc_ih = Cardbus_intr_establish(csc->sc_ct, IPL_NET, ex_intr, sc); 342 if (NULL == sc->sc_ih) { 343 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n"); 344 return (1); 345 } 346 347 return (0); 348} 349 350void 351ex_cardbus_disable(struct ex_softc *sc) 352{ 353 struct ex_cardbus_softc *csc = (struct ex_cardbus_softc *)sc; 354 355 if (sc->sc_ih != NULL) { 356 Cardbus_intr_disestablish(csc->sc_ct, sc->sc_ih); 357 sc->sc_ih = NULL; 358 } 359 360 Cardbus_function_disable(csc->sc_ct); 361 362} 363 364void 365ex_cardbus_setup(struct ex_cardbus_softc *csc) 366{ 367 cardbus_devfunc_t ct = csc->sc_ct; 368 pcireg_t reg; 369 370 (void)cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0); 371 372 /* Program the BAR */ 373 Cardbus_conf_write(ct, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val); 374 /* Make sure the right access type is on the CardBus bridge. */ 375 if (csc->sc_cardtype == EX_CB_CYCLONE) { 376 /* Program the BAR */ 377 Cardbus_conf_write(ct, csc->sc_tag, 378 csc->sc_bar_reg1, csc->sc_bar_val1); 379 /* 380 * Make sure CardBus brigde can access memory space. Usually 381 * memory access is enabled by BIOS, but some BIOSes do not 382 * enable it. 383 */ 384 } 385 386 /* Enable the appropriate bits in the CARDBUS CSR. */ 387 reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG); 388 reg |= csc->sc_csr; 389 Cardbus_conf_write(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); 390 391 /* 392 * set latency timer 393 */ 394 reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_BHLC_REG); 395 if (PCI_LATTIMER(reg) < 0x20) { 396 /* at least the value of latency timer should 0x20. */ 397 DPRINTF(("if_ex_cardbus: lattimer 0x%x -> 0x20\n", 398 PCI_LATTIMER(reg))); 399 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 400 reg |= (0x20 << PCI_LATTIMER_SHIFT); 401 Cardbus_conf_write(ct, csc->sc_tag, PCI_BHLC_REG, reg); 402 } 403} 404