1/* $NetBSD: if_mbe_pcmcia.c,v 1.47 2016/07/07 06:55:42 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2000, 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Enami Tsugutomo. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: if_mbe_pcmcia.c,v 1.47 2016/07/07 06:55:42 msaitoh Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/device.h> 38#include <sys/socket.h> 39 40#include <net/if.h> 41#include <net/if_ether.h> 42#include <net/if_media.h> 43 44#include <sys/intr.h> 45#include <sys/bus.h> 46 47#include <dev/ic/mb86960reg.h> 48#include <dev/ic/mb86960var.h> 49 50#include <dev/pcmcia/pcmciareg.h> 51#include <dev/pcmcia/pcmciavar.h> 52#include <dev/pcmcia/pcmciadevs.h> 53 54int mbe_pcmcia_match(device_t, cfdata_t, void *); 55int mbe_pcmcia_validate_config(struct pcmcia_config_entry *); 56void mbe_pcmcia_attach(device_t, device_t, void *); 57int mbe_pcmcia_detach(device_t, int); 58 59struct mbe_pcmcia_softc { 60 struct mb86960_softc sc_mb86960; /* real "mb" softc */ 61 62 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 63 void *sc_ih; /* interrupt cookie */ 64 65 int sc_state; 66#define MBE_PCMCIA_ATTACHED 3 67}; 68 69CFATTACH_DECL_NEW(mbe_pcmcia, sizeof(struct mbe_pcmcia_softc), 70 mbe_pcmcia_match, mbe_pcmcia_attach, mbe_pcmcia_detach, mb86960_activate); 71 72int mbe_pcmcia_enable(struct mb86960_softc *); 73void mbe_pcmcia_disable(struct mb86960_softc *); 74 75struct mbe_pcmcia_get_enaddr_args { 76 uint8_t enaddr[ETHER_ADDR_LEN]; 77 int maddr; 78}; 79int mbe_pcmcia_get_enaddr_from_cis(struct pcmcia_tuple *, void *); 80int mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc *, 81 struct mbe_pcmcia_get_enaddr_args *); 82int mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc *, 83 struct mbe_pcmcia_get_enaddr_args *); 84 85static const struct mbe_pcmcia_product { 86 struct pcmcia_product mpp_product; 87 int mpp_enet_maddr; 88 int mpp_flags; 89#define MBH10302 0x0001 /* FUJITSU MBH10302 */ 90} mbe_pcmcia_products[] = { 91 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CD021BX, 92 PCMCIA_CIS_TDK_LAK_CD021BX }, 93 -1, 0 }, 94 95 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CF010, 96 PCMCIA_CIS_TDK_LAK_CF010 }, 97 -1, 0 }, 98 99#if 0 /* XXX 86960-based? */ 100 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_DFL9610, 101 PCMCIA_CIS_TDK_DFL9610 }, 102 -1, MBH10302 /* XXX */ }, 103#endif 104 105 { { PCMCIA_VENDOR_CONTEC, PCMCIA_PRODUCT_CONTEC_CNETPC, 106 PCMCIA_CIS_CONTEC_CNETPC }, 107 -1, 0 }, 108 109 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA501, 110 PCMCIA_CIS_FUJITSU_LA501 }, 111 -1, 0 }, 112 113 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J181, 114 PCMCIA_CIS_FUJITSU_FMV_J181 }, 115 -1, MBH10302 }, 116 117 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182, 118 PCMCIA_CIS_FUJITSU_FMV_J182 }, 119 0xf2c, 0 }, 120 121 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182A, 122 PCMCIA_CIS_FUJITSU_FMV_J182A }, 123 0x1cc, 0 }, 124 125 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_ITCFJ182A, 126 PCMCIA_CIS_FUJITSU_ITCFJ182A }, 127 0x1cc, 0 }, 128 129 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA10S, 130 PCMCIA_CIS_FUJITSU_LA10S }, 131 -1, 0 }, 132 133 { { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_R280, 134 PCMCIA_CIS_RATOC_REX_R280 }, 135 0x1fc, 0 }, 136}; 137static const size_t mbe_pcmcia_nproducts = __arraycount(mbe_pcmcia_products); 138 139int 140mbe_pcmcia_match(device_t parent, cfdata_t cf, void *aux) 141{ 142 struct pcmcia_attach_args *pa = aux; 143 144 if (pcmcia_product_lookup(pa, mbe_pcmcia_products, 145 mbe_pcmcia_nproducts, sizeof(mbe_pcmcia_products[0]), NULL)) 146 return 1; 147 return 0; 148} 149 150int 151mbe_pcmcia_validate_config(struct pcmcia_config_entry *cfe) 152{ 153 154 if (cfe->iftype != PCMCIA_IFTYPE_IO || cfe->num_iospace < 1) 155 return EINVAL; 156 return 0; 157} 158 159void 160mbe_pcmcia_attach(device_t parent, device_t self, void *aux) 161{ 162 struct mbe_pcmcia_softc *psc = device_private(self); 163 struct mb86960_softc *sc = &psc->sc_mb86960; 164 struct pcmcia_attach_args *pa = aux; 165 struct pcmcia_config_entry *cfe; 166 struct mbe_pcmcia_get_enaddr_args pgea; 167 const struct mbe_pcmcia_product *mpp; 168 int error; 169 170 sc->sc_dev = self; 171 psc->sc_pf = pa->pf; 172 173 error = pcmcia_function_configure(pa->pf, mbe_pcmcia_validate_config); 174 if (error) { 175 aprint_error_dev(self, "configure failed, error=%d\n", error); 176 return; 177 } 178 179 cfe = pa->pf->cfe; 180 sc->sc_bst = cfe->iospace[0].handle.iot; 181 sc->sc_bsh = cfe->iospace[0].handle.ioh; 182 183 mpp = pcmcia_product_lookup(pa, mbe_pcmcia_products, 184 mbe_pcmcia_nproducts, sizeof(mbe_pcmcia_products[0]), NULL); 185 if (!mpp) 186 panic("%s: impossible", __func__); 187 188 /* Read station address from io/mem or CIS. */ 189 if (mpp->mpp_enet_maddr >= 0) { 190 pgea.maddr = mpp->mpp_enet_maddr; 191 if (mbe_pcmcia_get_enaddr_from_mem(psc, &pgea) != 0) { 192 aprint_error_dev(self, "couldn't get ethernet address " 193 "from memory\n"); 194 goto fail; 195 } 196 } else if (mpp->mpp_flags & MBH10302) { 197 bus_space_write_1(sc->sc_bst, sc->sc_bsh, FE_MBH0 , 198 FE_MBH0_MASK | FE_MBH0_INTR_ENABLE); 199 if (mbe_pcmcia_get_enaddr_from_io(psc, &pgea) != 0) { 200 aprint_error_dev(self, 201 "couldn't get ethernet address from i/o\n"); 202 goto fail; 203 } 204 } else { 205 if (pa->pf->pf_funce_lan_nidlen != ETHER_ADDR_LEN) { 206 aprint_error_dev(self, 207 "couldn't get ethernet address from CIS\n"); 208 goto fail; 209 } 210 memcpy(pgea.enaddr, pa->pf->pf_funce_lan_nid, ETHER_ADDR_LEN); 211 } 212 213 /* Perform generic initialization. */ 214 if (mpp->mpp_flags & MBH10302) 215 sc->sc_flags |= FE_FLAGS_MB86960; 216 217 sc->sc_enable = mbe_pcmcia_enable; 218 sc->sc_disable = mbe_pcmcia_disable; 219 220 error = mbe_pcmcia_enable(sc); 221 if (error) 222 goto fail; 223 224 mb86960_attach(sc, pgea.enaddr); 225 mb86960_config(sc, NULL, 0, 0); 226 227 mbe_pcmcia_disable(sc); 228 psc->sc_state = MBE_PCMCIA_ATTACHED; 229 return; 230 231fail: 232 pcmcia_function_unconfigure(pa->pf); 233} 234 235int 236mbe_pcmcia_detach(device_t self, int flags) 237{ 238 struct mbe_pcmcia_softc *psc = device_private(self); 239 int error; 240 241 if (psc->sc_state != MBE_PCMCIA_ATTACHED) 242 return 0; 243 244 error = mb86960_detach(&psc->sc_mb86960); 245 if (error) 246 return error; 247 248 pcmcia_function_unconfigure(psc->sc_pf); 249 250 return 0; 251} 252 253int 254mbe_pcmcia_enable(struct mb86960_softc *sc) 255{ 256 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 257 int error; 258 259 /* Establish the interrupt handler. */ 260 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, mb86960_intr, 261 sc); 262 if (!psc->sc_ih) 263 return EIO; 264 265 error = pcmcia_function_enable(psc->sc_pf); 266 if (error) { 267 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 268 psc->sc_ih = 0; 269 } 270 271 return error; 272} 273 274void 275mbe_pcmcia_disable(struct mb86960_softc *sc) 276{ 277 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 278 279 pcmcia_function_disable(psc->sc_pf); 280 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 281 psc->sc_ih = 0; 282} 283 284int 285mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc *psc, 286 struct mbe_pcmcia_get_enaddr_args *ea) 287{ 288 struct mb86960_softc *sc = &psc->sc_mb86960; 289 int i; 290 291 for (i = 0; i < ETHER_ADDR_LEN; i++) 292 ea->enaddr[i] = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 293 FE_MBH_ENADDR + i); 294 return 0; 295} 296 297int 298mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc *psc, 299 struct mbe_pcmcia_get_enaddr_args *ea) 300{ 301 struct mb86960_softc *sc = &psc->sc_mb86960; 302 struct pcmcia_mem_handle pcmh; 303 bus_size_t offset; 304 int i, mwindow, rv = 1; 305 306 if (ea->maddr < 0) 307 goto bad_memaddr; 308 309 if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { 310 aprint_error_dev(sc->sc_dev, "can't alloc mem for enet addr\n"); 311 goto memalloc_failed; 312 } 313 314 if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, ea->maddr, 315 ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { 316 aprint_error_dev(sc->sc_dev, "can't map mem for enet addr\n"); 317 goto memmap_failed; 318 } 319 320 for (i = 0; i < ETHER_ADDR_LEN; i++) 321 ea->enaddr[i] = bus_space_read_1(pcmh.memt, pcmh.memh, 322 offset + (i * 2)); 323 324 rv = 0; 325 pcmcia_mem_unmap(psc->sc_pf, mwindow); 326memmap_failed: 327 pcmcia_mem_free(psc->sc_pf, &pcmh); 328memalloc_failed: 329bad_memaddr: 330 331 return rv; 332} 333