1 1.26 rin /* $NetBSD: if_le_ebus.c,v 1.26 2024/07/05 04:31:49 rin Exp $ */ 2 1.1 pooka 3 1.1 pooka /*- 4 1.1 pooka * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 1.1 pooka * All rights reserved. 6 1.1 pooka * 7 1.1 pooka * This code was written by Alessandro Forin and Neil Pittman 8 1.1 pooka * at Microsoft Research and contributed to The NetBSD Foundation 9 1.1 pooka * by Microsoft Corporation. 10 1.1 pooka * 11 1.1 pooka * Redistribution and use in source and binary forms, with or without 12 1.1 pooka * modification, are permitted provided that the following conditions 13 1.1 pooka * are met: 14 1.1 pooka * 1. Redistributions of source code must retain the above copyright 15 1.1 pooka * notice, this list of conditions and the following disclaimer. 16 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 pooka * notice, this list of conditions and the following disclaimer in the 18 1.1 pooka * documentation and/or other materials provided with the distribution. 19 1.1 pooka * 20 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 pooka * POSSIBILITY OF SUCH DAMAGE. 31 1.1 pooka */ 32 1.1 pooka 33 1.1 pooka #include <sys/cdefs.h> 34 1.26 rin __KERNEL_RCSID(0, "$NetBSD: if_le_ebus.c,v 1.26 2024/07/05 04:31:49 rin Exp $"); 35 1.1 pooka 36 1.1 pooka #include "opt_inet.h" 37 1.1 pooka 38 1.4 tls 39 1.1 pooka 40 1.1 pooka #include <sys/param.h> 41 1.1 pooka #include <sys/systm.h> 42 1.1 pooka #include <sys/mbuf.h> 43 1.1 pooka #include <sys/syslog.h> 44 1.1 pooka #include <sys/socket.h> 45 1.1 pooka #include <sys/device.h> 46 1.1 pooka #include <sys/ioctl.h> 47 1.1 pooka #include <sys/errno.h> 48 1.1 pooka 49 1.1 pooka #include <net/if.h> 50 1.1 pooka #include <net/if_dl.h> 51 1.1 pooka #include <net/if_ether.h> 52 1.1 pooka #include <net/if_media.h> 53 1.14 msaitoh #include <net/bpf.h> 54 1.1 pooka 55 1.1 pooka #ifdef INET 56 1.1 pooka #include <netinet/in.h> 57 1.1 pooka #include <netinet/if_inarp.h> 58 1.1 pooka #endif 59 1.1 pooka 60 1.7 riastrad #include <sys/rndsource.h> 61 1.1 pooka 62 1.1 pooka #include <emips/ebus/ebusvar.h> 63 1.1 pooka #include <emips/emips/machdep.h> 64 1.1 pooka #include <machine/emipsreg.h> 65 1.1 pooka 66 1.1 pooka extern paddr_t kvtophys(vaddr_t); 67 1.1 pooka 68 1.1 pooka struct bufmap { 69 1.2 tsutsui struct mbuf *mbuf; 70 1.2 tsutsui paddr_t phys; 71 1.1 pooka }; 72 1.1 pooka 73 1.1 pooka struct enic_softc { 74 1.1 pooka device_t sc_dev; /* base device glue */ 75 1.1 pooka struct ethercom sc_ethercom; /* Ethernet common part */ 76 1.1 pooka struct ifmedia sc_media; /* our supported media */ 77 1.1 pooka 78 1.2 tsutsui struct _Enic *sc_regs; /* hw registers */ 79 1.1 pooka 80 1.2 tsutsui int sc_havecarrier; /* carrier status */ 81 1.2 tsutsui void *sc_sh; /* shutdownhook cookie */ 82 1.2 tsutsui int inited; 83 1.2 tsutsui 84 1.2 tsutsui int sc_no_rd; 85 1.2 tsutsui int sc_n_recv; 86 1.2 tsutsui int sc_recv_h; 87 1.2 tsutsui /* BUGBUG really should be malloc-ed */ 88 1.1 pooka #define SC_MAX_N_RECV 64 89 1.2 tsutsui struct bufmap sc_recv[SC_MAX_N_RECV]; 90 1.1 pooka 91 1.2 tsutsui int sc_no_td; 92 1.2 tsutsui int sc_n_xmit; 93 1.2 tsutsui int sc_xmit_h; 94 1.2 tsutsui /* BUGBUG really should be malloc-ed */ 95 1.1 pooka #define SC_MAX_N_XMIT 16 96 1.2 tsutsui struct bufmap sc_xmit[SC_MAX_N_XMIT]; 97 1.24 thorpej bool sc_txbusy; 98 1.1 pooka 99 1.1 pooka #if DEBUG 100 1.2 tsutsui int xhit; 101 1.2 tsutsui int xmiss; 102 1.2 tsutsui int tfull; 103 1.2 tsutsui int tfull2; 104 1.2 tsutsui int brh; 105 1.2 tsutsui int rf; 106 1.2 tsutsui int bxh; 107 1.1 pooka 108 1.2 tsutsui int it; 109 1.1 pooka #endif 110 1.1 pooka 111 1.2 tsutsui uint8_t sc_enaddr[ETHER_ADDR_LEN]; 112 1.2 tsutsui uint8_t sc_pad[2]; 113 1.3 tls krndsource_t rnd_source; 114 1.1 pooka }; 115 1.1 pooka 116 1.1 pooka void enic_reset(struct ifnet *); 117 1.1 pooka int enic_init(struct ifnet *); 118 1.2 tsutsui void enic_stop(struct ifnet *, int); 119 1.2 tsutsui void enic_start(struct ifnet *); 120 1.1 pooka void enic_shutdown(void *); 121 1.2 tsutsui void enic_watchdog(struct ifnet *); 122 1.2 tsutsui int enic_mediachange(struct ifnet *); 123 1.2 tsutsui void enic_mediastatus(struct ifnet *, struct ifmediareq *); 124 1.2 tsutsui int enic_ioctl(struct ifnet *, u_long, void *); 125 1.2 tsutsui int enic_intr(void *, void *); 126 1.1 pooka void enic_rint(struct enic_softc *, uint32_t, paddr_t); 127 1.1 pooka void enic_tint(struct enic_softc *, uint32_t, paddr_t); 128 1.2 tsutsui void enic_kill_xmit(struct enic_softc *); 129 1.2 tsutsui void enic_post_recv(struct enic_softc *, struct mbuf *); 130 1.2 tsutsui void enic_refill(struct enic_softc *); 131 1.2 tsutsui static int enic_gethwinfo(struct enic_softc *); 132 1.2 tsutsui int enic_put(struct enic_softc *, struct mbuf **); 133 1.1 pooka 134 1.2 tsutsui static int enic_match(device_t, cfdata_t, void *); 135 1.2 tsutsui static void enic_attach(device_t, device_t, void *); 136 1.1 pooka 137 1.1 pooka CFATTACH_DECL_NEW(enic_emips, sizeof(struct enic_softc), 138 1.1 pooka enic_match, enic_attach, NULL, NULL); 139 1.1 pooka 140 1.1 pooka int 141 1.2 tsutsui enic_match(device_t parent, cfdata_t cf, void *aux) 142 1.1 pooka { 143 1.1 pooka struct ebus_attach_args *d = aux; 144 1.1 pooka /* donno yet */ 145 1.1 pooka struct _Enic *et = (struct _Enic *)d->ia_vaddr; 146 1.1 pooka 147 1.1 pooka if (strcmp("enic", d->ia_name) != 0) 148 1.2 tsutsui return 0; 149 1.1 pooka if ((et == NULL) || (et->Tag != PMTTAG_ETHERNET)) 150 1.1 pooka return 0; 151 1.2 tsutsui return 1; 152 1.1 pooka } 153 1.1 pooka 154 1.1 pooka void 155 1.2 tsutsui enic_attach(device_t parent, device_t self, void *aux) 156 1.1 pooka { 157 1.1 pooka struct enic_softc *sc = device_private(self); 158 1.1 pooka struct ebus_attach_args *ia = aux; 159 1.1 pooka struct ifnet *ifp = &sc->sc_ethercom.ec_if; 160 1.1 pooka 161 1.1 pooka sc->sc_regs = (struct _Enic *)(ia->ia_vaddr); 162 1.1 pooka #if DEBUG 163 1.2 tsutsui printf(" virt=%p ", (void *)sc->sc_regs); 164 1.1 pooka #endif 165 1.1 pooka 166 1.1 pooka /* Get the MAC and the depth of the FIFOs */ 167 1.1 pooka if (!enic_gethwinfo(sc)) { 168 1.1 pooka printf(" <cannot get hw info> DISABLED.\n"); 169 1.1 pooka /* 170 1.1 pooka * NB: caveat maintainer: make sure what we 171 1.1 pooka * did NOT do below does not hurt the system 172 1.1 pooka */ 173 1.1 pooka return; 174 1.1 pooka } 175 1.1 pooka 176 1.1 pooka sc->sc_dev = self; 177 1.1 pooka sc->sc_no_td = 0; 178 1.1 pooka sc->sc_havecarrier = 1; /* BUGBUG */ 179 1.1 pooka sc->sc_recv_h = 0; 180 1.1 pooka sc->sc_xmit_h = 0; 181 1.1 pooka /* uhmm do I need to do this? */ 182 1.2 tsutsui memset(sc->sc_recv, 0, sizeof sc->sc_recv); 183 1.2 tsutsui memset(sc->sc_xmit, 0, sizeof sc->sc_xmit); 184 1.1 pooka 185 1.1 pooka /* Initialize ifnet structure. */ 186 1.1 pooka strcpy(ifp->if_xname, device_xname(sc->sc_dev)); 187 1.1 pooka ifp->if_softc = sc; 188 1.1 pooka ifp->if_start = enic_start; 189 1.1 pooka ifp->if_ioctl = enic_ioctl; 190 1.1 pooka ifp->if_watchdog = enic_watchdog; 191 1.1 pooka ifp->if_init = enic_init; 192 1.1 pooka ifp->if_stop = enic_stop; 193 1.17 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 194 1.1 pooka IFQ_SET_READY(&ifp->if_snd); 195 1.1 pooka 196 1.1 pooka /* Initialize ifmedia structures. */ 197 1.20 msaitoh sc->sc_ethercom.ec_ifmedia = &sc->sc_media; 198 1.1 pooka ifmedia_init(&sc->sc_media, 0, enic_mediachange, enic_mediastatus); 199 1.19 msaitoh ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); 200 1.19 msaitoh ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); 201 1.1 pooka 202 1.1 pooka /* Make sure the chip is stopped. */ 203 1.1 pooka enic_stop(ifp, 0); 204 1.1 pooka sc->inited = 0; 205 1.1 pooka 206 1.1 pooka /* Get the mac address and print it */ 207 1.1 pooka printf(": eNIC [%d %d], address %s\n", 208 1.1 pooka sc->sc_n_recv, sc->sc_n_xmit, ether_sprintf(sc->sc_enaddr)); 209 1.1 pooka 210 1.1 pooka /* claim 802.1q capability */ 211 1.2 tsutsui #if 0 212 1.2 tsutsui sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; 213 1.2 tsutsui #endif 214 1.1 pooka 215 1.1 pooka /* Attach the interface. */ 216 1.1 pooka if_attach(ifp); 217 1.12 ozaki if_deferred_start_init(ifp, NULL); 218 1.1 pooka ether_ifattach(ifp, sc->sc_enaddr); 219 1.1 pooka 220 1.1 pooka sc->sc_sh = shutdownhook_establish(enic_shutdown, ifp); 221 1.1 pooka if (sc->sc_sh == NULL) 222 1.1 pooka panic("enic_attach: cannot establish shutdown hook"); 223 1.1 pooka 224 1.1 pooka rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 225 1.6 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 226 1.1 pooka 227 1.2 tsutsui ebus_intr_establish(parent, (void *)ia->ia_cookie, IPL_NET, 228 1.1 pooka enic_intr, sc); 229 1.1 pooka } 230 1.1 pooka 231 1.2 tsutsui /* 232 1.2 tsutsui * Beware: does not work while the nic is running 233 1.1 pooka */ 234 1.1 pooka static int enic_gethwinfo(struct enic_softc *sc) 235 1.1 pooka { 236 1.2 tsutsui uint8_t buffer[8]; /* 64bits max */ 237 1.2 tsutsui PENIC_INFO hw = (PENIC_INFO)buffer; 238 1.2 tsutsui paddr_t phys = kvtophys((vaddr_t)&buffer[0]), phys2; 239 1.2 tsutsui int i; 240 1.2 tsutsui 241 1.2 tsutsui /* 242 1.2 tsutsui * First thing first, get the MAC address 243 1.2 tsutsui */ 244 1.18 msaitoh memset(buffer, 0, sizeof buffer); 245 1.2 tsutsui buffer[0] = ENIC_CMD_GET_ADDRESS; 246 1.2 tsutsui buffer[3] = ENIC_CMD_GET_ADDRESS; /* bswap bug */ 247 1.2 tsutsui sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 248 1.2 tsutsui sc->sc_regs->BufferAddressHi32 = 0; 249 1.2 tsutsui sc->sc_regs->BufferAddressLo32 = phys; /* go! */ 250 1.2 tsutsui 251 1.2 tsutsui for (i = 0; i < 100; i++) { 252 1.2 tsutsui DELAY(100); 253 1.2 tsutsui if ((sc->sc_regs->Control & EC_OF_EMPTY) == 0) 254 1.2 tsutsui break; 255 1.2 tsutsui } 256 1.2 tsutsui if (i == 100) 257 1.2 tsutsui return 0; 258 1.1 pooka 259 1.2 tsutsui phys2 = sc->sc_regs->BufferAddressLo32; 260 1.2 tsutsui if (phys2 != phys) { 261 1.2 tsutsui printf("enic uhu? %llx != %llx?\n", 262 1.2 tsutsui (long long)phys, (long long)phys2); 263 1.2 tsutsui return 0; 264 1.2 tsutsui } 265 1.2 tsutsui memcpy(sc->sc_enaddr, buffer, ETHER_ADDR_LEN); 266 1.2 tsutsui 267 1.2 tsutsui /* 268 1.2 tsutsui * Next get the HW parameters 269 1.2 tsutsui */ 270 1.18 msaitoh memset(buffer, 0, sizeof buffer); 271 1.2 tsutsui buffer[0] = ENIC_CMD_GET_INFO; 272 1.2 tsutsui buffer[3] = ENIC_CMD_GET_INFO; /* bswap bug */ 273 1.2 tsutsui sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 274 1.2 tsutsui sc->sc_regs->BufferAddressHi32 = 0; 275 1.2 tsutsui sc->sc_regs->BufferAddressLo32 = phys; /* go! */ 276 1.2 tsutsui 277 1.2 tsutsui for (i = 0; i < 100; i++) { 278 1.2 tsutsui DELAY(100); 279 1.2 tsutsui if ((sc->sc_regs->Control & EC_OF_EMPTY) == 0) 280 1.2 tsutsui break; 281 1.2 tsutsui } 282 1.2 tsutsui if (i == 100) 283 1.2 tsutsui return 0; 284 1.2 tsutsui 285 1.2 tsutsui phys2 = sc->sc_regs->BufferAddressLo32; 286 1.2 tsutsui if (phys2 != phys) { 287 1.2 tsutsui printf("enic uhu2? %llx != %llx?\n", 288 1.2 tsutsui (long long)phys, (long long)phys2); 289 1.2 tsutsui return 0; 290 1.2 tsutsui } 291 1.2 tsutsui #if 0 292 1.2 tsutsui printf("enic: hwinfo: %x %x %x %x %x %x \n", 293 1.2 tsutsui hw->InputFifoSize, hw->OutputFifoSize, hw->CompletionFifoSize, 294 1.2 tsutsui hw->ErrorCount, hw->FramesDropped, hw->Reserved); 295 1.2 tsutsui #endif 296 1.2 tsutsui 297 1.2 tsutsui /* 298 1.2 tsutsui * Get FIFO depths and cap them 299 1.2 tsutsui */ 300 1.2 tsutsui sc->sc_n_recv = hw->InputFifoSize; 301 1.2 tsutsui if (sc->sc_n_recv > SC_MAX_N_RECV) 302 1.2 tsutsui sc->sc_n_recv = SC_MAX_N_RECV; 303 1.2 tsutsui if (sc->sc_n_recv == 0) { /* sanity and compat with old hw/simulator */ 304 1.2 tsutsui sc->sc_n_recv = 8; 305 1.2 tsutsui sc->sc_n_xmit = 4; 306 1.2 tsutsui } else { 307 1.2 tsutsui sc->sc_n_xmit = hw->OutputFifoSize; 308 1.2 tsutsui if (sc->sc_n_xmit > SC_MAX_N_XMIT) 309 1.2 tsutsui sc->sc_n_xmit = SC_MAX_N_XMIT; 310 1.2 tsutsui } 311 1.2 tsutsui 312 1.2 tsutsui return 1; 313 1.1 pooka } 314 1.1 pooka 315 1.1 pooka void 316 1.1 pooka enic_reset(struct ifnet *ifp) 317 1.1 pooka { 318 1.1 pooka int s; 319 1.1 pooka 320 1.1 pooka s = splnet(); 321 1.19 msaitoh enic_stop(ifp, 0); 322 1.1 pooka enic_init(ifp); 323 1.1 pooka splx(s); 324 1.1 pooka } 325 1.1 pooka 326 1.1 pooka void 327 1.1 pooka enic_stop(struct ifnet *ifp, int suspend) 328 1.1 pooka { 329 1.1 pooka struct enic_softc *sc = ifp->if_softc; 330 1.1 pooka 331 1.2 tsutsui #if 0 332 1.2 tsutsui printf("enic_stop %x\n", sc->sc_regs->Control); 333 1.2 tsutsui #endif 334 1.1 pooka 335 1.2 tsutsui /* 336 1.2 tsutsui * NB: only "ifconfig down" says suspend=1 (then "up" calls init) 337 1.2 tsutsui * Could simply set RXDIS in this case 338 1.2 tsutsui */ 339 1.2 tsutsui sc->inited = 2; 340 1.2 tsutsui sc->sc_regs->Control = EC_RESET; 341 1.2 tsutsui sc->sc_no_rd = 0; /* they are gone */ 342 1.2 tsutsui sc->sc_no_td = 0; /* they are gone */ 343 1.1 pooka } 344 1.1 pooka 345 1.1 pooka void 346 1.1 pooka enic_shutdown(void *arg) 347 1.1 pooka { 348 1.1 pooka struct ifnet *ifp = arg; 349 1.1 pooka 350 1.1 pooka enic_stop(ifp, 0); 351 1.1 pooka } 352 1.1 pooka 353 1.1 pooka void 354 1.1 pooka enic_kill_xmit(struct enic_softc *sc) 355 1.1 pooka { 356 1.2 tsutsui int i; 357 1.2 tsutsui struct mbuf *m; 358 1.1 pooka 359 1.2 tsutsui for (i = 0; i < sc->sc_n_xmit; i++) { 360 1.2 tsutsui if ((m = sc->sc_xmit[i].mbuf) != NULL) { 361 1.2 tsutsui sc->sc_xmit[i].mbuf = NULL; 362 1.2 tsutsui sc->sc_xmit[i].phys = ~0; 363 1.2 tsutsui m_freem(m); 364 1.2 tsutsui } 365 1.2 tsutsui } 366 1.1 pooka sc->sc_no_td = 0; 367 1.2 tsutsui sc->sc_xmit_h = 0; 368 1.1 pooka } 369 1.1 pooka 370 1.1 pooka void 371 1.1 pooka enic_post_recv(struct enic_softc *sc, struct mbuf *m) 372 1.1 pooka { 373 1.2 tsutsui int i, waitmode = M_DONTWAIT; 374 1.2 tsutsui paddr_t phys; 375 1.1 pooka 376 1.1 pooka #define rpostone(_p_) \ 377 1.1 pooka sc->sc_regs->SizeAndFlags = ES_F_RECV | MCLBYTES; \ 378 1.1 pooka sc->sc_regs->BufferAddressHi32 = 0; \ 379 1.1 pooka sc->sc_regs->BufferAddressLo32 = _p_; 380 1.1 pooka #define tpostone(_p_,_s_) \ 381 1.1 pooka sc->sc_regs->SizeAndFlags = ES_F_XMIT | (_s_); \ 382 1.1 pooka sc->sc_regs->BufferAddressHi32 = 0; \ 383 1.1 pooka sc->sc_regs->BufferAddressLo32 = _p_; 384 1.1 pooka 385 1.2 tsutsui /* Operational reload? */ 386 1.2 tsutsui if (m != NULL) { 387 1.2 tsutsui /* But is the hw ready for it */ 388 1.2 tsutsui if (sc->sc_regs->Control & EC_IF_FULL) 389 1.2 tsutsui goto no_room; 390 1.2 tsutsui /* Yes, find a spot. Include empty q case. */ 391 1.2 tsutsui for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 392 1.2 tsutsui if (sc->sc_recv[i].mbuf == NULL) 393 1.2 tsutsui goto found; 394 1.2 tsutsui for (i = 0; i < sc->sc_recv_h; i++) 395 1.2 tsutsui if (sc->sc_recv[i].mbuf == NULL) 396 1.2 tsutsui goto found; 397 1.2 tsutsui /* no spot, drop it (sigh) */ 398 1.2 tsutsui no_room: 399 1.2 tsutsui #if DEBUG 400 1.2 tsutsui sc->rf++; 401 1.2 tsutsui #endif 402 1.2 tsutsui m_freem(m); 403 1.2 tsutsui return; 404 1.2 tsutsui found: 405 1.2 tsutsui phys = kvtophys((vaddr_t)m->m_data); 406 1.2 tsutsui sc->sc_recv[i].mbuf = m; 407 1.2 tsutsui sc->sc_recv[i].phys = phys; 408 1.2 tsutsui rpostone(phys); 409 1.2 tsutsui sc->sc_no_rd++; 410 1.2 tsutsui return; 411 1.2 tsutsui } 412 1.2 tsutsui 413 1.2 tsutsui /* Repost after reset? */ 414 1.2 tsutsui if (sc->inited) { 415 1.2 tsutsui /* order doesnt matter, might as well keep it clean */ 416 1.2 tsutsui int j = 0; 417 1.2 tsutsui sc->sc_recv_h = 0; 418 1.2 tsutsui for (i = 0; i < sc->sc_n_recv; i++) 419 1.2 tsutsui if ((m = sc->sc_recv[i].mbuf) != NULL) { 420 1.2 tsutsui phys = sc->sc_recv[i].phys; 421 1.2 tsutsui sc->sc_recv[i].mbuf = NULL; 422 1.2 tsutsui sc->sc_recv[i].phys = ~0; 423 1.2 tsutsui sc->sc_recv[j].mbuf = m; 424 1.2 tsutsui sc->sc_recv[j].phys = phys; 425 1.2 tsutsui #if DEBUG 426 1.2 tsutsui if (sc->sc_regs->Control & EC_IF_FULL) 427 1.2 tsutsui printf("?uhu? postrecv full? %d\n", 428 1.2 tsutsui sc->sc_no_rd); 429 1.2 tsutsui #endif 430 1.2 tsutsui sc->sc_no_rd++; 431 1.2 tsutsui rpostone(phys); 432 1.2 tsutsui j++; 433 1.2 tsutsui } 434 1.2 tsutsui /* Any holes left? */ 435 1.2 tsutsui sc->inited = 1; 436 1.2 tsutsui if (j >= sc->sc_n_recv) 437 1.2 tsutsui return; /* no, we are done */ 438 1.2 tsutsui /* continue on with the loop below */ 439 1.2 tsutsui i = j; m = NULL; 440 1.2 tsutsui goto fillem; 441 1.2 tsutsui } 442 1.2 tsutsui 443 1.2 tsutsui /* Initial refill, we can wait */ 444 1.2 tsutsui waitmode = M_WAIT; 445 1.2 tsutsui sc->sc_recv_h = 0; 446 1.2 tsutsui memset(sc->sc_recv, 0, sizeof(sc->sc_recv[0]) * sc->sc_n_recv); 447 1.2 tsutsui i = 0; 448 1.1 pooka fillem: 449 1.2 tsutsui for (; i < sc->sc_n_recv; i++) { 450 1.2 tsutsui MGETHDR(m, waitmode, MT_DATA); 451 1.2 tsutsui if (m == 0) 452 1.2 tsutsui break; 453 1.9 ozaki m_set_rcvif(m, &sc->sc_ethercom.ec_if); 454 1.2 tsutsui m->m_pkthdr.len = 0; 455 1.2 tsutsui 456 1.2 tsutsui MCLGET(m, waitmode); 457 1.2 tsutsui if ((m->m_flags & M_EXT) == 0) 458 1.2 tsutsui break; 459 1.1 pooka 460 1.2 tsutsui /* 461 1.2 tsutsui * This offset aligns IP/TCP headers and helps performance 462 1.2 tsutsui */ 463 1.1 pooka #if 1 464 1.1 pooka #define ADJUST_MBUF_OFFSET(_m_) { \ 465 1.2 tsutsui (_m_)->m_data += 2; \ 466 1.2 tsutsui (_m_)->m_len -= 2; \ 467 1.1 pooka } 468 1.1 pooka #else 469 1.2 tsutsui #define ADJUST_MBUF_OFFSET(_m_) 470 1.1 pooka #endif 471 1.1 pooka 472 1.1 pooka m->m_len = MCLBYTES; 473 1.1 pooka 474 1.2 tsutsui ADJUST_MBUF_OFFSET(m); 475 1.2 tsutsui phys = kvtophys((vaddr_t)m->m_data); 476 1.2 tsutsui sc->sc_recv[i].mbuf = m; 477 1.2 tsutsui sc->sc_recv[i].phys = phys; 478 1.2 tsutsui #if DEBUG 479 1.2 tsutsui if (sc->sc_regs->Control & EC_IF_FULL) 480 1.2 tsutsui printf("?uhu? postrecv2 full? %d\n", sc->sc_no_rd); 481 1.2 tsutsui #endif 482 1.2 tsutsui sc->sc_no_rd++; 483 1.2 tsutsui rpostone(phys); 484 1.2 tsutsui m = NULL; 485 1.1 pooka } 486 1.1 pooka 487 1.26 rin m_freem(m); 488 1.2 tsutsui sc->inited = 1; 489 1.1 pooka } 490 1.1 pooka 491 1.1 pooka void enic_refill(struct enic_softc *sc) 492 1.1 pooka { 493 1.2 tsutsui struct mbuf *m; 494 1.2 tsutsui int waitmode = M_DONTWAIT; 495 1.1 pooka 496 1.2 tsutsui MGETHDR(m, waitmode, MT_DATA); 497 1.2 tsutsui if (m == NULL) 498 1.2 tsutsui return; 499 1.9 ozaki m_set_rcvif(m, &sc->sc_ethercom.ec_if); 500 1.2 tsutsui m->m_pkthdr.len = 0; 501 1.1 pooka 502 1.2 tsutsui MCLGET(m, waitmode); 503 1.2 tsutsui if ((m->m_flags & M_EXT) == 0) { 504 1.2 tsutsui m_freem(m); 505 1.2 tsutsui return; 506 1.2 tsutsui } 507 1.2 tsutsui 508 1.2 tsutsui m->m_len = MCLBYTES; 509 1.2 tsutsui ADJUST_MBUF_OFFSET(m); 510 1.1 pooka 511 1.19 msaitoh enic_post_recv(sc, m); 512 1.1 pooka } 513 1.1 pooka 514 1.1 pooka int 515 1.1 pooka enic_init(struct ifnet *ifp) 516 1.1 pooka { 517 1.1 pooka struct enic_softc *sc = ifp->if_softc; 518 1.2 tsutsui uint32_t ctl; 519 1.2 tsutsui 520 1.2 tsutsui /* no need to init many times unless we are in reset */ 521 1.2 tsutsui if (sc->inited != 1) { 522 1.1 pooka 523 1.2 tsutsui /* Cancel all xmit buffers */ 524 1.2 tsutsui enic_kill_xmit(sc); 525 1.1 pooka 526 1.2 tsutsui /* Re-post all recv buffers */ 527 1.18 msaitoh enic_post_recv(sc, NULL); 528 1.2 tsutsui } 529 1.1 pooka 530 1.2 tsutsui /* Start the eNIC */ 531 1.2 tsutsui ifp->if_flags |= IFF_RUNNING; 532 1.24 thorpej sc->sc_txbusy = false; 533 1.2 tsutsui ifp->if_timer = 0; 534 1.2 tsutsui ctl = sc->sc_regs->Control | EC_INTEN; 535 1.2 tsutsui ctl &= ~EC_RXDIS; 536 1.2 tsutsui sc->sc_regs->Control = ctl; 537 1.2 tsutsui #if 0 538 1.18 msaitoh printf("enic_init <- %x\n", ctl); 539 1.2 tsutsui #endif 540 1.1 pooka 541 1.12 ozaki if_schedule_deferred_start(ifp); 542 1.1 pooka 543 1.2 tsutsui return 0; 544 1.1 pooka } 545 1.1 pooka 546 1.1 pooka 547 1.1 pooka void 548 1.1 pooka enic_watchdog(struct ifnet *ifp) 549 1.1 pooka { 550 1.1 pooka struct enic_softc *sc = ifp->if_softc; 551 1.1 pooka 552 1.2 tsutsui #if 0 553 1.2 tsutsui printf("enic_watch ctl=%x\n", sc->sc_regs->Control); 554 1.2 tsutsui #endif 555 1.1 pooka log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 556 1.23 martin if_statinc(ifp, if_oerrors); 557 1.1 pooka 558 1.1 pooka enic_reset(ifp); 559 1.1 pooka } 560 1.1 pooka 561 1.1 pooka int 562 1.1 pooka enic_mediachange(struct ifnet *ifp) 563 1.1 pooka { 564 1.2 tsutsui #if 0 565 1.2 tsutsui struct enic_softc *sc = ifp->if_softc; 566 1.2 tsutsui #endif 567 1.2 tsutsui /* more code here.. */ 568 1.1 pooka 569 1.2 tsutsui return 0; 570 1.1 pooka } 571 1.1 pooka 572 1.1 pooka void 573 1.2 tsutsui enic_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 574 1.1 pooka { 575 1.1 pooka struct enic_softc *sc = ifp->if_softc; 576 1.1 pooka 577 1.1 pooka if ((ifp->if_flags & IFF_UP) == 0) 578 1.1 pooka return; 579 1.1 pooka 580 1.1 pooka ifmr->ifm_status = IFM_AVALID; 581 1.1 pooka if (sc->sc_havecarrier) 582 1.1 pooka ifmr->ifm_status |= IFM_ACTIVE; 583 1.1 pooka 584 1.2 tsutsui /* more code here someday.. */ 585 1.1 pooka } 586 1.1 pooka 587 1.1 pooka /* 588 1.1 pooka * Process an ioctl request. 589 1.1 pooka */ 590 1.1 pooka int 591 1.1 pooka enic_ioctl(struct ifnet *ifp, u_long cmd, void *data) 592 1.1 pooka { 593 1.1 pooka int s, error = 0; 594 1.1 pooka 595 1.1 pooka s = splnet(); 596 1.1 pooka 597 1.1 pooka switch (cmd) { 598 1.1 pooka default: 599 1.1 pooka error = ether_ioctl(ifp, cmd, data); 600 1.1 pooka if (cmd == SIOCSIFADDR) { 601 1.1 pooka /* 602 1.1 pooka * hackattack: NFS does not turn us back 603 1.1 pooka * on after a stop. So. 604 1.1 pooka */ 605 1.2 tsutsui #if 0 606 1.19 msaitoh printf("enic_ioctl(%lx)\n", cmd); 607 1.2 tsutsui #endif 608 1.1 pooka enic_init(ifp); 609 1.1 pooka } 610 1.1 pooka if (error != ENETRESET) 611 1.1 pooka break; 612 1.1 pooka error = 0; 613 1.1 pooka if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) 614 1.1 pooka break; 615 1.1 pooka if (ifp->if_flags & IFF_RUNNING) { 616 1.1 pooka enic_reset(ifp); 617 1.1 pooka } 618 1.1 pooka break; 619 1.1 pooka } 620 1.1 pooka splx(s); 621 1.1 pooka 622 1.2 tsutsui return error; 623 1.1 pooka } 624 1.1 pooka 625 1.1 pooka int 626 1.1 pooka enic_intr(void *cookie, void *f) 627 1.1 pooka { 628 1.1 pooka struct enic_softc *sc = cookie; 629 1.2 tsutsui uint32_t isr, saf, hi, lo, fl; 630 1.1 pooka 631 1.1 pooka isr = sc->sc_regs->Control; 632 1.1 pooka 633 1.2 tsutsui /* Make sure there is one and that we should take it */ 634 1.19 msaitoh if ((isr & (EC_INTEN | EC_DONE)) != (EC_INTEN | EC_DONE)) 635 1.2 tsutsui return 0; 636 1.1 pooka 637 1.1 pooka if (isr & EC_ERROR) { 638 1.2 tsutsui printf("%s: internal error\n", device_xname(sc->sc_dev)); 639 1.2 tsutsui enic_reset(&sc->sc_ethercom.ec_if); 640 1.2 tsutsui return 1; 641 1.2 tsutsui } 642 1.1 pooka 643 1.2 tsutsui /* 644 1.2 tsutsui * pull out all completed buffers 645 1.2 tsutsui */ 646 1.2 tsutsui while ((isr & EC_OF_EMPTY) == 0) { 647 1.2 tsutsui 648 1.2 tsutsui /* beware, order matters */ 649 1.2 tsutsui saf = sc->sc_regs->SizeAndFlags; 650 1.2 tsutsui hi = sc->sc_regs->BufferAddressHi32; /* BUGBUG 64bit */ 651 1.2 tsutsui lo = sc->sc_regs->BufferAddressLo32; /* this pops the fifo */ 652 1.5 christos __USE(hi); 653 1.2 tsutsui 654 1.2 tsutsui fl = saf & (ES_F_MASK &~ ES_F_DONE); 655 1.2 tsutsui if (fl == ES_F_RECV) 656 1.19 msaitoh enic_rint(sc, saf, lo); 657 1.2 tsutsui else if (fl == ES_F_XMIT) 658 1.19 msaitoh enic_tint(sc, saf, lo); 659 1.2 tsutsui else { 660 1.2 tsutsui /* 661 1.2 tsutsui * we do not currently expect or care for 662 1.2 tsutsui * command completions? 663 1.2 tsutsui */ 664 1.2 tsutsui if (fl != ES_F_CMD) 665 1.2 tsutsui printf("%s: invalid saf=x%x (lo=%x)\n", 666 1.2 tsutsui device_xname(sc->sc_dev), saf, lo); 667 1.2 tsutsui } 668 1.2 tsutsui 669 1.2 tsutsui isr = sc->sc_regs->Control; 670 1.2 tsutsui } 671 1.1 pooka 672 1.1 pooka rnd_add_uint32(&sc->rnd_source, isr); 673 1.1 pooka 674 1.2 tsutsui return 1; 675 1.1 pooka } 676 1.1 pooka 677 1.1 pooka void 678 1.1 pooka enic_rint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 679 1.1 pooka { 680 1.1 pooka struct mbuf *m; 681 1.1 pooka struct ifnet *ifp = &sc->sc_ethercom.ec_if; 682 1.2 tsutsui int len = saf & ES_S_MASK, i; 683 1.1 pooka 684 1.2 tsutsui /* Find what buffer it is. Should be the first. */ 685 1.2 tsutsui for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++) 686 1.2 tsutsui if (sc->sc_recv[i].phys == phys) 687 1.2 tsutsui goto found; 688 1.2 tsutsui for (i = 0; i < sc->sc_recv_h; i++) 689 1.2 tsutsui if (sc->sc_recv[i].phys == phys) 690 1.2 tsutsui goto found; 691 1.2 tsutsui 692 1.2 tsutsui /* uhu?? */ 693 1.2 tsutsui printf("%s: bad recv phys %llx\n", device_xname(sc->sc_dev), 694 1.2 tsutsui (long long)phys); 695 1.22 skrll if_statinc(ifp, if_ierrors); 696 1.2 tsutsui return; 697 1.1 pooka 698 1.2 tsutsui /* got it, pop it */ 699 1.1 pooka found: 700 1.2 tsutsui sc->sc_no_rd--; 701 1.2 tsutsui m = sc->sc_recv[i].mbuf; 702 1.2 tsutsui sc->sc_recv[i].mbuf = NULL; 703 1.2 tsutsui sc->sc_recv[i].phys = ~0; 704 1.2 tsutsui if (i == sc->sc_recv_h) { /* should be */ 705 1.2 tsutsui sc->sc_recv_h = (++i == sc->sc_n_recv) ? 0 : i; 706 1.2 tsutsui } 707 1.1 pooka #if DEBUG 708 1.2 tsutsui else 709 1.2 tsutsui sc->brh++; 710 1.1 pooka #endif 711 1.1 pooka 712 1.1 pooka if (len <= sizeof(struct ether_header) || 713 1.1 pooka len > ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? 714 1.1 pooka ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) : 715 1.1 pooka ETHERMTU + sizeof(struct ether_header))) { 716 1.22 skrll if_statinc(ifp, if_ierrors); 717 1.1 pooka 718 1.2 tsutsui /* reuse it */ 719 1.19 msaitoh enic_post_recv(sc, m); 720 1.1 pooka return; 721 1.1 pooka } 722 1.1 pooka 723 1.1 pooka /* Adjust size */ 724 1.1 pooka m->m_pkthdr.len = len; 725 1.1 pooka m->m_len = len; /* recheck */ 726 1.1 pooka 727 1.1 pooka /* Pass the packet up. */ 728 1.8 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 729 1.1 pooka 730 1.1 pooka /* Need to refill now */ 731 1.1 pooka enic_refill(sc); 732 1.1 pooka } 733 1.1 pooka 734 1.1 pooka void enic_tint(struct enic_softc *sc, uint32_t saf, paddr_t phys) 735 1.1 pooka { 736 1.1 pooka struct mbuf *m; 737 1.1 pooka struct ifnet *ifp = &sc->sc_ethercom.ec_if; 738 1.2 tsutsui int i; 739 1.1 pooka 740 1.1 pooka #if DEBUG 741 1.2 tsutsui sc->it = 1; 742 1.1 pooka #endif 743 1.1 pooka 744 1.2 tsutsui /* BUGBUG should there be a per-buffer error bit in SAF? */ 745 1.1 pooka 746 1.2 tsutsui /* Find what buffer it is. Should be the first. */ 747 1.2 tsutsui for (i = sc->sc_xmit_h; i < sc->sc_n_xmit; i++) 748 1.2 tsutsui if (sc->sc_xmit[i].phys == phys) 749 1.2 tsutsui goto found; 750 1.2 tsutsui for (i = 0; i < sc->sc_xmit_h; i++) 751 1.2 tsutsui if (sc->sc_xmit[i].phys == phys) 752 1.2 tsutsui goto found; 753 1.1 pooka 754 1.2 tsutsui /* uhu?? */ 755 1.2 tsutsui printf("%s: bad xmit phys %llx\n", device_xname(sc->sc_dev), 756 1.2 tsutsui (long long)phys); 757 1.22 skrll if_statinc(ifp, if_oerrors); 758 1.2 tsutsui return; 759 1.1 pooka 760 1.2 tsutsui /* got it, pop it */ 761 1.1 pooka found: 762 1.2 tsutsui m = sc->sc_xmit[i].mbuf; 763 1.2 tsutsui sc->sc_xmit[i].mbuf = NULL; 764 1.2 tsutsui sc->sc_xmit[i].phys = ~0; 765 1.2 tsutsui if (i == sc->sc_xmit_h) { /* should be */ 766 1.2 tsutsui sc->sc_xmit_h = (++i == sc->sc_n_xmit) ? 0 : i; 767 1.2 tsutsui } 768 1.1 pooka #if DEBUG 769 1.2 tsutsui else 770 1.2 tsutsui sc->bxh++; 771 1.1 pooka #endif 772 1.2 tsutsui m_freem(m); 773 1.22 skrll if_statinc(ifp, if_opackets); 774 1.1 pooka 775 1.1 pooka if (--sc->sc_no_td == 0) 776 1.1 pooka ifp->if_timer = 0; 777 1.1 pooka 778 1.24 thorpej sc->sc_txbusy = false; 779 1.12 ozaki if_schedule_deferred_start(ifp); 780 1.1 pooka #if DEBUG 781 1.2 tsutsui sc->it = 1; 782 1.1 pooka #endif 783 1.1 pooka } 784 1.1 pooka 785 1.1 pooka /* 786 1.1 pooka * Setup output on interface. 787 1.1 pooka * Get another datagram to send off of the interface queue, and map it to the 788 1.1 pooka * interface before starting the output. 789 1.1 pooka * Called only at splnet or interrupt level. 790 1.1 pooka */ 791 1.1 pooka void 792 1.1 pooka enic_start(struct ifnet *ifp) 793 1.1 pooka { 794 1.1 pooka struct enic_softc *sc = ifp->if_softc; 795 1.1 pooka struct mbuf *m; 796 1.1 pooka int len, ix, s; 797 1.2 tsutsui paddr_t phys; 798 1.1 pooka 799 1.1 pooka #if DEBUG 800 1.2 tsutsui sc->it = 0; 801 1.1 pooka #endif 802 1.1 pooka 803 1.2 tsutsui #if 0 804 1.2 tsutsui printf("enic_start(%x)\n", ifp->if_flags); 805 1.2 tsutsui #endif 806 1.1 pooka 807 1.24 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0) 808 1.1 pooka return; 809 1.1 pooka 810 1.2 tsutsui s = splnet(); /* I know, I dont trust people.. */ 811 1.1 pooka 812 1.2 tsutsui ix = sc->sc_xmit_h; 813 1.1 pooka for (;;) { 814 1.1 pooka 815 1.2 tsutsui /* Anything to do? */ 816 1.2 tsutsui IFQ_POLL(&ifp->if_snd, m); 817 1.2 tsutsui if (m == NULL) 818 1.1 pooka break; 819 1.1 pooka 820 1.2 tsutsui /* find a spot, if any */ 821 1.2 tsutsui for (; ix < sc->sc_n_xmit; ix++) 822 1.2 tsutsui if (sc->sc_xmit[ix].mbuf == NULL) 823 1.2 tsutsui goto found; 824 1.2 tsutsui for (ix = 0; ix < sc->sc_xmit_h; ix++) 825 1.2 tsutsui if (sc->sc_xmit[ix].mbuf == NULL) 826 1.2 tsutsui goto found; 827 1.2 tsutsui /* oh well */ 828 1.24 thorpej sc->sc_txbusy = true; 829 1.1 pooka #if DEBUG 830 1.2 tsutsui sc->tfull++; 831 1.1 pooka #endif 832 1.2 tsutsui break; 833 1.1 pooka 834 1.2 tsutsui found: 835 1.1 pooka IFQ_DEQUEUE(&ifp->if_snd, m); 836 1.2 tsutsui if (m == NULL) 837 1.1 pooka break; 838 1.1 pooka 839 1.1 pooka /* 840 1.1 pooka * If BPF is listening on this interface, let it see the packet 841 1.1 pooka * before we commit it to the wire. 842 1.1 pooka */ 843 1.16 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 844 1.1 pooka 845 1.1 pooka /* 846 1.1 pooka * Copy the mbuf chain into a contiguous transmit buffer. 847 1.1 pooka */ 848 1.1 pooka len = enic_put(sc, &m); 849 1.2 tsutsui if (len == 0) 850 1.2 tsutsui break; /* sanity */ 851 1.2 tsutsui if (len > (ETHERMTU + sizeof(struct ether_header))) { 852 1.2 tsutsui printf("enic? tlen %d > %d\n", 853 1.2 tsutsui len, ETHERMTU + sizeof(struct ether_header)); 854 1.2 tsutsui len = ETHERMTU + sizeof(struct ether_header); 855 1.2 tsutsui } 856 1.1 pooka 857 1.1 pooka ifp->if_timer = 5; 858 1.1 pooka 859 1.1 pooka /* 860 1.1 pooka * Remember and post the buffer 861 1.1 pooka */ 862 1.2 tsutsui phys = kvtophys((vaddr_t)m->m_data); 863 1.2 tsutsui sc->sc_xmit[ix].mbuf = m; 864 1.2 tsutsui sc->sc_xmit[ix].phys = phys; 865 1.1 pooka 866 1.2 tsutsui sc->sc_no_td++; 867 1.1 pooka 868 1.19 msaitoh tpostone(phys, len); 869 1.1 pooka 870 1.1 pooka if (sc->sc_regs->Control & EC_IF_FULL) { 871 1.24 thorpej sc->sc_txbusy = true; 872 1.1 pooka #if DEBUG 873 1.2 tsutsui sc->tfull2++; 874 1.1 pooka #endif 875 1.1 pooka break; 876 1.1 pooka } 877 1.1 pooka 878 1.2 tsutsui ix++; 879 1.1 pooka } 880 1.1 pooka 881 1.2 tsutsui splx(s); 882 1.1 pooka } 883 1.1 pooka 884 1.1 pooka int enic_put(struct enic_softc *sc, struct mbuf **pm) 885 1.1 pooka { 886 1.1 pooka struct mbuf *n, *m = *pm, *mm; 887 1.1 pooka int len, tlen = 0, xlen = m->m_pkthdr.len; 888 1.2 tsutsui uint8_t *cp; 889 1.1 pooka 890 1.1 pooka #if 0 891 1.2 tsutsui /* drop garbage */ 892 1.2 tsutsui tlen = xlen; 893 1.1 pooka for (; m; m = n) { 894 1.1 pooka len = m->m_len; 895 1.1 pooka if (len == 0) { 896 1.10 christos n = m_free(m); 897 1.11 maya if (m == *pm) 898 1.11 maya *pm = n; 899 1.1 pooka continue; 900 1.1 pooka } 901 1.1 pooka tlen -= len; 902 1.2 tsutsui KASSERT(m != m->m_next); 903 1.2 tsutsui n = m->m_next; 904 1.2 tsutsui if (tlen <= 0) 905 1.2 tsutsui break; 906 1.2 tsutsui } 907 1.1 pooka 908 1.2 tsutsui /* 909 1.2 tsutsui * We might be done: 910 1.2 tsutsui * (a) empty chain (b) only one segment (c) bad chain 911 1.2 tsutsui */ 912 1.2 tsutsui if (((m = *pm) == NULL) || (tlen > 0)) 913 1.2 tsutsui xlen = 0; 914 1.2 tsutsui #endif 915 1.2 tsutsui 916 1.2 tsutsui if ((xlen == 0) || (xlen <= m->m_len)) { 917 1.2 tsutsui #if DEBUG 918 1.2 tsutsui sc->xhit++; 919 1.2 tsutsui #endif 920 1.2 tsutsui return xlen; 921 1.2 tsutsui } 922 1.2 tsutsui 923 1.2 tsutsui /* Nope, true chain. Copy to contig :-(( */ 924 1.2 tsutsui tlen = xlen; 925 1.2 tsutsui MGETHDR(n, M_NOWAIT, MT_DATA); 926 1.2 tsutsui if (n == NULL) 927 1.2 tsutsui goto Bad; 928 1.9 ozaki m_set_rcvif(n, &sc->sc_ethercom.ec_if); 929 1.2 tsutsui n->m_pkthdr.len = tlen; 930 1.2 tsutsui 931 1.2 tsutsui MCLGET(n, M_NOWAIT); 932 1.2 tsutsui if ((n->m_flags & M_EXT) == 0) { 933 1.2 tsutsui m_freem(n); 934 1.2 tsutsui goto Bad; 935 1.2 tsutsui } 936 1.2 tsutsui 937 1.2 tsutsui n->m_len = tlen; 938 1.2 tsutsui cp = mtod(n, uint8_t *); 939 1.1 pooka for (; m && tlen; m = mm) { 940 1.1 pooka 941 1.2 tsutsui len = m->m_len; 942 1.2 tsutsui if (len > tlen) 943 1.2 tsutsui len = tlen; 944 1.2 tsutsui if (len) 945 1.2 tsutsui memcpy(cp, mtod(m, void *), len); 946 1.1 pooka 947 1.1 pooka cp += len; 948 1.2 tsutsui tlen -= len; 949 1.10 christos mm = m_free(m); 950 1.2 tsutsui 951 1.1 pooka } 952 1.1 pooka 953 1.2 tsutsui *pm = n; 954 1.1 pooka #if DEBUG 955 1.2 tsutsui sc->xmiss++; 956 1.1 pooka #endif 957 1.1 pooka return (xlen); 958 1.1 pooka 959 1.1 pooka Bad: 960 1.2 tsutsui printf("enic_put: no mem?\n"); 961 1.2 tsutsui m_freem(m); 962 1.2 tsutsui return 0; 963 1.1 pooka } 964