1256752Sbrooks/*- 2256752Sbrooks * Copyright (c) 2012,2013 Bjoern A. Zeeb 3271969Sbz * Copyright (c) 2014 Robert N. M. Watson 4256752Sbrooks * All rights reserved. 5256752Sbrooks * 6256752Sbrooks * This software was developed by SRI International and the University of 7256752Sbrooks * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) 8256752Sbrooks * ("MRC2"), as part of the DARPA MRC research programme. 9256752Sbrooks * 10256752Sbrooks * Redistribution and use in source and binary forms, with or without 11256752Sbrooks * modification, are permitted provided that the following conditions 12256752Sbrooks * are met: 13256752Sbrooks * 1. Redistributions of source code must retain the above copyright 14256752Sbrooks * notice, this list of conditions and the following disclaimer. 15256752Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 16256752Sbrooks * notice, this list of conditions and the following disclaimer in the 17256752Sbrooks * documentation and/or other materials provided with the distribution. 18256752Sbrooks * 19256752Sbrooks * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20256752Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21256752Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22256752Sbrooks * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23256752Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24256752Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25256752Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26256752Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27256752Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28256752Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29256752Sbrooks * SUCH DAMAGE. 30256752Sbrooks */ 31256752Sbrooks/* 32256752Sbrooks * Altera Triple-Speed Ethernet MegaCore, Function User Guide 33256752Sbrooks * UG-01008-3.0, Software Version: 12.0, June 2012. 34256752Sbrooks * Available at the time of writing at: 35256752Sbrooks * http://www.altera.com/literature/ug/ug_ethernet.pdf 36256752Sbrooks * 37256752Sbrooks * We are using an Marvell E1111 (Alaska) PHY on the DE4. See mii/e1000phy.c. 38256752Sbrooks */ 39256752Sbrooks/* 40256752Sbrooks * XXX-BZ NOTES: 41256752Sbrooks * - ifOutBroadcastPkts are only counted if both ether dst and src are all-1s; 42256752Sbrooks * seems an IP core bug, they count ether broadcasts as multicast. Is this 43256752Sbrooks * still the case? 44256752Sbrooks * - figure out why the TX FIFO fill status and intr did not work as expected. 45256752Sbrooks * - test 100Mbit/s and 10Mbit/s 46256752Sbrooks * - blacklist the one special factory programmed ethernet address (for now 47256752Sbrooks * hardcoded, later from loader?) 48256752Sbrooks * - resolve all XXX, left as reminders to shake out details later 49256752Sbrooks * - Jumbo frame support 50256752Sbrooks */ 51256752Sbrooks 52256752Sbrooks#include <sys/cdefs.h> 53256752Sbrooks__FBSDID("$FreeBSD$"); 54256752Sbrooks 55256752Sbrooks#include "opt_device_polling.h" 56256752Sbrooks 57256752Sbrooks#include <sys/param.h> 58256752Sbrooks#include <sys/systm.h> 59256752Sbrooks#include <sys/kernel.h> 60256752Sbrooks#include <sys/bus.h> 61256752Sbrooks#include <sys/endian.h> 62256752Sbrooks#include <sys/jail.h> 63256752Sbrooks#include <sys/lock.h> 64256752Sbrooks#include <sys/module.h> 65256752Sbrooks#include <sys/mutex.h> 66256752Sbrooks#include <sys/proc.h> 67256752Sbrooks#include <sys/socket.h> 68256752Sbrooks#include <sys/sockio.h> 69256752Sbrooks#include <sys/types.h> 70256752Sbrooks 71256752Sbrooks#include <net/ethernet.h> 72256752Sbrooks#include <net/if.h> 73256752Sbrooks#include <net/if_var.h> 74256752Sbrooks#include <net/if_dl.h> 75256752Sbrooks#include <net/if_media.h> 76256752Sbrooks#include <net/if_types.h> 77256752Sbrooks#include <net/if_vlan_var.h> 78256752Sbrooks 79256752Sbrooks#include <net/bpf.h> 80256752Sbrooks 81256752Sbrooks#include <machine/bus.h> 82256752Sbrooks#include <machine/resource.h> 83256752Sbrooks#include <sys/rman.h> 84256752Sbrooks 85256752Sbrooks#include <dev/mii/mii.h> 86256752Sbrooks#include <dev/mii/miivar.h> 87256752Sbrooks 88256752Sbrooks#include <dev/altera/atse/if_atsereg.h> 89256752Sbrooks#include <dev/altera/atse/a_api.h> 90256752Sbrooks 91256752SbrooksMODULE_DEPEND(atse, ether, 1, 1, 1); 92256752SbrooksMODULE_DEPEND(atse, miibus, 1, 1, 1); 93256752Sbrooks 94256752Sbrooks 95256752Sbrooks#define ATSE_WATCHDOG_TIME 5 96256752Sbrooks 97256752Sbrooks#ifdef DEVICE_POLLING 98256752Sbrooksstatic poll_handler_t atse_poll; 99256752Sbrooks#endif 100256752Sbrooks 101256752Sbrooks/* XXX once we'd do parallel attach, we need a global lock for this. */ 102256752Sbrooks#define ATSE_ETHERNET_OPTION_BITS_UNDEF 0 103256752Sbrooks#define ATSE_ETHERNET_OPTION_BITS_READ 1 104256752Sbrooksstatic int atse_ethernet_option_bits_flag = ATSE_ETHERNET_OPTION_BITS_UNDEF; 105256752Sbrooksstatic uint8_t atse_ethernet_option_bits[ALTERA_ETHERNET_OPTION_BITS_LEN]; 106256752Sbrooks 107271969Sbzstatic int atse_intr_debug_enable = 0; 108271969SbzSYSCTL_INT(_debug, OID_AUTO, atse_intr_debug_enable, CTLFLAG_RW, 109271969Sbz &atse_intr_debug_enable, 0, 110271969Sbz "Extra debugging output for atse interrupts"); 111271969Sbz 112256752Sbrooks/* 113256752Sbrooks * Softc and critical resource locking. 114256752Sbrooks */ 115256752Sbrooks#define ATSE_LOCK(_sc) mtx_lock(&(_sc)->atse_mtx) 116256752Sbrooks#define ATSE_UNLOCK(_sc) mtx_unlock(&(_sc)->atse_mtx) 117256752Sbrooks#define ATSE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->atse_mtx, MA_OWNED) 118256752Sbrooks 119271969Sbz#define ATSE_TX_PENDING(sc) (sc->atse_tx_m != NULL || \ 120271969Sbz !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 121271969Sbz 122256752Sbrooks#ifdef DEBUG 123256752Sbrooks#define DPRINTF(format, ...) printf(format, __VA_ARGS__) 124256752Sbrooks#else 125256752Sbrooks#define DPRINTF(format, ...) 126256752Sbrooks#endif 127256752Sbrooks 128256752Sbrooks/* a_api.c functions; factor out? */ 129256752Sbrooksstatic inline void 130256752Sbrooksa_onchip_fifo_mem_core_write(struct resource *res, uint32_t off, 131256752Sbrooks uint32_t val4, const char *desc, const char *f, const int l) 132256752Sbrooks{ 133256752Sbrooks 134256752Sbrooks val4 = htole32(val4); 135256752Sbrooks DPRINTF("[%s:%d] FIFOW %s 0x%08x = 0x%08x\n", f, l, desc, off, val4); 136256752Sbrooks bus_write_4(res, off, val4); 137256752Sbrooks} 138256752Sbrooksstatic inline uint32_t 139256752Sbrooksa_onchip_fifo_mem_core_read(struct resource *res, uint32_t off, 140256752Sbrooks const char *desc, const char *f, const int l) 141256752Sbrooks{ 142256752Sbrooks uint32_t val4; 143256752Sbrooks 144256752Sbrooks val4 = le32toh(bus_read_4(res, off)); 145256752Sbrooks DPRINTF("[%s:%d] FIFOR %s 0x%08x = 0x%08x\n", f, l, desc, off, val4); 146256752Sbrooks return (val4); 147256752Sbrooks} 148256752Sbrooks 149256752Sbrooks/* The FIFO does an endian convertion, so we must not do it as well. */ 150256752Sbrooks/* XXX-BZ in fact we should do a htobe32 so le would be fine as well? */ 151256752Sbrooks#define ATSE_TX_DATA_WRITE(sc, val4) \ 152256752Sbrooks bus_write_4((sc)->atse_tx_mem_res, A_ONCHIP_FIFO_MEM_CORE_DATA, val4) 153256752Sbrooks 154256752Sbrooks#define ATSE_TX_META_WRITE(sc, val4) \ 155256752Sbrooks a_onchip_fifo_mem_core_write((sc)->atse_tx_mem_res, \ 156256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_METADATA, \ 157256752Sbrooks (val4), "TXM", __func__, __LINE__) 158256752Sbrooks#define ATSE_TX_META_READ(sc) \ 159256752Sbrooks a_onchip_fifo_mem_core_read((sc)->atse_tx_mem_res, \ 160256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_METADATA, \ 161256752Sbrooks "TXM", __func__, __LINE__) 162256752Sbrooks 163256752Sbrooks#define ATSE_TX_READ_FILL_LEVEL(sc) \ 164256752Sbrooks a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ 165256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL, \ 166256752Sbrooks "TX_FILL", __func__, __LINE__) 167256752Sbrooks#define ATSE_RX_READ_FILL_LEVEL(sc) \ 168256752Sbrooks a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ 169256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL, \ 170256752Sbrooks "RX_FILL", __func__, __LINE__) 171256752Sbrooks 172256752Sbrooks/* The FIFO does an endian convertion, so we must not do it as well. */ 173256752Sbrooks/* XXX-BZ in fact we shoudl do a htobe32 so le would be fine as well? */ 174256752Sbrooks#define ATSE_RX_DATA_READ(sc) \ 175256752Sbrooks bus_read_4((sc)->atse_rx_mem_res, A_ONCHIP_FIFO_MEM_CORE_DATA) 176256752Sbrooks#define ATSE_RX_META_READ(sc) \ 177256752Sbrooks a_onchip_fifo_mem_core_read((sc)->atse_rx_mem_res, \ 178256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_METADATA, \ 179256752Sbrooks "RXM", __func__, __LINE__) 180256752Sbrooks 181271969Sbz#define ATSE_RX_STATUS_READ(sc) \ 182271969Sbz a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ 183271969Sbz A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS, \ 184271969Sbz "RX_EVENT", __func__, __LINE__) 185271969Sbz 186271969Sbz#define ATSE_TX_STATUS_READ(sc) \ 187271969Sbz a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ 188271969Sbz A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS, \ 189271969Sbz "TX_EVENT", __func__, __LINE__) 190271969Sbz 191256752Sbrooks#define ATSE_RX_EVENT_READ(sc) \ 192256752Sbrooks a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ 193256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ 194256752Sbrooks "RX_EVENT", __func__, __LINE__) 195256752Sbrooks 196256752Sbrooks#define ATSE_TX_EVENT_READ(sc) \ 197256752Sbrooks a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ 198256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ 199256752Sbrooks "TX_EVENT", __func__, __LINE__) 200256752Sbrooks 201256752Sbrooks#define ATSE_RX_EVENT_CLEAR(sc) \ 202256752Sbrooks do { \ 203256752Sbrooks uint32_t val4; \ 204256752Sbrooks \ 205256752Sbrooks val4 = a_onchip_fifo_mem_core_read( \ 206256752Sbrooks (sc)->atse_rxc_mem_res, \ 207256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ 208256752Sbrooks "RX_EVENT", __func__, __LINE__); \ 209256752Sbrooks if (val4 != 0x00) \ 210256752Sbrooks a_onchip_fifo_mem_core_write( \ 211256752Sbrooks (sc)->atse_rxc_mem_res, \ 212256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ 213256752Sbrooks val4, "RX_EVENT", __func__, __LINE__); \ 214256752Sbrooks } while(0) 215256752Sbrooks#define ATSE_TX_EVENT_CLEAR(sc) \ 216256752Sbrooks do { \ 217256752Sbrooks uint32_t val4; \ 218256752Sbrooks \ 219256752Sbrooks val4 = a_onchip_fifo_mem_core_read( \ 220256752Sbrooks (sc)->atse_txc_mem_res, \ 221256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ 222256752Sbrooks "TX_EVENT", __func__, __LINE__); \ 223256752Sbrooks if (val4 != 0x00) \ 224256752Sbrooks a_onchip_fifo_mem_core_write( \ 225256752Sbrooks (sc)->atse_txc_mem_res, \ 226256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ 227256752Sbrooks val4, "TX_EVENT", __func__, __LINE__); \ 228256752Sbrooks } while(0) 229256752Sbrooks 230271969Sbz#define ATSE_RX_EVENTS (A_ONCHIP_FIFO_MEM_CORE_INTR_FULL | \ 231271969Sbz A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW | \ 232271969Sbz A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW) 233256752Sbrooks#define ATSE_RX_INTR_ENABLE(sc) \ 234256752Sbrooks a_onchip_fifo_mem_core_write((sc)->atse_rxc_mem_res, \ 235256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ 236271969Sbz ATSE_RX_EVENTS, \ 237256752Sbrooks "RX_INTR", __func__, __LINE__) /* XXX-BZ review later. */ 238256752Sbrooks#define ATSE_RX_INTR_DISABLE(sc) \ 239256752Sbrooks a_onchip_fifo_mem_core_write((sc)->atse_rxc_mem_res, \ 240256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, 0, \ 241256752Sbrooks "RX_INTR", __func__, __LINE__) 242271969Sbz#define ATSE_RX_INTR_READ(sc) \ 243271969Sbz a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ 244271969Sbz A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ 245271969Sbz "RX_INTR", __func__, __LINE__) 246271969Sbz 247271969Sbz#define ATSE_TX_EVENTS (A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY | \ 248271969Sbz A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW | \ 249271969Sbz A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW) 250256752Sbrooks#define ATSE_TX_INTR_ENABLE(sc) \ 251256752Sbrooks a_onchip_fifo_mem_core_write((sc)->atse_txc_mem_res, \ 252256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ 253271969Sbz ATSE_TX_EVENTS, \ 254256752Sbrooks "TX_INTR", __func__, __LINE__) /* XXX-BZ review later. */ 255256752Sbrooks#define ATSE_TX_INTR_DISABLE(sc) \ 256256752Sbrooks a_onchip_fifo_mem_core_write((sc)->atse_txc_mem_res, \ 257256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, 0, \ 258256752Sbrooks "TX_INTR", __func__, __LINE__) 259271969Sbz#define ATSE_TX_INTR_READ(sc) \ 260271969Sbz a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ 261271969Sbz A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ 262271969Sbz "TX_INTR", __func__, __LINE__) 263256752Sbrooks 264271969Sbzstatic int atse_rx_locked(struct atse_softc *sc); 265271969Sbz 266256752Sbrooks/* 267256752Sbrooks * Register space access macros. 268256752Sbrooks */ 269256752Sbrooksstatic inline void 270256752Sbrookscsr_write_4(struct atse_softc *sc, uint32_t reg, uint32_t val4, 271256752Sbrooks const char *f, const int l) 272256752Sbrooks{ 273256752Sbrooks 274256752Sbrooks val4 = htole32(val4); 275256752Sbrooks DPRINTF("[%s:%d] CSR W %s 0x%08x (0x%08x) = 0x%08x\n", f, l, 276256752Sbrooks "atse_mem_res", reg, reg * 4, val4); 277256752Sbrooks bus_write_4(sc->atse_mem_res, reg * 4, val4); 278256752Sbrooks} 279256752Sbrooks 280256752Sbrooksstatic inline uint32_t 281256752Sbrookscsr_read_4(struct atse_softc *sc, uint32_t reg, const char *f, const int l) 282256752Sbrooks{ 283256752Sbrooks uint32_t val4; 284256752Sbrooks 285256752Sbrooks val4 = le32toh(bus_read_4(sc->atse_mem_res, reg * 4)); 286256752Sbrooks DPRINTF("[%s:%d] CSR R %s 0x%08x (0x%08x) = 0x%08x\n", f, l, 287256752Sbrooks "atse_mem_res", reg, reg * 4, val4); 288256752Sbrooks return (val4); 289256752Sbrooks} 290256752Sbrooks 291256752Sbrooks/* 292256752Sbrooks * See page 5-2 that it's all dword offsets and the MS 16 bits need to be zero 293256752Sbrooks * on write and ignored on read. 294256752Sbrooks */ 295256752Sbrooksstatic inline void 296256752Sbrookspxx_write_2(struct atse_softc *sc, bus_addr_t bmcr, uint32_t reg, uint16_t val, 297256752Sbrooks const char *f, const int l, const char *s) 298256752Sbrooks{ 299256752Sbrooks uint32_t val4; 300256752Sbrooks 301256752Sbrooks val4 = htole32(val & 0x0000ffff); 302256752Sbrooks DPRINTF("[%s:%d] %s W %s 0x%08x (0x%08jx) = 0x%08x\n", f, l, s, 303256752Sbrooks "atse_mem_res", reg, (bmcr + reg) * 4, val4); 304256752Sbrooks bus_write_4(sc->atse_mem_res, (bmcr + reg) * 4, val4); 305256752Sbrooks} 306256752Sbrooks 307256752Sbrooksstatic inline uint16_t 308256752Sbrookspxx_read_2(struct atse_softc *sc, bus_addr_t bmcr, uint32_t reg, const char *f, 309256752Sbrooks const int l, const char *s) 310256752Sbrooks{ 311256752Sbrooks uint32_t val4; 312256752Sbrooks uint16_t val; 313256752Sbrooks 314256752Sbrooks val4 = bus_read_4(sc->atse_mem_res, (bmcr + reg) * 4); 315256752Sbrooks val = le32toh(val4) & 0x0000ffff; 316256752Sbrooks DPRINTF("[%s:%d] %s R %s 0x%08x (0x%08jx) = 0x%04x\n", f, l, s, 317256752Sbrooks "atse_mem_res", reg, (bmcr + reg) * 4, val); 318256752Sbrooks return (val); 319256752Sbrooks} 320256752Sbrooks 321256752Sbrooks#define CSR_WRITE_4(sc, reg, val) \ 322256752Sbrooks csr_write_4((sc), (reg), (val), __func__, __LINE__) 323256752Sbrooks#define CSR_READ_4(sc, reg) \ 324256752Sbrooks csr_read_4((sc), (reg), __func__, __LINE__) 325256752Sbrooks#define PCS_WRITE_2(sc, reg, val) \ 326256752Sbrooks pxx_write_2((sc), sc->atse_bmcr0, (reg), (val), __func__, __LINE__, \ 327256752Sbrooks "PCS") 328256752Sbrooks#define PCS_READ_2(sc, reg) \ 329256752Sbrooks pxx_read_2((sc), sc->atse_bmcr0, (reg), __func__, __LINE__, "PCS") 330256752Sbrooks#define PHY_WRITE_2(sc, reg, val) \ 331256752Sbrooks pxx_write_2((sc), sc->atse_bmcr1, (reg), (val), __func__, __LINE__, \ 332256752Sbrooks "PHY") 333256752Sbrooks#define PHY_READ_2(sc, reg) \ 334256752Sbrooks pxx_read_2((sc), sc->atse_bmcr1, (reg), __func__, __LINE__, "PHY") 335256752Sbrooks 336256752Sbrooksstatic void atse_tick(void *); 337256752Sbrooksstatic int atse_detach(device_t); 338256752Sbrooks 339256752Sbrooksdevclass_t atse_devclass; 340256752Sbrooks 341256752Sbrooksstatic int 342256752Sbrooksatse_tx_locked(struct atse_softc *sc, int *sent) 343256752Sbrooks{ 344256752Sbrooks struct mbuf *m; 345256752Sbrooks uint32_t val4, fill_level; 346256752Sbrooks int c; 347256752Sbrooks 348256752Sbrooks ATSE_LOCK_ASSERT(sc); 349256752Sbrooks 350256752Sbrooks m = sc->atse_tx_m; 351256752Sbrooks KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc)); 352256752Sbrooks KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m)); 353256752Sbrooks 354256752Sbrooks /* 355256752Sbrooks * Copy to buffer to minimize our pain as we can only store 356256752Sbrooks * double words which, after the first mbuf gets out of alignment 357256752Sbrooks * quite quickly. 358256752Sbrooks */ 359256752Sbrooks if (sc->atse_tx_m_offset == 0) { 360256752Sbrooks m_copydata(m, 0, m->m_pkthdr.len, sc->atse_tx_buf); 361256752Sbrooks sc->atse_tx_buf_len = m->m_pkthdr.len; 362256752Sbrooks } 363256752Sbrooks 364256752Sbrooks fill_level = ATSE_TX_READ_FILL_LEVEL(sc); 365256752Sbrooks#if 0 /* Returns 0xdeadc0de. */ 366256752Sbrooks val4 = ATSE_TX_META_READ(sc); 367256752Sbrooks#endif 368256752Sbrooks if (sc->atse_tx_m_offset == 0) { 369256752Sbrooks /* Write start of packet. */ 370256752Sbrooks val4 = A_ONCHIP_FIFO_MEM_CORE_SOP; 371256752Sbrooks val4 &= ~A_ONCHIP_FIFO_MEM_CORE_EOP; 372256752Sbrooks ATSE_TX_META_WRITE(sc, val4); 373256752Sbrooks } 374256752Sbrooks 375256752Sbrooks /* TX FIFO is single clock mode, so we have the full FIFO. */ 376256752Sbrooks c = 0; 377256752Sbrooks while ((sc->atse_tx_buf_len - sc->atse_tx_m_offset) > 4 && 378256752Sbrooks fill_level < AVALON_FIFO_TX_BASIC_OPTS_DEPTH) { 379256752Sbrooks 380256752Sbrooks bcopy(&sc->atse_tx_buf[sc->atse_tx_m_offset], &val4, 381256752Sbrooks sizeof(val4)); 382256752Sbrooks ATSE_TX_DATA_WRITE(sc, val4); 383256752Sbrooks sc->atse_tx_m_offset += sizeof(val4); 384256752Sbrooks c += sizeof(val4); 385256752Sbrooks 386256752Sbrooks fill_level++; 387256752Sbrooks if (fill_level == AVALON_FIFO_TX_BASIC_OPTS_DEPTH) 388256752Sbrooks fill_level = ATSE_TX_READ_FILL_LEVEL(sc); 389256752Sbrooks } 390256752Sbrooks if (sent != NULL) 391256752Sbrooks *sent += c; 392256752Sbrooks 393256752Sbrooks /* Set EOP *before* writing the last symbol. */ 394256752Sbrooks if (sc->atse_tx_m_offset >= (sc->atse_tx_buf_len - 4) && 395256752Sbrooks fill_level < AVALON_FIFO_TX_BASIC_OPTS_DEPTH) { 396256752Sbrooks int leftm; 397256752Sbrooks uint32_t x; 398256752Sbrooks 399256752Sbrooks /* Set EndOfPacket. */ 400256752Sbrooks val4 = A_ONCHIP_FIFO_MEM_CORE_EOP; 401256752Sbrooks /* Set EMPTY. */ 402256752Sbrooks leftm = sc->atse_tx_buf_len - sc->atse_tx_m_offset; 403256752Sbrooks val4 |= ((4 - leftm) << A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT); 404256752Sbrooks x = val4; 405256752Sbrooks ATSE_TX_META_WRITE(sc, val4); 406256752Sbrooks 407256752Sbrooks /* Write last symbol. */ 408256752Sbrooks val4 = 0; 409256752Sbrooks bcopy(sc->atse_tx_buf + sc->atse_tx_m_offset, &val4, leftm); 410256752Sbrooks ATSE_TX_DATA_WRITE(sc, val4); 411256752Sbrooks 412256752Sbrooks if (sent != NULL) 413256752Sbrooks *sent += leftm; 414256752Sbrooks 415256752Sbrooks /* OK, the packet is gone. */ 416256752Sbrooks sc->atse_tx_m = NULL; 417256752Sbrooks sc->atse_tx_m_offset = 0; 418256752Sbrooks 419256752Sbrooks /* If anyone is interested give them a copy. */ 420256752Sbrooks BPF_MTAP(sc->atse_ifp, m); 421256752Sbrooks 422256752Sbrooks m_freem(m); 423256752Sbrooks return (0); 424256752Sbrooks } 425256752Sbrooks 426256752Sbrooks return (EBUSY); 427256752Sbrooks} 428256752Sbrooks 429256752Sbrooksstatic void 430256752Sbrooksatse_start_locked(struct ifnet *ifp) 431256752Sbrooks{ 432256752Sbrooks struct atse_softc *sc; 433256752Sbrooks int error, sent; 434256752Sbrooks 435256752Sbrooks sc = ifp->if_softc; 436256752Sbrooks ATSE_LOCK_ASSERT(sc); 437256752Sbrooks 438256752Sbrooks if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 439256752Sbrooks IFF_DRV_RUNNING || (sc->atse_flags & ATSE_FLAGS_LINK) == 0) 440256752Sbrooks return; 441256752Sbrooks 442256752Sbrooks#if 1 443256752Sbrooks /* 444256752Sbrooks * Disable the watchdog while sending, we are batching packets. 445256752Sbrooks * Though we should never reach 5 seconds, and are holding the lock, 446256752Sbrooks * but who knows. 447256752Sbrooks */ 448256752Sbrooks sc->atse_watchdog_timer = 0; 449256752Sbrooks#endif 450256752Sbrooks 451256752Sbrooks if (sc->atse_tx_m != NULL) { 452256752Sbrooks error = atse_tx_locked(sc, &sent); 453256752Sbrooks if (error != 0) 454256752Sbrooks goto done; 455256752Sbrooks } 456256752Sbrooks /* We have more space to send so continue ... */ 457256752Sbrooks for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 458256752Sbrooks 459256752Sbrooks IFQ_DRV_DEQUEUE(&ifp->if_snd, sc->atse_tx_m); 460256752Sbrooks sc->atse_tx_m_offset = 0; 461256752Sbrooks if (sc->atse_tx_m == NULL) 462256752Sbrooks break; 463256752Sbrooks error = atse_tx_locked(sc, &sent); 464256752Sbrooks if (error != 0) 465256752Sbrooks goto done; 466256752Sbrooks } 467256752Sbrooks 468256752Sbrooksdone: 469256752Sbrooks /* If the IP core walks into Nekromanteion try to bail out. */ 470256752Sbrooks if (sent > 0) 471256752Sbrooks sc->atse_watchdog_timer = ATSE_WATCHDOG_TIME; 472256752Sbrooks} 473256752Sbrooks 474256752Sbrooksstatic void 475256752Sbrooksatse_start(struct ifnet *ifp) 476256752Sbrooks{ 477256752Sbrooks struct atse_softc *sc; 478256752Sbrooks 479256752Sbrooks sc = ifp->if_softc; 480256752Sbrooks ATSE_LOCK(sc); 481256752Sbrooks atse_start_locked(ifp); 482256752Sbrooks ATSE_UNLOCK(sc); 483256752Sbrooks} 484256752Sbrooks 485256752Sbrooksstatic int 486256752Sbrooksatse_stop_locked(struct atse_softc *sc) 487256752Sbrooks{ 488256752Sbrooks struct ifnet *ifp; 489256752Sbrooks uint32_t mask, val4; 490256752Sbrooks int i; 491256752Sbrooks 492256752Sbrooks ATSE_LOCK_ASSERT(sc); 493256752Sbrooks 494256752Sbrooks sc->atse_watchdog_timer = 0; 495256752Sbrooks callout_stop(&sc->atse_tick); 496256752Sbrooks 497256752Sbrooks ifp = sc->atse_ifp; 498256752Sbrooks ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 499256752Sbrooks ATSE_RX_INTR_DISABLE(sc); 500256752Sbrooks ATSE_TX_INTR_DISABLE(sc); 501256752Sbrooks ATSE_RX_EVENT_CLEAR(sc); 502256752Sbrooks ATSE_TX_EVENT_CLEAR(sc); 503256752Sbrooks 504256752Sbrooks /* Disable MAC transmit and receive datapath. */ 505256752Sbrooks mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA; 506256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 507256752Sbrooks val4 &= ~mask; 508256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 509256752Sbrooks /* Wait for bits to be cleared; i=100 is excessive. */ 510256752Sbrooks for (i = 0; i < 100; i++) { 511256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 512256752Sbrooks if ((val4 & mask) == 0) 513256752Sbrooks break; 514256752Sbrooks DELAY(10); 515256752Sbrooks } 516256752Sbrooks if ((val4 & mask) != 0) 517256752Sbrooks device_printf(sc->atse_dev, "Disabling MAC TX/RX timed out.\n"); 518256752Sbrooks /* Punt. */ 519256752Sbrooks 520256752Sbrooks sc->atse_flags &= ~ATSE_FLAGS_LINK; 521256752Sbrooks 522256752Sbrooks /* XXX-BZ free the RX/TX rings. */ 523256752Sbrooks 524256752Sbrooks return (0); 525256752Sbrooks} 526256752Sbrooks 527256752Sbrooksstatic uint8_t 528256752Sbrooksatse_mchash(struct atse_softc *sc __unused, const uint8_t *addr) 529256752Sbrooks{ 530256752Sbrooks int i, j; 531256752Sbrooks uint8_t x, y; 532256752Sbrooks 533256752Sbrooks x = 0; 534256752Sbrooks for (i = 0; i < ETHER_ADDR_LEN; i++) { 535256752Sbrooks y = addr[i] & 0x01; 536256752Sbrooks for (j = 1; j < 8; j++) 537256752Sbrooks y ^= (addr[i] >> j) & 0x01; 538256752Sbrooks x |= (y << i); 539256752Sbrooks } 540256752Sbrooks return (x); 541256752Sbrooks} 542256752Sbrooks 543256752Sbrooksstatic int 544256752Sbrooksatse_rxfilter_locked(struct atse_softc *sc) 545256752Sbrooks{ 546256752Sbrooks struct ifnet *ifp; 547256752Sbrooks struct ifmultiaddr *ifma; 548256752Sbrooks uint32_t val4; 549256752Sbrooks int i; 550256752Sbrooks 551256752Sbrooks /* XXX-BZ can we find out if we have the MHASH synthesized? */ 552256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 553256752Sbrooks /* For simplicity always hash full 48 bits of addresses. */ 554256752Sbrooks if ((val4 & BASE_CFG_COMMAND_CONFIG_MHASH_SEL) != 0) 555256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_MHASH_SEL; 556256752Sbrooks 557256752Sbrooks ifp = sc->atse_ifp; 558256752Sbrooks if (ifp->if_flags & IFF_PROMISC) 559256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_PROMIS_EN; 560256752Sbrooks else 561256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_PROMIS_EN; 562256752Sbrooks 563256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 564256752Sbrooks 565256752Sbrooks if (ifp->if_flags & IFF_ALLMULTI) { 566256752Sbrooks /* Accept all multicast addresses. */ 567256752Sbrooks for (i = 0; i <= MHASH_LEN; i++) 568256752Sbrooks CSR_WRITE_4(sc, MHASH_START + i, 0x1); 569256752Sbrooks } else { 570256752Sbrooks /* 571256752Sbrooks * Can hold MHASH_LEN entries. 572256752Sbrooks * XXX-BZ bitstring.h would be more general. 573256752Sbrooks */ 574256752Sbrooks uint64_t h; 575256752Sbrooks 576256752Sbrooks h = 0; 577256752Sbrooks /* 578256752Sbrooks * Re-build and re-program hash table. First build the 579256752Sbrooks * bit-field "yes" or "no" for each slot per address, then 580256752Sbrooks * do all the programming afterwards. 581256752Sbrooks */ 582256752Sbrooks if_maddr_rlock(ifp); 583256752Sbrooks TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 584256752Sbrooks if (ifma->ifma_addr->sa_family != AF_LINK) 585256752Sbrooks continue; 586256752Sbrooks 587256752Sbrooks h |= (1 << atse_mchash(sc, 588256752Sbrooks LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); 589256752Sbrooks } 590256752Sbrooks if_maddr_runlock(ifp); 591256752Sbrooks for (i = 0; i <= MHASH_LEN; i++) 592256752Sbrooks CSR_WRITE_4(sc, MHASH_START + i, 593256752Sbrooks (h & (1 << i)) ? 0x01 : 0x00); 594256752Sbrooks } 595256752Sbrooks 596256752Sbrooks return (0); 597256752Sbrooks} 598256752Sbrooks 599256752Sbrooksstatic int 600256752Sbrooksatse_ethernet_option_bits_read_fdt(device_t dev) 601256752Sbrooks{ 602256752Sbrooks struct resource *res; 603256752Sbrooks device_t fdev; 604256752Sbrooks int i, rid; 605256752Sbrooks 606256752Sbrooks if (atse_ethernet_option_bits_flag & ATSE_ETHERNET_OPTION_BITS_READ) 607256752Sbrooks return (0); 608256752Sbrooks 609256752Sbrooks fdev = device_find_child(device_get_parent(dev), "cfi", 0); 610256752Sbrooks if (fdev == NULL) 611256752Sbrooks return (ENOENT); 612256752Sbrooks 613256752Sbrooks rid = 0; 614256752Sbrooks res = bus_alloc_resource_any(fdev, SYS_RES_MEMORY, &rid, 615256752Sbrooks RF_ACTIVE | RF_SHAREABLE); 616256752Sbrooks if (res == NULL) 617256752Sbrooks return (ENXIO); 618256752Sbrooks 619256752Sbrooks for (i = 0; i < ALTERA_ETHERNET_OPTION_BITS_LEN; i++) 620256752Sbrooks atse_ethernet_option_bits[i] = bus_read_1(res, 621256752Sbrooks ALTERA_ETHERNET_OPTION_BITS_OFF + i); 622256752Sbrooks 623256752Sbrooks bus_release_resource(fdev, SYS_RES_MEMORY, rid, res); 624256752Sbrooks atse_ethernet_option_bits_flag |= ATSE_ETHERNET_OPTION_BITS_READ; 625256752Sbrooks 626256752Sbrooks return (0); 627256752Sbrooks} 628256752Sbrooks 629256752Sbrooksstatic int 630256752Sbrooksatse_ethernet_option_bits_read(device_t dev) 631256752Sbrooks{ 632256752Sbrooks int error; 633256752Sbrooks 634256752Sbrooks error = atse_ethernet_option_bits_read_fdt(dev); 635256752Sbrooks if (error == 0) 636256752Sbrooks return (0); 637256752Sbrooks 638256752Sbrooks device_printf(dev, "Cannot read Ethernet addresses from flash.\n"); 639256752Sbrooks return (error); 640256752Sbrooks} 641256752Sbrooks 642256752Sbrooksstatic int 643256752Sbrooksatse_get_eth_address(struct atse_softc *sc) 644256752Sbrooks{ 645256752Sbrooks unsigned long hostid; 646256752Sbrooks uint32_t val4; 647256752Sbrooks int unit; 648256752Sbrooks 649256752Sbrooks /* 650256752Sbrooks * Make sure to only ever do this once. Otherwise a reset would 651256752Sbrooks * possibly change our ethernet address, which is not good at all. 652256752Sbrooks */ 653256752Sbrooks if (sc->atse_eth_addr[0] != 0x00 || sc->atse_eth_addr[1] != 0x00 || 654256752Sbrooks sc->atse_eth_addr[2] != 0x00) 655256752Sbrooks return (0); 656256752Sbrooks 657256752Sbrooks if ((atse_ethernet_option_bits_flag & 658256752Sbrooks ATSE_ETHERNET_OPTION_BITS_READ) == 0) 659256752Sbrooks goto get_random; 660256752Sbrooks 661256752Sbrooks val4 = atse_ethernet_option_bits[0] << 24; 662256752Sbrooks val4 |= atse_ethernet_option_bits[1] << 16; 663256752Sbrooks val4 |= atse_ethernet_option_bits[2] << 8; 664256752Sbrooks val4 |= atse_ethernet_option_bits[3]; 665256752Sbrooks /* They chose "safe". */ 666256752Sbrooks if (val4 != le32toh(0x00005afe)) { 667256752Sbrooks device_printf(sc->atse_dev, "Magic '5afe' is not safe: 0x%08x. " 668256752Sbrooks "Falling back to random numbers for hardware address.\n", 669256752Sbrooks val4); 670256752Sbrooks goto get_random; 671256752Sbrooks } 672256752Sbrooks 673256752Sbrooks sc->atse_eth_addr[0] = atse_ethernet_option_bits[4]; 674256752Sbrooks sc->atse_eth_addr[1] = atse_ethernet_option_bits[5]; 675256752Sbrooks sc->atse_eth_addr[2] = atse_ethernet_option_bits[6]; 676256752Sbrooks sc->atse_eth_addr[3] = atse_ethernet_option_bits[7]; 677256752Sbrooks sc->atse_eth_addr[4] = atse_ethernet_option_bits[8]; 678256752Sbrooks sc->atse_eth_addr[5] = atse_ethernet_option_bits[9]; 679256752Sbrooks 680256752Sbrooks /* Handle factory default ethernet addresss: 00:07:ed:ff:ed:15 */ 681256752Sbrooks if (sc->atse_eth_addr[0] == 0x00 && sc->atse_eth_addr[1] == 0x07 && 682256752Sbrooks sc->atse_eth_addr[2] == 0xed && sc->atse_eth_addr[3] == 0xff && 683256752Sbrooks sc->atse_eth_addr[4] == 0xed && sc->atse_eth_addr[5] == 0x15) { 684256752Sbrooks 685256752Sbrooks device_printf(sc->atse_dev, "Factory programmed Ethernet " 686256752Sbrooks "hardware address blacklisted. Falling back to random " 687256752Sbrooks "address to avoid collisions.\n"); 688256752Sbrooks device_printf(sc->atse_dev, "Please re-program your flash.\n"); 689256752Sbrooks goto get_random; 690256752Sbrooks } 691256752Sbrooks 692256752Sbrooks if (sc->atse_eth_addr[0] == 0x00 && sc->atse_eth_addr[1] == 0x00 && 693256752Sbrooks sc->atse_eth_addr[2] == 0x00 && sc->atse_eth_addr[3] == 0x00 && 694256752Sbrooks sc->atse_eth_addr[4] == 0x00 && sc->atse_eth_addr[5] == 0x00) { 695256752Sbrooks device_printf(sc->atse_dev, "All zero's Ethernet hardware " 696256752Sbrooks "address blacklisted. Falling back to random address.\n"); 697256752Sbrooks device_printf(sc->atse_dev, "Please re-program your flash.\n"); 698256752Sbrooks goto get_random; 699256752Sbrooks } 700256752Sbrooks 701256752Sbrooks if (ETHER_IS_MULTICAST(sc->atse_eth_addr)) { 702256752Sbrooks device_printf(sc->atse_dev, "Multicast Ethernet hardware " 703256752Sbrooks "address blacklisted. Falling back to random address.\n"); 704256752Sbrooks device_printf(sc->atse_dev, "Please re-program your flash.\n"); 705256752Sbrooks goto get_random; 706256752Sbrooks } 707256752Sbrooks 708256752Sbrooks /* 709256752Sbrooks * If we find an Altera prefixed address with a 0x0 ending 710256752Sbrooks * adjust by device unit. If not and this is not the first 711256752Sbrooks * Ethernet, go to random. 712256752Sbrooks */ 713256752Sbrooks unit = device_get_unit(sc->atse_dev); 714256752Sbrooks if (unit == 0x00) 715256752Sbrooks return (0); 716256752Sbrooks 717256752Sbrooks if (unit > 0x0f) { 718256752Sbrooks device_printf(sc->atse_dev, "We do not support Ethernet " 719256752Sbrooks "addresses for more than 16 MACs. Falling back to " 720256752Sbrooks "random hadware address.\n"); 721256752Sbrooks goto get_random; 722256752Sbrooks } 723256752Sbrooks if ((sc->atse_eth_addr[0] & ~0x2) != 0 || 724256752Sbrooks sc->atse_eth_addr[1] != 0x07 || sc->atse_eth_addr[2] != 0xed || 725256752Sbrooks (sc->atse_eth_addr[5] & 0x0f) != 0x0) { 726256752Sbrooks device_printf(sc->atse_dev, "Ethernet address not meeting our " 727256752Sbrooks "multi-MAC standards. Falling back to random hadware " 728256752Sbrooks "address.\n"); 729256752Sbrooks goto get_random; 730256752Sbrooks } 731256752Sbrooks sc->atse_eth_addr[5] |= (unit & 0x0f); 732256752Sbrooks 733256752Sbrooks return (0); 734256752Sbrooks 735256752Sbrooksget_random: 736256752Sbrooks /* 737256752Sbrooks * Fall back to random code we also use on bridge(4). 738256752Sbrooks */ 739256752Sbrooks getcredhostid(curthread->td_ucred, &hostid); 740256752Sbrooks if (hostid == 0) { 741256752Sbrooks arc4rand(sc->atse_eth_addr, ETHER_ADDR_LEN, 1); 742256752Sbrooks sc->atse_eth_addr[0] &= ~1;/* clear multicast bit */ 743256752Sbrooks sc->atse_eth_addr[0] |= 2; /* set the LAA bit */ 744256752Sbrooks } else { 745256752Sbrooks sc->atse_eth_addr[0] = 0x2; 746256752Sbrooks sc->atse_eth_addr[1] = (hostid >> 24) & 0xff; 747256752Sbrooks sc->atse_eth_addr[2] = (hostid >> 16) & 0xff; 748256752Sbrooks sc->atse_eth_addr[3] = (hostid >> 8 ) & 0xff; 749256752Sbrooks sc->atse_eth_addr[4] = hostid & 0xff; 750256752Sbrooks sc->atse_eth_addr[5] = sc->atse_unit & 0xff; 751256752Sbrooks } 752256752Sbrooks 753256752Sbrooks return (0); 754256752Sbrooks} 755256752Sbrooks 756256752Sbrooksstatic int 757256752Sbrooksatse_set_eth_address(struct atse_softc *sc, int n) 758256752Sbrooks{ 759256752Sbrooks uint32_t v0, v1; 760256752Sbrooks 761256752Sbrooks v0 = (sc->atse_eth_addr[3] << 24) | (sc->atse_eth_addr[2] << 16) | 762256752Sbrooks (sc->atse_eth_addr[1] << 8) | sc->atse_eth_addr[0]; 763256752Sbrooks v1 = (sc->atse_eth_addr[5] << 8) | sc->atse_eth_addr[4]; 764256752Sbrooks 765256752Sbrooks if (n & ATSE_ETH_ADDR_DEF) { 766256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_MAC_0, v0); 767256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_MAC_1, v1); 768256752Sbrooks } 769256752Sbrooks if (n & ATSE_ETH_ADDR_SUPP1) { 770256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_0_0, v0); 771256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_0_1, v1); 772256752Sbrooks } 773256752Sbrooks if (n & ATSE_ETH_ADDR_SUPP2) { 774256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_1_0, v0); 775256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_1_1, v1); 776256752Sbrooks } 777256752Sbrooks if (n & ATSE_ETH_ADDR_SUPP3) { 778256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_2_0, v0); 779256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_2_1, v1); 780256752Sbrooks } 781256752Sbrooks if (n & ATSE_ETH_ADDR_SUPP4) { 782256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_3_0, v0); 783256752Sbrooks CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_3_1, v1); 784256752Sbrooks } 785256752Sbrooks 786256752Sbrooks return (0); 787256752Sbrooks} 788256752Sbrooks 789256752Sbrooksstatic int 790256752Sbrooksatse_reset(struct atse_softc *sc) 791256752Sbrooks{ 792256752Sbrooks int i; 793256752Sbrooks uint32_t val4, mask; 794256752Sbrooks uint16_t val; 795256752Sbrooks 796256752Sbrooks /* 1. External PHY Initialization using MDIO. */ 797256752Sbrooks /* 798256752Sbrooks * We select the right MDIO space in atse_attach() and let MII do 799256752Sbrooks * anything else. 800256752Sbrooks */ 801256752Sbrooks 802256752Sbrooks /* 2. PCS Configuration Register Initialization. */ 803256752Sbrooks /* a. Set auto negotiation link timer to 1.6ms for SGMII. */ 804256752Sbrooks PCS_WRITE_2(sc, PCS_EXT_LINK_TIMER_0, 0x0D40); 805256752Sbrooks PCS_WRITE_2(sc, PCS_EXT_LINK_TIMER_1, 0x0003); 806256752Sbrooks 807256752Sbrooks /* b. Configure SGMII. */ 808256752Sbrooks val = PCS_EXT_IF_MODE_SGMII_ENA|PCS_EXT_IF_MODE_USE_SGMII_AN; 809256752Sbrooks PCS_WRITE_2(sc, PCS_EXT_IF_MODE, val); 810256752Sbrooks 811256752Sbrooks /* c. Enable auto negotiation. */ 812256752Sbrooks /* Ignore Bits 6,8,13; should be set,set,unset. */ 813256752Sbrooks val = PCS_READ_2(sc, PCS_CONTROL); 814256752Sbrooks val &= ~(PCS_CONTROL_ISOLATE|PCS_CONTROL_POWERDOWN); 815256752Sbrooks val &= ~PCS_CONTROL_LOOPBACK; /* Make this a -link1 option? */ 816256752Sbrooks val |= PCS_CONTROL_AUTO_NEGOTIATION_ENABLE; 817256752Sbrooks PCS_WRITE_2(sc, PCS_CONTROL, val); 818256752Sbrooks 819256752Sbrooks /* d. PCS reset. */ 820256752Sbrooks val = PCS_READ_2(sc, PCS_CONTROL); 821256752Sbrooks val |= PCS_CONTROL_RESET; 822256752Sbrooks PCS_WRITE_2(sc, PCS_CONTROL, val); 823256752Sbrooks /* Wait for reset bit to clear; i=100 is excessive. */ 824256752Sbrooks for (i = 0; i < 100; i++) { 825256752Sbrooks val = PCS_READ_2(sc, PCS_CONTROL); 826256752Sbrooks if ((val & PCS_CONTROL_RESET) == 0) 827256752Sbrooks break; 828256752Sbrooks DELAY(10); 829256752Sbrooks } 830256752Sbrooks if ((val & PCS_CONTROL_RESET) != 0) { 831256752Sbrooks device_printf(sc->atse_dev, "PCS reset timed out.\n"); 832256752Sbrooks return (ENXIO); 833256752Sbrooks } 834256752Sbrooks 835256752Sbrooks /* 3. MAC Configuration Register Initialization. */ 836256752Sbrooks /* a. Disable MAC transmit and receive datapath. */ 837256752Sbrooks mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA; 838256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 839256752Sbrooks val4 &= ~mask; 840256752Sbrooks /* Samples in the manual do have the SW_RESET bit set here, why? */ 841256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 842256752Sbrooks /* Wait for bits to be cleared; i=100 is excessive. */ 843256752Sbrooks for (i = 0; i < 100; i++) { 844256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 845256752Sbrooks if ((val4 & mask) == 0) 846256752Sbrooks break; 847256752Sbrooks DELAY(10); 848256752Sbrooks } 849256752Sbrooks if ((val4 & mask) != 0) { 850256752Sbrooks device_printf(sc->atse_dev, "Disabling MAC TX/RX timed out.\n"); 851256752Sbrooks return (ENXIO); 852256752Sbrooks } 853256752Sbrooks /* b. MAC FIFO configuration. */ 854256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_EMPTY, FIFO_DEPTH_TX - 16); 855256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_TX_ALMOST_FULL, 3); 856256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_TX_ALMOST_EMPTY, 8); 857256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_EMPTY, FIFO_DEPTH_RX - 16); 858256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_RX_ALMOST_FULL, 8); 859256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_RX_ALMOST_EMPTY, 8); 860256752Sbrooks#if 0 861256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_FULL, 16); 862256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_FULL, 16); 863256752Sbrooks#else 864256752Sbrooks /* For store-and-forward mode, set this threshold to 0. */ 865256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_FULL, 0); 866256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_FULL, 0); 867256752Sbrooks#endif 868256752Sbrooks /* c. MAC address configuration. */ 869256752Sbrooks /* Also intialize supplementary addresses to our primary one. */ 870256752Sbrooks /* XXX-BZ FreeBSD really needs to grow and API for using these. */ 871256752Sbrooks atse_get_eth_address(sc); 872256752Sbrooks atse_set_eth_address(sc, ATSE_ETH_ADDR_ALL); 873256752Sbrooks 874256752Sbrooks /* d. MAC function configuration. */ 875256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_FRM_LENGTH, 1518); /* Default. */ 876256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_TX_IPG_LENGTH, 12); 877256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_PAUSE_QUANT, 0xFFFF); 878256752Sbrooks 879256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 880256752Sbrooks /* 881256752Sbrooks * If 1000BASE-X/SGMII PCS is initialized, set the ETH_SPEED (bit 3) 882256752Sbrooks * and ENA_10 (bit 25) in command_config register to 0. If half duplex 883256752Sbrooks * is reported in the PHY/PCS status register, set the HD_ENA (bit 10) 884256752Sbrooks * to 1 in command_config register. 885256752Sbrooks * BZ: We shoot for 1000 instead. 886256752Sbrooks */ 887256752Sbrooks#if 0 888256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_ETH_SPEED; 889256752Sbrooks#else 890256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED; 891256752Sbrooks#endif 892256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10; 893256752Sbrooks#if 0 894256752Sbrooks /* 895256752Sbrooks * We do not want to set this, otherwise, we could not even send 896256752Sbrooks * random raw ethernet frames for various other research. By default 897256752Sbrooks * FreeBSD will use the right ether source address. 898256752Sbrooks */ 899256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_TX_ADDR_INS; 900256752Sbrooks#endif 901256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_PAD_EN; 902256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_CRC_FWD; 903256752Sbrooks#if 0 904256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_CNTL_FRM_ENA; 905256752Sbrooks#endif 906256752Sbrooks#if 1 907256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC; 908256752Sbrooks#endif 909256752Sbrooks val &= ~BASE_CFG_COMMAND_CONFIG_LOOP_ENA; /* link0? */ 910256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 911256752Sbrooks 912256752Sbrooks /* 913256752Sbrooks * Make sure we do not enable 32bit alignment; FreeBSD cannot 914256752Sbrooks * cope with the additional padding (though we should!?). 915256752Sbrooks * Also make sure we get the CRC appended. 916256752Sbrooks */ 917256752Sbrooks val4 = CSR_READ_4(sc, TX_CMD_STAT); 918256752Sbrooks val4 &= ~(TX_CMD_STAT_OMIT_CRC|TX_CMD_STAT_TX_SHIFT16); 919256752Sbrooks CSR_WRITE_4(sc, TX_CMD_STAT, val4); 920256752Sbrooks val4 = CSR_READ_4(sc, RX_CMD_STAT); 921256752Sbrooks val4 &= ~RX_CMD_STAT_RX_SHIFT16; 922256752Sbrooks CSR_WRITE_4(sc, RX_CMD_STAT, val4); 923256752Sbrooks 924256752Sbrooks /* e. Reset MAC. */ 925256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 926256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_SW_RESET; 927256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 928256752Sbrooks /* Wait for bits to be cleared; i=100 is excessive. */ 929256752Sbrooks for (i = 0; i < 100; i++) { 930256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 931256752Sbrooks if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) == 0) 932256752Sbrooks break; 933256752Sbrooks DELAY(10); 934256752Sbrooks } 935256752Sbrooks if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) != 0) { 936256752Sbrooks device_printf(sc->atse_dev, "MAC reset timed out.\n"); 937256752Sbrooks return (ENXIO); 938256752Sbrooks } 939256752Sbrooks 940256752Sbrooks /* f. Enable MAC transmit and receive datapath. */ 941256752Sbrooks mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA; 942256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 943256752Sbrooks val4 |= mask; 944256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 945256752Sbrooks /* Wait for bits to be cleared; i=100 is excessive. */ 946256752Sbrooks for (i = 0; i < 100; i++) { 947256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 948256752Sbrooks if ((val4 & mask) == mask) 949256752Sbrooks break; 950256752Sbrooks DELAY(10); 951256752Sbrooks } 952256752Sbrooks if ((val4 & mask) != mask) { 953256752Sbrooks device_printf(sc->atse_dev, "Enabling MAC TX/RX timed out.\n"); 954256752Sbrooks return (ENXIO); 955256752Sbrooks } 956256752Sbrooks 957256752Sbrooks return (0); 958256752Sbrooks} 959256752Sbrooks 960256752Sbrooksstatic void 961256752Sbrooksatse_init_locked(struct atse_softc *sc) 962256752Sbrooks{ 963256752Sbrooks struct ifnet *ifp; 964256752Sbrooks struct mii_data *mii; 965256752Sbrooks uint8_t *eaddr; 966256752Sbrooks 967256752Sbrooks ATSE_LOCK_ASSERT(sc); 968256752Sbrooks ifp = sc->atse_ifp; 969256752Sbrooks 970256752Sbrooks if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 971256752Sbrooks return; 972256752Sbrooks 973256752Sbrooks /* 974256752Sbrooks * Must update the ether address if changed. Given we do not handle 975256752Sbrooks * in atse_ioctl() but it's in the general framework, just always 976256752Sbrooks * do it here before atse_reset(). 977256752Sbrooks */ 978256752Sbrooks eaddr = IF_LLADDR(sc->atse_ifp); 979256752Sbrooks bcopy(eaddr, &sc->atse_eth_addr, ETHER_ADDR_LEN); 980256752Sbrooks 981256752Sbrooks /* Make things frind to halt, cleanup, ... */ 982256752Sbrooks atse_stop_locked(sc); 983256752Sbrooks /* ... reset, ... */ 984256752Sbrooks atse_reset(sc); 985256752Sbrooks 986256752Sbrooks /* ... and fire up the engine again. */ 987256752Sbrooks atse_rxfilter_locked(sc); 988256752Sbrooks 989256752Sbrooks /* Memory rings? DMA engine? */ 990256752Sbrooks 991256752Sbrooks sc->atse_rx_buf_len = 0; 992256752Sbrooks sc->atse_flags &= ATSE_FLAGS_LINK; /* Preserve. */ 993256752Sbrooks 994256752Sbrooks#ifdef DEVICE_POLLING 995256752Sbrooks /* Only enable interrupts if we are not polling. */ 996256752Sbrooks if (ifp->if_capenable & IFCAP_POLLING) { 997256752Sbrooks ATSE_RX_INTR_DISABLE(sc); 998256752Sbrooks ATSE_TX_INTR_DISABLE(sc); 999256752Sbrooks ATSE_RX_EVENT_CLEAR(sc); 1000256752Sbrooks ATSE_TX_EVENT_CLEAR(sc); 1001256752Sbrooks } else 1002256752Sbrooks#endif 1003256752Sbrooks { 1004256752Sbrooks ATSE_RX_INTR_ENABLE(sc); 1005256752Sbrooks ATSE_TX_INTR_ENABLE(sc); 1006256752Sbrooks } 1007256752Sbrooks 1008256752Sbrooks mii = device_get_softc(sc->atse_miibus); 1009256752Sbrooks 1010256752Sbrooks sc->atse_flags &= ~ATSE_FLAGS_LINK; 1011256752Sbrooks mii_mediachg(mii); 1012256752Sbrooks 1013256752Sbrooks ifp->if_drv_flags |= IFF_DRV_RUNNING; 1014256752Sbrooks ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1015256752Sbrooks 1016256752Sbrooks callout_reset(&sc->atse_tick, hz, atse_tick, sc); 1017256752Sbrooks} 1018256752Sbrooks 1019256752Sbrooksstatic void 1020256752Sbrooksatse_init(void *xsc) 1021256752Sbrooks{ 1022256752Sbrooks struct atse_softc *sc; 1023256752Sbrooks 1024271969Sbz /* 1025271969Sbz * XXXRW: There is some argument that we should immediately do RX 1026271969Sbz * processing after enabling interrupts, or one may not fire if there 1027271969Sbz * are buffered packets. 1028271969Sbz */ 1029256752Sbrooks sc = (struct atse_softc *)xsc; 1030256752Sbrooks ATSE_LOCK(sc); 1031256752Sbrooks atse_init_locked(sc); 1032256752Sbrooks ATSE_UNLOCK(sc); 1033256752Sbrooks} 1034256752Sbrooks 1035256752Sbrooksstatic int 1036256752Sbrooksatse_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1037256752Sbrooks{ 1038256752Sbrooks struct atse_softc *sc; 1039256752Sbrooks struct ifreq *ifr; 1040256752Sbrooks int error, mask; 1041256752Sbrooks 1042256752Sbrooks 1043256752Sbrooks error = 0; 1044256752Sbrooks sc = ifp->if_softc; 1045256752Sbrooks ifr = (struct ifreq *)data; 1046256752Sbrooks 1047256752Sbrooks switch (command) { 1048256752Sbrooks case SIOCSIFFLAGS: 1049256752Sbrooks ATSE_LOCK(sc); 1050256752Sbrooks if (ifp->if_flags & IFF_UP) { 1051256752Sbrooks if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 1052256752Sbrooks ((ifp->if_flags ^ sc->atse_if_flags) & 1053256752Sbrooks (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1054256752Sbrooks atse_rxfilter_locked(sc); 1055256752Sbrooks else 1056256752Sbrooks atse_init_locked(sc); 1057256752Sbrooks } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1058256752Sbrooks atse_stop_locked(sc); 1059256752Sbrooks sc->atse_if_flags = ifp->if_flags; 1060256752Sbrooks ATSE_UNLOCK(sc); 1061256752Sbrooks break; 1062256752Sbrooks case SIOCSIFCAP: 1063256752Sbrooks ATSE_LOCK(sc); 1064256752Sbrooks mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1065256752Sbrooks#ifdef DEVICE_POLLING 1066256752Sbrooks if ((mask & IFCAP_POLLING) != 0 && 1067256752Sbrooks (IFCAP_POLLING & ifp->if_capabilities) != 0) { 1068256752Sbrooks ifp->if_capenable ^= IFCAP_POLLING; 1069256752Sbrooks if ((IFCAP_POLLING & ifp->if_capenable) != 0) { 1070256752Sbrooks 1071256752Sbrooks error = ether_poll_register(atse_poll, ifp); 1072256752Sbrooks if (error != 0) { 1073256752Sbrooks ATSE_UNLOCK(sc); 1074256752Sbrooks break; 1075256752Sbrooks } 1076256752Sbrooks /* Disable interrupts. */ 1077256752Sbrooks ATSE_RX_INTR_DISABLE(sc); 1078256752Sbrooks ATSE_TX_INTR_DISABLE(sc); 1079256752Sbrooks ATSE_RX_EVENT_CLEAR(sc); 1080256752Sbrooks ATSE_TX_EVENT_CLEAR(sc); 1081256752Sbrooks 1082256752Sbrooks /* 1083256752Sbrooks * Do not allow disabling of polling if we do 1084256752Sbrooks * not have interrupts. 1085256752Sbrooks */ 1086256752Sbrooks } else if (sc->atse_rx_irq_res != NULL || 1087256752Sbrooks sc->atse_tx_irq_res != NULL) { 1088256752Sbrooks error = ether_poll_deregister(ifp); 1089256752Sbrooks /* Enable interrupts. */ 1090256752Sbrooks ATSE_RX_INTR_ENABLE(sc); 1091256752Sbrooks ATSE_TX_INTR_ENABLE(sc); 1092256752Sbrooks } else { 1093256752Sbrooks ifp->if_capenable ^= IFCAP_POLLING; 1094256752Sbrooks error = EINVAL; 1095256752Sbrooks } 1096256752Sbrooks } 1097256752Sbrooks#endif /* DEVICE_POLLING */ 1098256752Sbrooks ATSE_UNLOCK(sc); 1099256752Sbrooks break; 1100256752Sbrooks case SIOCADDMULTI: 1101256752Sbrooks case SIOCDELMULTI: 1102256752Sbrooks ATSE_LOCK(sc); 1103256752Sbrooks atse_rxfilter_locked(sc); 1104256752Sbrooks ATSE_UNLOCK(sc); 1105256752Sbrooks break; 1106256752Sbrooks case SIOCGIFMEDIA: 1107256752Sbrooks case SIOCSIFMEDIA: 1108256752Sbrooks { 1109256752Sbrooks struct mii_data *mii; 1110256752Sbrooks struct ifreq *ifr; 1111256752Sbrooks 1112256752Sbrooks mii = device_get_softc(sc->atse_miibus); 1113256752Sbrooks ifr = (struct ifreq *)data; 1114256752Sbrooks error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1115256752Sbrooks break; 1116256752Sbrooks } 1117256752Sbrooks default: 1118256752Sbrooks error = ether_ioctl(ifp, command, data); 1119256752Sbrooks break; 1120256752Sbrooks } 1121256752Sbrooks 1122256752Sbrooks return (error); 1123256752Sbrooks} 1124256752Sbrooks 1125256752Sbrooksstatic void 1126271969Sbzatse_intr_debug(struct atse_softc *sc, const char *intrname) 1127271969Sbz{ 1128271969Sbz uint32_t rxs, rxe, rxi, rxf, txs, txe, txi, txf; 1129271969Sbz 1130271969Sbz if (!atse_intr_debug_enable) 1131271969Sbz return; 1132271969Sbz 1133271969Sbz rxs = ATSE_RX_STATUS_READ(sc); 1134271969Sbz rxe = ATSE_RX_EVENT_READ(sc); 1135271969Sbz rxi = ATSE_RX_INTR_READ(sc); 1136271969Sbz rxf = ATSE_RX_READ_FILL_LEVEL(sc); 1137271969Sbz 1138271969Sbz txs = ATSE_TX_STATUS_READ(sc); 1139271969Sbz txe = ATSE_TX_EVENT_READ(sc); 1140271969Sbz txi = ATSE_TX_INTR_READ(sc); 1141271969Sbz txf = ATSE_TX_READ_FILL_LEVEL(sc); 1142271969Sbz 1143271969Sbz printf( 1144271969Sbz "%s - %s: " 1145271969Sbz "rxs 0x%x rxe 0x%x rxi 0x%x rxf 0x%x " 1146271969Sbz "txs 0x%x txe 0x%x txi 0x%x txf 0x%x\n", 1147271969Sbz __func__, intrname, 1148271969Sbz rxs, rxe, rxi, rxf, 1149271969Sbz txs, txe, txi, txf); 1150271969Sbz} 1151271969Sbz 1152271969Sbzstatic void 1153256752Sbrooksatse_watchdog(struct atse_softc *sc) 1154256752Sbrooks{ 1155256752Sbrooks 1156256752Sbrooks ATSE_LOCK_ASSERT(sc); 1157256752Sbrooks 1158256752Sbrooks if (sc->atse_watchdog_timer == 0 || --sc->atse_watchdog_timer > 0) 1159256752Sbrooks return; 1160256752Sbrooks 1161256752Sbrooks device_printf(sc->atse_dev, "watchdog timeout\n"); 1162256752Sbrooks sc->atse_ifp->if_oerrors++; 1163256752Sbrooks 1164271969Sbz atse_intr_debug(sc, "poll"); 1165271969Sbz 1166256752Sbrooks sc->atse_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1167256752Sbrooks atse_init_locked(sc); 1168256752Sbrooks 1169271969Sbz atse_rx_locked(sc); 1170256752Sbrooks if (!IFQ_DRV_IS_EMPTY(&sc->atse_ifp->if_snd)) 1171256752Sbrooks atse_start_locked(sc->atse_ifp); 1172256752Sbrooks} 1173256752Sbrooks 1174256752Sbrooksstatic void 1175256752Sbrooksatse_tick(void *xsc) 1176256752Sbrooks{ 1177256752Sbrooks struct atse_softc *sc; 1178256752Sbrooks struct mii_data *mii; 1179256752Sbrooks struct ifnet *ifp; 1180256752Sbrooks 1181256752Sbrooks sc = (struct atse_softc *)xsc; 1182256752Sbrooks ATSE_LOCK_ASSERT(sc); 1183256752Sbrooks ifp = sc->atse_ifp; 1184256752Sbrooks 1185256752Sbrooks mii = device_get_softc(sc->atse_miibus); 1186256752Sbrooks mii_tick(mii); 1187256752Sbrooks atse_watchdog(sc); 1188256752Sbrooks if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) 1189256752Sbrooks atse_miibus_statchg(sc->atse_dev); 1190256752Sbrooks callout_reset(&sc->atse_tick, hz, atse_tick, sc); 1191256752Sbrooks} 1192256752Sbrooks 1193256752Sbrooks/* 1194256752Sbrooks * Set media options. 1195256752Sbrooks */ 1196256752Sbrooksstatic int 1197256752Sbrooksatse_ifmedia_upd(struct ifnet *ifp) 1198256752Sbrooks{ 1199256752Sbrooks struct atse_softc *sc; 1200256752Sbrooks struct mii_data *mii; 1201256752Sbrooks struct mii_softc *miisc; 1202256752Sbrooks int error; 1203256752Sbrooks 1204256752Sbrooks sc = ifp->if_softc; 1205256752Sbrooks 1206256752Sbrooks ATSE_LOCK(sc); 1207256752Sbrooks mii = device_get_softc(sc->atse_miibus); 1208256752Sbrooks LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1209256752Sbrooks PHY_RESET(miisc); 1210256752Sbrooks error = mii_mediachg(mii); 1211256752Sbrooks ATSE_UNLOCK(sc); 1212256752Sbrooks 1213256752Sbrooks return (error); 1214256752Sbrooks} 1215256752Sbrooks 1216256752Sbrooksstatic void 1217256752Sbrooksatse_update_rx_err(struct atse_softc *sc, uint32_t mask) 1218256752Sbrooks{ 1219256752Sbrooks int i; 1220256752Sbrooks 1221256752Sbrooks /* RX error are 6 bits, we only know 4 of them. */ 1222256752Sbrooks for (i = 0; i < ATSE_RX_ERR_MAX; i++) 1223256752Sbrooks if ((mask & (1 << i)) != 0) 1224256752Sbrooks sc->atse_rx_err[i]++; 1225256752Sbrooks} 1226256752Sbrooks 1227256752Sbrooksstatic int 1228256752Sbrooksatse_rx_locked(struct atse_softc *sc) 1229256752Sbrooks{ 1230256752Sbrooks struct ifnet *ifp; 1231256752Sbrooks struct mbuf *m; 1232256752Sbrooks uint32_t fill, i, j; 1233256752Sbrooks uint32_t data, meta; 1234256752Sbrooks int rx_npkts = 0; 1235256752Sbrooks 1236256752Sbrooks ATSE_LOCK_ASSERT(sc); 1237256752Sbrooks 1238256752Sbrooks ifp = sc->atse_ifp; 1239256752Sbrooks j = 0; 1240256752Sbrooks meta = 0; 1241256752Sbrooks do { 1242256752Sbrooksouter: 1243256752Sbrooks if (sc->atse_rx_m == NULL) { 1244256752Sbrooks m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1245256752Sbrooks if (m == NULL) 1246256752Sbrooks return (rx_npkts); 1247256752Sbrooks m->m_len = m->m_pkthdr.len = MCLBYTES; 1248256752Sbrooks /* Make sure upper layers will be aligned. */ 1249270059Sbz m_adj(m, ETHER_ALIGN); 1250256752Sbrooks sc->atse_rx_m = m; 1251256752Sbrooks } 1252256752Sbrooks 1253256752Sbrooks fill = ATSE_RX_READ_FILL_LEVEL(sc); 1254256752Sbrooks for (i = 0; i < fill; i++) { 1255256752Sbrooks /* 1256256752Sbrooks * XXX-BZ for whatever reason the FIFO requires the 1257256752Sbrooks * the data read before we can access the meta data. 1258256752Sbrooks */ 1259256752Sbrooks data = ATSE_RX_DATA_READ(sc); 1260256752Sbrooks meta = ATSE_RX_META_READ(sc); 1261256752Sbrooks if (meta & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) { 1262256752Sbrooks /* XXX-BZ evaluate error. */ 1263256752Sbrooks atse_update_rx_err(sc, ((meta & 1264256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> 1265256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff); 1266256752Sbrooks ifp->if_ierrors++; 1267256752Sbrooks sc->atse_rx_buf_len = 0; 1268256752Sbrooks /* 1269256752Sbrooks * Should still read till EOP or next SOP. 1270256752Sbrooks * 1271256752Sbrooks * XXX-BZ might also depend on 1272256752Sbrooks * BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC 1273256752Sbrooks */ 1274256752Sbrooks sc->atse_flags |= ATSE_FLAGS_ERROR; 1275256752Sbrooks return (rx_npkts); 1276256752Sbrooks } 1277256752Sbrooks if ((meta & A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) != 0) 1278256752Sbrooks device_printf(sc->atse_dev, "%s: unexpected " 1279256752Sbrooks "channel %u\n", __func__, (meta & 1280256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) >> 1281256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_CHANNEL_SHIFT); 1282256752Sbrooks 1283256752Sbrooks if (meta & A_ONCHIP_FIFO_MEM_CORE_SOP) { 1284256752Sbrooks /* 1285256752Sbrooks * There is no need to clear SOP between 1st 1286256752Sbrooks * and subsequent packet data junks. 1287256752Sbrooks */ 1288256752Sbrooks if (sc->atse_rx_buf_len != 0 && 1289256752Sbrooks (sc->atse_flags & ATSE_FLAGS_SOP_SEEN) == 0) 1290256752Sbrooks { 1291256752Sbrooks device_printf(sc->atse_dev, "%s: SOP " 1292256752Sbrooks "without empty buffer: %u\n", 1293256752Sbrooks __func__, sc->atse_rx_buf_len); 1294256752Sbrooks /* XXX-BZ any better counter? */ 1295256752Sbrooks ifp->if_ierrors++; 1296256752Sbrooks } 1297256752Sbrooks 1298256752Sbrooks if ((sc->atse_flags & ATSE_FLAGS_SOP_SEEN) == 0) 1299256752Sbrooks { 1300256752Sbrooks sc->atse_flags |= ATSE_FLAGS_SOP_SEEN; 1301256752Sbrooks sc->atse_rx_buf_len = 0; 1302256752Sbrooks } 1303256752Sbrooks } 1304256752Sbrooks#if 0 /* We had to read the data before we could access meta data. See above. */ 1305256752Sbrooks data = ATSE_RX_DATA_READ(sc); 1306256752Sbrooks#endif 1307256752Sbrooks /* Make sure to not overflow the mbuf data size. */ 1308271969Sbz if (sc->atse_rx_buf_len >= sc->atse_rx_m->m_len - 1309271969Sbz sizeof(data)) { 1310256752Sbrooks /* 1311256752Sbrooks * XXX-BZ Error. We need more mbufs and are 1312256752Sbrooks * not setup for this yet. 1313256752Sbrooks */ 1314256752Sbrooks ifp->if_ierrors++; 1315256752Sbrooks sc->atse_flags |= ATSE_FLAGS_ERROR; 1316256752Sbrooks } 1317256752Sbrooks if ((sc->atse_flags & ATSE_FLAGS_ERROR) == 0) 1318256752Sbrooks /* 1319256752Sbrooks * MUST keep this bcopy as m_data after m_adj 1320256752Sbrooks * for IP header aligment is on half-word 1321256752Sbrooks * and not word alignment. 1322256752Sbrooks */ 1323256752Sbrooks bcopy(&data, (uint8_t *)(sc->atse_rx_m->m_data + 1324256752Sbrooks sc->atse_rx_buf_len), sizeof(data)); 1325256752Sbrooks if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP) { 1326256752Sbrooks uint8_t empty; 1327256752Sbrooks 1328256752Sbrooks empty = (meta & 1329256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK) >> 1330256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT; 1331256752Sbrooks sc->atse_rx_buf_len += (4 - empty); 1332256752Sbrooks 1333256752Sbrooks ifp->if_ipackets++; 1334256752Sbrooks rx_npkts++; 1335256752Sbrooks 1336256752Sbrooks m = sc->atse_rx_m; 1337256752Sbrooks m->m_pkthdr.len = m->m_len = 1338256752Sbrooks sc->atse_rx_buf_len; 1339256752Sbrooks sc->atse_rx_m = NULL; 1340256752Sbrooks 1341256752Sbrooks sc->atse_rx_buf_len = 0; 1342256752Sbrooks sc->atse_flags &= ~ATSE_FLAGS_SOP_SEEN; 1343256752Sbrooks if (sc->atse_flags & ATSE_FLAGS_ERROR) { 1344256752Sbrooks sc->atse_flags &= ~ATSE_FLAGS_ERROR; 1345256752Sbrooks m_freem(m); 1346271969Sbz } else { 1347271969Sbz m->m_pkthdr.rcvif = ifp; 1348271969Sbz ATSE_UNLOCK(sc); 1349271969Sbz (*ifp->if_input)(ifp, m); 1350271969Sbz ATSE_LOCK(sc); 1351256752Sbrooks } 1352271969Sbz#ifdef DEVICE_POLLING 1353271969Sbz if (ifp->if_capenable & IFCAP_POLLING) { 1354271969Sbz if (sc->atse_rx_cycles <= 0) 1355271969Sbz return (rx_npkts); 1356271969Sbz sc->atse_rx_cycles--; 1357271969Sbz } 1358271969Sbz#endif 1359256752Sbrooks goto outer; /* Need a new mbuf. */ 1360256752Sbrooks } else { 1361256752Sbrooks sc->atse_rx_buf_len += sizeof(data); 1362256752Sbrooks } 1363256752Sbrooks } /* for */ 1364256752Sbrooks 1365256752Sbrooks /* XXX-BZ could optimize in case of another packet waiting. */ 1366271969Sbz } while (fill > 0); 1367256752Sbrooks 1368256752Sbrooks return (rx_npkts); 1369256752Sbrooks} 1370256752Sbrooks 1371256752Sbrooks 1372256752Sbrooks/* 1373256752Sbrooks * Report current media status. 1374256752Sbrooks */ 1375256752Sbrooksstatic void 1376256752Sbrooksatse_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1377256752Sbrooks{ 1378256752Sbrooks struct atse_softc *sc; 1379256752Sbrooks struct mii_data *mii; 1380256752Sbrooks 1381256752Sbrooks sc = ifp->if_softc; 1382256752Sbrooks 1383256752Sbrooks ATSE_LOCK(sc); 1384256752Sbrooks mii = device_get_softc(sc->atse_miibus); 1385256752Sbrooks mii_pollstat(mii); 1386256752Sbrooks ifmr->ifm_active = mii->mii_media_active; 1387256752Sbrooks ifmr->ifm_status = mii->mii_media_status; 1388256752Sbrooks ATSE_UNLOCK(sc); 1389256752Sbrooks} 1390256752Sbrooks 1391256752Sbrooksstatic void 1392271969Sbzatse_rx_intr(void *arg) 1393256752Sbrooks{ 1394256752Sbrooks struct atse_softc *sc; 1395256752Sbrooks struct ifnet *ifp; 1396271969Sbz uint32_t rxe; 1397256752Sbrooks 1398256752Sbrooks sc = (struct atse_softc *)arg; 1399256752Sbrooks ifp = sc->atse_ifp; 1400256752Sbrooks 1401256752Sbrooks ATSE_LOCK(sc); 1402256752Sbrooks#ifdef DEVICE_POLLING 1403256752Sbrooks if (ifp->if_capenable & IFCAP_POLLING) { 1404256752Sbrooks ATSE_UNLOCK(sc); 1405256752Sbrooks return; 1406256752Sbrooks } 1407256752Sbrooks#endif 1408256752Sbrooks 1409271969Sbz atse_intr_debug(sc, "rx"); 1410271969Sbz rxe = ATSE_RX_EVENT_READ(sc); 1411271969Sbz if (rxe & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| 1412271969Sbz A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { 1413271969Sbz /* XXX-BZ ERROR HANDLING. */ 1414271969Sbz atse_update_rx_err(sc, ((rxe & 1415271969Sbz A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> 1416271969Sbz A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff); 1417271969Sbz ifp->if_ierrors++; 1418271969Sbz } 1419256752Sbrooks 1420271969Sbz /* 1421271969Sbz * There is considerable subtlety in the race-free handling of rx 1422271969Sbz * interrupts: we must disable interrupts whenever we manipulate the 1423271969Sbz * FIFO to prevent further interrupts from firing before we are done; 1424271969Sbz * we must clear the event after processing to prevent the event from 1425271969Sbz * being immediately reposted due to data remaining; we must clear the 1426271969Sbz * event mask before reenabling interrupts or risk missing a positive 1427271969Sbz * edge; and we must recheck everything after completing in case the 1428271969Sbz * event posted between clearing events and reenabling interrupts. If 1429271969Sbz * a race is experienced, we must restart the whole mechanism. 1430271969Sbz */ 1431271969Sbz do { 1432271969Sbz ATSE_RX_INTR_DISABLE(sc); 1433256752Sbrooks#if 0 1434271969Sbz sc->atse_rx_cycles = RX_CYCLES_IN_INTR; 1435256752Sbrooks#endif 1436271969Sbz atse_rx_locked(sc); 1437271969Sbz ATSE_RX_EVENT_CLEAR(sc); 1438256752Sbrooks 1439271969Sbz /* Disable interrupts if interface is down. */ 1440271969Sbz if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1441271969Sbz ATSE_RX_INTR_ENABLE(sc); 1442271969Sbz } while (!(ATSE_RX_STATUS_READ(sc) & 1443271969Sbz A_ONCHIP_FIFO_MEM_CORE_STATUS_EMPTY)); 1444271969Sbz ATSE_UNLOCK(sc); 1445256752Sbrooks 1446271969Sbz} 1447256752Sbrooks 1448271969Sbzstatic void 1449271969Sbzatse_tx_intr(void *arg) 1450271969Sbz{ 1451271969Sbz struct atse_softc *sc; 1452271969Sbz struct ifnet *ifp; 1453271969Sbz uint32_t txe; 1454271969Sbz 1455271969Sbz sc = (struct atse_softc *)arg; 1456271969Sbz ifp = sc->atse_ifp; 1457271969Sbz 1458271969Sbz ATSE_LOCK(sc); 1459271969Sbz#ifdef DEVICE_POLLING 1460271969Sbz if (ifp->if_capenable & IFCAP_POLLING) { 1461271969Sbz ATSE_UNLOCK(sc); 1462271969Sbz return; 1463271969Sbz } 1464271969Sbz#endif 1465271969Sbz 1466271969Sbz /* XXX-BZ build histogram. */ 1467271969Sbz atse_intr_debug(sc, "tx"); 1468271969Sbz txe = ATSE_TX_EVENT_READ(sc); 1469271969Sbz if (txe & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| 1470271969Sbz A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { 1471271969Sbz /* XXX-BZ ERROR HANDLING. */ 1472271969Sbz ifp->if_oerrors++; 1473256752Sbrooks } 1474256752Sbrooks 1475271969Sbz /* 1476271969Sbz * There is also considerable subtlety in the race-free handling of 1477271969Sbz * tx interrupts: all processing occurs with interrupts disabled to 1478271969Sbz * prevent spurious refiring while transmit is in progress (which 1479271969Sbz * could occur if the FIFO drains while sending -- quite likely); we 1480271969Sbz * must not clear the event mask until after we've sent, also to 1481271969Sbz * prevent spurious refiring; once we've cleared the event mask we can 1482271969Sbz * reenable interrupts, but there is a possible race between clear and 1483271969Sbz * enable, so we must recheck and potentially repeat the whole process 1484271969Sbz * if it is detected. 1485271969Sbz */ 1486271969Sbz do { 1487271969Sbz ATSE_TX_INTR_DISABLE(sc); 1488271969Sbz sc->atse_watchdog_timer = 0; 1489271969Sbz atse_start_locked(ifp); 1490271969Sbz ATSE_TX_EVENT_CLEAR(sc); 1491271969Sbz 1492271969Sbz /* Disable interrupts if interface is down. */ 1493271969Sbz if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1494271969Sbz ATSE_TX_INTR_ENABLE(sc); 1495271969Sbz } while (ATSE_TX_PENDING(sc) && 1496271969Sbz !(ATSE_TX_STATUS_READ(sc) & A_ONCHIP_FIFO_MEM_CORE_STATUS_FULL)); 1497256752Sbrooks ATSE_UNLOCK(sc); 1498256752Sbrooks} 1499256752Sbrooks 1500256752Sbrooks#ifdef DEVICE_POLLING 1501256752Sbrooksstatic int 1502256752Sbrooksatse_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1503256752Sbrooks{ 1504256752Sbrooks struct atse_softc *sc; 1505256752Sbrooks int rx_npkts = 0; 1506256752Sbrooks 1507256752Sbrooks sc = ifp->if_softc; 1508256752Sbrooks ATSE_LOCK(sc); 1509256752Sbrooks if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1510256752Sbrooks ATSE_UNLOCK(sc); 1511256752Sbrooks return (rx_npkts); 1512256752Sbrooks } 1513256752Sbrooks 1514256752Sbrooks sc->atse_rx_cycles = count; 1515256752Sbrooks rx_npkts = atse_rx_locked(sc); 1516256752Sbrooks atse_start_locked(ifp); 1517256752Sbrooks 1518256752Sbrooks if (sc->atse_rx_cycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1519256752Sbrooks uint32_t rx, tx; 1520256752Sbrooks 1521256752Sbrooks rx = ATSE_RX_EVENT_READ(sc); 1522256752Sbrooks tx = ATSE_TX_EVENT_READ(sc); 1523256752Sbrooks 1524256752Sbrooks if (rx & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| 1525256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { 1526256752Sbrooks /* XXX-BZ ERROR HANDLING. */ 1527256752Sbrooks atse_update_rx_err(sc, ((rx & 1528256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> 1529256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff); 1530256752Sbrooks ifp->if_ierrors++; 1531256752Sbrooks } 1532256752Sbrooks if (tx & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| 1533256752Sbrooks A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { 1534256752Sbrooks /* XXX-BZ ERROR HANDLING. */ 1535256752Sbrooks ifp->if_oerrors++; 1536256752Sbrooks } 1537271969Sbz if (ATSE_TX_READ_FILL_LEVEL(sc) == 0) 1538256752Sbrooks sc->atse_watchdog_timer = 0; 1539256752Sbrooks 1540256752Sbrooks#if 0 1541256752Sbrooks if (/* Severe error; if only we could find out. */) { 1542256752Sbrooks ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1543256752Sbrooks atse_init_locked(sc); 1544256752Sbrooks } 1545256752Sbrooks#endif 1546256752Sbrooks } 1547256752Sbrooks 1548256752Sbrooks ATSE_UNLOCK(sc); 1549256752Sbrooks return (rx_npkts); 1550256752Sbrooks} 1551256752Sbrooks#endif /* DEVICE_POLLING */ 1552256752Sbrooks 1553256752Sbrooksstatic struct atse_mac_stats_regs { 1554256752Sbrooks const char *name; 1555256752Sbrooks const char *descr; /* Mostly copied from Altera datasheet. */ 1556256752Sbrooks} atse_mac_stats_regs[] = { 1557256752Sbrooks [0x1a] = 1558256752Sbrooks { "aFramesTransmittedOK", 1559256752Sbrooks "The number of frames that are successfully transmitted including " 1560256752Sbrooks "the pause frames." }, 1561256752Sbrooks { "aFramesReceivedOK", 1562256752Sbrooks "The number of frames that are successfully received including the " 1563256752Sbrooks "pause frames." }, 1564256752Sbrooks { "aFrameCheckSequenceErrors", 1565256752Sbrooks "The number of receive frames with CRC error." }, 1566256752Sbrooks { "aAlignmentErrors", 1567256752Sbrooks "The number of receive frames with alignment error." }, 1568256752Sbrooks { "aOctetsTransmittedOK", 1569256752Sbrooks "The lower 32 bits of the number of data and padding octets that " 1570256752Sbrooks "are successfully transmitted." }, 1571256752Sbrooks { "aOctetsReceivedOK", 1572256752Sbrooks "The lower 32 bits of the number of data and padding octets that " 1573256752Sbrooks " are successfully received." }, 1574256752Sbrooks { "aTxPAUSEMACCtrlFrames", 1575256752Sbrooks "The number of pause frames transmitted." }, 1576256752Sbrooks { "aRxPAUSEMACCtrlFrames", 1577256752Sbrooks "The number received pause frames received." }, 1578256752Sbrooks { "ifInErrors", 1579256752Sbrooks "The number of errored frames received." }, 1580256752Sbrooks { "ifOutErrors", 1581256752Sbrooks "The number of transmit frames with either a FIFO overflow error, " 1582256752Sbrooks "a FIFO underflow error, or a error defined by the user " 1583256752Sbrooks "application." }, 1584256752Sbrooks { "ifInUcastPkts", 1585256752Sbrooks "The number of valid unicast frames received." }, 1586256752Sbrooks { "ifInMulticastPkts", 1587256752Sbrooks "The number of valid multicast frames received. The count does " 1588256752Sbrooks "not include pause frames." }, 1589256752Sbrooks { "ifInBroadcastPkts", 1590256752Sbrooks "The number of valid broadcast frames received." }, 1591256752Sbrooks { "ifOutDiscards", 1592256752Sbrooks "This statistics counter is not in use. The MAC function does not " 1593256752Sbrooks "discard frames that are written to the FIFO buffer by the user " 1594256752Sbrooks "application." }, 1595256752Sbrooks { "ifOutUcastPkts", 1596256752Sbrooks "The number of valid unicast frames transmitted." }, 1597256752Sbrooks { "ifOutMulticastPkts", 1598256752Sbrooks "The number of valid multicast frames transmitted, excluding pause " 1599256752Sbrooks "frames." }, 1600256752Sbrooks { "ifOutBroadcastPkts", 1601256752Sbrooks "The number of valid broadcast frames transmitted." }, 1602256752Sbrooks { "etherStatsDropEvents", 1603256752Sbrooks "The number of frames that are dropped due to MAC internal errors " 1604256752Sbrooks "when FIFO buffer overflow persists." }, 1605256752Sbrooks { "etherStatsOctets", 1606256752Sbrooks "The lower 32 bits of the total number of octets received. This " 1607256752Sbrooks "count includes both good and errored frames." }, 1608256752Sbrooks { "etherStatsPkts", 1609256752Sbrooks "The total number of good and errored frames received." }, 1610256752Sbrooks { "etherStatsUndersizePkts", 1611256752Sbrooks "The number of frames received with length less than 64 bytes. " 1612256752Sbrooks "This count does not include errored frames." }, 1613256752Sbrooks { "etherStatsOversizePkts", 1614256752Sbrooks "The number of frames received that are longer than the value " 1615256752Sbrooks "configured in the frm_length register. This count does not " 1616256752Sbrooks "include errored frames." }, 1617256752Sbrooks { "etherStatsPkts64Octets", 1618256752Sbrooks "The number of 64-byte frames received. This count includes good " 1619256752Sbrooks "and errored frames." }, 1620256752Sbrooks { "etherStatsPkts65to127Octets", 1621256752Sbrooks "The number of received good and errored frames between the length " 1622256752Sbrooks "of 65 and 127 bytes." }, 1623256752Sbrooks { "etherStatsPkts128to255Octets", 1624256752Sbrooks "The number of received good and errored frames between the length " 1625256752Sbrooks "of 128 and 255 bytes." }, 1626256752Sbrooks { "etherStatsPkts256to511Octets", 1627256752Sbrooks "The number of received good and errored frames between the length " 1628256752Sbrooks "of 256 and 511 bytes." }, 1629256752Sbrooks { "etherStatsPkts512to1023Octets", 1630256752Sbrooks "The number of received good and errored frames between the length " 1631256752Sbrooks "of 512 and 1023 bytes." }, 1632256752Sbrooks { "etherStatsPkts1024to1518Octets", 1633256752Sbrooks "The number of received good and errored frames between the length " 1634256752Sbrooks "of 1024 and 1518 bytes." }, 1635256752Sbrooks { "etherStatsPkts1519toXOctets", 1636256752Sbrooks "The number of received good and errored frames between the length " 1637256752Sbrooks "of 1519 and the maximum frame length configured in the frm_length " 1638256752Sbrooks "register." }, 1639256752Sbrooks { "etherStatsJabbers", 1640256752Sbrooks "Too long frames with CRC error." }, 1641256752Sbrooks { "etherStatsFragments", 1642256752Sbrooks "Too short frames with CRC error." }, 1643256752Sbrooks /* 0x39 unused, 0x3a/b non-stats. */ 1644256752Sbrooks [0x3c] = 1645256752Sbrooks /* Extended Statistics Counters */ 1646256752Sbrooks { "msb_aOctetsTransmittedOK", 1647256752Sbrooks "Upper 32 bits of the number of data and padding octets that are " 1648256752Sbrooks "successfully transmitted." }, 1649256752Sbrooks { "msb_aOctetsReceivedOK", 1650256752Sbrooks "Upper 32 bits of the number of data and padding octets that are " 1651256752Sbrooks "successfully received." }, 1652256752Sbrooks { "msb_etherStatsOctets", 1653256752Sbrooks "Upper 32 bits of the total number of octets received. This count " 1654256752Sbrooks "includes both good and errored frames." } 1655256752Sbrooks}; 1656256752Sbrooks 1657256752Sbrooksstatic int 1658256752Sbrookssysctl_atse_mac_stats_proc(SYSCTL_HANDLER_ARGS) 1659256752Sbrooks{ 1660256752Sbrooks struct atse_softc *sc; 1661256752Sbrooks int error, offset, s; 1662256752Sbrooks 1663256752Sbrooks sc = arg1; 1664256752Sbrooks offset = arg2; 1665256752Sbrooks 1666256752Sbrooks s = CSR_READ_4(sc, offset); 1667256752Sbrooks error = sysctl_handle_int(oidp, &s, 0, req); 1668256752Sbrooks if (error || !req->newptr) 1669256752Sbrooks return (error); 1670256752Sbrooks 1671256752Sbrooks return (0); 1672256752Sbrooks} 1673256752Sbrooks 1674256752Sbrooksstatic struct atse_rx_err_stats_regs { 1675256752Sbrooks const char *name; 1676256752Sbrooks const char *descr; 1677256752Sbrooks} atse_rx_err_stats_regs[] = { 1678256752Sbrooks 1679256752Sbrooks#define ATSE_RX_ERR_FIFO_THRES_EOP 0 /* FIFO threshold reached, on EOP. */ 1680256752Sbrooks#define ATSE_RX_ERR_ELEN 1 /* Frame/payload length not valid. */ 1681256752Sbrooks#define ATSE_RX_ERR_CRC32 2 /* CRC-32 error. */ 1682256752Sbrooks#define ATSE_RX_ERR_FIFO_THRES_TRUNC 3 /* FIFO thresh., truncated frame. */ 1683256752Sbrooks#define ATSE_RX_ERR_4 4 /* ? */ 1684256752Sbrooks#define ATSE_RX_ERR_5 5 /* / */ 1685256752Sbrooks 1686256752Sbrooks { "rx_err_fifo_thres_eop", 1687256752Sbrooks "FIFO threshold reached, reported on EOP." }, 1688256752Sbrooks { "rx_err_fifo_elen", 1689256752Sbrooks "Frame or payload length not valid." }, 1690256752Sbrooks { "rx_err_fifo_crc32", 1691256752Sbrooks "CRC-32 error." }, 1692256752Sbrooks { "rx_err_fifo_thres_trunc", 1693256752Sbrooks "FIFO threshold reached, truncated frame" }, 1694256752Sbrooks { "rx_err_4", 1695256752Sbrooks "?" }, 1696256752Sbrooks { "rx_err_5", 1697256752Sbrooks "?" }, 1698256752Sbrooks}; 1699256752Sbrooks 1700256752Sbrooksstatic int 1701256752Sbrookssysctl_atse_rx_err_stats_proc(SYSCTL_HANDLER_ARGS) 1702256752Sbrooks{ 1703256752Sbrooks struct atse_softc *sc; 1704256752Sbrooks int error, offset, s; 1705256752Sbrooks 1706256752Sbrooks sc = arg1; 1707256752Sbrooks offset = arg2; 1708256752Sbrooks 1709256752Sbrooks s = sc->atse_rx_err[offset]; 1710256752Sbrooks error = sysctl_handle_int(oidp, &s, 0, req); 1711256752Sbrooks if (error || !req->newptr) 1712256752Sbrooks return (error); 1713256752Sbrooks 1714256752Sbrooks return (0); 1715256752Sbrooks} 1716256752Sbrooks 1717256752Sbrooksstatic void 1718256752Sbrooksatse_sysctl_stats_attach(device_t dev) 1719256752Sbrooks{ 1720256752Sbrooks struct sysctl_ctx_list *sctx; 1721256752Sbrooks struct sysctl_oid *soid; 1722256752Sbrooks struct atse_softc *sc; 1723256752Sbrooks int i; 1724256752Sbrooks 1725256752Sbrooks sc = device_get_softc(dev); 1726256752Sbrooks sctx = device_get_sysctl_ctx(dev); 1727256752Sbrooks soid = device_get_sysctl_tree(dev); 1728256752Sbrooks 1729256752Sbrooks /* MAC statistics. */ 1730256752Sbrooks for (i = 0; i < sizeof(atse_mac_stats_regs) / 1731256752Sbrooks sizeof(*atse_mac_stats_regs); i++) { 1732256752Sbrooks if (atse_mac_stats_regs[i].name == NULL || 1733256752Sbrooks atse_mac_stats_regs[i].descr == NULL) 1734256752Sbrooks continue; 1735256752Sbrooks 1736256752Sbrooks SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 1737256752Sbrooks atse_mac_stats_regs[i].name, CTLTYPE_UINT|CTLFLAG_RD, 1738256752Sbrooks sc, i, sysctl_atse_mac_stats_proc, "IU", 1739256752Sbrooks atse_mac_stats_regs[i].descr); 1740256752Sbrooks } 1741256752Sbrooks 1742256752Sbrooks /* rx_err[]. */ 1743256752Sbrooks for (i = 0; i < ATSE_RX_ERR_MAX; i++) { 1744256752Sbrooks if (atse_rx_err_stats_regs[i].name == NULL || 1745256752Sbrooks atse_rx_err_stats_regs[i].descr == NULL) 1746256752Sbrooks continue; 1747256752Sbrooks 1748256752Sbrooks SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 1749256752Sbrooks atse_rx_err_stats_regs[i].name, CTLTYPE_UINT|CTLFLAG_RD, 1750256752Sbrooks sc, i, sysctl_atse_rx_err_stats_proc, "IU", 1751256752Sbrooks atse_rx_err_stats_regs[i].descr); 1752256752Sbrooks } 1753256752Sbrooks} 1754256752Sbrooks 1755256752Sbrooks/* 1756256752Sbrooks * Generic device handling routines. 1757256752Sbrooks */ 1758256752Sbrooksint 1759256752Sbrooksatse_attach(device_t dev) 1760256752Sbrooks{ 1761256752Sbrooks struct atse_softc *sc; 1762256752Sbrooks struct ifnet *ifp; 1763256752Sbrooks int error; 1764256752Sbrooks 1765256752Sbrooks sc = device_get_softc(dev); 1766256752Sbrooks 1767256752Sbrooks atse_ethernet_option_bits_read(dev); 1768256752Sbrooks 1769256752Sbrooks mtx_init(&sc->atse_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 1770256752Sbrooks MTX_DEF); 1771256752Sbrooks 1772256752Sbrooks callout_init_mtx(&sc->atse_tick, &sc->atse_mtx, 0); 1773256752Sbrooks 1774256752Sbrooks sc->atse_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK); 1775256752Sbrooks 1776256752Sbrooks /* 1777256752Sbrooks * We are only doing single-PHY with this driver currently. The 1778256752Sbrooks * defaults would be right so that BASE_CFG_MDIO_ADDR0 points to the 1779256752Sbrooks * 1st PHY address (0) apart from the fact that BMCR0 is always 1780256752Sbrooks * the PCS mapping, so we always use BMCR1. See Table 5-1 0xA0-0xBF. 1781256752Sbrooks */ 1782256752Sbrooks#if 0 /* Always PCS. */ 1783256752Sbrooks sc->atse_bmcr0 = MDIO_0_START; 1784256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_MDIO_ADDR0, 0x00); 1785256752Sbrooks#endif 1786256752Sbrooks /* Always use matching PHY for atse[0..]. */ 1787256752Sbrooks sc->atse_phy_addr = device_get_unit(dev); 1788256752Sbrooks sc->atse_bmcr1 = MDIO_1_START; 1789256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_MDIO_ADDR1, sc->atse_phy_addr); 1790256752Sbrooks 1791256752Sbrooks /* Reset the adapter. */ 1792256752Sbrooks atse_reset(sc); 1793256752Sbrooks 1794256752Sbrooks /* Setup interface. */ 1795256752Sbrooks ifp = sc->atse_ifp = if_alloc(IFT_ETHER); 1796256752Sbrooks if (ifp == NULL) { 1797256752Sbrooks device_printf(dev, "if_alloc() failed\n"); 1798256752Sbrooks error = ENOSPC; 1799256752Sbrooks goto err; 1800256752Sbrooks } 1801256752Sbrooks ifp->if_softc = sc; 1802256752Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1803256752Sbrooks ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1804256752Sbrooks ifp->if_ioctl = atse_ioctl; 1805256752Sbrooks ifp->if_start = atse_start; 1806256752Sbrooks ifp->if_init = atse_init; 1807256752Sbrooks IFQ_SET_MAXLEN(&ifp->if_snd, ATSE_TX_LIST_CNT - 1); 1808256752Sbrooks ifp->if_snd.ifq_drv_maxlen = ATSE_TX_LIST_CNT - 1; 1809256752Sbrooks IFQ_SET_READY(&ifp->if_snd); 1810256752Sbrooks 1811256752Sbrooks /* MII setup. */ 1812256752Sbrooks error = mii_attach(dev, &sc->atse_miibus, ifp, atse_ifmedia_upd, 1813256752Sbrooks atse_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 1814256752Sbrooks if (error != 0) { 1815256752Sbrooks device_printf(dev, "attaching PHY failed: %d\n", error); 1816256752Sbrooks goto err; 1817256752Sbrooks } 1818256752Sbrooks 1819256752Sbrooks /* Call media-indepedent attach routine. */ 1820256752Sbrooks ether_ifattach(ifp, sc->atse_eth_addr); 1821256752Sbrooks 1822256752Sbrooks /* Tell the upper layer(s) about vlan mtu support. */ 1823256752Sbrooks ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1824256752Sbrooks ifp->if_capabilities |= IFCAP_VLAN_MTU; 1825256752Sbrooks ifp->if_capenable = ifp->if_capabilities; 1826256752Sbrooks#ifdef DEVICE_POLLING 1827256752Sbrooks /* We will enable polling by default if no irqs available. See below. */ 1828256752Sbrooks ifp->if_capabilities |= IFCAP_POLLING; 1829256752Sbrooks#endif 1830256752Sbrooks 1831256752Sbrooks /* Hook up interrupts. */ 1832256752Sbrooks if (sc->atse_rx_irq_res != NULL) { 1833256752Sbrooks error = bus_setup_intr(dev, sc->atse_rx_irq_res, INTR_TYPE_NET | 1834271969Sbz INTR_MPSAFE, NULL, atse_rx_intr, sc, &sc->atse_rx_intrhand); 1835256752Sbrooks if (error != 0) { 1836256752Sbrooks device_printf(dev, "enabling RX IRQ failed\n"); 1837256752Sbrooks ether_ifdetach(ifp); 1838256752Sbrooks goto err; 1839256752Sbrooks } 1840256752Sbrooks } 1841256752Sbrooks 1842256752Sbrooks if (sc->atse_tx_irq_res != NULL) { 1843256752Sbrooks error = bus_setup_intr(dev, sc->atse_tx_irq_res, INTR_TYPE_NET | 1844271969Sbz INTR_MPSAFE, NULL, atse_tx_intr, sc, &sc->atse_tx_intrhand); 1845256752Sbrooks if (error != 0) { 1846256752Sbrooks bus_teardown_intr(dev, sc->atse_rx_irq_res, 1847256752Sbrooks sc->atse_rx_intrhand); 1848256752Sbrooks device_printf(dev, "enabling TX IRQ failed\n"); 1849256752Sbrooks ether_ifdetach(ifp); 1850256752Sbrooks goto err; 1851256752Sbrooks } 1852256752Sbrooks } 1853256752Sbrooks 1854256752Sbrooks if ((ifp->if_capenable & IFCAP_POLLING) != 0 || 1855256752Sbrooks (sc->atse_rx_irq_res == NULL && sc->atse_tx_irq_res == NULL)) { 1856256752Sbrooks#ifdef DEVICE_POLLING 1857256752Sbrooks /* If not on and no IRQs force it on. */ 1858256752Sbrooks if (sc->atse_rx_irq_res == NULL && sc->atse_tx_irq_res == NULL){ 1859256752Sbrooks ifp->if_capenable |= IFCAP_POLLING; 1860256752Sbrooks device_printf(dev, "forcing to polling due to no " 1861256752Sbrooks "interrupts\n"); 1862256752Sbrooks } 1863256752Sbrooks error = ether_poll_register(atse_poll, ifp); 1864256752Sbrooks if (error != 0) 1865256752Sbrooks goto err; 1866256752Sbrooks#else 1867256752Sbrooks device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n"); 1868256752Sbrooks error = ENXIO; 1869256752Sbrooks#endif 1870256752Sbrooks } else { 1871256752Sbrooks ATSE_RX_INTR_ENABLE(sc); 1872256752Sbrooks ATSE_TX_INTR_ENABLE(sc); 1873256752Sbrooks } 1874256752Sbrooks 1875256752Sbrookserr: 1876256752Sbrooks if (error != 0) 1877256752Sbrooks atse_detach(dev); 1878256752Sbrooks 1879256752Sbrooks if (error == 0) 1880256752Sbrooks atse_sysctl_stats_attach(dev); 1881256752Sbrooks 1882256752Sbrooks return (error); 1883256752Sbrooks} 1884256752Sbrooks 1885256752Sbrooksstatic int 1886256752Sbrooksatse_detach(device_t dev) 1887256752Sbrooks{ 1888256752Sbrooks struct atse_softc *sc; 1889256752Sbrooks struct ifnet *ifp; 1890256752Sbrooks 1891256752Sbrooks sc = device_get_softc(dev); 1892256752Sbrooks KASSERT(mtx_initialized(&sc->atse_mtx), ("%s: mutex not initialized", 1893256752Sbrooks device_get_nameunit(dev))); 1894256752Sbrooks ifp = sc->atse_ifp; 1895256752Sbrooks 1896256752Sbrooks#ifdef DEVICE_POLLING 1897256752Sbrooks if (ifp->if_capenable & IFCAP_POLLING) 1898256752Sbrooks ether_poll_deregister(ifp); 1899256752Sbrooks#endif 1900256752Sbrooks 1901256752Sbrooks /* Only cleanup if attach succeeded. */ 1902256752Sbrooks if (device_is_attached(dev)) { 1903256752Sbrooks ATSE_LOCK(sc); 1904256752Sbrooks atse_stop_locked(sc); 1905256752Sbrooks ATSE_UNLOCK(sc); 1906256752Sbrooks callout_drain(&sc->atse_tick); 1907256752Sbrooks ether_ifdetach(ifp); 1908256752Sbrooks } 1909256752Sbrooks if (sc->atse_miibus != NULL) 1910256752Sbrooks device_delete_child(dev, sc->atse_miibus); 1911256752Sbrooks 1912256752Sbrooks if (sc->atse_tx_intrhand) 1913256752Sbrooks bus_teardown_intr(dev, sc->atse_tx_irq_res, 1914256752Sbrooks sc->atse_tx_intrhand); 1915256752Sbrooks if (sc->atse_rx_intrhand) 1916256752Sbrooks bus_teardown_intr(dev, sc->atse_rx_irq_res, 1917256752Sbrooks sc->atse_rx_intrhand); 1918256752Sbrooks 1919256752Sbrooks if (ifp != NULL) 1920256752Sbrooks if_free(ifp); 1921256752Sbrooks 1922256752Sbrooks if (sc->atse_tx_buf != NULL) 1923256752Sbrooks free(sc->atse_tx_buf, M_DEVBUF); 1924256752Sbrooks 1925256752Sbrooks mtx_destroy(&sc->atse_mtx); 1926256752Sbrooks 1927256752Sbrooks return (0); 1928256752Sbrooks} 1929256752Sbrooks 1930270059Sbz/* Shared between nexus and fdt implementation. */ 1931256752Sbrooksvoid 1932256752Sbrooksatse_detach_resources(device_t dev) 1933256752Sbrooks{ 1934256752Sbrooks struct atse_softc *sc; 1935256752Sbrooks 1936256752Sbrooks sc = device_get_softc(dev); 1937256752Sbrooks 1938256752Sbrooks if (sc->atse_txc_mem_res != NULL) { 1939256752Sbrooks bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_txc_mem_rid, 1940256752Sbrooks sc->atse_txc_mem_res); 1941256752Sbrooks sc->atse_txc_mem_res = NULL; 1942256752Sbrooks } 1943256752Sbrooks if (sc->atse_tx_mem_res != NULL) { 1944256752Sbrooks bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_tx_mem_rid, 1945256752Sbrooks sc->atse_tx_mem_res); 1946256752Sbrooks sc->atse_tx_mem_res = NULL; 1947256752Sbrooks } 1948256752Sbrooks if (sc->atse_tx_irq_res != NULL) { 1949256752Sbrooks bus_release_resource(dev, SYS_RES_IRQ, sc->atse_tx_irq_rid, 1950256752Sbrooks sc->atse_tx_irq_res); 1951256752Sbrooks sc->atse_tx_irq_res = NULL; 1952256752Sbrooks } 1953256752Sbrooks if (sc->atse_rxc_mem_res != NULL) { 1954256752Sbrooks bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_rxc_mem_rid, 1955256752Sbrooks sc->atse_rxc_mem_res); 1956256752Sbrooks sc->atse_rxc_mem_res = NULL; 1957256752Sbrooks } 1958256752Sbrooks if (sc->atse_rx_mem_res != NULL) { 1959256752Sbrooks bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_rx_mem_rid, 1960256752Sbrooks sc->atse_rx_mem_res); 1961256752Sbrooks sc->atse_rx_mem_res = NULL; 1962256752Sbrooks } 1963256752Sbrooks if (sc->atse_rx_irq_res != NULL) { 1964256752Sbrooks bus_release_resource(dev, SYS_RES_IRQ, sc->atse_rx_irq_rid, 1965256752Sbrooks sc->atse_rx_irq_res); 1966256752Sbrooks sc->atse_rx_irq_res = NULL; 1967256752Sbrooks } 1968256752Sbrooks if (sc->atse_mem_res != NULL) { 1969256752Sbrooks bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_mem_rid, 1970256752Sbrooks sc->atse_mem_res); 1971256752Sbrooks sc->atse_mem_res = NULL; 1972256752Sbrooks } 1973256752Sbrooks} 1974256752Sbrooks 1975256752Sbrooksint 1976256752Sbrooksatse_detach_dev(device_t dev) 1977256752Sbrooks{ 1978256752Sbrooks int error; 1979256752Sbrooks 1980256752Sbrooks error = atse_detach(dev); 1981256752Sbrooks if (error) { 1982256752Sbrooks /* We are basically in undefined state now. */ 1983256752Sbrooks device_printf(dev, "atse_detach() failed: %d\n", error); 1984256752Sbrooks return (error); 1985256752Sbrooks } 1986256752Sbrooks 1987256752Sbrooks atse_detach_resources(dev); 1988256752Sbrooks 1989256752Sbrooks return (0); 1990256752Sbrooks} 1991256752Sbrooks 1992256752Sbrooksint 1993256752Sbrooksatse_miibus_readreg(device_t dev, int phy, int reg) 1994256752Sbrooks{ 1995256752Sbrooks struct atse_softc *sc; 1996256752Sbrooks 1997256752Sbrooks sc = device_get_softc(dev); 1998256752Sbrooks 1999256752Sbrooks /* 2000256752Sbrooks * We currently do not support re-mapping of MDIO space on-the-fly 2001256752Sbrooks * but de-facto hard-code the phy#. 2002256752Sbrooks */ 2003256752Sbrooks if (phy != sc->atse_phy_addr) 2004256752Sbrooks return (0); 2005256752Sbrooks 2006256752Sbrooks return (PHY_READ_2(sc, reg)); 2007256752Sbrooks} 2008256752Sbrooks 2009256752Sbrooksint 2010256752Sbrooksatse_miibus_writereg(device_t dev, int phy, int reg, int data) 2011256752Sbrooks{ 2012256752Sbrooks struct atse_softc *sc; 2013256752Sbrooks 2014256752Sbrooks sc = device_get_softc(dev); 2015256752Sbrooks 2016256752Sbrooks /* 2017256752Sbrooks * We currently do not support re-mapping of MDIO space on-the-fly 2018256752Sbrooks * but de-facto hard-code the phy#. 2019256752Sbrooks */ 2020256752Sbrooks if (phy != sc->atse_phy_addr) 2021256752Sbrooks return (0); 2022256752Sbrooks 2023256752Sbrooks PHY_WRITE_2(sc, reg, data); 2024256752Sbrooks return (0); 2025256752Sbrooks} 2026256752Sbrooks 2027256752Sbrooksvoid 2028256752Sbrooksatse_miibus_statchg(device_t dev) 2029256752Sbrooks{ 2030256752Sbrooks struct atse_softc *sc; 2031256752Sbrooks struct mii_data *mii; 2032256752Sbrooks struct ifnet *ifp; 2033256752Sbrooks uint32_t val4; 2034256752Sbrooks 2035256752Sbrooks sc = device_get_softc(dev); 2036256752Sbrooks ATSE_LOCK_ASSERT(sc); 2037256752Sbrooks 2038256752Sbrooks mii = device_get_softc(sc->atse_miibus); 2039256752Sbrooks ifp = sc->atse_ifp; 2040256752Sbrooks if (mii == NULL || ifp == NULL || 2041256752Sbrooks (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2042256752Sbrooks return; 2043256752Sbrooks 2044256752Sbrooks val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); 2045256752Sbrooks 2046256752Sbrooks /* Assume no link. */ 2047256752Sbrooks sc->atse_flags &= ~ATSE_FLAGS_LINK; 2048256752Sbrooks 2049256752Sbrooks if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 2050256752Sbrooks (IFM_ACTIVE | IFM_AVALID)) { 2051256752Sbrooks 2052256752Sbrooks switch (IFM_SUBTYPE(mii->mii_media_active)) { 2053256752Sbrooks case IFM_10_T: 2054256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_ENA_10; 2055256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED; 2056256752Sbrooks sc->atse_flags |= ATSE_FLAGS_LINK; 2057256752Sbrooks break; 2058256752Sbrooks case IFM_100_TX: 2059256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10; 2060256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED; 2061256752Sbrooks sc->atse_flags |= ATSE_FLAGS_LINK; 2062256752Sbrooks break; 2063256752Sbrooks case IFM_1000_T: 2064256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10; 2065256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_ETH_SPEED; 2066256752Sbrooks sc->atse_flags |= ATSE_FLAGS_LINK; 2067256752Sbrooks break; 2068256752Sbrooks default: 2069256752Sbrooks break; 2070256752Sbrooks } 2071256752Sbrooks } 2072256752Sbrooks 2073256752Sbrooks if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) { 2074256752Sbrooks /* XXX-BZ need to stop the MAC? */ 2075256752Sbrooks return; 2076256752Sbrooks } 2077256752Sbrooks 2078256752Sbrooks if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) 2079256752Sbrooks val4 &= ~BASE_CFG_COMMAND_CONFIG_HD_ENA; 2080256752Sbrooks else 2081256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_HD_ENA; 2082256752Sbrooks /* XXX-BZ flow control? */ 2083256752Sbrooks 2084256752Sbrooks /* Make sure the MAC is activated. */ 2085256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_TX_ENA; 2086256752Sbrooks val4 |= BASE_CFG_COMMAND_CONFIG_RX_ENA; 2087256752Sbrooks 2088256752Sbrooks CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); 2089256752Sbrooks} 2090256752Sbrooks 2091256752Sbrooks/* end */ 2092