1 /* $NetBSD: zz9k_if.c,v 1.2 2024/02/05 21:46:05 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Alain Runa. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: zz9k_if.c,v 1.2 2024/02/05 21:46:05 andvar Exp $"); 33 34 /* miscellaneous */ 35 #include <sys/types.h> /* size_t */ 36 #include <sys/stdint.h> /* uintXX_t */ 37 #include <sys/stdbool.h> /* bool */ 38 #include <sys/syslog.h> /* log(), LOG_ERR */ 39 40 /* driver(9) */ 41 #include <sys/param.h> /* NODEV */ 42 #include <sys/device.h> /* CFATTACH_DECL_NEW(), device_priv() */ 43 #include <sys/errno.h> /* EINVAL, ENODEV, EPASSTHROUGH */ 44 45 /* bus_space(9) and zorro bus */ 46 #include <sys/bus.h> /* bus_space_xxx(), bus_space_xxx_t */ 47 #include <sys/cpu.h> /* kvtop() */ 48 #include <sys/systm.h> /* aprint_xxx(), memcpy() */ 49 #include <amiga/dev/zbusvar.h> /* zbus_args */ 50 51 /* arp(9) and mbuf(9) */ 52 #include <net/if.h> /* if_oerrors */ 53 #include <net/if_ether.h> /* ethercom, ifnet, ether_ifattach() */ 54 #include <net/if_dl.h> /* satosdl(), sockaddr_dl, dl_addr */ 55 #include <net/bpf.h> /* bpf_mtap(), BPF_D_OUT */ 56 #include <netinet/if_inarp.h> /* arp_ifinit() */ 57 #include <sys/mbuf.h> /* mbuf_xxx */ 58 #include <sys/sockio.h> /* SIOXXX */ 59 60 /* Interrupt related */ 61 #include <sys/intr.h> /* splvm(), splx() */ 62 #include <amiga/amiga/isr.h> /* isr */ 63 64 /* zz9k related */ 65 #include <amiga/dev/zz9kvar.h> /* zz9kbus_attach_args */ 66 #include <amiga/dev/zz9kreg.h> /* ZZ9000 registers */ 67 #include "zz9k_if.h" /* NZZ9K_IF */ 68 69 70 /* The allmighty softc structure */ 71 struct zzif_softc { 72 device_t sc_dev; 73 struct bus_space_tag sc_bst; 74 bus_space_tag_t sc_iot; 75 bus_space_handle_t sc_regh; 76 bus_space_handle_t sc_rxh; 77 bus_space_handle_t sc_txh; 78 79 struct ethercom sc_ethercom; 80 struct isr sc_isr; 81 void* sc_txbuffer; 82 void* sc_rxbuffer; 83 uint16_t sc_sequence; 84 }; 85 86 /* rx buffer contents */ 87 struct zzif_frame { 88 uint16_t size; 89 uint16_t serial; 90 struct ether_header header; 91 uint8_t payload[ETHER_MAX_LEN - ETHER_HDR_LEN]; 92 }; 93 94 95 /* ifnet related callbacks */ 96 static void zzif_init(struct zzif_softc *sc); 97 static void zzif_stop(struct zzif_softc *sc); 98 static void zzif_start(struct ifnet *ifp); 99 static int zzif_intr(void *arg); 100 static int zzif_ioctl(struct ifnet *ifp, u_long cmd, void *data); 101 102 /* driver(9) essentials */ 103 static int zzif_match(device_t parent, cfdata_t match, void *aux); 104 static void zzif_attach(device_t parent, device_t self, void *aux); 105 CFATTACH_DECL_NEW( 106 zz9k_if, sizeof(struct zzif_softc), zzif_match, zzif_attach, NULL, NULL); 107 108 109 /* Oh my God, it's full of stars! */ 110 111 static int 112 zzif_match(device_t parent, cfdata_t match, void *aux) 113 { 114 struct zz9kbus_attach_args *bap = aux; 115 116 if (strcmp(bap->zzaa_name, "zz9k_if") != 0) 117 return 0; 118 119 return 1; 120 } 121 122 static void 123 zzif_attach(device_t parent, device_t self, void *aux) 124 { 125 struct zz9kbus_attach_args *bap = aux; 126 struct zzif_softc *sc = device_private(self); 127 struct zz9k_softc *psc = device_private(parent); 128 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 129 uint8_t lla[ETHER_ADDR_LEN]; 130 131 sc->sc_dev = self; 132 sc->sc_bst.base = bap->zzaa_base; 133 sc->sc_bst.absm = &amiga_bus_stride_1; 134 sc->sc_iot = &sc->sc_bst; 135 sc->sc_regh = psc->sc_regh; 136 137 if (bus_space_map(sc->sc_iot, ZZ9K_RX_BASE, ZZ9K_RX_SIZE, 138 BUS_SPACE_MAP_LINEAR, &sc->sc_rxh)) { 139 aprint_error(": Failed to map MNT ZZ9000 eth rx buffer.\n"); 140 return; 141 } 142 143 if (bus_space_map(sc->sc_iot, ZZ9K_TX_BASE, ZZ9K_TX_SIZE, 144 BUS_SPACE_MAP_LINEAR, &sc->sc_txh)) { 145 aprint_error(": Failed to map MNT ZZ9000 eth tx buffer.\n"); 146 return; 147 } 148 149 /* get MAC from NIC */ 150 uint16_t macHI = ZZREG_R(ZZ9K_ETH_MAC_HI); 151 uint16_t macMD = ZZREG_R(ZZ9K_ETH_MAC_MD); 152 uint16_t macLO = ZZREG_R(ZZ9K_ETH_MAC_LO); 153 lla[0] = macHI >> 8; 154 lla[1] = macHI & 0xff; 155 lla[2] = macMD >> 8; 156 lla[3] = macMD & 0xff; 157 lla[4] = macLO >> 8; 158 lla[5] = macLO & 0xff; 159 160 #if 0 161 aprint_normal(": Ethernet address %s " 162 "(10BASE-T, 100BASE-TX, AUTO)\n", ether_sprintf(lla)); 163 #endif 164 165 aprint_debug_dev(sc->sc_dev, "[DEBUG] registers at %p/%p (pa/va), " 166 "rx buffer at %p/%p (pa/va), tx buffer at %p/%p (pa/va)\n", 167 (void *)kvtop((void *)sc->sc_regh), 168 bus_space_vaddr(sc->sc_iot, sc->sc_regh), 169 (void *)kvtop((void *)sc->sc_rxh), 170 bus_space_vaddr(sc->sc_iot, sc->sc_rxh), 171 (void *)kvtop((void *)sc->sc_txh), 172 bus_space_vaddr(sc->sc_iot, sc->sc_txh)); 173 174 /* set rx/tx buffers */ 175 sc->sc_txbuffer = bus_space_vaddr(sc->sc_iot, sc->sc_txh); 176 sc->sc_rxbuffer = bus_space_vaddr(sc->sc_iot, sc->sc_rxh); 177 178 /* configure the network interface */ 179 memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 180 ifp->if_softc = sc; 181 ifp->if_ioctl = zzif_ioctl; 182 ifp->if_start = zzif_start; 183 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 184 ifp->if_mtu = ETHERMTU; 185 186 /* attach the network interface. */ 187 if_attach(ifp); 188 if_deferred_start_init(ifp, NULL); 189 ether_ifattach(ifp, lla); 190 191 aprint_normal(": Ethernet address %s\n", ether_sprintf(lla)); 192 193 /* setup the (receiving) interrupt service routine on int6 (default) */ 194 sc->sc_isr.isr_intr = zzif_intr; 195 sc->sc_isr.isr_arg = sc; 196 sc->sc_isr.isr_ipl = 6; 197 add_isr(&sc->sc_isr); 198 } 199 200 static void 201 zzif_init(struct zzif_softc *sc) 202 { 203 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 204 int s = splvm(); 205 206 ZZREG_W(ZZ9K_CONFIG, ZZREG_R(ZZ9K_CONFIG) | ZZ9K_CONFIG_INT_ETH); 207 ifp->if_flags |= IFF_RUNNING; 208 ifp->if_flags &= ~IFF_OACTIVE; 209 if_schedule_deferred_start(ifp); 210 splx(s); 211 } 212 213 static void 214 zzif_stop(struct zzif_softc *sc) 215 { 216 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 217 int s = splvm(); 218 219 ZZREG_W(ZZ9K_CONFIG, ZZREG_R(ZZ9K_CONFIG) & ~ZZ9K_CONFIG_INT_ETH); 220 ifp->if_flags &= ~IFF_RUNNING; 221 splx(s); 222 } 223 224 static void 225 zzif_start(struct ifnet *ifp) 226 { 227 struct zzif_softc *sc = ifp->if_softc; 228 uint8_t *frame= (uint8_t *)sc->sc_txbuffer; 229 struct mbuf *m; 230 int size; 231 232 if ((ifp->if_flags & IFF_RUNNING) == 0) 233 return; 234 235 ifp->if_flags |= IFF_OACTIVE; 236 237 for (;;) { 238 IF_DEQUEUE(&ifp->if_snd, m); 239 if (m == NULL) 240 break; 241 242 /* this should never happen, otherwise there's no help */ 243 if ((m->m_flags & M_PKTHDR) == 0) 244 panic("zzif_start: no packet header mbuf"); 245 246 size = m->m_pkthdr.len; 247 if (size == 0) 248 panic("zzif_start: header mbuf with 0 len"); 249 250 if ((size < (ETHER_HDR_LEN)) || 251 (size > (ETHER_MAX_LEN-ETHER_CRC_LEN))) { 252 aprint_error_dev(sc->sc_dev, 253 ": abnormal tx frame size of %i bytes\n", size); 254 m_freem(m); 255 break; 256 } 257 258 /* make bpf happy */ 259 bpf_mtap(ifp, m, BPF_D_OUT); 260 261 /* copy dequeued mbuf data to transmit buffer of the ZZ9000 */ 262 for (struct mbuf *n = m; n != NULL; n = n->m_next) { 263 memcpy(frame, n->m_data, n->m_len); 264 frame += n->m_len; 265 } 266 267 m_freem(m); /* we don't need it anymore */ 268 269 /* tell ZZ9000 to transmit packet with size and check result */ 270 ZZREG_W(ZZ9K_ETH_TX, size); 271 size = ZZREG_R(ZZ9K_ETH_TX); 272 if (size == 0) { 273 if_statinc(ifp, if_opackets); 274 } else { 275 if_statinc(ifp, if_oerrors); 276 } 277 } 278 279 ifp->if_flags &= ~IFF_OACTIVE; 280 } 281 282 static int 283 zzif_intr(void *arg) 284 { 285 struct zzif_softc *sc = arg; 286 287 uint16_t conf = ZZREG_R(ZZ9K_CONFIG); 288 if ((conf & ZZ9K_CONFIG_INT_ETH) == 0) 289 return 0; 290 291 ZZREG_W(ZZ9K_CONFIG, conf & ~ZZ9K_CONFIG_INT_ETH); /* disable INT */ 292 ZZREG_W(ZZ9K_CONFIG, ZZ9K_CONFIG_INT_ACK | ZZ9K_CONFIG_INT_ACK_ETH); 293 294 struct zzif_frame *frame = (struct zzif_frame *)sc->sc_rxbuffer; 295 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 296 struct mbuf *m; 297 298 /* check if interrupt was due to new packet arrival */ 299 if (frame->serial == sc->sc_sequence) { 300 ZZREG_W(ZZ9K_ETH_RX, 1); /* discard packet */ 301 ZZREG_W(ZZ9K_CONFIG, conf); /* restore interrupt */ 302 return 0; /* nope, something else triggered it */ 303 } 304 305 sc->sc_sequence = frame->serial; 306 307 if ((frame->size < (ETHER_MIN_LEN-ETHER_CRC_LEN)) || 308 (frame->size > ETHER_MAX_LEN)) { 309 aprint_error_dev(sc->sc_dev, 310 ": abnormal rx frame size of %i bytes\n", frame->size); 311 ZZREG_W(ZZ9K_ETH_RX, 1); /* discard packet */ 312 ZZREG_W(ZZ9K_CONFIG, conf); /* restore interrupt */ 313 return 0; 314 } 315 316 int s = splvm(); 317 m = m_devget((char *)&frame->header, frame->size, 0, ifp); 318 if_percpuq_enqueue(ifp->if_percpuq, m); 319 splx(s); 320 ZZREG_W(ZZ9K_ETH_RX, 1); /* packet served */ 321 ZZREG_W(ZZ9K_CONFIG, conf); /* restore interrupt */ 322 323 return 1; 324 } 325 326 static int 327 zzif_ioctl(struct ifnet *ifp, u_long cmd, void *data) 328 { 329 struct zzif_softc *sc = ifp->if_softc; 330 struct ifaddr *ifa; 331 struct if_laddrreq *lar; 332 const struct sockaddr_dl *sdl; 333 int retval = 0; 334 335 int s = splvm(); 336 337 switch (cmd) { 338 case SIOCINITIFADDR: 339 ifa = (struct ifaddr *)data; 340 zzif_stop(sc); 341 zzif_init(sc); 342 switch (ifa->ifa_addr->sa_family) { 343 case AF_INET: 344 arp_ifinit(ifp, ifa); 345 break; 346 default: 347 break; 348 } 349 break; 350 case SIOCSIFFLAGS: 351 retval = ifioctl_common(ifp, cmd, data); 352 if (retval != 0) 353 break; 354 355 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 356 case IFF_RUNNING: /* and not UP */ 357 zzif_stop(sc); 358 break; 359 case IFF_UP: /* and not RUNNING */ 360 zzif_init(sc); 361 break; 362 case (IFF_UP | IFF_RUNNING): 363 zzif_stop(sc); 364 zzif_init(sc); 365 break; 366 default: 367 break; 368 } 369 break; 370 case SIOCADDMULTI: 371 case SIOCDELMULTI: 372 retval = EINVAL; 373 break; 374 case SIOCALIFADDR: 375 lar = (struct if_laddrreq *)data; 376 sdl = satocsdl(&lar->addr); 377 uint8_t *mac = (uint8_t *)&sdl->sdl_addr.dl_data; 378 379 if ((lar->flags==IFLR_ACTIVE) && (sdl->sdl_family==AF_LINK)) { 380 ZZREG_W(ZZ9K_ETH_MAC_HI, (mac[0] << 8) | mac[1]); 381 ZZREG_W(ZZ9K_ETH_MAC_MD, (mac[2] << 8) | mac[3]); 382 ZZREG_W(ZZ9K_ETH_MAC_LO, (mac[4] << 8) | mac[5]); 383 } 384 aprint_normal(": Ethernet address %s", ether_sprintf(mac)); 385 retval = ether_ioctl(ifp, cmd, data); 386 break; 387 default: 388 retval = ether_ioctl(ifp, cmd, data); 389 break; 390 } 391 392 splx(s); 393 394 return retval; 395 } 396