if_xe_pccard.c revision 292079
1/*- 2 * Copyright (c) 2002 Takeshi Shibagaki 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/dev/xe/if_xe_pccard.c 292079 2015-12-11 05:27:56Z imp $"); 29 30/* xe pccard interface driver */ 31 32#include <sys/param.h> 33#include <sys/bus.h> 34#include <sys/kernel.h> 35#include <sys/lock.h> 36#include <sys/module.h> 37#include <sys/mutex.h> 38#include <sys/socket.h> 39#include <sys/systm.h> 40 41#include <machine/bus.h> 42#include <machine/resource.h> 43#include <sys/rman.h> 44 45#include <net/ethernet.h> 46#include <net/if.h> 47#include <net/if_arp.h> 48#include <net/if_media.h> 49#include <net/if_mib.h> 50 51#include <dev/xe/if_xereg.h> 52#include <dev/xe/if_xevar.h> 53 54#include <dev/pccard/pccardvar.h> 55#include <dev/pccard/pccard_cis.h> 56 57#include "card_if.h" 58#include "pccarddevs.h" 59 60/* 61 * Debug logging levels - set with hw.xe.debug sysctl 62 * 0 = None 63 * 1 = More hardware details, probe/attach progress 64 * 2 = Most function calls, ioctls and media selection progress 65 * 3 = Everything - interrupts, packets in/out and multicast address setup 66 */ 67#define XE_DEBUG 68#ifdef XE_DEBUG 69 70extern int xe_debug; 71 72#define DEVPRINTF(level, arg) if (xe_debug >= (level)) device_printf arg 73#define DPRINTF(level, arg) if (xe_debug >= (level)) printf arg 74#else 75#define DEVPRINTF(level, arg) 76#define DPRINTF(level, arg) 77#endif 78 79 80#define XE_CARD_TYPE_FLAGS_NO 0x0 81#define XE_CARD_TYPE_FLAGS_CE2 0x1 82#define XE_CARD_TYPE_FLAGS_MOHAWK 0x2 83#define XE_CARD_TYPE_FLAGS_DINGO 0x4 84#define XE_PROD_ETHER_MASK 0x0100 85#define XE_PROD_MODEM_MASK 0x1000 86 87#define XE_BOGUS_MAC_OFFSET 0x90 88 89/* MAC vendor prefix used by most Xircom cards is 00:80:c7 */ 90#define XE_MAC_ADDR_0 0x00 91#define XE_MAC_ADDR_1 0x80 92#define XE_MAC_ADDR_2 0xc7 93 94/* Some (all?) REM56 cards have vendor prefix 00:10:a4 */ 95#define XE_REM56_MAC_ADDR_0 0x00 96#define XE_REM56_MAC_ADDR_1 0x10 97#define XE_REM56_MAC_ADDR_2 0xa4 98 99struct xe_pccard_product { 100 struct pccard_product product; 101 uint16_t prodext; 102 uint16_t flags; 103}; 104 105static const struct xe_pccard_product xe_pccard_products[] = { 106 { PCMCIA_CARD_D(COMPAQ, CPQ550), 0x43, XE_CARD_TYPE_FLAGS_CE2 }, 107 { PCMCIA_CARD_D(COMPAQ2, CPQ_10_100), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 108 { PCMCIA_CARD_D(INTEL, EEPRO100), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 109 { PCMCIA_CARD_D(INTEL, PRO100LAN56), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, 110 { PCMCIA_CARD_D(RACORE, ACCTON_EN2226),0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 111 { PCMCIA_CARD_D(XIRCOM, CE), 0x41, XE_CARD_TYPE_FLAGS_NO }, 112 { PCMCIA_CARD_D(XIRCOM, CE2), 0x41, XE_CARD_TYPE_FLAGS_CE2 }, 113 { PCMCIA_CARD_D(XIRCOM, CE2), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, 114 { PCMCIA_CARD_D(XIRCOM, CE2_2), 0x41, XE_CARD_TYPE_FLAGS_CE2 }, 115 { PCMCIA_CARD_D(XIRCOM, CE2_2), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, 116 { PCMCIA_CARD_D(XIRCOM, CE3), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 117 { PCMCIA_CARD_D(XIRCOM, CEM), 0x41, XE_CARD_TYPE_FLAGS_NO }, 118 { PCMCIA_CARD_D(XIRCOM, CEM2), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, 119 { PCMCIA_CARD_D(XIRCOM, CEM28), 0x43, XE_CARD_TYPE_FLAGS_CE2 }, 120 { PCMCIA_CARD_D(XIRCOM, CEM33), 0x44, XE_CARD_TYPE_FLAGS_CE2 }, 121 { PCMCIA_CARD_D(XIRCOM, CEM33_2), 0x44, XE_CARD_TYPE_FLAGS_CE2 }, 122 { PCMCIA_CARD_D(XIRCOM, CEM56), 0x45, XE_CARD_TYPE_FLAGS_DINGO }, 123 { PCMCIA_CARD_D(XIRCOM, CEM56_2), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, 124 { PCMCIA_CARD_D(XIRCOM, REM56), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, 125 { PCMCIA_CARD_D(XIRCOM, REM10), 0x47, XE_CARD_TYPE_FLAGS_DINGO }, 126 { PCMCIA_CARD_D(XIRCOM, XEM5600), 0x56, XE_CARD_TYPE_FLAGS_DINGO }, 127 { { NULL }, 0, 0 } 128}; 129 130/* 131 * Fixing for CEM2, CEM3 and CEM56/REM56 cards. These need some magic to 132 * enable the Ethernet function, which isn't mentioned anywhere in the CIS. 133 * Despite the register names, most of this isn't Dingo-specific. 134 */ 135static int 136xe_cemfix(device_t dev) 137{ 138 struct xe_softc *sc = device_get_softc(dev); 139 int ioport; 140 141 DEVPRINTF(2, (dev, "cemfix\n")); 142 143 DEVPRINTF(1, (dev, "CEM I/O port 0x%0lx, size 0x%0lx\n", 144 bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid), 145 bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid))); 146 147 pccard_attr_write_1(dev, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL | 148 DINGO_ECOR_INT_ENABLE | DINGO_ECOR_IOB_ENABLE | 149 DINGO_ECOR_ETH_ENABLE); 150 ioport = bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid); 151 pccard_attr_write_1(dev, DINGO_EBAR0, ioport & 0xff); 152 pccard_attr_write_1(dev, DINGO_EBAR1, (ioport >> 8) & 0xff); 153 154 if (sc->dingo) { 155 pccard_attr_write_1(dev, DINGO_DCOR0, DINGO_DCOR0_SF_INT); 156 pccard_attr_write_1(dev, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL | 157 DINGO_DCOR1_EEDIO); 158 pccard_attr_write_1(dev, DINGO_DCOR2, 0x00); 159 pccard_attr_write_1(dev, DINGO_DCOR3, 0x00); 160 pccard_attr_write_1(dev, DINGO_DCOR4, 0x00); 161 } 162 /* success! */ 163 return (0); 164} 165 166static int 167xe_pccard_product_match(device_t dev, const struct pccard_product* ent, 168 int vpfmatch) 169{ 170 const struct xe_pccard_product* xpp; 171 uint16_t prodext; 172 173 if (vpfmatch == 0) 174 return (0); 175 176 xpp = (const struct xe_pccard_product*)ent; 177 pccard_get_prodext(dev, &prodext); 178 if (xpp->prodext != prodext) 179 vpfmatch = 0; 180 else 181 vpfmatch++; 182 return (vpfmatch); 183} 184 185static const struct xe_pccard_product * 186xe_pccard_get_product(device_t dev) 187{ 188 return ((const struct xe_pccard_product *)pccard_product_lookup(dev, 189 (const struct pccard_product *)xe_pccard_products, 190 sizeof(xe_pccard_products[0]), xe_pccard_product_match)); 191} 192 193/* 194 * Fixing for CE2-class cards with bogus CIS entry for MAC address. 195 */ 196static int 197xe_pccard_mac(const struct pccard_tuple *tuple, void *argp) 198{ 199 uint8_t *enaddr = argp, test; 200 int i; 201 202 /* Code 0x89 is Xircom special cis node contianing the MAC */ 203 if (tuple->code != 0x89) 204 return (0); 205 206 /* Make sure this is a sane node */ 207 if (tuple->length != ETHER_ADDR_LEN + 2) 208 return (0); 209 test = pccard_tuple_read_1(tuple, 0); 210 if (test != PCCARD_TPLFE_TYPE_LAN_NID) 211 return (0); 212 test = pccard_tuple_read_1(tuple, 1); 213 if (test != ETHER_ADDR_LEN) 214 return (0); 215 216 /* Copy the MAC ADDR and return success */ 217 for (i = 0; i < ETHER_ADDR_LEN; i++) 218 enaddr[i] = pccard_tuple_read_1(tuple, i + 2); 219 return (1); 220} 221 222static int 223xe_bad_mac(uint8_t *enaddr) 224{ 225 int i; 226 uint8_t sum; 227 228 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 229 sum |= enaddr[i]; 230 return (sum == 0); 231} 232 233/* 234 * PCMCIA attach routine. 235 * Identify the device. Called from the bus driver when the card is 236 * inserted or otherwise powers up. 237 */ 238static int 239xe_pccard_attach(device_t dev) 240{ 241 struct xe_softc *scp = device_get_softc(dev); 242 uint32_t vendor,product; 243 uint16_t prodext; 244 const char* vendor_str = NULL; 245 const char* product_str = NULL; 246 const char* cis4_str = NULL; 247 const char *cis3_str=NULL; 248 const struct xe_pccard_product *xpp; 249 int err; 250 251 DEVPRINTF(2, (dev, "pccard_attach\n")); 252 253 pccard_get_vendor(dev, &vendor); 254 pccard_get_product(dev, &product); 255 pccard_get_prodext(dev, &prodext); 256 pccard_get_vendor_str(dev, &vendor_str); 257 pccard_get_product_str(dev, &product_str); 258 pccard_get_cis3_str(dev, &cis3_str); 259 pccard_get_cis4_str(dev, &cis4_str); 260 261 DEVPRINTF(1, (dev, "vendor = 0x%04x\n", vendor)); 262 DEVPRINTF(1, (dev, "product = 0x%04x\n", product)); 263 DEVPRINTF(1, (dev, "prodext = 0x%02x\n", prodext)); 264 DEVPRINTF(1, (dev, "vendor_str = %s\n", vendor_str)); 265 DEVPRINTF(1, (dev, "product_str = %s\n", product_str)); 266 DEVPRINTF(1, (dev, "cis3_str = %s\n", cis3_str)); 267 DEVPRINTF(1, (dev, "cis4_str = %s\n", cis4_str)); 268 269 xpp = xe_pccard_get_product(dev); 270 if (xpp == NULL) 271 return (ENXIO); 272 273 /* Set various card ID fields in softc */ 274 scp->vendor = vendor_str; 275 scp->card_type = product_str; 276 if (xpp->flags & XE_CARD_TYPE_FLAGS_CE2) 277 scp->ce2 = 1; 278 if (xpp->flags & XE_CARD_TYPE_FLAGS_MOHAWK) 279 scp->mohawk = 1; 280 if (xpp->flags & XE_CARD_TYPE_FLAGS_DINGO) { 281 scp->dingo = 1; 282 scp->mohawk = 1; 283 } 284 if (xpp->product.pp_product & XE_PROD_MODEM_MASK) 285 scp->modem = 1; 286 287 /* Get MAC address */ 288 pccard_get_ether(dev, scp->enaddr); 289 290 /* Deal with bogus MAC address */ 291 if (xe_bad_mac(scp->enaddr) && 292 !pccard_cis_scan(dev, xe_pccard_mac, scp->enaddr)) { 293 device_printf(dev, 294 "Unable to find MAC address for your %s card\n", 295 device_get_desc(dev)); 296 return (ENXIO); 297 } 298 299 if ((err = xe_activate(dev)) != 0) 300 return (err); 301 302 /* Hack RealPorts into submission */ 303 if (scp->modem && xe_cemfix(dev) < 0) { 304 device_printf(dev, "Unable to fix your %s combo card\n", 305 device_get_desc(dev)); 306 xe_deactivate(dev); 307 return (ENXIO); 308 } 309 if ((err = xe_attach(dev))) { 310 device_printf(dev, "xe_attach() failed! (%d)\n", err); 311 xe_deactivate(dev); 312 return (err); 313 } 314 return (0); 315} 316 317/* 318 * The device entry is being removed, probably because someone ejected the 319 * card. The interface should have been brought down manually before calling 320 * this function; if not you may well lose packets. In any case, I shut down 321 * the card and the interface, and hope for the best. 322 */ 323static int 324xe_pccard_detach(device_t dev) 325{ 326 struct xe_softc *sc = device_get_softc(dev); 327 328 DEVPRINTF(2, (dev, "pccard_detach\n")); 329 330 XE_LOCK(sc); 331 xe_stop(sc); 332 XE_UNLOCK(sc); 333 callout_drain(&sc->media_timer); 334 callout_drain(&sc->wdog_timer); 335 ether_ifdetach(sc->ifp); 336 xe_deactivate(dev); 337 mtx_destroy(&sc->lock); 338 return (0); 339} 340 341static int 342xe_pccard_probe(device_t dev) 343{ 344 const struct xe_pccard_product *xpp; 345 346 DEVPRINTF(2, (dev, "pccard_probe\n")); 347 348 /* 349 * Xircom cards aren't proper MFC cards, so we have to take all 350 * cards that match, not just ones that are network. 351 */ 352 353 /* If we match something in the table, it is our device. */ 354 if ((xpp = xe_pccard_get_product(dev)) == NULL) 355 return (ENXIO); 356 357 /* Set card name for logging later */ 358 if (xpp->product.pp_name != NULL) 359 device_set_desc(dev, xpp->product.pp_name); 360 361 /* Reject known but unsupported cards */ 362 if (xpp->flags & XE_CARD_TYPE_FLAGS_NO) { 363 device_printf(dev, "Sorry, your %s card is not supported :(\n", 364 device_get_desc(dev)); 365 return (ENXIO); 366 } 367 368 return (0); 369} 370 371static device_method_t xe_pccard_methods[] = { 372 /* Device interface */ 373 DEVMETHOD(device_probe, xe_pccard_probe), 374 DEVMETHOD(device_attach, xe_pccard_attach), 375 DEVMETHOD(device_detach, xe_pccard_detach), 376 377 { 0, 0 } 378}; 379 380static driver_t xe_pccard_driver = { 381 "xe", 382 xe_pccard_methods, 383 sizeof(struct xe_softc), 384}; 385 386devclass_t xe_devclass; 387 388DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0); 389PCCARD_PNP_INFO(xe_pccard_products); 390