1/* $NetBSD: if_we_pnpbus.c,v 1.8 2011/07/01 16:55:42 dyoung Exp $ */ 2 3/*- 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet 35 * adapters. 36 * 37 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. 38 * 39 * Copyright (C) 1993, David Greenman. This software may be used, modified, 40 * copied, distributed, and sold, in both source and binary form provided that 41 * the above copyright and these terms are retained. Under no circumstances is 42 * the author responsible for the proper functioning of this software, nor does 43 * the author assume any responsibility for damages incurred with its use. 44 */ 45 46/* 47 * Device driver for the Western Digital/SMC 8003 and 8013 series, 48 * and the SMC Elite Ultra (8216). 49 */ 50 51#include <sys/cdefs.h> 52__KERNEL_RCSID(0, "$NetBSD: if_we_pnpbus.c,v 1.8 2011/07/01 16:55:42 dyoung Exp $"); 53 54#include <sys/types.h> 55#include <sys/param.h> 56#include <sys/systm.h> 57#include <sys/device.h> 58#include <sys/socket.h> 59#include <sys/mbuf.h> 60#include <sys/syslog.h> 61#include <sys/bswap.h> 62 63#include <net/if.h> 64#include <net/if_dl.h> 65#include <net/if_types.h> 66#include <net/if_media.h> 67 68#include <net/if_ether.h> 69 70#include <sys/bus.h> 71#include <machine/intr.h> 72#include <machine/isa_machdep.h> 73#include <machine/residual.h> 74 75#include <dev/ic/dp8390reg.h> 76#include <dev/ic/dp8390var.h> 77#include <dev/ic/wereg.h> 78#include <dev/ic/wevar.h> 79 80#include <prep/pnpbus/pnpbusvar.h> 81 82int we_pnpbus_probe(device_t, cfdata_t, void *); 83void we_pnpbus_attach(device_t, device_t, void *); 84 85CFATTACH_DECL_NEW(we_pnpbus, sizeof(struct we_softc), 86 we_pnpbus_probe, we_pnpbus_attach, NULL, NULL); 87 88extern struct cfdriver we_cd; 89 90static const char *we_params(bus_space_tag_t, bus_space_handle_t, 91 u_int8_t *, bus_size_t *, u_int8_t *, int *); 92 93#define WE_DEFAULT_IOMEM 0xe4000 94 95/* 96 * Delay needed when switching 16-bit access to shared memory. 97 */ 98#define WE_DELAY(wsc) delay(3) 99 100/* 101 * Enable card RAM, and 16-bit access. 102 */ 103#define WE_MEM_ENABLE(wsc) \ 104do { \ 105 if ((wsc)->sc_16bitp) \ 106 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 107 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \ 108 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 109 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \ 110 WE_DELAY((wsc)); \ 111} while (0) 112 113/* 114 * Disable card RAM, and 16-bit access. 115 */ 116#define WE_MEM_DISABLE(wsc) \ 117do { \ 118 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 119 WE_MSR, (wsc)->sc_msr_proto); \ 120 if ((wsc)->sc_16bitp) \ 121 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 122 WE_LAAR, (wsc)->sc_laar_proto); \ 123 WE_DELAY((wsc)); \ 124} while (0) 125 126int 127we_pnpbus_probe(device_t parent, cfdata_t cf, void *aux) 128{ 129 struct pnpbus_dev_attach_args *pna = aux; 130 int ret = 0; 131 132 if (strcmp(pna->pna_devid, "IBM2001") == 0) 133 ret = 1; 134 135 if (strcmp(pna->pna_devid, "IBM0010") == 0) 136 ret = 1; 137 138 if (ret) 139 pnpbus_scan(pna, pna->pna_ppc_dev); 140 141 return ret; 142} 143 144void 145we_pnpbus_attach(device_t parent, device_t self, void *aux) 146{ 147 struct we_softc *wsc = device_private(self); 148 struct dp8390_softc *sc = &wsc->sc_dp8390; 149 struct pnpbus_dev_attach_args *pna = aux; 150 struct pnpbus_irq *irq; 151 bus_space_tag_t nict, asict, memt; 152 bus_space_handle_t nich, asich, memh; 153 bus_size_t memsize = 0x4000; 154 const char *typestr; 155 int memfound = 0, i, irqnum; 156 157 sc->sc_dev = self; 158 159 nict = asict = pna->pna_iot; 160 memt = pna->pna_memt; 161 162 aprint_normal("\n"); 163 164 if (pnpbus_io_map(&pna->pna_res, 0, &asict, &asich)) { 165 aprint_error("%s: can't map nic i/o space\n", 166 device_xname(self)); 167 return; 168 } 169 170 if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS, 171 &nich)) { 172 aprint_error("%s: can't subregion i/o space\n", 173 device_xname(self)); 174 return; 175 } 176 177 typestr = we_params(asict, asich, &wsc->sc_type, &memsize, 178 &wsc->sc_flags, &sc->is790); 179 if (typestr == NULL) { 180 aprint_error("%s: where did the card go?\n", 181 device_xname(self)); 182 return; 183 } 184 185 /* 186 * Map memory space. See if any was allocated via PNP, if not, use 187 * the default. 188 */ 189 if (pnpbus_iomem_map(&pna->pna_res, 0, &memt, &memh) == 0) 190 memfound = 1; 191 else if (bus_space_map(memt, WE_DEFAULT_IOMEM, memsize, 0, &memh)) { 192 aprint_error("%s: can't map shared memory\n", 193 device_xname(self)); 194 return; 195 } 196 197 wsc->sc_asict = asict; 198 wsc->sc_asich = asich; 199 200 sc->sc_regt = nict; 201 sc->sc_regh = nich; 202 203 sc->sc_buft = memt; 204 sc->sc_bufh = memh; 205 206 if (memfound) 207 pnpbus_getiomem(&pna->pna_res, 0, &wsc->sc_maddr, 208 &sc->mem_size); 209 else { 210 wsc->sc_maddr = WE_DEFAULT_IOMEM; 211 sc->mem_size = memsize; 212 } 213 214 /* Interface is always enabled. */ 215 sc->sc_enabled = 1; 216 217 if (we_config(self, wsc, typestr)) 218 return; 219 220 /* 221 * Enable the configured interrupt. 222 */ 223#if 0 224 if (sc->is790) 225 bus_space_write_1(asict, asich, WE790_ICR, 226 bus_space_read_1(asict, asich, WE790_ICR) | 227 WE790_ICR_EIL); 228 else if (wsc->sc_type & WE_SOFTCONFIG) 229 bus_space_write_1(asict, asich, WE_IRR, 230 bus_space_read_1(asict, asich, WE_IRR) | WE_IRR_IEN); 231#endif 232 233 /* 234 * Establish interrupt handler. 235 * Loop through all probed IRQs until one looks sane. 236 */ 237 for (i = 0, irq = SIMPLEQ_FIRST(&pna->pna_res.irq); 238 i < pna->pna_res.numirq; i++, irq = SIMPLEQ_NEXT(irq, next)) { 239 irqnum = ffs(irq->mask) - 1; 240 /* some cards think they are level. force them to edge */ 241 if (irq->flags & 0x0c) 242 irq->flags = 0x01; 243 if (!LEGAL_HWIRQ_P(irqnum)) 244 continue; 245 if (irqnum < 2) 246 continue; 247 break; 248 } 249 wsc->sc_ih = pnpbus_intr_establish(i, IPL_NET, IST_PNP, dp8390_intr, sc, 250 &pna->pna_res); 251 if (wsc->sc_ih == NULL) 252 aprint_error("%s: can't establish interrupt\n", 253 device_xname(self)); 254} 255 256static const char * 257we_params(bus_space_tag_t asict, bus_space_handle_t asich, u_int8_t *typep, bus_size_t *memsizep, u_int8_t *flagp, int *is790p) 258{ 259 const char *typestr; 260 bus_size_t memsize; 261 int is16bit, is790; 262 u_int8_t type; 263 264 memsize = 8192; 265 is16bit = is790 = 0; 266 267 type = bus_space_read_1(asict, asich, WE_CARD_ID); 268 switch (type) { 269 case WE_TYPE_WD8003S: 270 typestr = "WD8003S"; 271 break; 272 case WE_TYPE_WD8003E: 273 typestr = "WD8003E"; 274 break; 275 case WE_TYPE_WD8003EB: 276 typestr = "WD8003EB"; 277 break; 278 case WE_TYPE_WD8003W: 279 typestr = "WD8003W"; 280 break; 281 case WE_TYPE_WD8013EBT: 282 typestr = "WD8013EBT"; 283 memsize = 16384; 284 is16bit = 1; 285 break; 286 case WE_TYPE_WD8013W: 287 typestr = "WD8013W"; 288 memsize = 16384; 289 is16bit = 1; 290 break; 291 case WE_TYPE_WD8013EP: /* also WD8003EP */ 292 if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) { 293 is16bit = 1; 294 memsize = 16384; 295 typestr = "WD8013EP"; 296 } else 297 typestr = "WD8003EP"; 298 break; 299 case WE_TYPE_WD8013WC: 300 typestr = "WD8013WC"; 301 memsize = 16384; 302 is16bit = 1; 303 break; 304 case WE_TYPE_WD8013EBP: 305 typestr = "WD8013EBP"; 306 memsize = 16384; 307 is16bit = 1; 308 break; 309 case WE_TYPE_WD8013EPC: 310 typestr = "WD8013EPC"; 311 memsize = 16384; 312 is16bit = 1; 313 break; 314 case WE_TYPE_SMC8216C: 315 case WE_TYPE_SMC8216T: 316 { 317 u_int8_t hwr; 318 319 typestr = (type == WE_TYPE_SMC8216C) ? 320 "SMC8216/SMC8216C" : "SMC8216T"; 321 322 hwr = bus_space_read_1(asict, asich, WE790_HWR); 323 bus_space_write_1(asict, asich, WE790_HWR, 324 hwr | WE790_HWR_SWH); 325 switch (bus_space_read_1(asict, asich, WE790_RAR) & 326 WE790_RAR_SZ64) { 327 case WE790_RAR_SZ64: 328 memsize = 65536; 329 break; 330 case WE790_RAR_SZ32: 331 memsize = 32768; 332 break; 333 case WE790_RAR_SZ16: 334 memsize = 16384; 335 break; 336 case WE790_RAR_SZ8: 337 /* 8216 has 16K shared mem -- 8416 has 8K */ 338 typestr = (type == WE_TYPE_SMC8216C) ? 339 "SMC8416C/SMC8416BT" : "SMC8416T"; 340 memsize = 8192; 341 break; 342 } 343 bus_space_write_1(asict, asich, WE790_HWR, hwr); 344 345 is16bit = 1; 346 is790 = 1; 347 break; 348 } 349#ifdef TOSH_ETHER 350 case WE_TYPE_TOSHIBA1: 351 typestr = "Toshiba1"; 352 memsize = 32768; 353 is16bit = 1; 354 break; 355 case WE_TYPE_TOSHIBA4: 356 typestr = "Toshiba4"; 357 memsize = 32768; 358 is16bit = 1; 359 break; 360#endif 361 default: 362 /* Not one we recognize. */ 363 return (NULL); 364 } 365 366 /* 367 * Make some adjustments to initial values depending on what is 368 * found in the ICR. 369 */ 370 if (is16bit && (type != WE_TYPE_WD8013EBT) && 371#ifdef TOSH_ETHER 372 (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) && 373#endif 374 (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) { 375 is16bit = 0; 376 memsize = 8192; 377 } 378 379#ifdef WE_DEBUG 380 { 381 int i; 382 383 aprint_debug("we_params: type = 0x%x, typestr = %s," 384 " is16bit = %d, memsize = %d\n", type, typestr, is16bit, 385 memsize); 386 for (i = 0; i < 8; i++) 387 aprint_debug(" %d -> 0x%x\n", i, 388 bus_space_read_1(asict, asich, i)); 389 } 390#endif 391 392 if (typep != NULL) 393 *typep = type; 394 if (memsizep != NULL) 395 *memsizep = memsize; 396 if (flagp != NULL && is16bit) 397 *flagp |= WE_16BIT_ENABLE; 398 if (is790p != NULL) 399 *is790p = is790; 400 return (typestr); 401} 402