1/*- 2 * Copyright (c) 2012-2014 Bjoern A. Zeeb 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 7 * ("MRC2"), as part of the DARPA MRC research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * This driver is modelled after atse(4). We need to seriously reduce the 31 * per-driver code we have to write^wcopy & paste. 32 * 33 * TODO: 34 * - figure out on the HW side why some data is LE and some is BE. 35 * - general set of improvements possible (e.g., reduce times of copying, 36 * do on-the-copy checksum calculations) 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD$"); 41 42#include "opt_device_polling.h" 43#include "opt_netfpga.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/bus.h> 49#include <sys/endian.h> 50#include <sys/lock.h> 51#include <sys/module.h> 52#include <sys/mutex.h> 53#include <sys/proc.h> 54#include <sys/socket.h> 55#include <sys/sockio.h> 56#include <sys/types.h> 57 58#include <net/ethernet.h> 59#include <net/if.h> 60#include <net/if_var.h> 61#include <net/if_dl.h> 62#include <net/if_media.h> 63#include <net/if_types.h> 64#include <net/if_vlan_var.h> 65 66#include <net/bpf.h> 67 68#include <machine/bus.h> 69#include <machine/resource.h> 70#include <sys/rman.h> 71 72#include "if_nf10bmacreg.h" 73 74#ifndef NF10BMAC_MAX_PKTS 75/* 76 * We have a 4k buffer in HW, so do not try to send more than 3 packets. 77 * At the time of writing HW is orders of magnitude faster than we can 78 * enqueue so it would not matter but need an escape. 79 */ 80#define NF10BMAC_MAX_PKTS 3 81#endif 82 83#ifndef NF10BMAC_WATCHDOG_TIME 84#define NF10BMAC_WATCHDOG_TIME 5 /* seconds */ 85#endif 86 87#ifdef DEVICE_POLLING 88static poll_handler_t nf10bmac_poll; 89#endif 90 91#define NF10BMAC_LOCK(_sc) mtx_lock(&(_sc)->nf10bmac_mtx) 92#define NF10BMAC_UNLOCK(_sc) mtx_unlock(&(_sc)->nf10bmac_mtx) 93#define NF10BMAC_LOCK_ASSERT(_sc) \ 94 mtx_assert(&(_sc)->nf10bmac_mtx, MA_OWNED) 95 96#define NF10BMAC_CTRL0 0x00 97#define NF10BMAC_TX_DATA 0x00 98#define NF10BMAC_TX_META 0x08 99#define NF10BMAC_TX_LEN 0x10 100#define NF10BMAC_RX_DATA 0x00 101#define NF10BMAC_RX_META 0x08 102#define NF10BMAC_RX_LEN 0x10 103#define NF10BMAC_INTR_CLEAR_DIS 0x00 104#define NF10BMAC_INTR_CTRL 0x08 105 106#define NF10BMAC_TUSER_MAC0 (1 << 0) 107#define NF10BMAC_TUSER_CPU0 (1 << 1) 108#define NF10BMAC_TUSER_MAC1 (1 << 2) 109#define NF10BMAC_TUSER_CPU1 (1 << 3) 110#define NF10BMAC_TUSER_MAC2 (1 << 4) 111#define NF10BMAC_TUSER_CPU2 (1 << 5) 112#define NF10BMAC_TUSER_MAC3 (1 << 6) 113#define NF10BMAC_TUSER_CPU3 (1 << 7) 114 115#define NF10BMAC_DATA_LEN_MASK 0x0000ffff 116#define NF10BMAC_DATA_DPORT_MASK 0xff000000 117#define NF10BMAC_DATA_DPORT_SHIFT 24 118#define NF10BMAC_DATA_SPORT_MASK 0x00ff0000 119#define NF10BMAC_DATA_SPORT_SHIFT 16 120#define NF10BMAC_DATA_LAST 0x00008000 121#ifdef NF10BMAC_64BIT 122#define NF10BMAC_DATA_STRB 0x000000ff 123#define REGWTYPE uint64_t 124#else 125#define NF10BMAC_DATA_STRB 0x0000000f 126#define REGWTYPE uint32_t 127#endif 128 129 130static inline void 131nf10bmac_write(struct resource *res, REGWTYPE reg, REGWTYPE val, 132 const char *f __unused, const int l __unused) 133{ 134 135#ifdef NF10BMAC_64BIT 136 bus_write_8(res, reg, htole64(val)); 137#else 138 bus_write_4(res, reg, htole32(val)); 139#endif 140} 141 142static inline REGWTYPE 143nf10bmac_read(struct resource *res, REGWTYPE reg, 144 const char *f __unused, const int l __unused) 145{ 146 147#ifdef NF10BMAC_64BIT 148 return (le64toh(bus_read_8(res, reg))); 149#else 150 return (le32toh(bus_read_4(res, reg))); 151#endif 152} 153 154static inline void 155nf10bmac_write_be(struct resource *res, REGWTYPE reg, REGWTYPE val, 156 const char *f __unused, const int l __unused) 157{ 158 159#ifdef NF10BMAC_64BIT 160 bus_write_8(res, reg, htobe64(val)); 161#else 162 bus_write_4(res, reg, htobe32(val)); 163#endif 164} 165 166 167static inline REGWTYPE 168nf10bmac_read_be(struct resource *res, REGWTYPE reg, 169 const char *f __unused, const int l __unused) 170{ 171 172#ifdef NF10BMAC_64BIT 173 return (be64toh(bus_read_8(res, reg))); 174#else 175 return (be32toh(bus_read_4(res, reg))); 176#endif 177} 178 179#define NF10BMAC_WRITE_CTRL(sc, reg, val) \ 180 nf10bmac_write((sc)->nf10bmac_ctrl_res, (reg), (val), \ 181 __func__, __LINE__) 182#define NF10BMAC_WRITE(sc, reg, val) \ 183 nf10bmac_write((sc)->nf10bmac_tx_mem_res, (reg), (val), \ 184 __func__, __LINE__) 185#define NF10BMAC_READ(sc, reg) \ 186 nf10bmac_read((sc)->nf10bmac_rx_mem_res, (reg), \ 187 __func__, __LINE__) 188#define NF10BMAC_WRITE_BE(sc, reg, val) \ 189 nf10bmac_write_be((sc)->nf10bmac_tx_mem_res, (reg), (val), \ 190 __func__, __LINE__) 191#define NF10BMAC_READ_BE(sc, reg) \ 192 nf10bmac_read_be((sc)->nf10bmac_rx_mem_res, (reg), \ 193 __func__, __LINE__) 194 195#define NF10BMAC_WRITE_INTR(sc, reg, val, _f, _l) \ 196 nf10bmac_write((sc)->nf10bmac_intr_res, (reg), (val), \ 197 (_f), (_l)) 198 199#define NF10BMAC_RX_INTR_CLEAR_DIS(sc) \ 200 NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CLEAR_DIS, 1, \ 201 __func__, __LINE__) 202#define NF10BMAC_RX_INTR_ENABLE(sc) \ 203 NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 1, \ 204 __func__, __LINE__) 205#define NF10BMAC_RX_INTR_DISABLE(sc) \ 206 NF10BMAC_WRITE_INTR((sc), NF10BMAC_INTR_CTRL, 0, \ 207 __func__, __LINE__) 208 209 210#ifdef ENABLE_WATCHDOG 211static void nf10bmac_tick(void *); 212#endif 213static int nf10bmac_detach(device_t); 214 215devclass_t nf10bmac_devclass; 216 217 218static int 219nf10bmac_tx_locked(struct nf10bmac_softc *sc, struct mbuf *m) 220{ 221 int32_t len, l, ml; 222 REGWTYPE md, val; 223 224 NF10BMAC_LOCK_ASSERT(sc); 225 226 KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc)); 227 KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m)); 228 /* 229 * Copy to buffer to minimize our pain as we can only store 230 * double words which, after the first mbuf gets out of alignment 231 * quite quickly. 232 */ 233 m_copydata(m, 0, m->m_pkthdr.len, sc->nf10bmac_tx_buf); 234 len = m->m_pkthdr.len; 235 236 /* Write the length at start of packet. */ 237 NF10BMAC_WRITE(sc, NF10BMAC_TX_LEN, len); 238 239 /* Write the meta data and data. */ 240 ml = len / sizeof(val); 241 len -= (ml * sizeof(val)); 242 for (l = 0; l <= ml; l++) { 243 int32_t cl; 244 245 cl = sizeof(val); 246 md = (NF10BMAC_TUSER_CPU0 << NF10BMAC_DATA_SPORT_SHIFT); 247 if (l == ml || (len == 0 && l == (ml - 1))) { 248 if (l == ml && len == 0) { 249 break; 250 } else { 251 uint8_t s; 252 int sl; 253 254 if (l == (ml - 1)) 255 len = sizeof(val); 256 cl = len; 257 258 for (s = 0, sl = len; sl > 0; sl--) 259 s |= (1 << (sl - 1)); 260 md |= (s & NF10BMAC_DATA_STRB); 261 md |= NF10BMAC_DATA_LAST; 262 } 263 } else { 264 md |= NF10BMAC_DATA_STRB; 265 } 266 NF10BMAC_WRITE(sc, NF10BMAC_TX_META, md); 267 bcopy(&sc->nf10bmac_tx_buf[l*sizeof(val)], &val, cl); 268 NF10BMAC_WRITE_BE(sc, NF10BMAC_TX_DATA, val); 269 } 270 271 /* If anyone is interested give them a copy. */ 272 BPF_MTAP(sc->nf10bmac_ifp, m); 273 274 m_freem(m); 275 276 return (0); 277} 278 279static void 280nf10bmac_start_locked(struct ifnet *ifp) 281{ 282 struct nf10bmac_softc *sc; 283 int count, error; 284 285 sc = ifp->if_softc; 286 NF10BMAC_LOCK_ASSERT(sc); 287 288 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 289 IFF_DRV_RUNNING || (sc->nf10bmac_flags & NF10BMAC_FLAGS_LINK) == 0) 290 return; 291 292#ifdef ENABLE_WATCHDOG 293 /* 294 * Disable the watchdog while sending, we are batching packets. 295 * Though we should never reach 5 seconds, and are holding the lock, 296 * but who knows. 297 */ 298 sc->nf10bmac_watchdog_timer = 0; 299#endif 300 301 /* Send up to MAX_PKTS_PER_TX_LOOP packets. */ 302 for (count = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 303 count < NF10BMAC_MAX_PKTS; count++) { 304 struct mbuf *m; 305 306 IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 307 if (m == NULL) 308 break; 309 error = nf10bmac_tx_locked(sc, m); 310 if (error != 0) 311 break; 312 } 313 314#ifdef ENABLE_WATCHDOG 315done: 316 /* If the IP core walks into Nekromanteion try to bail out. */ 317 /* XXX-BZ useless until we have direct FIFO fill status feedback. */ 318 if (count > 0) 319 sc->nf10bmac_watchdog_timer = NF10BMAC_WATCHDOG_TIME; 320#endif 321} 322 323static void 324nf10bmac_start(struct ifnet *ifp) 325{ 326 struct nf10bmac_softc *sc; 327 328 sc = ifp->if_softc; 329 NF10BMAC_LOCK(sc); 330 nf10bmac_start_locked(ifp); 331 NF10BMAC_UNLOCK(sc); 332} 333 334static void 335nf10bmac_eat_packet_munch_munch(struct nf10bmac_softc *sc) 336{ 337 REGWTYPE md, val; 338 339 do { 340 md = NF10BMAC_READ_BE(sc, NF10BMAC_RX_META); 341 if ((md & NF10BMAC_DATA_STRB) != 0) 342 val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA); 343 } while ((md & NF10BMAC_DATA_STRB) != 0 && 344 (md & NF10BMAC_DATA_LAST) == 0); 345} 346 347static int 348nf10bmac_rx_locked(struct nf10bmac_softc *sc) 349{ 350 struct ifnet *ifp; 351 struct mbuf *m; 352 REGWTYPE md, val; 353 int32_t len, l; 354 355 /* 356 * General problem here in case we need to sync ourselves to the 357 * beginning of a packet. Length will only be set for the first 358 * read, and together with strb we can detect the beginning (or 359 * skip to tlast). 360 */ 361 362 len = NF10BMAC_READ(sc, NF10BMAC_RX_LEN) & NF10BMAC_DATA_LEN_MASK; 363 if (len > (MCLBYTES - ETHER_ALIGN)) { 364 nf10bmac_eat_packet_munch_munch(sc); 365 return (0); 366 } 367 368 md = NF10BMAC_READ(sc, NF10BMAC_RX_META); 369 if (len == 0 && (md & NF10BMAC_DATA_STRB) == 0) { 370 /* No packet data available. */ 371 return (0); 372 } else if (len == 0 && (md & NF10BMAC_DATA_STRB) != 0) { 373 /* We are in the middle of a packet. */ 374 nf10bmac_eat_packet_munch_munch(sc); 375 return (0); 376 } else if ((md & NF10BMAC_DATA_STRB) == 0) { 377 /* Invalid length "hint". */ 378 device_printf(sc->nf10bmac_dev, 379 "Unexpected length %d on zero strb\n", len); 380 return (0); 381 } 382 383 /* Assume at this point that we have data and a full packet. */ 384 if ((len + ETHER_ALIGN) >= MINCLSIZE) { 385 /* Get a cluster. */ 386 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 387 if (m == NULL) 388 return (0); 389 m->m_len = m->m_pkthdr.len = MCLBYTES; 390 } else { 391 /* Hey this still fits into the mbuf+pkthdr. */ 392 m = m_gethdr(M_NOWAIT, MT_DATA); 393 if (m == NULL) 394 return (0); 395 m->m_len = m->m_pkthdr.len = MHLEN; 396 } 397 /* Make sure upper layers will be aligned. */ 398 m_adj(m, ETHER_ALIGN); 399 400 ifp = sc->nf10bmac_ifp; 401 l = 0; 402/* 403 while ((md & NF10BMAC_DATA_STRB) != 0 && l < len) { 404*/ 405 while (l < len) { 406 size_t cl; 407 408 if ((md & NF10BMAC_DATA_LAST) == 0 && 409 (len - l) < sizeof(val)) { 410 /* 411 * Our length and LAST disagree. We have a valid STRB. 412 * We could continue until we fill the mbuf and just 413 * log the invlid length "hint". For now drop the 414 * packet on the floor and count the error. 415 */ 416 nf10bmac_eat_packet_munch_munch(sc); 417 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 418 m_freem(m); 419 return (0); 420 } else if ((len - l) <= sizeof(val)) { 421 cl = len - l; 422 } else { 423 cl = sizeof(val); 424 } 425 426 /* Read the first bytes of data as well. */ 427 val = NF10BMAC_READ_BE(sc, NF10BMAC_RX_DATA); 428 bcopy(&val, (uint8_t *)(m->m_data + l), cl); 429 l += cl; 430 431 if ((md & NF10BMAC_DATA_LAST) != 0 || l >= len) 432 break; 433 else { 434 DELAY(50); 435 md = NF10BMAC_READ(sc, NF10BMAC_RX_META); 436 } 437 438 cl = 10; 439 while ((md & NF10BMAC_DATA_STRB) == 0 && cl-- > 0) { 440 DELAY(10); 441 md = NF10BMAC_READ(sc, NF10BMAC_RX_META); 442 } 443 } 444 /* We should get out of this loop with tlast and tsrb. */ 445 if ((md & NF10BMAC_DATA_LAST) == 0 || (md & NF10BMAC_DATA_STRB) == 0) { 446 device_printf(sc->nf10bmac_dev, "Unexpected rx loop end state: " 447 "md=0x%08jx len=%d l=%d\n", (uintmax_t)md, len, l); 448 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 449 m_freem(m); 450 return (0); 451 } 452 453 m->m_pkthdr.len = m->m_len = len; 454 m->m_pkthdr.rcvif = ifp; 455 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 456 457 NF10BMAC_UNLOCK(sc); 458 (*ifp->if_input)(ifp, m); 459 NF10BMAC_LOCK(sc); 460 461 return (1); 462} 463 464 465static int 466nf10bmac_stop_locked(struct nf10bmac_softc *sc) 467{ 468 struct ifnet *ifp; 469 470 NF10BMAC_LOCK_ASSERT(sc); 471 472#ifdef ENABLE_WATCHDOG 473 sc->nf10bmac_watchdog_timer = 0; 474 callout_stop(&sc->nf10bmac_tick); 475#endif 476 477 ifp = sc->nf10bmac_ifp; 478 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 479 NF10BMAC_RX_INTR_CLEAR_DIS(sc); 480 481 sc->nf10bmac_flags &= ~NF10BMAC_FLAGS_LINK; 482 if_link_state_change(ifp, LINK_STATE_DOWN); 483 484 return (0); 485} 486 487static int 488nf10bmac_reset(struct nf10bmac_softc *sc) 489{ 490 491 /* 492 * If we do not have an ether address set, initialize to the same 493 * OUI as NetFPGA-10G Linux driver does (which luckily seems 494 * unallocated). We just change the NIC specific part from 495 * the slightly long "\0NF10C0" to "\0NFBSD". 496 * Oh and we keep the way of setting it from a string as they do. 497 * It's an amazing way to hide it. 498 * XXX-BZ If NetFPGA gets their own OUI we should fix this. 499 */ 500 if (sc->nf10bmac_eth_addr[0] == 0x00 && 501 sc->nf10bmac_eth_addr[1] == 0x00 && 502 sc->nf10bmac_eth_addr[2] == 0x00 && 503 sc->nf10bmac_eth_addr[3] == 0x00 && 504 sc->nf10bmac_eth_addr[4] == 0x00 && 505 sc->nf10bmac_eth_addr[5] == 0x00) { 506 memcpy(&sc->nf10bmac_eth_addr, "\0NFBSD", ETHER_ADDR_LEN); 507 sc->nf10bmac_eth_addr[5] += sc->nf10bmac_unit; 508 } 509 510 return (0); 511} 512 513static void 514nf10bmac_init_locked(struct nf10bmac_softc *sc) 515{ 516 struct ifnet *ifp; 517 uint8_t *eaddr; 518 519 NF10BMAC_LOCK_ASSERT(sc); 520 ifp = sc->nf10bmac_ifp; 521 522 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 523 return; 524 525 /* 526 * Must update the ether address if changed. Given we do not handle 527 * in nf10bmac_ioctl() but it's in the general framework, just always 528 * do it here before nf10bmac_reset(). 529 */ 530 eaddr = IF_LLADDR(sc->nf10bmac_ifp); 531 bcopy(eaddr, &sc->nf10bmac_eth_addr, ETHER_ADDR_LEN); 532 /* XXX-BZ we do not have any way to tell the NIC our ether address. */ 533 534 /* Make things frind to halt, cleanup, ... */ 535 nf10bmac_stop_locked(sc); 536 /* ... reset, ... */ 537 nf10bmac_reset(sc); 538 539 /* Memory rings? DMA engine? MC filter? MII? */ 540 /* Instead drain the FIFO; or at least a possible first packet.. */ 541 nf10bmac_eat_packet_munch_munch(sc); 542 543#ifdef DEVICE_POLLING 544 /* Only enable interrupts if we are not polling. */ 545 if (ifp->if_capenable & IFCAP_POLLING) { 546 NF10BMAC_RX_INTR_CLEAR_DIS(sc); 547 } else 548#endif 549 { 550 NF10BMAC_RX_INTR_ENABLE(sc); 551 } 552 553 ifp->if_drv_flags |= IFF_DRV_RUNNING; 554 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 555 556 /* We have no underlying media, fake link state. */ 557 sc->nf10bmac_flags = NF10BMAC_FLAGS_LINK; /* Always up. */ 558 if_link_state_change(sc->nf10bmac_ifp, LINK_STATE_UP); 559 560#ifdef ENABLE_WATCHDOG 561 callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc); 562#endif 563} 564 565static void 566nf10bmac_init(void *xsc) 567{ 568 struct nf10bmac_softc *sc; 569 570 sc = (struct nf10bmac_softc *)xsc; 571 NF10BMAC_LOCK(sc); 572 nf10bmac_init_locked(sc); 573 NF10BMAC_UNLOCK(sc); 574} 575 576#ifdef ENABLE_WATCHDOG 577static void 578nf10bmac_watchdog(struct nf10bmac_softc *sc) 579{ 580 581 NF10BMAC_LOCK_ASSERT(sc); 582 583 if (sc->nf10bmac_watchdog_timer == 0 || --sc->nf10bmac_watchdog_timer > 0) 584 return; 585 586 device_printf(sc->nf10bmac_dev, "watchdog timeout\n"); 587 sc->nf10if_inc_counter(bmac_ifp, IFCOUNTER_OERRORS, 1); 588 589 sc->nf10bmac_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 590 nf10bmac_init_locked(sc); 591 592 if (!IFQ_DRV_IS_EMPTY(&sc->nf10bmac_ifp->if_snd)) 593 nf10bmac_start_locked(sc->nf10bmac_ifp); 594} 595 596static void 597nf10bmac_tick(void *xsc) 598{ 599 struct nf10bmac_softc *sc; 600 struct ifnet *ifp; 601 602 sc = (struct nf10bmac_softc *)xsc; 603 NF10BMAC_LOCK_ASSERT(sc); 604 ifp = sc->nf10bmac_ifp; 605 606 nf10bmac_watchdog(sc); 607 callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc); 608} 609#endif 610 611static void 612nf10bmac_intr(void *arg) 613{ 614 struct nf10bmac_softc *sc; 615 struct ifnet *ifp; 616 int rx_npkts; 617 618 sc = (struct nf10bmac_softc *)arg; 619 ifp = sc->nf10bmac_ifp; 620 621 NF10BMAC_LOCK(sc); 622#ifdef DEVICE_POLLING 623 if (ifp->if_capenable & IFCAP_POLLING) { 624 NF10BMAC_UNLOCK(sc); 625 return; 626 } 627#endif 628 629 /* NF10BMAC_RX_INTR_DISABLE(sc); */ 630 NF10BMAC_RX_INTR_CLEAR_DIS(sc); 631 632 /* We only have an RX interrupt and no status information. */ 633 rx_npkts = 0; 634 while (rx_npkts < NF10BMAC_MAX_PKTS) { 635 int c; 636 637 c = nf10bmac_rx_locked(sc); 638 rx_npkts += c; 639 if (c == 0) 640 break; 641 } 642 643 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 644 /* Re-enable interrupts. */ 645 NF10BMAC_RX_INTR_ENABLE(sc); 646 647 if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 648 nf10bmac_start_locked(ifp); 649 } 650 NF10BMAC_UNLOCK(sc); 651} 652 653 654#ifdef DEVICE_POLLING 655static int 656nf10bmac_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 657{ 658 struct nf10bmac_softc *sc; 659 int rx_npkts = 0; 660 661 sc = ifp->if_softc; 662 NF10BMAC_LOCK(sc); 663 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 664 NF10BMAC_UNLOCK(sc); 665 return (rx_npkts); 666 } 667 668 while (rx_npkts < count) { 669 int c; 670 671 c = nf10bmac_rx_locked(sc); 672 rx_npkts += c; 673 if (c == 0) 674 break; 675 } 676 nf10bmac_start_locked(ifp); 677 678 if (rx_npkts > 0 || cmd == POLL_AND_CHECK_STATUS) { 679 /* We currently cannot do much. */ 680 ; 681 } 682 683 NF10BMAC_UNLOCK(sc); 684 return (rx_npkts); 685} 686#else 687#error We only support polling mode 688#endif /* DEVICE_POLLING */ 689 690static int 691nf10bmac_media_change(struct ifnet *ifp __unused) 692{ 693 694 /* Do nothing. */ 695 return (0); 696} 697 698static void 699nf10bmac_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr) 700{ 701 702 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 703 imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX; 704} 705 706static int 707nf10bmac_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 708{ 709 struct nf10bmac_softc *sc; 710 struct ifreq *ifr; 711 int error, mask; 712 713 error = 0; 714 sc = ifp->if_softc; 715 ifr = (struct ifreq *)data; 716 717 switch (command) { 718 case SIOCSIFFLAGS: 719 NF10BMAC_LOCK(sc); 720 if (ifp->if_flags & IFF_UP) { 721 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 722 ((ifp->if_flags ^ sc->nf10bmac_if_flags) & 723 (IFF_PROMISC | IFF_ALLMULTI)) != 0) 724 /* Nothing we can do. */ ; 725 else 726 nf10bmac_init_locked(sc); 727 } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 728 nf10bmac_stop_locked(sc); 729 sc->nf10bmac_if_flags = ifp->if_flags; 730 NF10BMAC_UNLOCK(sc); 731 break; 732 case SIOCSIFCAP: 733 NF10BMAC_LOCK(sc); 734 mask = ifr->ifr_reqcap ^ ifp->if_capenable; 735#ifdef DEVICE_POLLING 736 if ((mask & IFCAP_POLLING) != 0 && 737 (IFCAP_POLLING & ifp->if_capabilities) != 0) { 738 ifp->if_capenable ^= IFCAP_POLLING; 739 if ((IFCAP_POLLING & ifp->if_capenable) != 0) { 740 741 error = ether_poll_register(nf10bmac_poll, ifp); 742 if (error != 0) { 743 NF10BMAC_UNLOCK(sc); 744 break; 745 } 746 747 NF10BMAC_RX_INTR_CLEAR_DIS(sc); 748 749 /* 750 * Do not allow disabling of polling if we do 751 * not have interrupts. 752 */ 753 } else if (sc->nf10bmac_rx_irq_res != NULL) { 754 error = ether_poll_deregister(ifp); 755 /* Enable interrupts. */ 756 NF10BMAC_RX_INTR_ENABLE(sc); 757 } else { 758 ifp->if_capenable ^= IFCAP_POLLING; 759 error = EINVAL; 760 } 761 } 762#endif /* DEVICE_POLLING */ 763 NF10BMAC_UNLOCK(sc); 764 break; 765 case SIOCGIFMEDIA: 766 case SIOCSIFMEDIA: 767 error = ifmedia_ioctl(ifp, ifr, &sc->nf10bmac_media, command); 768 break; 769 default: 770 error = ether_ioctl(ifp, command, data); 771 break; 772 } 773 774 return (error); 775} 776 777/* 778 * Generic device handling routines. 779 */ 780int 781nf10bmac_attach(device_t dev) 782{ 783 struct nf10bmac_softc *sc; 784 struct ifnet *ifp; 785 int error; 786 787 sc = device_get_softc(dev); 788 789 mtx_init(&sc->nf10bmac_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 790 MTX_DEF); 791 792#ifdef ENABLE_WATCHDOG 793 callout_init_mtx(&sc->nf10bmac_tick, &sc->nf10bmac_mtx, 0); 794#endif 795 796 sc->nf10bmac_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK); 797 798 /* Reset the adapter. */ 799 nf10bmac_reset(sc); 800 801 /* Setup interface. */ 802 ifp = sc->nf10bmac_ifp = if_alloc(IFT_ETHER); 803 if (ifp == NULL) { 804 device_printf(dev, "if_alloc() failed\n"); 805 error = ENOSPC; 806 goto err; 807 } 808 ifp->if_softc = sc; 809 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 810 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; /* | IFF_MULTICAST; */ 811 ifp->if_ioctl = nf10bmac_ioctl; 812 ifp->if_start = nf10bmac_start; 813 ifp->if_init = nf10bmac_init; 814 IFQ_SET_MAXLEN(&ifp->if_snd, NF10BMAC_MAX_PKTS - 1); 815 ifp->if_snd.ifq_drv_maxlen = NF10BMAC_MAX_PKTS - 1; 816 IFQ_SET_READY(&ifp->if_snd); 817 818 /* Call media-indepedent attach routine. */ 819 ether_ifattach(ifp, sc->nf10bmac_eth_addr); 820 821 /* Tell the upper layer(s) about vlan mtu support. */ 822 ifp->if_hdrlen = sizeof(struct ether_vlan_header); 823 ifp->if_capabilities |= IFCAP_VLAN_MTU; 824 ifp->if_capenable = ifp->if_capabilities; 825#ifdef DEVICE_POLLING 826 /* We will enable polling by default if no irqs available. See below. */ 827 ifp->if_capabilities |= IFCAP_POLLING; 828#endif 829 830 /* We need more media attention. Fake it! */ 831 ifmedia_init(&sc->nf10bmac_media, 0, nf10bmac_media_change, 832 nf10bmac_media_status); 833 ifmedia_add(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T, 0, NULL); 834 ifmedia_set(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T); 835 836 /* Initialise. */ 837 error = 0; 838 839 /* Hook up interrupts. Well the one. */ 840 if (sc->nf10bmac_rx_irq_res != NULL) { 841 error = bus_setup_intr(dev, sc->nf10bmac_rx_irq_res, 842 INTR_TYPE_NET | INTR_MPSAFE, NULL, nf10bmac_intr, 843 sc, &sc->nf10bmac_rx_intrhand); 844 if (error != 0) { 845 device_printf(dev, "enabling RX IRQ failed\n"); 846 ether_ifdetach(ifp); 847 goto err; 848 } 849 } 850 851 if ((ifp->if_capenable & IFCAP_POLLING) != 0 || 852 sc->nf10bmac_rx_irq_res == NULL) { 853#ifdef DEVICE_POLLING 854 /* If not on and no IRQs force it on. */ 855 if (sc->nf10bmac_rx_irq_res == NULL) { 856 ifp->if_capenable |= IFCAP_POLLING; 857 device_printf(dev, 858 "forcing to polling due to no interrupts\n"); 859 } 860 error = ether_poll_register(nf10bmac_poll, ifp); 861 if (error != 0) 862 goto err; 863#else 864 device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n"); 865 error = ENXIO; 866#endif 867 } else { 868 NF10BMAC_RX_INTR_ENABLE(sc); 869 } 870 871err: 872 if (error != 0) 873 nf10bmac_detach(dev); 874 875 return (error); 876} 877 878static int 879nf10bmac_detach(device_t dev) 880{ 881 struct nf10bmac_softc *sc; 882 struct ifnet *ifp; 883 884 sc = device_get_softc(dev); 885 KASSERT(mtx_initialized(&sc->nf10bmac_mtx), 886 ("%s: mutex not initialized", device_get_nameunit(dev))); 887 ifp = sc->nf10bmac_ifp; 888 889#ifdef DEVICE_POLLING 890 if (ifp->if_capenable & IFCAP_POLLING) 891 ether_poll_deregister(ifp); 892#endif 893 894 /* Only cleanup if attach succeeded. */ 895 if (device_is_attached(dev)) { 896 NF10BMAC_LOCK(sc); 897 nf10bmac_stop_locked(sc); 898 NF10BMAC_UNLOCK(sc); 899#ifdef ENABLE_WATCHDOG 900 callout_drain(&sc->nf10bmac_tick); 901#endif 902 ether_ifdetach(ifp); 903 } 904 905 if (sc->nf10bmac_rx_intrhand) 906 bus_teardown_intr(dev, sc->nf10bmac_rx_irq_res, 907 sc->nf10bmac_rx_intrhand); 908 909 if (ifp != NULL) 910 if_free(ifp); 911 ifmedia_removeall(&sc->nf10bmac_media); 912 913 mtx_destroy(&sc->nf10bmac_mtx); 914 915 return (0); 916} 917 918/* Shared with the attachment specific (e.g., fdt) implementation. */ 919void 920nf10bmac_detach_resources(device_t dev) 921{ 922 struct nf10bmac_softc *sc; 923 924 sc = device_get_softc(dev); 925 926 if (sc->nf10bmac_rx_irq_res != NULL) { 927 bus_release_resource(dev, SYS_RES_IRQ, sc->nf10bmac_rx_irq_rid, 928 sc->nf10bmac_rx_irq_res); 929 sc->nf10bmac_rx_irq_res = NULL; 930 } 931 if (sc->nf10bmac_intr_res != NULL) { 932 bus_release_resource(dev, SYS_RES_MEMORY, 933 sc->nf10bmac_intr_rid, sc->nf10bmac_intr_res); 934 sc->nf10bmac_intr_res = NULL; 935 } 936 if (sc->nf10bmac_rx_mem_res != NULL) { 937 bus_release_resource(dev, SYS_RES_MEMORY, 938 sc->nf10bmac_rx_mem_rid, sc->nf10bmac_rx_mem_res); 939 sc->nf10bmac_rx_mem_res = NULL; 940 } 941 if (sc->nf10bmac_tx_mem_res != NULL) { 942 bus_release_resource(dev, SYS_RES_MEMORY, 943 sc->nf10bmac_tx_mem_rid, sc->nf10bmac_tx_mem_res); 944 sc->nf10bmac_tx_mem_res = NULL; 945 } 946 if (sc->nf10bmac_ctrl_res != NULL) { 947 bus_release_resource(dev, SYS_RES_MEMORY, 948 sc->nf10bmac_ctrl_rid, sc->nf10bmac_ctrl_res); 949 sc->nf10bmac_ctrl_res = NULL; 950 } 951} 952 953int 954nf10bmac_detach_dev(device_t dev) 955{ 956 int error; 957 958 error = nf10bmac_detach(dev); 959 if (error) { 960 /* We are basically in undefined state now. */ 961 device_printf(dev, "nf10bmac_detach() failed: %d\n", error); 962 return (error); 963 } 964 965 nf10bmac_detach_resources(dev); 966 967 return (0); 968} 969 970/* end */ 971