if_nf10bmac.c revision 264601
1251875Speter/*- 2251875Speter * Copyright (c) 2012-2014 Bjoern A. Zeeb 3251875Speter * All rights reserved. 4251875Speter * 5251875Speter * This software was developed by SRI International and the University of 6251875Speter * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 7251875Speter * ("MRC2"), as part of the DARPA MRC research programme. 8251875Speter * 9251875Speter * Redistribution and use in source and binary forms, with or without 10251875Speter * modification, are permitted provided that the following conditions 11251875Speter * are met: 12251875Speter * 1. Redistributions of source code must retain the above copyright 13251875Speter * notice, this list of conditions and the following disclaimer. 14251875Speter * 2. Redistributions in binary form must reproduce the above copyright 15251875Speter * notice, this list of conditions and the following disclaimer in the 16251875Speter * documentation and/or other materials provided with the distribution. 17251875Speter * 18251875Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19251875Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20251875Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21251875Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22251875Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23251875Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24251875Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25251875Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26251875Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27251875Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28251875Speter * SUCH DAMAGE. 29251875Speter * 30251875Speter * This driver is modelled after atse(4). We need to seriously reduce the 31251875Speter * per-driver code we have to write^wcopy & paste. 32251875Speter * 33251875Speter * TODO: 34251875Speter * - figure out on the HW side why some data is LE and some is BE. 35251875Speter * - general set of improvements possible (e.g., reduce times of copying, 36251875Speter * do on-the-copy checksum calculations) 37251875Speter */ 38251875Speter 39251875Speter#include <sys/cdefs.h> 40251875Speter__FBSDID("$FreeBSD: head/sys/dev/netfpga10g/nf10bmac/if_nf10bmac.c 264601 2014-04-17 12:33:26Z bz $"); 41251875Speter 42251875Speter#include "opt_device_polling.h" 43251875Speter 44251875Speter#include <sys/param.h> 45251875Speter#include <sys/systm.h> 46251875Speter#include <sys/kernel.h> 47251875Speter#include <sys/bus.h> 48251875Speter#include <sys/endian.h> 49251875Speter#include <sys/lock.h> 50251875Speter#include <sys/module.h> 51251875Speter#include <sys/mutex.h> 52251875Speter#include <sys/proc.h> 53251875Speter#include <sys/socket.h> 54251875Speter#include <sys/sockio.h> 55251875Speter#include <sys/types.h> 56251875Speter 57251875Speter#include <net/ethernet.h> 58251875Speter#include <net/if.h> 59251875Speter#include <net/if_var.h> 60251875Speter#include <net/if_dl.h> 61251875Speter#include <net/if_media.h> 62251875Speter#include <net/if_types.h> 63251875Speter#include <net/if_vlan_var.h> 64251875Speter 65251875Speter#include <net/bpf.h> 66251875Speter 67251875Speter#include <machine/bus.h> 68251875Speter#include <machine/resource.h> 69251875Speter#include <sys/rman.h> 70251875Speter 71251875Speter#include "if_nf10bmacreg.h" 72251875Speter 73251875Speter#ifndef NF10BMAC_MAX_PKTS 74251875Speter/* 75251875Speter * We have a 4k buffer in HW, so do not try to send more than 3 packets. 76251875Speter * At the time of writing HW is orders of magnitude faster than we can 77251875Speter * enqueue so it would not matter but need an escape. 78251875Speter */ 79251875Speter#define NF10BMAC_MAX_PKTS 3 80251875Speter#endif 81251875Speter 82251875Speter#ifndef NF10BMAC_WATCHDOG_TIME 83251875Speter#define NF10BMAC_WATCHDOG_TIME 5 /* seconds */ 84251875Speter#endif 85251875Speter 86251875Speter#ifdef DEVICE_POLLING 87251875Speterstatic poll_handler_t nf10bmac_poll; 88251875Speter#endif 89251875Speter 90251875Speter#define NF10BMAC_LOCK(_sc) mtx_lock(&(_sc)->nf10bmac_mtx) 91251875Speter#define NF10BMAC_UNLOCK(_sc) mtx_unlock(&(_sc)->nf10bmac_mtx) 92251875Speter#define NF10BMAC_LOCK_ASSERT(_sc) \ 93251875Speter mtx_assert(&(_sc)->nf10bmac_mtx, MA_OWNED) 94251875Speter 95251875Speter#define NF10BMAC_TX_LEN 0x08 96251875Speter#define NF10BMAC_TX_META 0x04 97251875Speter#define NF10BMAC_TX_DATA 0x00 98251875Speter#define NF10BMAC_RX_LEN 0x08 99251875Speter#define NF10BMAC_RX_META 0x04 100251875Speter#define NF10BMAC_RX_DATA 0x00 101251875Speter#define NF10BMAC_CTRL0 0x00 102251875Speter 103251875Speter#define NF10BMAC_TUSER_MAC0 (1 << 0) 104251875Speter#define NF10BMAC_TUSER_CPU0 (1 << 1) 105251875Speter#define NF10BMAC_TUSER_MAC1 (1 << 2) 106251875Speter#define NF10BMAC_TUSER_CPU1 (1 << 3) 107251875Speter#define NF10BMAC_TUSER_MAC2 (1 << 4) 108251875Speter#define NF10BMAC_TUSER_CPU2 (1 << 5) 109251875Speter#define NF10BMAC_TUSER_MAC3 (1 << 6) 110251875Speter#define NF10BMAC_TUSER_CPU3 (1 << 7) 111251875Speter 112251875Speter#define NF10BMAC_DATA_DPORT_MASK 0xff000000 113251875Speter#define NF10BMAC_DATA_DPORT_SHIFT 24 114251875Speter#define NF10BMAC_DATA_SPORT_MASK 0x00ff0000 115251875Speter#define NF10BMAC_DATA_SPORT_SHIFT 16 116251875Speter#define NF10BMAC_DATA_LAST 0x00000080 117251875Speter#define NF10BMAC_DATA_STRB 0x0000000f 118251875Speter 119251875Speter 120251875Speterstatic inline void 121251875Speternf10bmac_write_4(struct resource *res, uint32_t reg, uint32_t val4, 122251875Speter const char *f __unused, const int l __unused) 123251875Speter{ 124251875Speter 125251875Speter bus_write_4(res, reg, htole32(val4)); 126251875Speter} 127251875Speter 128251875Speterstatic inline uint32_t 129251875Speternf10bmac_read_4(struct resource *res, uint32_t reg, 130251875Speter const char *f __unused, const int l __unused) 131251875Speter{ 132251875Speter 133251875Speter return (le32toh(bus_read_4(res, reg))); 134251875Speter} 135251875Speter 136251875Speterstatic inline void 137251875Speternf10bmac_write_4_be(struct resource *res, uint32_t reg, uint32_t val4, 138251875Speter const char *f __unused, const int l __unused) 139251875Speter{ 140251875Speter 141251875Speter bus_write_4(res, reg, htobe32(val4)); 142251875Speter} 143251875Speter 144251875Speter 145251875Speterstatic inline uint32_t 146251875Speternf10bmac_read_4_be(struct resource *res, uint32_t reg, 147251875Speter const char *f __unused, const int l __unused) 148251875Speter{ 149251875Speter 150251875Speter return (be32toh(bus_read_4(res, reg))); 151251875Speter} 152251875Speter 153251875Speter#define NF10BMAC_WRITE_CTRL_4(sc, reg, val) \ 154251875Speter nf10bmac_write_4((sc)->nf10bmac_mem_res, (reg), (val), \ 155251875Speter __func__, __LINE__) 156251875Speter#define NF10BMAC_WRITE_4(sc, reg, val) \ 157251875Speter nf10bmac_write_4((sc)->nf10bmac_tx_mem_res, (reg), (val), \ 158251875Speter __func__, __LINE__) 159251875Speter#define NF10BMAC_READ_4(sc, reg) \ 160251875Speter nf10bmac_read_4((sc)->nf10bmac_rx_mem_res, (reg), \ 161251875Speter __func__, __LINE__) 162251875Speter#define NF10BMAC_WRITE_4_BE(sc, reg, val) \ 163251875Speter nf10bmac_write_4_be((sc)->nf10bmac_tx_mem_res, (reg), (val), \ 164251875Speter __func__, __LINE__) 165251875Speter#define NF10BMAC_READ_4_BE(sc, reg) \ 166251875Speter nf10bmac_read_4_be((sc)->nf10bmac_rx_mem_res, (reg), \ 167251875Speter __func__, __LINE__) 168251875Speter 169251875Speter#ifdef ENABLE_WATCHDOG 170251875Speterstatic void nf10bmac_tick(void *); 171251875Speter#endif 172251875Speterstatic int nf10bmac_detach(device_t); 173251875Speter 174251875Speterdevclass_t nf10bmac_devclass; 175251875Speter 176251875Speter 177251875Speterstatic int 178251875Speternf10bmac_tx_locked(struct nf10bmac_softc *sc, struct mbuf *m) 179251875Speter{ 180251875Speter int32_t len, l, ml; 181251875Speter uint32_t m4, val4; 182251875Speter 183251875Speter NF10BMAC_LOCK_ASSERT(sc); 184251875Speter 185251875Speter KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc)); 186251875Speter KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m)); 187251875Speter /* 188251875Speter * Copy to buffer to minimize our pain as we can only store 189251875Speter * double words which, after the first mbuf gets out of alignment 190251875Speter * quite quickly. 191251875Speter */ 192251875Speter m_copydata(m, 0, m->m_pkthdr.len, sc->nf10bmac_tx_buf); 193251875Speter len = m->m_pkthdr.len; 194251875Speter 195251875Speter /* Write the length at start of packet. */ 196251875Speter NF10BMAC_WRITE_4(sc, NF10BMAC_TX_LEN, len); 197251875Speter 198251875Speter /* Write the meta data and data. */ 199251875Speter ml = len / sizeof(val4); 200251875Speter len -= (ml * sizeof(val4)); 201251875Speter for (l = 0; l <= ml; l++) { 202251875Speter int32_t cl; 203251875Speter 204251875Speter cl = sizeof(val4); 205251875Speter m4 = (NF10BMAC_TUSER_CPU0 << NF10BMAC_DATA_SPORT_SHIFT); 206251875Speter if (l == ml || (len == 0 && l == (ml - 1))) { 207251875Speter if (l == ml && len == 0) { 208251875Speter break; 209251875Speter } else { 210251875Speter uint8_t s; 211251875Speter int sl; 212251875Speter 213251875Speter if (l == (ml - 1)) 214251875Speter len = 4; 215251875Speter cl = len; 216251875Speter 217251875Speter for (s = 0, sl = len; sl > 0; sl--) 218251875Speter s |= (1 << (sl - 1)); 219251875Speter m4 |= (s & NF10BMAC_DATA_STRB); 220251875Speter m4 |= NF10BMAC_DATA_LAST; 221251875Speter } 222251875Speter } else { 223251875Speter m4 |= NF10BMAC_DATA_STRB; 224251875Speter } 225251875Speter NF10BMAC_WRITE_4(sc, NF10BMAC_TX_META, m4); 226251875Speter bcopy(&sc->nf10bmac_tx_buf[l*sizeof(val4)], &val4, cl); 227251875Speter NF10BMAC_WRITE_4_BE(sc, NF10BMAC_TX_DATA, val4); 228251875Speter } 229251875Speter 230251875Speter /* If anyone is interested give them a copy. */ 231251875Speter BPF_MTAP(sc->nf10bmac_ifp, m); 232251875Speter 233251875Speter m_freem(m); 234251875Speter 235251875Speter return (0); 236251875Speter} 237251875Speter 238251875Speterstatic void 239251875Speternf10bmac_start_locked(struct ifnet *ifp) 240251875Speter{ 241251875Speter struct nf10bmac_softc *sc; 242251875Speter int count, error; 243251875Speter 244 sc = ifp->if_softc; 245 NF10BMAC_LOCK_ASSERT(sc); 246 247 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 248 IFF_DRV_RUNNING || (sc->nf10bmac_flags & NF10BMAC_FLAGS_LINK) == 0) 249 return; 250 251#ifdef ENABLE_WATCHDOG 252 /* 253 * Disable the watchdog while sending, we are batching packets. 254 * Though we should never reach 5 seconds, and are holding the lock, 255 * but who knows. 256 */ 257 sc->nf10bmac_watchdog_timer = 0; 258#endif 259 260 /* Send up to MAX_PKTS_PER_TX_LOOP packets. */ 261 for (count = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 262 count < NF10BMAC_MAX_PKTS; count++) { 263 struct mbuf *m; 264 265 IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 266 if (m == NULL) 267 break; 268 error = nf10bmac_tx_locked(sc, m); 269 if (error != 0) 270 break; 271 } 272 273#ifdef ENABLE_WATCHDOG 274done: 275 /* If the IP core walks into Nekromanteion try to bail out. */ 276 /* XXX-BZ useless until we have direct FIFO fill status feedback. */ 277 if (count > 0) 278 sc->nf10bmac_watchdog_timer = NF10BMAC_WATCHDOG_TIME; 279#endif 280} 281 282static void 283nf10bmac_start(struct ifnet *ifp) 284{ 285 struct nf10bmac_softc *sc; 286 287 sc = ifp->if_softc; 288 NF10BMAC_LOCK(sc); 289 nf10bmac_start_locked(ifp); 290 NF10BMAC_UNLOCK(sc); 291} 292 293static void 294nf10bmac_eat_packet_munch_munch(struct nf10bmac_softc *sc) 295{ 296 uint32_t m4, val4; 297 298 do { 299 m4 = NF10BMAC_READ_4_BE(sc, NF10BMAC_RX_META); 300 if ((m4 & NF10BMAC_DATA_STRB) != 0) 301 val4 = NF10BMAC_READ_4_BE(sc, NF10BMAC_RX_DATA); 302 } while ((m4 & NF10BMAC_DATA_STRB) != 0 && 303 (m4 & NF10BMAC_DATA_LAST) == 0); 304} 305 306static int 307nf10bmac_rx_locked(struct nf10bmac_softc *sc) 308{ 309 struct ifnet *ifp; 310 struct mbuf *m; 311 uint32_t m4, val4; 312 int32_t len, l; 313 314 /* 315 * General problem here in case we need to sync ourselves to the 316 * beginning of a packet. Length will only be set for the first 317 * read, and together with strb we can detect the begining (or 318 * skip to tlast). 319 */ 320 321 len = NF10BMAC_READ_4(sc, NF10BMAC_RX_LEN); 322 if (len > (MCLBYTES - ETHER_ALIGN)) { 323 nf10bmac_eat_packet_munch_munch(sc); 324 return (0); 325 } 326 327 m4 = NF10BMAC_READ_4(sc, NF10BMAC_RX_META); 328 if (len == 0 && (m4 & NF10BMAC_DATA_STRB) == 0) { 329 /* No packet data available. */ 330 return (0); 331 } else if (len == 0 && (m4 & NF10BMAC_DATA_STRB) != 0) { 332 /* We are in the middle of a packet. */ 333 nf10bmac_eat_packet_munch_munch(sc); 334 return (0); 335 } else if ((m4 & NF10BMAC_DATA_STRB) == 0) { 336 /* Invalid length "hint". */ 337 device_printf(sc->nf10bmac_dev, 338 "Unexpected length %d on zero strb\n", len); 339 return (0); 340 } 341 342 /* Assume at this point that we have data and a full packet. */ 343 if ((len + ETHER_ALIGN) >= MINCLSIZE) { 344 /* Get a cluster. */ 345 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 346 if (m == NULL) 347 return (0); 348 m->m_len = m->m_pkthdr.len = MCLBYTES; 349 } else { 350 /* Hey this still fits into the mbuf+pkthdr. */ 351 m = m_gethdr(M_NOWAIT, MT_DATA); 352 if (m == NULL) 353 return (0); 354 m->m_len = m->m_pkthdr.len = MHLEN; 355 } 356 /* Make sure upper layers will be aligned. */ 357 m_adj(m, ETHER_ALIGN); 358 359 ifp = sc->nf10bmac_ifp; 360 l = 0; 361/* 362 while ((m4 & NF10BMAC_DATA_STRB) != 0 && l < len) { 363*/ 364 while (l < len) { 365 size_t cl; 366 367 if ((m4 & NF10BMAC_DATA_LAST) == 0 && 368 (len - l) < sizeof(val4)) { 369 /* 370 * Our length and LAST disagree. We have a valid STRB. 371 * We could continue until we fill the mbuf and just 372 * log the invlid length "hint". For now drop the 373 * packet on the floor and count the error. 374 */ 375 nf10bmac_eat_packet_munch_munch(sc); 376 ifp->if_ierrors++; 377 m_freem(m); 378 return (0); 379 } else if ((len - l) <= sizeof(val4)) { 380 cl = len - l; 381 } else { 382 cl = sizeof(val4); 383 } 384 385 /* Read the first bytes of data as well. */ 386 val4 = NF10BMAC_READ_4_BE(sc, NF10BMAC_RX_DATA); 387 bcopy(&val4, (uint8_t *)(m->m_data + l), cl); 388 l += cl; 389 390 if ((m4 & NF10BMAC_DATA_LAST) != 0 || l >= len) 391 break; 392 else { 393 DELAY(50); 394 m4 = NF10BMAC_READ_4(sc, NF10BMAC_RX_META); 395 } 396 397 cl = 10; 398 while ((m4 & NF10BMAC_DATA_STRB) == 0 && cl-- > 0) { 399 DELAY(10); 400 m4 = NF10BMAC_READ_4(sc, NF10BMAC_RX_META); 401 } 402 } 403 /* We should get out of this loop with tlast and tsrb. */ 404 if ((m4 & NF10BMAC_DATA_LAST) == 0 || (m4 & NF10BMAC_DATA_STRB) == 0) { 405 device_printf(sc->nf10bmac_dev, "Unexpected rx loop end state: " 406 "m4=0x%08x len=%d l=%d\n", m4, len, l); 407 ifp->if_ierrors++; 408 m_freem(m); 409 return (0); 410 } 411 412 m->m_pkthdr.len = m->m_len = len; 413 m->m_pkthdr.rcvif = ifp; 414 ifp->if_ipackets++; 415 416 NF10BMAC_UNLOCK(sc); 417 (*ifp->if_input)(ifp, m); 418 NF10BMAC_LOCK(sc); 419 420 return (1); 421} 422 423 424static int 425nf10bmac_stop_locked(struct nf10bmac_softc *sc) 426{ 427 struct ifnet *ifp; 428 429 NF10BMAC_LOCK_ASSERT(sc); 430 431#ifdef ENABLE_WATCHDOG 432 sc->nf10bmac_watchdog_timer = 0; 433 callout_stop(&sc->nf10bmac_tick); 434#endif 435 436 ifp = sc->nf10bmac_ifp; 437 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 438 439 sc->nf10bmac_flags &= ~NF10BMAC_FLAGS_LINK; 440 if_link_state_change(ifp, LINK_STATE_DOWN); 441 442 return (0); 443} 444 445static int 446nf10bmac_reset(struct nf10bmac_softc *sc) 447{ 448 449 /* Currently we cannot do anything. */ 450 return (0); 451} 452 453static void 454nf10bmac_init_locked(struct nf10bmac_softc *sc) 455{ 456 struct ifnet *ifp; 457 uint8_t *eaddr; 458 459 NF10BMAC_LOCK_ASSERT(sc); 460 ifp = sc->nf10bmac_ifp; 461 462 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 463 return; 464 465 /* 466 * Must update the ether address if changed. Given we do not handle 467 * in nf10bmac_ioctl() but it's in the general framework, just always 468 * do it here before nf10bmac_reset(). 469 */ 470 eaddr = IF_LLADDR(sc->nf10bmac_ifp); 471 bcopy(eaddr, &sc->nf10bmac_eth_addr, ETHER_ADDR_LEN); 472 /* XXX-BZ we do not have any way to tell the NIC our ether address. */ 473 474 /* Make things frind to halt, cleanup, ... */ 475 nf10bmac_stop_locked(sc); 476 /* ... reset, ... */ 477 nf10bmac_reset(sc); 478 479 /* Memory rings? DMA engine? MC filter? MII? */ 480 /* Instead drain the FIFO; or at least a possible first packet.. */ 481 nf10bmac_eat_packet_munch_munch(sc); 482 483 ifp->if_drv_flags |= IFF_DRV_RUNNING; 484 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 485 486 /* We have no underlying media, fake link state. */ 487 sc->nf10bmac_flags = NF10BMAC_FLAGS_LINK; /* Always up. */ 488 if_link_state_change(sc->nf10bmac_ifp, LINK_STATE_UP); 489 490#ifdef ENABLE_WATCHDOG 491 callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc); 492#endif 493} 494 495static void 496nf10bmac_init(void *xsc) 497{ 498 struct nf10bmac_softc *sc; 499 500 sc = (struct nf10bmac_softc *)xsc; 501 NF10BMAC_LOCK(sc); 502 nf10bmac_init_locked(sc); 503 NF10BMAC_UNLOCK(sc); 504} 505 506#ifdef ENABLE_WATCHDOG 507static void 508nf10bmac_watchdog(struct nf10bmac_softc *sc) 509{ 510 511 NF10BMAC_LOCK_ASSERT(sc); 512 513 if (sc->nf10bmac_watchdog_timer == 0 || --sc->nf10bmac_watchdog_timer > 0) 514 return; 515 516 device_printf(sc->nf10bmac_dev, "watchdog timeout\n"); 517 sc->nf10bmac_ifp->if_oerrors++; 518 519 sc->nf10bmac_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 520 nf10bmac_init_locked(sc); 521 522 if (!IFQ_DRV_IS_EMPTY(&sc->nf10bmac_ifp->if_snd)) 523 nf10bmac_start_locked(sc->nf10bmac_ifp); 524} 525 526static void 527nf10bmac_tick(void *xsc) 528{ 529 struct nf10bmac_softc *sc; 530 struct ifnet *ifp; 531 532 sc = (struct nf10bmac_softc *)xsc; 533 NF10BMAC_LOCK_ASSERT(sc); 534 ifp = sc->nf10bmac_ifp; 535 536 nf10bmac_watchdog(sc); 537 callout_reset(&sc->nf10bmac_tick, hz, nf10bmac_tick, sc); 538} 539#endif 540 541#ifdef DEVICE_POLLING 542static int 543nf10bmac_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 544{ 545 struct nf10bmac_softc *sc; 546 int rx_npkts = 0; 547 548 sc = ifp->if_softc; 549 NF10BMAC_LOCK(sc); 550 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 551 NF10BMAC_UNLOCK(sc); 552 return (rx_npkts); 553 } 554 555 while (rx_npkts < count) { 556 int c; 557 558 c = nf10bmac_rx_locked(sc); 559 rx_npkts += c; 560 if (c == 0) 561 break; 562 } 563 nf10bmac_start_locked(ifp); 564 565 if (rx_npkts > 0 || cmd == POLL_AND_CHECK_STATUS) { 566 /* We currently cannot do much. */ 567 ; 568 } 569 570 NF10BMAC_UNLOCK(sc); 571 return (rx_npkts); 572} 573#else 574#error We only support polling mode 575#endif /* DEVICE_POLLING */ 576 577static int 578nf10bmac_media_change(struct ifnet *ifp __unused) 579{ 580 581 /* Do nothing. */ 582 return (0); 583} 584 585static void 586nf10bmac_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr) 587{ 588 589 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 590 imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX; 591} 592 593static int 594nf10bmac_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 595{ 596 struct nf10bmac_softc *sc; 597 struct ifreq *ifr; 598 int error, mask; 599 600 error = 0; 601 sc = ifp->if_softc; 602 ifr = (struct ifreq *)data; 603 604 switch (command) { 605 case SIOCSIFFLAGS: 606 NF10BMAC_LOCK(sc); 607 if (ifp->if_flags & IFF_UP) { 608 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 609 ((ifp->if_flags ^ sc->nf10bmac_if_flags) & 610 (IFF_PROMISC | IFF_ALLMULTI)) != 0) 611 /* Nothing we can do. */ ; 612 else 613 nf10bmac_init_locked(sc); 614 } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 615 nf10bmac_stop_locked(sc); 616 sc->nf10bmac_if_flags = ifp->if_flags; 617 NF10BMAC_UNLOCK(sc); 618 break; 619 case SIOCSIFCAP: 620 NF10BMAC_LOCK(sc); 621 mask = ifr->ifr_reqcap ^ ifp->if_capenable; 622#ifdef DEVICE_POLLING 623 if ((mask & IFCAP_POLLING) != 0 && 624 (IFCAP_POLLING & ifp->if_capabilities) != 0) { 625 ifp->if_capenable ^= IFCAP_POLLING; 626 if ((IFCAP_POLLING & ifp->if_capenable) != 0) { 627 628 error = ether_poll_register(nf10bmac_poll, ifp); 629 if (error != 0) { 630 NF10BMAC_UNLOCK(sc); 631 break; 632 } 633 634 /* 635 * Do not allow disabling of polling if we do 636 * not have interrupts. 637 */ 638 } else { 639 ifp->if_capenable ^= IFCAP_POLLING; 640 error = EINVAL; 641 } 642 } 643#endif /* DEVICE_POLLING */ 644 NF10BMAC_UNLOCK(sc); 645 break; 646 case SIOCGIFMEDIA: 647 case SIOCSIFMEDIA: 648 error = ifmedia_ioctl(ifp, ifr, &sc->nf10bmac_media, command); 649 break; 650 default: 651 error = ether_ioctl(ifp, command, data); 652 break; 653 } 654 655 return (error); 656} 657 658 659/* 660 * Generic device handling routines. 661 */ 662int 663nf10bmac_attach(device_t dev) 664{ 665 struct nf10bmac_softc *sc; 666 struct ifnet *ifp; 667 int error; 668 669 sc = device_get_softc(dev); 670 671 mtx_init(&sc->nf10bmac_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 672 MTX_DEF); 673 674#ifdef ENABLE_WATCHDOG 675 callout_init_mtx(&sc->nf10bmac_tick, &sc->nf10bmac_mtx, 0); 676#endif 677 678 sc->nf10bmac_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK); 679 680 /* Reset the adapter. */ 681 nf10bmac_reset(sc); 682 683 /* Setup interface. */ 684 ifp = sc->nf10bmac_ifp = if_alloc(IFT_ETHER); 685 if (ifp == NULL) { 686 device_printf(dev, "if_alloc() failed\n"); 687 error = ENOSPC; 688 goto err; 689 } 690 ifp->if_softc = sc; 691 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 692 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; /* | IFF_MULTICAST; */ 693 ifp->if_ioctl = nf10bmac_ioctl; 694 ifp->if_start = nf10bmac_start; 695 ifp->if_init = nf10bmac_init; 696 IFQ_SET_MAXLEN(&ifp->if_snd, NF10BMAC_MAX_PKTS - 1); 697 ifp->if_snd.ifq_drv_maxlen = NF10BMAC_MAX_PKTS - 1; 698 IFQ_SET_READY(&ifp->if_snd); 699 700 /* Call media-indepedent attach routine. */ 701 ether_ifattach(ifp, sc->nf10bmac_eth_addr); 702 703 /* Tell the upper layer(s) about vlan mtu support. */ 704 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 705 ifp->if_capabilities |= IFCAP_VLAN_MTU; 706 ifp->if_capenable = ifp->if_capabilities; 707#ifdef DEVICE_POLLING 708 /* We will enable polling by default if no irqs available. See below. */ 709 ifp->if_capabilities |= IFCAP_POLLING; 710#endif 711 712 /* We need more media attention. Fake it! */ 713 ifmedia_init(&sc->nf10bmac_media, 0, nf10bmac_media_change, 714 nf10bmac_media_status); 715 ifmedia_add(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T, 0, NULL); 716 ifmedia_set(&sc->nf10bmac_media, IFM_ETHER | IFM_10G_T); 717 718 /* Interrupts would go here. */ 719 720#ifdef DEVICE_POLLING 721 ifp->if_capenable |= IFCAP_POLLING; 722 device_printf(dev, "forcing to polling due to no interrupts\n"); 723 error = ether_poll_register(nf10bmac_poll, ifp); 724 if (error != 0) 725 goto err; 726#else 727 device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n"); 728 error = ENXIO; 729#endif 730 731err: 732 if (error != 0) 733 nf10bmac_detach(dev); 734 735 return (error); 736} 737 738static int 739nf10bmac_detach(device_t dev) 740{ 741 struct nf10bmac_softc *sc; 742 struct ifnet *ifp; 743 744 sc = device_get_softc(dev); 745 KASSERT(mtx_initialized(&sc->nf10bmac_mtx), 746 ("%s: mutex not initialized", device_get_nameunit(dev))); 747 ifp = sc->nf10bmac_ifp; 748 749#ifdef DEVICE_POLLING 750 if (ifp->if_capenable & IFCAP_POLLING) 751 ether_poll_deregister(ifp); 752#endif 753 754 /* Only cleanup if attach succeeded. */ 755 if (device_is_attached(dev)) { 756 NF10BMAC_LOCK(sc); 757 nf10bmac_stop_locked(sc); 758 NF10BMAC_UNLOCK(sc); 759#ifdef ENABLE_WATCHDOG 760 callout_drain(&sc->nf10bmac_tick); 761#endif 762 ether_ifdetach(ifp); 763 } 764 765 if (ifp != NULL) 766 if_free(ifp); 767 ifmedia_removeall(&sc->nf10bmac_media); 768 769 mtx_destroy(&sc->nf10bmac_mtx); 770 771 return (0); 772} 773 774/* Shared with the attachment specific (e.g., fdt) implementation. */ 775void 776nf10bmac_detach_resources(device_t dev) 777{ 778 struct nf10bmac_softc *sc; 779 780 sc = device_get_softc(dev); 781 782 if (sc->nf10bmac_mem_res != NULL) { 783 bus_release_resource(dev, SYS_RES_MEMORY, 784 sc->nf10bmac_mem_rid, sc->nf10bmac_mem_res); 785 sc->nf10bmac_mem_res = NULL; 786 } 787 if (sc->nf10bmac_rx_mem_res != NULL) { 788 bus_release_resource(dev, SYS_RES_MEMORY, 789 sc->nf10bmac_rx_mem_rid, sc->nf10bmac_rx_mem_res); 790 sc->nf10bmac_rx_mem_res = NULL; 791 } 792 if (sc->nf10bmac_tx_mem_res != NULL) { 793 bus_release_resource(dev, SYS_RES_MEMORY, 794 sc->nf10bmac_tx_mem_rid, sc->nf10bmac_tx_mem_res); 795 sc->nf10bmac_tx_mem_res = NULL; 796 } 797} 798 799int 800nf10bmac_detach_dev(device_t dev) 801{ 802 int error; 803 804 error = nf10bmac_detach(dev); 805 if (error) { 806 /* We are basically in undefined state now. */ 807 device_printf(dev, "nf10bmac_detach() failed: %d\n", error); 808 return (error); 809 } 810 811 nf10bmac_detach_resources(dev); 812 813 return (0); 814} 815 816/* end */ 817