Index: head/sys/dev/altera/atse/if_atse.c =================================================================== --- head/sys/dev/altera/atse/if_atse.c (revision 332473) +++ head/sys/dev/altera/atse/if_atse.c (revision 332474) @@ -1,2099 +1,1603 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012, 2013 Bjoern A. Zeeb * Copyright (c) 2014 Robert N. M. Watson + * Copyright (c) 2016-2017 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) * ("MRC2"), as part of the DARPA MRC research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Altera Triple-Speed Ethernet MegaCore, Function User Guide * UG-01008-3.0, Software Version: 12.0, June 2012. * Available at the time of writing at: * http://www.altera.com/literature/ug/ug_ethernet.pdf * * We are using an Marvell E1111 (Alaska) PHY on the DE4. See mii/e1000phy.c. */ /* * XXX-BZ NOTES: * - ifOutBroadcastPkts are only counted if both ether dst and src are all-1s; * seems an IP core bug, they count ether broadcasts as multicast. Is this * still the case? * - figure out why the TX FIFO fill status and intr did not work as expected. * - test 100Mbit/s and 10Mbit/s * - blacklist the one special factory programmed ethernet address (for now * hardcoded, later from loader?) * - resolve all XXX, left as reminders to shake out details later * - Jumbo frame support */ #include __FBSDID("$FreeBSD$"); #include "opt_device_polling.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include -MODULE_DEPEND(atse, ether, 1, 1, 1); -MODULE_DEPEND(atse, miibus, 1, 1, 1); +#define RX_QUEUE_SIZE 4096 +#define TX_QUEUE_SIZE 4096 +#define NUM_RX_MBUF 512 +#define BUFRING_SIZE 8192 +#include -#define ATSE_WATCHDOG_TIME 5 - -#ifdef DEVICE_POLLING -static poll_handler_t atse_poll; -#endif - /* XXX once we'd do parallel attach, we need a global lock for this. */ #define ATSE_ETHERNET_OPTION_BITS_UNDEF 0 #define ATSE_ETHERNET_OPTION_BITS_READ 1 static int atse_ethernet_option_bits_flag = ATSE_ETHERNET_OPTION_BITS_UNDEF; static uint8_t atse_ethernet_option_bits[ALTERA_ETHERNET_OPTION_BITS_LEN]; -static int atse_intr_debug_enable = 0; -SYSCTL_INT(_debug, OID_AUTO, atse_intr_debug_enable, CTLFLAG_RW, - &atse_intr_debug_enable, 0, - "Extra debugging output for atse interrupts"); - /* * Softc and critical resource locking. */ #define ATSE_LOCK(_sc) mtx_lock(&(_sc)->atse_mtx) #define ATSE_UNLOCK(_sc) mtx_unlock(&(_sc)->atse_mtx) #define ATSE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->atse_mtx, MA_OWNED) -#define ATSE_TX_PENDING(sc) (sc->atse_tx_m != NULL || \ - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) +#define ATSE_DEBUG +#undef ATSE_DEBUG -#ifdef DEBUG +#ifdef ATSE_DEBUG #define DPRINTF(format, ...) printf(format, __VA_ARGS__) #else #define DPRINTF(format, ...) #endif -/* a_api.c functions; factor out? */ -static inline void -a_onchip_fifo_mem_core_write(struct resource *res, uint32_t off, - uint32_t val4, const char *desc, const char *f, const int l) -{ - - val4 = htole32(val4); - DPRINTF("[%s:%d] FIFOW %s 0x%08x = 0x%08x\n", f, l, desc, off, val4); - bus_write_4(res, off, val4); -} - -static inline uint32_t -a_onchip_fifo_mem_core_read(struct resource *res, uint32_t off, - const char *desc, const char *f, const int l) -{ - uint32_t val4; - - val4 = le32toh(bus_read_4(res, off)); - DPRINTF("[%s:%d] FIFOR %s 0x%08x = 0x%08x\n", f, l, desc, off, val4); - - return (val4); -} - -/* The FIFO does an endian conversion, so we must not do it as well. */ -/* XXX-BZ in fact we should do a htobe32 so le would be fine as well? */ -#define ATSE_TX_DATA_WRITE(sc, val4) \ - bus_write_4((sc)->atse_tx_mem_res, A_ONCHIP_FIFO_MEM_CORE_DATA, val4) - -#define ATSE_TX_META_WRITE(sc, val4) \ - a_onchip_fifo_mem_core_write((sc)->atse_tx_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_METADATA, \ - (val4), "TXM", __func__, __LINE__) -#define ATSE_TX_META_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_tx_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_METADATA, \ - "TXM", __func__, __LINE__) - -#define ATSE_TX_READ_FILL_LEVEL(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL, \ - "TX_FILL", __func__, __LINE__) -#define ATSE_RX_READ_FILL_LEVEL(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL, \ - "RX_FILL", __func__, __LINE__) - -/* The FIFO does an endian conversion, so we must not do it as well. */ -/* XXX-BZ in fact we should do a htobe32 so le would be fine as well? */ -#define ATSE_RX_DATA_READ(sc) \ - bus_read_4((sc)->atse_rx_mem_res, A_ONCHIP_FIFO_MEM_CORE_DATA) -#define ATSE_RX_META_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_rx_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_METADATA, \ - "RXM", __func__, __LINE__) - -#define ATSE_RX_STATUS_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS, \ - "RX_EVENT", __func__, __LINE__) - -#define ATSE_TX_STATUS_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS, \ - "TX_EVENT", __func__, __LINE__) - -#define ATSE_RX_EVENT_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ - "RX_EVENT", __func__, __LINE__) - -#define ATSE_TX_EVENT_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ - "TX_EVENT", __func__, __LINE__) - -#define ATSE_RX_EVENT_CLEAR(sc) \ - do { \ - uint32_t val4; \ - \ - val4 = a_onchip_fifo_mem_core_read( \ - (sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ - "RX_EVENT", __func__, __LINE__); \ - if (val4 != 0x00) \ - a_onchip_fifo_mem_core_write( \ - (sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ - val4, "RX_EVENT", __func__, __LINE__); \ - } while(0) -#define ATSE_TX_EVENT_CLEAR(sc) \ - do { \ - uint32_t val4; \ - \ - val4 = a_onchip_fifo_mem_core_read( \ - (sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ - "TX_EVENT", __func__, __LINE__); \ - if (val4 != 0x00) \ - a_onchip_fifo_mem_core_write( \ - (sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, \ - val4, "TX_EVENT", __func__, __LINE__); \ - } while(0) - -#define ATSE_RX_EVENTS (A_ONCHIP_FIFO_MEM_CORE_INTR_FULL | \ - A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW | \ - A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW) -#define ATSE_RX_INTR_ENABLE(sc) \ - a_onchip_fifo_mem_core_write((sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ - ATSE_RX_EVENTS, \ - "RX_INTR", __func__, __LINE__) /* XXX-BZ review later. */ -#define ATSE_RX_INTR_DISABLE(sc) \ - a_onchip_fifo_mem_core_write((sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, 0, \ - "RX_INTR", __func__, __LINE__) -#define ATSE_RX_INTR_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ - "RX_INTR", __func__, __LINE__) - -#define ATSE_TX_EVENTS (A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY | \ - A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW | \ - A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW) -#define ATSE_TX_INTR_ENABLE(sc) \ - a_onchip_fifo_mem_core_write((sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ - ATSE_TX_EVENTS, \ - "TX_INTR", __func__, __LINE__) /* XXX-BZ review later. */ -#define ATSE_TX_INTR_DISABLE(sc) \ - a_onchip_fifo_mem_core_write((sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, 0, \ - "TX_INTR", __func__, __LINE__) -#define ATSE_TX_INTR_READ(sc) \ - a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res, \ - A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, \ - "TX_INTR", __func__, __LINE__) - -static int atse_rx_locked(struct atse_softc *sc); - /* * Register space access macros. */ static inline void csr_write_4(struct atse_softc *sc, uint32_t reg, uint32_t val4, const char *f, const int l) { val4 = htole32(val4); DPRINTF("[%s:%d] CSR W %s 0x%08x (0x%08x) = 0x%08x\n", f, l, "atse_mem_res", reg, reg * 4, val4); bus_write_4(sc->atse_mem_res, reg * 4, val4); } static inline uint32_t csr_read_4(struct atse_softc *sc, uint32_t reg, const char *f, const int l) { uint32_t val4; val4 = le32toh(bus_read_4(sc->atse_mem_res, reg * 4)); DPRINTF("[%s:%d] CSR R %s 0x%08x (0x%08x) = 0x%08x\n", f, l, "atse_mem_res", reg, reg * 4, val4); return (val4); } /* * See page 5-2 that it's all dword offsets and the MS 16 bits need to be zero * on write and ignored on read. */ static inline void pxx_write_2(struct atse_softc *sc, bus_addr_t bmcr, uint32_t reg, uint16_t val, const char *f, const int l, const char *s) { uint32_t val4; val4 = htole32(val & 0x0000ffff); DPRINTF("[%s:%d] %s W %s 0x%08x (0x%08jx) = 0x%08x\n", f, l, s, "atse_mem_res", reg, (bmcr + reg) * 4, val4); bus_write_4(sc->atse_mem_res, (bmcr + reg) * 4, val4); } static inline uint16_t pxx_read_2(struct atse_softc *sc, bus_addr_t bmcr, uint32_t reg, const char *f, const int l, const char *s) { uint32_t val4; uint16_t val; val4 = bus_read_4(sc->atse_mem_res, (bmcr + reg) * 4); val = le32toh(val4) & 0x0000ffff; DPRINTF("[%s:%d] %s R %s 0x%08x (0x%08jx) = 0x%04x\n", f, l, s, "atse_mem_res", reg, (bmcr + reg) * 4, val); return (val); } #define CSR_WRITE_4(sc, reg, val) \ csr_write_4((sc), (reg), (val), __func__, __LINE__) #define CSR_READ_4(sc, reg) \ csr_read_4((sc), (reg), __func__, __LINE__) #define PCS_WRITE_2(sc, reg, val) \ pxx_write_2((sc), sc->atse_bmcr0, (reg), (val), __func__, __LINE__, \ "PCS") #define PCS_READ_2(sc, reg) \ pxx_read_2((sc), sc->atse_bmcr0, (reg), __func__, __LINE__, "PCS") #define PHY_WRITE_2(sc, reg, val) \ pxx_write_2((sc), sc->atse_bmcr1, (reg), (val), __func__, __LINE__, \ "PHY") #define PHY_READ_2(sc, reg) \ pxx_read_2((sc), sc->atse_bmcr1, (reg), __func__, __LINE__, "PHY") static void atse_tick(void *); static int atse_detach(device_t); devclass_t atse_devclass; static int -atse_tx_locked(struct atse_softc *sc, int *sent) +atse_rx_enqueue(struct atse_softc *sc, uint32_t n) { struct mbuf *m; - uint32_t val4, fill_level; - int leftm; - int c; + int i; - ATSE_LOCK_ASSERT(sc); + for (i = 0; i < n; i++) { + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + device_printf(sc->dev, + "%s: Can't alloc rx mbuf\n", __func__); + return (-1); + } - m = sc->atse_tx_m; - KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc)); - KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m)); - - /* - * Copy to buffer to minimize our pain as we can only store - * double words which, after the first mbuf gets out of alignment - * quite quickly. - */ - if (sc->atse_tx_m_offset == 0) { - m_copydata(m, 0, m->m_pkthdr.len, sc->atse_tx_buf); - sc->atse_tx_buf_len = m->m_pkthdr.len; + m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; + xdma_enqueue_mbuf(sc->xchan_rx, &m, 0, 4, 4, XDMA_DEV_TO_MEM); } - fill_level = ATSE_TX_READ_FILL_LEVEL(sc); -#if 0 /* Returns 0xdeadc0de. */ - val4 = ATSE_TX_META_READ(sc); -#endif - if (sc->atse_tx_m_offset == 0) { - /* Write start of packet. */ - val4 = A_ONCHIP_FIFO_MEM_CORE_SOP; - val4 &= ~A_ONCHIP_FIFO_MEM_CORE_EOP; - ATSE_TX_META_WRITE(sc, val4); + return (0); +} + +static int +atse_xdma_tx_intr(void *arg, xdma_transfer_status_t *status) +{ + xdma_transfer_status_t st; + struct atse_softc *sc; + struct ifnet *ifp; + struct mbuf *m; + int err; + + sc = arg; + + ATSE_LOCK(sc); + + ifp = sc->atse_ifp; + + for (;;) { + err = xdma_dequeue_mbuf(sc->xchan_tx, &m, &st); + if (err != 0) { + break; + } + + if (st.error != 0) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } + + m_freem(m); + sc->txcount--; } - /* TX FIFO is single clock mode, so we have the full FIFO. */ - c = 0; - while ((sc->atse_tx_buf_len - sc->atse_tx_m_offset) > 4 && - fill_level < AVALON_FIFO_TX_BASIC_OPTS_DEPTH) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - bcopy(&sc->atse_tx_buf[sc->atse_tx_m_offset], &val4, - sizeof(val4)); - ATSE_TX_DATA_WRITE(sc, val4); - sc->atse_tx_m_offset += sizeof(val4); - c += sizeof(val4); + ATSE_UNLOCK(sc); - fill_level++; - if (fill_level == AVALON_FIFO_TX_BASIC_OPTS_DEPTH) - fill_level = ATSE_TX_READ_FILL_LEVEL(sc); + return (0); +} + +static int +atse_xdma_rx_intr(void *arg, xdma_transfer_status_t *status) +{ + xdma_transfer_status_t st; + struct atse_softc *sc; + struct ifnet *ifp; + struct mbuf *m; + int err; + uint32_t cnt_processed; + + sc = arg; + + ATSE_LOCK(sc); + + ifp = sc->atse_ifp; + + cnt_processed = 0; + for (;;) { + err = xdma_dequeue_mbuf(sc->xchan_rx, &m, &st); + if (err != 0) { + break; + } + cnt_processed++; + + if (st.error != 0) { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + m_freem(m); + continue; + } + + m->m_pkthdr.len = m->m_len = st.transferred; + m->m_pkthdr.rcvif = ifp; + m_adj(m, ETHER_ALIGN); + ATSE_UNLOCK(sc); + (*ifp->if_input)(ifp, m); + ATSE_LOCK(sc); } - if (sent != NULL) - *sent += c; - /* Set EOP *before* writing the last symbol. */ - if (sc->atse_tx_m_offset >= (sc->atse_tx_buf_len - 4) && - fill_level < AVALON_FIFO_TX_BASIC_OPTS_DEPTH) { + atse_rx_enqueue(sc, cnt_processed); - /* Set EndOfPacket. */ - val4 = A_ONCHIP_FIFO_MEM_CORE_EOP; + ATSE_UNLOCK(sc); - /* Set EMPTY. */ - leftm = sc->atse_tx_buf_len - sc->atse_tx_m_offset; - val4 |= ((4 - leftm) << A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT); - ATSE_TX_META_WRITE(sc, val4); + return (0); +} - /* Write last symbol. */ - val4 = 0; - bcopy(sc->atse_tx_buf + sc->atse_tx_m_offset, &val4, leftm); - ATSE_TX_DATA_WRITE(sc, val4); +static int +atse_transmit_locked(struct ifnet *ifp) +{ + struct atse_softc *sc; + struct mbuf *m; + struct buf_ring *br; + int error; + int enq; - if (sent != NULL) - *sent += leftm; + sc = ifp->if_softc; + br = sc->br; - /* OK, the packet is gone. */ - sc->atse_tx_m = NULL; - sc->atse_tx_m_offset = 0; + enq = 0; + while ((m = drbr_peek(ifp, br)) != NULL) { + error = xdma_enqueue_mbuf(sc->xchan_tx, &m, 0, 4, 4, XDMA_MEM_TO_DEV); + if (error != 0) { + /* No space in request queue available yet. */ + drbr_putback(ifp, br, m); + break; + } + + drbr_advance(ifp, br); + + sc->txcount++; + enq++; + /* If anyone is interested give them a copy. */ - BPF_MTAP(sc->atse_ifp, m); + ETHER_BPF_MTAP(ifp, m); + } - m_freem(m); - return (0); - } + if (enq > 0) + xdma_queue_submit(sc->xchan_tx); - return (EBUSY); + return (0); } -static void -atse_start_locked(struct ifnet *ifp) +static int +atse_transmit(struct ifnet *ifp, struct mbuf *m) { struct atse_softc *sc; - int error, sent; + struct buf_ring *br; + int error; sc = ifp->if_softc; - ATSE_LOCK_ASSERT(sc); + br = sc->br; - if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING || (sc->atse_flags & ATSE_FLAGS_LINK) == 0) - return; + ATSE_LOCK(sc); -#if 1 - /* - * Disable the watchdog while sending, we are batching packets. - * Though we should never reach 5 seconds, and are holding the lock, - * but who knows. - */ - sc->atse_watchdog_timer = 0; -#endif + mtx_lock(&sc->br_mtx); - if (sc->atse_tx_m != NULL) { - error = atse_tx_locked(sc, &sent); - if (error != 0) - goto done; + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) { + error = drbr_enqueue(ifp, sc->br, m); + mtx_unlock(&sc->br_mtx); + ATSE_UNLOCK(sc); + return (error); } - /* We have more space to send so continue ... */ - for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { - IFQ_DRV_DEQUEUE(&ifp->if_snd, sc->atse_tx_m); - sc->atse_tx_m_offset = 0; - if (sc->atse_tx_m == NULL) - break; - error = atse_tx_locked(sc, &sent); - if (error != 0) - goto done; + if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) { + error = drbr_enqueue(ifp, sc->br, m); + mtx_unlock(&sc->br_mtx); + ATSE_UNLOCK(sc); + return (error); } -done: - /* If the IP core walks into Nekromanteion try to bail out. */ - if (sent > 0) - sc->atse_watchdog_timer = ATSE_WATCHDOG_TIME; + error = drbr_enqueue(ifp, br, m); + if (error) { + mtx_unlock(&sc->br_mtx); + ATSE_UNLOCK(sc); + return (error); + } + error = atse_transmit_locked(ifp); + + mtx_unlock(&sc->br_mtx); + ATSE_UNLOCK(sc); + + return (error); } static void -atse_start(struct ifnet *ifp) +atse_qflush(struct ifnet *ifp) { struct atse_softc *sc; sc = ifp->if_softc; - ATSE_LOCK(sc); - atse_start_locked(ifp); - ATSE_UNLOCK(sc); + + printf("%s\n", __func__); } static int atse_stop_locked(struct atse_softc *sc) { uint32_t mask, val4; struct ifnet *ifp; int i; ATSE_LOCK_ASSERT(sc); - sc->atse_watchdog_timer = 0; callout_stop(&sc->atse_tick); ifp = sc->atse_ifp; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - ATSE_RX_INTR_DISABLE(sc); - ATSE_TX_INTR_DISABLE(sc); - ATSE_RX_EVENT_CLEAR(sc); - ATSE_TX_EVENT_CLEAR(sc); /* Disable MAC transmit and receive datapath. */ mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA; val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); val4 &= ~mask; CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); + /* Wait for bits to be cleared; i=100 is excessive. */ for (i = 0; i < 100; i++) { val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); - if ((val4 & mask) == 0) + if ((val4 & mask) == 0) { break; + } DELAY(10); } - if ((val4 & mask) != 0) + + if ((val4 & mask) != 0) { device_printf(sc->atse_dev, "Disabling MAC TX/RX timed out.\n"); /* Punt. */ + } sc->atse_flags &= ~ATSE_FLAGS_LINK; - /* XXX-BZ free the RX/TX rings. */ - return (0); } static uint8_t atse_mchash(struct atse_softc *sc __unused, const uint8_t *addr) { uint8_t x, y; int i, j; x = 0; for (i = 0; i < ETHER_ADDR_LEN; i++) { y = addr[i] & 0x01; for (j = 1; j < 8; j++) y ^= (addr[i] >> j) & 0x01; x |= (y << i); } return (x); } static int atse_rxfilter_locked(struct atse_softc *sc) { struct ifmultiaddr *ifma; struct ifnet *ifp; uint32_t val4; int i; /* XXX-BZ can we find out if we have the MHASH synthesized? */ val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); /* For simplicity always hash full 48 bits of addresses. */ if ((val4 & BASE_CFG_COMMAND_CONFIG_MHASH_SEL) != 0) val4 &= ~BASE_CFG_COMMAND_CONFIG_MHASH_SEL; ifp = sc->atse_ifp; - if (ifp->if_flags & IFF_PROMISC) + if (ifp->if_flags & IFF_PROMISC) { val4 |= BASE_CFG_COMMAND_CONFIG_PROMIS_EN; - else + } else { val4 &= ~BASE_CFG_COMMAND_CONFIG_PROMIS_EN; + } CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); if (ifp->if_flags & IFF_ALLMULTI) { /* Accept all multicast addresses. */ for (i = 0; i <= MHASH_LEN; i++) CSR_WRITE_4(sc, MHASH_START + i, 0x1); } else { /* * Can hold MHASH_LEN entries. * XXX-BZ bitstring.h would be more general. */ uint64_t h; h = 0; /* * Re-build and re-program hash table. First build the * bit-field "yes" or "no" for each slot per address, then * do all the programming afterwards. */ if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) + if (ifma->ifma_addr->sa_family != AF_LINK) { continue; + } h |= (1 << atse_mchash(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); } if_maddr_runlock(ifp); - for (i = 0; i <= MHASH_LEN; i++) + for (i = 0; i <= MHASH_LEN; i++) { CSR_WRITE_4(sc, MHASH_START + i, (h & (1 << i)) ? 0x01 : 0x00); + } } return (0); } static int atse_ethernet_option_bits_read_fdt(device_t dev) { struct resource *res; device_t fdev; int i, rid; - if (atse_ethernet_option_bits_flag & ATSE_ETHERNET_OPTION_BITS_READ) + if (atse_ethernet_option_bits_flag & ATSE_ETHERNET_OPTION_BITS_READ) { return (0); + } fdev = device_find_child(device_get_parent(dev), "cfi", 0); - if (fdev == NULL) + if (fdev == NULL) { return (ENOENT); + } rid = 0; res = bus_alloc_resource_any(fdev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE); - if (res == NULL) + if (res == NULL) { return (ENXIO); + } - for (i = 0; i < ALTERA_ETHERNET_OPTION_BITS_LEN; i++) + for (i = 0; i < ALTERA_ETHERNET_OPTION_BITS_LEN; i++) { atse_ethernet_option_bits[i] = bus_read_1(res, ALTERA_ETHERNET_OPTION_BITS_OFF + i); + } bus_release_resource(fdev, SYS_RES_MEMORY, rid, res); atse_ethernet_option_bits_flag |= ATSE_ETHERNET_OPTION_BITS_READ; return (0); } static int atse_ethernet_option_bits_read(device_t dev) { int error; error = atse_ethernet_option_bits_read_fdt(dev); if (error == 0) return (0); device_printf(dev, "Cannot read Ethernet addresses from flash.\n"); return (error); } static int atse_get_eth_address(struct atse_softc *sc) { unsigned long hostid; uint32_t val4; int unit; /* * Make sure to only ever do this once. Otherwise a reset would * possibly change our ethernet address, which is not good at all. */ if (sc->atse_eth_addr[0] != 0x00 || sc->atse_eth_addr[1] != 0x00 || - sc->atse_eth_addr[2] != 0x00) + sc->atse_eth_addr[2] != 0x00) { return (0); + } if ((atse_ethernet_option_bits_flag & - ATSE_ETHERNET_OPTION_BITS_READ) == 0) + ATSE_ETHERNET_OPTION_BITS_READ) == 0) { goto get_random; + } val4 = atse_ethernet_option_bits[0] << 24; val4 |= atse_ethernet_option_bits[1] << 16; val4 |= atse_ethernet_option_bits[2] << 8; val4 |= atse_ethernet_option_bits[3]; /* They chose "safe". */ if (val4 != le32toh(0x00005afe)) { device_printf(sc->atse_dev, "Magic '5afe' is not safe: 0x%08x. " "Falling back to random numbers for hardware address.\n", val4); goto get_random; } sc->atse_eth_addr[0] = atse_ethernet_option_bits[4]; sc->atse_eth_addr[1] = atse_ethernet_option_bits[5]; sc->atse_eth_addr[2] = atse_ethernet_option_bits[6]; sc->atse_eth_addr[3] = atse_ethernet_option_bits[7]; sc->atse_eth_addr[4] = atse_ethernet_option_bits[8]; sc->atse_eth_addr[5] = atse_ethernet_option_bits[9]; /* Handle factory default ethernet addresss: 00:07:ed:ff:ed:15 */ if (sc->atse_eth_addr[0] == 0x00 && sc->atse_eth_addr[1] == 0x07 && sc->atse_eth_addr[2] == 0xed && sc->atse_eth_addr[3] == 0xff && sc->atse_eth_addr[4] == 0xed && sc->atse_eth_addr[5] == 0x15) { device_printf(sc->atse_dev, "Factory programmed Ethernet " "hardware address blacklisted. Falling back to random " "address to avoid collisions.\n"); device_printf(sc->atse_dev, "Please re-program your flash.\n"); goto get_random; } if (sc->atse_eth_addr[0] == 0x00 && sc->atse_eth_addr[1] == 0x00 && sc->atse_eth_addr[2] == 0x00 && sc->atse_eth_addr[3] == 0x00 && sc->atse_eth_addr[4] == 0x00 && sc->atse_eth_addr[5] == 0x00) { device_printf(sc->atse_dev, "All zero's Ethernet hardware " "address blacklisted. Falling back to random address.\n"); device_printf(sc->atse_dev, "Please re-program your flash.\n"); goto get_random; } if (ETHER_IS_MULTICAST(sc->atse_eth_addr)) { device_printf(sc->atse_dev, "Multicast Ethernet hardware " "address blacklisted. Falling back to random address.\n"); device_printf(sc->atse_dev, "Please re-program your flash.\n"); goto get_random; } /* * If we find an Altera prefixed address with a 0x0 ending * adjust by device unit. If not and this is not the first * Ethernet, go to random. */ unit = device_get_unit(sc->atse_dev); - if (unit == 0x00) + if (unit == 0x00) { return (0); + } if (unit > 0x0f) { device_printf(sc->atse_dev, "We do not support Ethernet " "addresses for more than 16 MACs. Falling back to " "random hadware address.\n"); goto get_random; } if ((sc->atse_eth_addr[0] & ~0x2) != 0 || sc->atse_eth_addr[1] != 0x07 || sc->atse_eth_addr[2] != 0xed || (sc->atse_eth_addr[5] & 0x0f) != 0x0) { device_printf(sc->atse_dev, "Ethernet address not meeting our " "multi-MAC standards. Falling back to random hadware " "address.\n"); goto get_random; } sc->atse_eth_addr[5] |= (unit & 0x0f); return (0); get_random: /* * Fall back to random code we also use on bridge(4). */ getcredhostid(curthread->td_ucred, &hostid); if (hostid == 0) { arc4rand(sc->atse_eth_addr, ETHER_ADDR_LEN, 1); sc->atse_eth_addr[0] &= ~1;/* clear multicast bit */ sc->atse_eth_addr[0] |= 2; /* set the LAA bit */ } else { sc->atse_eth_addr[0] = 0x2; sc->atse_eth_addr[1] = (hostid >> 24) & 0xff; sc->atse_eth_addr[2] = (hostid >> 16) & 0xff; sc->atse_eth_addr[3] = (hostid >> 8 ) & 0xff; sc->atse_eth_addr[4] = hostid & 0xff; sc->atse_eth_addr[5] = sc->atse_unit & 0xff; } return (0); } static int atse_set_eth_address(struct atse_softc *sc, int n) { uint32_t v0, v1; v0 = (sc->atse_eth_addr[3] << 24) | (sc->atse_eth_addr[2] << 16) | (sc->atse_eth_addr[1] << 8) | sc->atse_eth_addr[0]; v1 = (sc->atse_eth_addr[5] << 8) | sc->atse_eth_addr[4]; if (n & ATSE_ETH_ADDR_DEF) { CSR_WRITE_4(sc, BASE_CFG_MAC_0, v0); CSR_WRITE_4(sc, BASE_CFG_MAC_1, v1); } if (n & ATSE_ETH_ADDR_SUPP1) { CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_0_0, v0); CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_0_1, v1); } if (n & ATSE_ETH_ADDR_SUPP2) { CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_1_0, v0); CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_1_1, v1); } if (n & ATSE_ETH_ADDR_SUPP3) { CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_2_0, v0); CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_2_1, v1); } if (n & ATSE_ETH_ADDR_SUPP4) { CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_3_0, v0); CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_3_1, v1); } return (0); } static int atse_reset(struct atse_softc *sc) { uint32_t val4, mask; uint16_t val; int i; /* 1. External PHY Initialization using MDIO. */ /* * We select the right MDIO space in atse_attach() and let MII do * anything else. */ /* 2. PCS Configuration Register Initialization. */ /* a. Set auto negotiation link timer to 1.6ms for SGMII. */ PCS_WRITE_2(sc, PCS_EXT_LINK_TIMER_0, 0x0D40); PCS_WRITE_2(sc, PCS_EXT_LINK_TIMER_1, 0x0003); /* b. Configure SGMII. */ val = PCS_EXT_IF_MODE_SGMII_ENA|PCS_EXT_IF_MODE_USE_SGMII_AN; PCS_WRITE_2(sc, PCS_EXT_IF_MODE, val); /* c. Enable auto negotiation. */ /* Ignore Bits 6,8,13; should be set,set,unset. */ val = PCS_READ_2(sc, PCS_CONTROL); val &= ~(PCS_CONTROL_ISOLATE|PCS_CONTROL_POWERDOWN); val &= ~PCS_CONTROL_LOOPBACK; /* Make this a -link1 option? */ val |= PCS_CONTROL_AUTO_NEGOTIATION_ENABLE; PCS_WRITE_2(sc, PCS_CONTROL, val); /* d. PCS reset. */ val = PCS_READ_2(sc, PCS_CONTROL); val |= PCS_CONTROL_RESET; PCS_WRITE_2(sc, PCS_CONTROL, val); /* Wait for reset bit to clear; i=100 is excessive. */ for (i = 0; i < 100; i++) { val = PCS_READ_2(sc, PCS_CONTROL); - if ((val & PCS_CONTROL_RESET) == 0) + if ((val & PCS_CONTROL_RESET) == 0) { break; + } DELAY(10); } if ((val & PCS_CONTROL_RESET) != 0) { device_printf(sc->atse_dev, "PCS reset timed out.\n"); return (ENXIO); } /* 3. MAC Configuration Register Initialization. */ /* a. Disable MAC transmit and receive datapath. */ mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA; val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); val4 &= ~mask; /* Samples in the manual do have the SW_RESET bit set here, why? */ CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); /* Wait for bits to be cleared; i=100 is excessive. */ for (i = 0; i < 100; i++) { val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); - if ((val4 & mask) == 0) + if ((val4 & mask) == 0) { break; + } DELAY(10); } if ((val4 & mask) != 0) { device_printf(sc->atse_dev, "Disabling MAC TX/RX timed out.\n"); return (ENXIO); } /* b. MAC FIFO configuration. */ CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_EMPTY, FIFO_DEPTH_TX - 16); CSR_WRITE_4(sc, BASE_CFG_TX_ALMOST_FULL, 3); CSR_WRITE_4(sc, BASE_CFG_TX_ALMOST_EMPTY, 8); CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_EMPTY, FIFO_DEPTH_RX - 16); CSR_WRITE_4(sc, BASE_CFG_RX_ALMOST_FULL, 8); CSR_WRITE_4(sc, BASE_CFG_RX_ALMOST_EMPTY, 8); #if 0 CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_FULL, 16); CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_FULL, 16); #else /* For store-and-forward mode, set this threshold to 0. */ CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_FULL, 0); CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_FULL, 0); #endif /* c. MAC address configuration. */ /* Also intialize supplementary addresses to our primary one. */ /* XXX-BZ FreeBSD really needs to grow and API for using these. */ atse_get_eth_address(sc); atse_set_eth_address(sc, ATSE_ETH_ADDR_ALL); /* d. MAC function configuration. */ CSR_WRITE_4(sc, BASE_CFG_FRM_LENGTH, 1518); /* Default. */ CSR_WRITE_4(sc, BASE_CFG_TX_IPG_LENGTH, 12); CSR_WRITE_4(sc, BASE_CFG_PAUSE_QUANT, 0xFFFF); val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); /* * If 1000BASE-X/SGMII PCS is initialized, set the ETH_SPEED (bit 3) * and ENA_10 (bit 25) in command_config register to 0. If half duplex * is reported in the PHY/PCS status register, set the HD_ENA (bit 10) * to 1 in command_config register. * BZ: We shoot for 1000 instead. */ #if 0 val4 |= BASE_CFG_COMMAND_CONFIG_ETH_SPEED; #else val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED; #endif val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10; #if 0 /* * We do not want to set this, otherwise, we could not even send * random raw ethernet frames for various other research. By default * FreeBSD will use the right ether source address. */ val4 |= BASE_CFG_COMMAND_CONFIG_TX_ADDR_INS; #endif val4 |= BASE_CFG_COMMAND_CONFIG_PAD_EN; val4 &= ~BASE_CFG_COMMAND_CONFIG_CRC_FWD; #if 0 val4 |= BASE_CFG_COMMAND_CONFIG_CNTL_FRM_ENA; #endif #if 1 val4 |= BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC; #endif val &= ~BASE_CFG_COMMAND_CONFIG_LOOP_ENA; /* link0? */ CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); /* * Make sure we do not enable 32bit alignment; FreeBSD cannot * cope with the additional padding (though we should!?). * Also make sure we get the CRC appended. */ val4 = CSR_READ_4(sc, TX_CMD_STAT); val4 &= ~(TX_CMD_STAT_OMIT_CRC|TX_CMD_STAT_TX_SHIFT16); CSR_WRITE_4(sc, TX_CMD_STAT, val4); + val4 = CSR_READ_4(sc, RX_CMD_STAT); val4 &= ~RX_CMD_STAT_RX_SHIFT16; + val4 |= RX_CMD_STAT_RX_SHIFT16; CSR_WRITE_4(sc, RX_CMD_STAT, val4); /* e. Reset MAC. */ val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); val4 |= BASE_CFG_COMMAND_CONFIG_SW_RESET; CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); /* Wait for bits to be cleared; i=100 is excessive. */ for (i = 0; i < 100; i++) { val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); - if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) == 0) + if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) == 0) { break; + } DELAY(10); } if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) != 0) { device_printf(sc->atse_dev, "MAC reset timed out.\n"); return (ENXIO); } /* f. Enable MAC transmit and receive datapath. */ mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA; val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); val4 |= mask; CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); /* Wait for bits to be cleared; i=100 is excessive. */ for (i = 0; i < 100; i++) { val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); - if ((val4 & mask) == mask) + if ((val4 & mask) == mask) { break; + } DELAY(10); } if ((val4 & mask) != mask) { device_printf(sc->atse_dev, "Enabling MAC TX/RX timed out.\n"); return (ENXIO); } return (0); } static void atse_init_locked(struct atse_softc *sc) { struct ifnet *ifp; struct mii_data *mii; uint8_t *eaddr; ATSE_LOCK_ASSERT(sc); ifp = sc->atse_ifp; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { return; + } /* * Must update the ether address if changed. Given we do not handle * in atse_ioctl() but it's in the general framework, just always * do it here before atse_reset(). */ eaddr = IF_LLADDR(sc->atse_ifp); bcopy(eaddr, &sc->atse_eth_addr, ETHER_ADDR_LEN); /* Make things frind to halt, cleanup, ... */ atse_stop_locked(sc); - /* ... reset, ... */ + atse_reset(sc); /* ... and fire up the engine again. */ atse_rxfilter_locked(sc); - /* Memory rings? DMA engine? */ - - sc->atse_rx_buf_len = 0; sc->atse_flags &= ATSE_FLAGS_LINK; /* Preserve. */ -#ifdef DEVICE_POLLING - /* Only enable interrupts if we are not polling. */ - if (ifp->if_capenable & IFCAP_POLLING) { - ATSE_RX_INTR_DISABLE(sc); - ATSE_TX_INTR_DISABLE(sc); - ATSE_RX_EVENT_CLEAR(sc); - ATSE_TX_EVENT_CLEAR(sc); - } else -#endif - { - ATSE_RX_INTR_ENABLE(sc); - ATSE_TX_INTR_ENABLE(sc); - } - mii = device_get_softc(sc->atse_miibus); sc->atse_flags &= ~ATSE_FLAGS_LINK; mii_mediachg(mii); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; callout_reset(&sc->atse_tick, hz, atse_tick, sc); } static void atse_init(void *xsc) { struct atse_softc *sc; /* * XXXRW: There is some argument that we should immediately do RX * processing after enabling interrupts, or one may not fire if there * are buffered packets. */ sc = (struct atse_softc *)xsc; ATSE_LOCK(sc); atse_init_locked(sc); ATSE_UNLOCK(sc); } static int atse_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct atse_softc *sc; struct ifreq *ifr; int error, mask; error = 0; sc = ifp->if_softc; ifr = (struct ifreq *)data; switch (command) { case SIOCSIFFLAGS: ATSE_LOCK(sc); if (ifp->if_flags & IFF_UP) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && ((ifp->if_flags ^ sc->atse_if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) != 0) atse_rxfilter_locked(sc); else atse_init_locked(sc); } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) atse_stop_locked(sc); sc->atse_if_flags = ifp->if_flags; ATSE_UNLOCK(sc); break; case SIOCSIFCAP: ATSE_LOCK(sc); mask = ifr->ifr_reqcap ^ ifp->if_capenable; -#ifdef DEVICE_POLLING - if ((mask & IFCAP_POLLING) != 0 && - (IFCAP_POLLING & ifp->if_capabilities) != 0) { - ifp->if_capenable ^= IFCAP_POLLING; - if ((IFCAP_POLLING & ifp->if_capenable) != 0) { - - error = ether_poll_register(atse_poll, ifp); - if (error != 0) { - ATSE_UNLOCK(sc); - break; - } - /* Disable interrupts. */ - ATSE_RX_INTR_DISABLE(sc); - ATSE_TX_INTR_DISABLE(sc); - ATSE_RX_EVENT_CLEAR(sc); - ATSE_TX_EVENT_CLEAR(sc); - - /* - * Do not allow disabling of polling if we do - * not have interrupts. - */ - } else if (sc->atse_rx_irq_res != NULL || - sc->atse_tx_irq_res != NULL) { - error = ether_poll_deregister(ifp); - /* Enable interrupts. */ - ATSE_RX_INTR_ENABLE(sc); - ATSE_TX_INTR_ENABLE(sc); - } else { - ifp->if_capenable ^= IFCAP_POLLING; - error = EINVAL; - } - } -#endif /* DEVICE_POLLING */ ATSE_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: ATSE_LOCK(sc); atse_rxfilter_locked(sc); ATSE_UNLOCK(sc); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: { struct mii_data *mii; struct ifreq *ifr; mii = device_get_softc(sc->atse_miibus); ifr = (struct ifreq *)data; error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; } default: error = ether_ioctl(ifp, command, data); break; } return (error); } static void -atse_intr_debug(struct atse_softc *sc, const char *intrname) -{ - uint32_t rxs, rxe, rxi, rxf, txs, txe, txi, txf; - - if (!atse_intr_debug_enable) - return; - - rxs = ATSE_RX_STATUS_READ(sc); - rxe = ATSE_RX_EVENT_READ(sc); - rxi = ATSE_RX_INTR_READ(sc); - rxf = ATSE_RX_READ_FILL_LEVEL(sc); - - txs = ATSE_TX_STATUS_READ(sc); - txe = ATSE_TX_EVENT_READ(sc); - txi = ATSE_TX_INTR_READ(sc); - txf = ATSE_TX_READ_FILL_LEVEL(sc); - - printf( - "%s - %s: " - "rxs 0x%x rxe 0x%x rxi 0x%x rxf 0x%x " - "txs 0x%x txe 0x%x txi 0x%x txf 0x%x\n", - __func__, intrname, - rxs, rxe, rxi, rxf, - txs, txe, txi, txf); -} - -static void -atse_watchdog(struct atse_softc *sc) -{ - - ATSE_LOCK_ASSERT(sc); - - if (sc->atse_watchdog_timer == 0 || --sc->atse_watchdog_timer > 0) - return; - - device_printf(sc->atse_dev, "watchdog timeout\n"); - if_inc_counter(sc->atse_ifp, IFCOUNTER_OERRORS, 1); - - atse_intr_debug(sc, "poll"); - - sc->atse_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - atse_init_locked(sc); - - atse_rx_locked(sc); - if (!IFQ_DRV_IS_EMPTY(&sc->atse_ifp->if_snd)) - atse_start_locked(sc->atse_ifp); -} - -static void atse_tick(void *xsc) { struct atse_softc *sc; struct mii_data *mii; struct ifnet *ifp; sc = (struct atse_softc *)xsc; ATSE_LOCK_ASSERT(sc); ifp = sc->atse_ifp; mii = device_get_softc(sc->atse_miibus); mii_tick(mii); - atse_watchdog(sc); - if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) + if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) { atse_miibus_statchg(sc->atse_dev); + } + callout_reset(&sc->atse_tick, hz, atse_tick, sc); } /* * Set media options. */ static int atse_ifmedia_upd(struct ifnet *ifp) { struct atse_softc *sc; struct mii_data *mii; struct mii_softc *miisc; int error; sc = ifp->if_softc; ATSE_LOCK(sc); mii = device_get_softc(sc->atse_miibus); - LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { PHY_RESET(miisc); + } error = mii_mediachg(mii); ATSE_UNLOCK(sc); return (error); } -static void -atse_update_rx_err(struct atse_softc *sc, uint32_t mask) -{ - int i; - - /* RX error are 6 bits, we only know 4 of them. */ - for (i = 0; i < ATSE_RX_ERR_MAX; i++) - if ((mask & (1 << i)) != 0) - sc->atse_rx_err[i]++; -} - -static int -atse_rx_locked(struct atse_softc *sc) -{ - uint32_t fill, i, j; - uint32_t data, meta; - struct ifnet *ifp; - struct mbuf *m; - int rx_npkts; - - ATSE_LOCK_ASSERT(sc); - - ifp = sc->atse_ifp; - rx_npkts = 0; - j = 0; - meta = 0; - do { -outer: - if (sc->atse_rx_m == NULL) { - m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); - if (m == NULL) - return (rx_npkts); - m->m_len = m->m_pkthdr.len = MCLBYTES; - /* Make sure upper layers will be aligned. */ - m_adj(m, ETHER_ALIGN); - sc->atse_rx_m = m; - } - - fill = ATSE_RX_READ_FILL_LEVEL(sc); - for (i = 0; i < fill; i++) { - /* - * XXX-BZ for whatever reason the FIFO requires the - * the data read before we can access the meta data. - */ - data = ATSE_RX_DATA_READ(sc); - meta = ATSE_RX_META_READ(sc); - if (meta & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) { - /* XXX-BZ evaluate error. */ - atse_update_rx_err(sc, ((meta & - A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> - A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - sc->atse_rx_buf_len = 0; - /* - * Should still read till EOP or next SOP. - * - * XXX-BZ might also depend on - * BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC - */ - sc->atse_flags |= ATSE_FLAGS_ERROR; - return (rx_npkts); - } - if ((meta & A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) != 0) - device_printf(sc->atse_dev, "%s: unexpected " - "channel %u\n", __func__, (meta & - A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) >> - A_ONCHIP_FIFO_MEM_CORE_CHANNEL_SHIFT); - - if (meta & A_ONCHIP_FIFO_MEM_CORE_SOP) { - /* - * There is no need to clear SOP between 1st - * and subsequent packet data junks. - */ - if (sc->atse_rx_buf_len != 0 && - (sc->atse_flags & ATSE_FLAGS_SOP_SEEN) == 0) - { - device_printf(sc->atse_dev, "%s: SOP " - "without empty buffer: %u\n", - __func__, sc->atse_rx_buf_len); - /* XXX-BZ any better counter? */ - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - } - - if ((sc->atse_flags & ATSE_FLAGS_SOP_SEEN) == 0) - { - sc->atse_flags |= ATSE_FLAGS_SOP_SEEN; - sc->atse_rx_buf_len = 0; - } - } -#if 0 /* We had to read the data before we could access meta data. See above. */ - data = ATSE_RX_DATA_READ(sc); -#endif - /* Make sure to not overflow the mbuf data size. */ - if (sc->atse_rx_buf_len >= sc->atse_rx_m->m_len - - sizeof(data)) { - /* - * XXX-BZ Error. We need more mbufs and are - * not setup for this yet. - */ - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - sc->atse_flags |= ATSE_FLAGS_ERROR; - } - if ((sc->atse_flags & ATSE_FLAGS_ERROR) == 0) - /* - * MUST keep this bcopy as m_data after m_adj - * for IP header aligment is on half-word - * and not word alignment. - */ - bcopy(&data, (uint8_t *)(sc->atse_rx_m->m_data + - sc->atse_rx_buf_len), sizeof(data)); - if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP) { - uint8_t empty; - - empty = (meta & - A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK) >> - A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT; - sc->atse_rx_buf_len += (4 - empty); - - if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); - rx_npkts++; - - m = sc->atse_rx_m; - m->m_pkthdr.len = m->m_len = - sc->atse_rx_buf_len; - sc->atse_rx_m = NULL; - - sc->atse_rx_buf_len = 0; - sc->atse_flags &= ~ATSE_FLAGS_SOP_SEEN; - if (sc->atse_flags & ATSE_FLAGS_ERROR) { - sc->atse_flags &= ~ATSE_FLAGS_ERROR; - m_freem(m); - } else { - m->m_pkthdr.rcvif = ifp; - ATSE_UNLOCK(sc); - (*ifp->if_input)(ifp, m); - ATSE_LOCK(sc); - } -#ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) { - if (sc->atse_rx_cycles <= 0) - return (rx_npkts); - sc->atse_rx_cycles--; - } -#endif - goto outer; /* Need a new mbuf. */ - } else { - sc->atse_rx_buf_len += sizeof(data); - } - } /* for */ - - /* XXX-BZ could optimize in case of another packet waiting. */ - } while (fill > 0); - - return (rx_npkts); -} - - /* * Report current media status. */ static void atse_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct atse_softc *sc; struct mii_data *mii; sc = ifp->if_softc; ATSE_LOCK(sc); mii = device_get_softc(sc->atse_miibus); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; ATSE_UNLOCK(sc); } -static void -atse_rx_intr(void *arg) -{ - struct atse_softc *sc; - struct ifnet *ifp; - uint32_t rxe; - - sc = (struct atse_softc *)arg; - ifp = sc->atse_ifp; - - ATSE_LOCK(sc); -#ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) { - ATSE_UNLOCK(sc); - return; - } -#endif - - atse_intr_debug(sc, "rx"); - rxe = ATSE_RX_EVENT_READ(sc); - if (rxe & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| - A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { - /* XXX-BZ ERROR HANDLING. */ - atse_update_rx_err(sc, ((rxe & - A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> - A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - } - - /* - * There is considerable subtlety in the race-free handling of rx - * interrupts: we must disable interrupts whenever we manipulate the - * FIFO to prevent further interrupts from firing before we are done; - * we must clear the event after processing to prevent the event from - * being immediately reposted due to data remaining; we must clear the - * event mask before reenabling interrupts or risk missing a positive - * edge; and we must recheck everything after completing in case the - * event posted between clearing events and reenabling interrupts. If - * a race is experienced, we must restart the whole mechanism. - */ - do { - ATSE_RX_INTR_DISABLE(sc); -#if 0 - sc->atse_rx_cycles = RX_CYCLES_IN_INTR; -#endif - atse_rx_locked(sc); - ATSE_RX_EVENT_CLEAR(sc); - - /* Disable interrupts if interface is down. */ - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ATSE_RX_INTR_ENABLE(sc); - } while (!(ATSE_RX_STATUS_READ(sc) & - A_ONCHIP_FIFO_MEM_CORE_STATUS_EMPTY)); - ATSE_UNLOCK(sc); - -} - -static void -atse_tx_intr(void *arg) -{ - struct atse_softc *sc; - struct ifnet *ifp; - uint32_t txe; - - sc = (struct atse_softc *)arg; - ifp = sc->atse_ifp; - - ATSE_LOCK(sc); -#ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) { - ATSE_UNLOCK(sc); - return; - } -#endif - - /* XXX-BZ build histogram. */ - atse_intr_debug(sc, "tx"); - txe = ATSE_TX_EVENT_READ(sc); - if (txe & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| - A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { - /* XXX-BZ ERROR HANDLING. */ - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - } - - /* - * There is also considerable subtlety in the race-free handling of - * tx interrupts: all processing occurs with interrupts disabled to - * prevent spurious refiring while transmit is in progress (which - * could occur if the FIFO drains while sending -- quite likely); we - * must not clear the event mask until after we've sent, also to - * prevent spurious refiring; once we've cleared the event mask we can - * reenable interrupts, but there is a possible race between clear and - * enable, so we must recheck and potentially repeat the whole process - * if it is detected. - */ - do { - ATSE_TX_INTR_DISABLE(sc); - sc->atse_watchdog_timer = 0; - atse_start_locked(ifp); - ATSE_TX_EVENT_CLEAR(sc); - - /* Disable interrupts if interface is down. */ - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ATSE_TX_INTR_ENABLE(sc); - } while (ATSE_TX_PENDING(sc) && - !(ATSE_TX_STATUS_READ(sc) & A_ONCHIP_FIFO_MEM_CORE_STATUS_FULL)); - ATSE_UNLOCK(sc); -} - -#ifdef DEVICE_POLLING -static int -atse_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) -{ - struct atse_softc *sc; - int rx_npkts = 0; - - sc = ifp->if_softc; - ATSE_LOCK(sc); - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - ATSE_UNLOCK(sc); - return (rx_npkts); - } - - sc->atse_rx_cycles = count; - rx_npkts = atse_rx_locked(sc); - atse_start_locked(ifp); - - if (sc->atse_rx_cycles > 0 || cmd == POLL_AND_CHECK_STATUS) { - uint32_t rx, tx; - - rx = ATSE_RX_EVENT_READ(sc); - tx = ATSE_TX_EVENT_READ(sc); - - if (rx & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| - A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { - /* XXX-BZ ERROR HANDLING. */ - atse_update_rx_err(sc, ((rx & - A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> - A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - } - if (tx & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW| - A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) { - /* XXX-BZ ERROR HANDLING. */ - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - } - if (ATSE_TX_READ_FILL_LEVEL(sc) == 0) - sc->atse_watchdog_timer = 0; - -#if 0 - if (/* Severe error; if only we could find out. */) { - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - atse_init_locked(sc); - } -#endif - } - - ATSE_UNLOCK(sc); - return (rx_npkts); -} -#endif /* DEVICE_POLLING */ - static struct atse_mac_stats_regs { const char *name; const char *descr; /* Mostly copied from Altera datasheet. */ } atse_mac_stats_regs[] = { [0x1a] = { "aFramesTransmittedOK", "The number of frames that are successfully transmitted including " "the pause frames." }, { "aFramesReceivedOK", "The number of frames that are successfully received including the " "pause frames." }, { "aFrameCheckSequenceErrors", "The number of receive frames with CRC error." }, { "aAlignmentErrors", "The number of receive frames with alignment error." }, { "aOctetsTransmittedOK", "The lower 32 bits of the number of data and padding octets that " "are successfully transmitted." }, { "aOctetsReceivedOK", "The lower 32 bits of the number of data and padding octets that " " are successfully received." }, { "aTxPAUSEMACCtrlFrames", "The number of pause frames transmitted." }, { "aRxPAUSEMACCtrlFrames", "The number received pause frames received." }, { "ifInErrors", "The number of errored frames received." }, { "ifOutErrors", "The number of transmit frames with either a FIFO overflow error, " "a FIFO underflow error, or a error defined by the user " "application." }, { "ifInUcastPkts", "The number of valid unicast frames received." }, { "ifInMulticastPkts", "The number of valid multicast frames received. The count does " "not include pause frames." }, { "ifInBroadcastPkts", "The number of valid broadcast frames received." }, { "ifOutDiscards", "This statistics counter is not in use. The MAC function does not " "discard frames that are written to the FIFO buffer by the user " "application." }, { "ifOutUcastPkts", "The number of valid unicast frames transmitted." }, { "ifOutMulticastPkts", "The number of valid multicast frames transmitted, excluding pause " "frames." }, { "ifOutBroadcastPkts", "The number of valid broadcast frames transmitted." }, { "etherStatsDropEvents", "The number of frames that are dropped due to MAC internal errors " "when FIFO buffer overflow persists." }, { "etherStatsOctets", "The lower 32 bits of the total number of octets received. This " "count includes both good and errored frames." }, { "etherStatsPkts", "The total number of good and errored frames received." }, { "etherStatsUndersizePkts", "The number of frames received with length less than 64 bytes. " "This count does not include errored frames." }, { "etherStatsOversizePkts", "The number of frames received that are longer than the value " "configured in the frm_length register. This count does not " "include errored frames." }, { "etherStatsPkts64Octets", "The number of 64-byte frames received. This count includes good " "and errored frames." }, { "etherStatsPkts65to127Octets", "The number of received good and errored frames between the length " "of 65 and 127 bytes." }, { "etherStatsPkts128to255Octets", "The number of received good and errored frames between the length " "of 128 and 255 bytes." }, { "etherStatsPkts256to511Octets", "The number of received good and errored frames between the length " "of 256 and 511 bytes." }, { "etherStatsPkts512to1023Octets", "The number of received good and errored frames between the length " "of 512 and 1023 bytes." }, { "etherStatsPkts1024to1518Octets", "The number of received good and errored frames between the length " "of 1024 and 1518 bytes." }, { "etherStatsPkts1519toXOctets", "The number of received good and errored frames between the length " "of 1519 and the maximum frame length configured in the frm_length " "register." }, { "etherStatsJabbers", "Too long frames with CRC error." }, { "etherStatsFragments", "Too short frames with CRC error." }, /* 0x39 unused, 0x3a/b non-stats. */ [0x3c] = /* Extended Statistics Counters */ { "msb_aOctetsTransmittedOK", "Upper 32 bits of the number of data and padding octets that are " "successfully transmitted." }, { "msb_aOctetsReceivedOK", "Upper 32 bits of the number of data and padding octets that are " "successfully received." }, { "msb_etherStatsOctets", "Upper 32 bits of the total number of octets received. This count " "includes both good and errored frames." } }; static int sysctl_atse_mac_stats_proc(SYSCTL_HANDLER_ARGS) { struct atse_softc *sc; int error, offset, s; sc = arg1; offset = arg2; s = CSR_READ_4(sc, offset); error = sysctl_handle_int(oidp, &s, 0, req); - if (error || !req->newptr) + if (error || !req->newptr) { return (error); + } return (0); } static struct atse_rx_err_stats_regs { const char *name; const char *descr; } atse_rx_err_stats_regs[] = { #define ATSE_RX_ERR_FIFO_THRES_EOP 0 /* FIFO threshold reached, on EOP. */ #define ATSE_RX_ERR_ELEN 1 /* Frame/payload length not valid. */ #define ATSE_RX_ERR_CRC32 2 /* CRC-32 error. */ #define ATSE_RX_ERR_FIFO_THRES_TRUNC 3 /* FIFO thresh., truncated frame. */ #define ATSE_RX_ERR_4 4 /* ? */ #define ATSE_RX_ERR_5 5 /* / */ { "rx_err_fifo_thres_eop", "FIFO threshold reached, reported on EOP." }, { "rx_err_fifo_elen", "Frame or payload length not valid." }, { "rx_err_fifo_crc32", "CRC-32 error." }, { "rx_err_fifo_thres_trunc", "FIFO threshold reached, truncated frame" }, { "rx_err_4", "?" }, { "rx_err_5", "?" }, }; static int sysctl_atse_rx_err_stats_proc(SYSCTL_HANDLER_ARGS) { struct atse_softc *sc; int error, offset, s; sc = arg1; offset = arg2; s = sc->atse_rx_err[offset]; error = sysctl_handle_int(oidp, &s, 0, req); - if (error || !req->newptr) + if (error || !req->newptr) { return (error); + } return (0); } static void atse_sysctl_stats_attach(device_t dev) { struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; struct atse_softc *sc; int i; sc = device_get_softc(dev); sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); /* MAC statistics. */ for (i = 0; i < nitems(atse_mac_stats_regs); i++) { if (atse_mac_stats_regs[i].name == NULL || - atse_mac_stats_regs[i].descr == NULL) + atse_mac_stats_regs[i].descr == NULL) { continue; + } SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, atse_mac_stats_regs[i].name, CTLTYPE_UINT|CTLFLAG_RD, sc, i, sysctl_atse_mac_stats_proc, "IU", atse_mac_stats_regs[i].descr); } /* rx_err[]. */ for (i = 0; i < ATSE_RX_ERR_MAX; i++) { if (atse_rx_err_stats_regs[i].name == NULL || - atse_rx_err_stats_regs[i].descr == NULL) + atse_rx_err_stats_regs[i].descr == NULL) { continue; + } SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, atse_rx_err_stats_regs[i].name, CTLTYPE_UINT|CTLFLAG_RD, sc, i, sysctl_atse_rx_err_stats_proc, "IU", atse_rx_err_stats_regs[i].descr); } } /* * Generic device handling routines. */ int atse_attach(device_t dev) { struct atse_softc *sc; struct ifnet *ifp; + uint32_t caps; int error; sc = device_get_softc(dev); + sc->dev = dev; + /* Get xDMA controller */ + sc->xdma_tx = xdma_ofw_get(sc->dev, "tx"); + if (sc->xdma_tx == NULL) { + device_printf(dev, "Can't find DMA controller.\n"); + return (ENXIO); + } + + /* + * Only final (EOP) write can be less than "symbols per beat" value + * so we have to defrag mbuf chain. + * Chapter 15. On-Chip FIFO Memory Core. + * Embedded Peripherals IP User Guide. + */ + caps = XCHAN_CAP_BUSDMA_NOSEG; + + /* Alloc xDMA virtual channel. */ + sc->xchan_tx = xdma_channel_alloc(sc->xdma_tx, caps); + if (sc->xchan_tx == NULL) { + device_printf(dev, "Can't alloc virtual DMA channel.\n"); + return (ENXIO); + } + + /* Setup interrupt handler. */ + error = xdma_setup_intr(sc->xchan_tx, atse_xdma_tx_intr, sc, &sc->ih_tx); + if (error) { + device_printf(sc->dev, + "Can't setup xDMA interrupt handler.\n"); + return (ENXIO); + } + + xdma_prep_sg(sc->xchan_tx, + TX_QUEUE_SIZE, /* xchan requests queue size */ + MCLBYTES, /* maxsegsize */ + 8, /* maxnsegs */ + 16, /* alignment */ + 0, /* boundary */ + BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR); + + /* Get RX xDMA controller */ + sc->xdma_rx = xdma_ofw_get(sc->dev, "rx"); + if (sc->xdma_rx == NULL) { + device_printf(dev, "Can't find DMA controller.\n"); + return (ENXIO); + } + + /* Alloc xDMA virtual channel. */ + sc->xchan_rx = xdma_channel_alloc(sc->xdma_rx, caps); + if (sc->xchan_rx == NULL) { + device_printf(dev, "Can't alloc virtual DMA channel.\n"); + return (ENXIO); + } + + /* Setup interrupt handler. */ + error = xdma_setup_intr(sc->xchan_rx, atse_xdma_rx_intr, sc, &sc->ih_rx); + if (error) { + device_printf(sc->dev, + "Can't setup xDMA interrupt handler.\n"); + return (ENXIO); + } + + xdma_prep_sg(sc->xchan_rx, + RX_QUEUE_SIZE, /* xchan requests queue size */ + MCLBYTES, /* maxsegsize */ + 1, /* maxnsegs */ + 16, /* alignment */ + 0, /* boundary */ + BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR); + + mtx_init(&sc->br_mtx, "buf ring mtx", NULL, MTX_DEF); + sc->br = buf_ring_alloc(BUFRING_SIZE, M_DEVBUF, + M_NOWAIT, &sc->br_mtx); + if (sc->br == NULL) { + return (ENOMEM); + } + atse_ethernet_option_bits_read(dev); mtx_init(&sc->atse_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->atse_tick, &sc->atse_mtx, 0); - sc->atse_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK); - /* * We are only doing single-PHY with this driver currently. The * defaults would be right so that BASE_CFG_MDIO_ADDR0 points to the * 1st PHY address (0) apart from the fact that BMCR0 is always * the PCS mapping, so we always use BMCR1. See Table 5-1 0xA0-0xBF. */ #if 0 /* Always PCS. */ sc->atse_bmcr0 = MDIO_0_START; CSR_WRITE_4(sc, BASE_CFG_MDIO_ADDR0, 0x00); #endif /* Always use matching PHY for atse[0..]. */ sc->atse_phy_addr = device_get_unit(dev); sc->atse_bmcr1 = MDIO_1_START; CSR_WRITE_4(sc, BASE_CFG_MDIO_ADDR1, sc->atse_phy_addr); /* Reset the adapter. */ atse_reset(sc); /* Setup interface. */ ifp = sc->atse_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "if_alloc() failed\n"); error = ENOSPC; goto err; } ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = atse_ioctl; - ifp->if_start = atse_start; + ifp->if_transmit = atse_transmit; + ifp->if_qflush = atse_qflush; ifp->if_init = atse_init; IFQ_SET_MAXLEN(&ifp->if_snd, ATSE_TX_LIST_CNT - 1); ifp->if_snd.ifq_drv_maxlen = ATSE_TX_LIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); /* MII setup. */ error = mii_attach(dev, &sc->atse_miibus, ifp, atse_ifmedia_upd, atse_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); if (error != 0) { device_printf(dev, "attaching PHY failed: %d\n", error); goto err; } /* Call media-indepedent attach routine. */ ether_ifattach(ifp, sc->atse_eth_addr); /* Tell the upper layer(s) about vlan mtu support. */ ifp->if_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; ifp->if_capenable = ifp->if_capabilities; -#ifdef DEVICE_POLLING - /* We will enable polling by default if no irqs available. See below. */ - ifp->if_capabilities |= IFCAP_POLLING; -#endif - /* Hook up interrupts. */ - if (sc->atse_rx_irq_res != NULL) { - error = bus_setup_intr(dev, sc->atse_rx_irq_res, INTR_TYPE_NET | - INTR_MPSAFE, NULL, atse_rx_intr, sc, &sc->atse_rx_intrhand); - if (error != 0) { - device_printf(dev, "enabling RX IRQ failed\n"); - ether_ifdetach(ifp); - goto err; - } - } - - if (sc->atse_tx_irq_res != NULL) { - error = bus_setup_intr(dev, sc->atse_tx_irq_res, INTR_TYPE_NET | - INTR_MPSAFE, NULL, atse_tx_intr, sc, &sc->atse_tx_intrhand); - if (error != 0) { - bus_teardown_intr(dev, sc->atse_rx_irq_res, - sc->atse_rx_intrhand); - device_printf(dev, "enabling TX IRQ failed\n"); - ether_ifdetach(ifp); - goto err; - } - } - - if ((ifp->if_capenable & IFCAP_POLLING) != 0 || - (sc->atse_rx_irq_res == NULL && sc->atse_tx_irq_res == NULL)) { -#ifdef DEVICE_POLLING - /* If not on and no IRQs force it on. */ - if (sc->atse_rx_irq_res == NULL && sc->atse_tx_irq_res == NULL){ - ifp->if_capenable |= IFCAP_POLLING; - device_printf(dev, "forcing to polling due to no " - "interrupts\n"); - } - error = ether_poll_register(atse_poll, ifp); - if (error != 0) - goto err; -#else - device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n"); - error = ENXIO; -#endif - } else { - ATSE_RX_INTR_ENABLE(sc); - ATSE_TX_INTR_ENABLE(sc); - } - err: - if (error != 0) + if (error != 0) { atse_detach(dev); + } - if (error == 0) + if (error == 0) { atse_sysctl_stats_attach(dev); + } + atse_rx_enqueue(sc, NUM_RX_MBUF); + xdma_queue_submit(sc->xchan_rx); + return (error); } static int atse_detach(device_t dev) { struct atse_softc *sc; struct ifnet *ifp; sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->atse_mtx), ("%s: mutex not initialized", device_get_nameunit(dev))); ifp = sc->atse_ifp; -#ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) - ether_poll_deregister(ifp); -#endif - /* Only cleanup if attach succeeded. */ if (device_is_attached(dev)) { ATSE_LOCK(sc); atse_stop_locked(sc); ATSE_UNLOCK(sc); callout_drain(&sc->atse_tick); ether_ifdetach(ifp); } - if (sc->atse_miibus != NULL) + if (sc->atse_miibus != NULL) { device_delete_child(dev, sc->atse_miibus); + } - if (sc->atse_tx_intrhand) - bus_teardown_intr(dev, sc->atse_tx_irq_res, - sc->atse_tx_intrhand); - if (sc->atse_rx_intrhand) - bus_teardown_intr(dev, sc->atse_rx_irq_res, - sc->atse_rx_intrhand); - - if (ifp != NULL) + if (ifp != NULL) { if_free(ifp); + } - if (sc->atse_tx_buf != NULL) - free(sc->atse_tx_buf, M_DEVBUF); - mtx_destroy(&sc->atse_mtx); return (0); } /* Shared between nexus and fdt implementation. */ void atse_detach_resources(device_t dev) { struct atse_softc *sc; sc = device_get_softc(dev); - if (sc->atse_txc_mem_res != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_txc_mem_rid, - sc->atse_txc_mem_res); - sc->atse_txc_mem_res = NULL; - } - if (sc->atse_tx_mem_res != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_tx_mem_rid, - sc->atse_tx_mem_res); - sc->atse_tx_mem_res = NULL; - } - if (sc->atse_tx_irq_res != NULL) { - bus_release_resource(dev, SYS_RES_IRQ, sc->atse_tx_irq_rid, - sc->atse_tx_irq_res); - sc->atse_tx_irq_res = NULL; - } - if (sc->atse_rxc_mem_res != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_rxc_mem_rid, - sc->atse_rxc_mem_res); - sc->atse_rxc_mem_res = NULL; - } - if (sc->atse_rx_mem_res != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_rx_mem_rid, - sc->atse_rx_mem_res); - sc->atse_rx_mem_res = NULL; - } - if (sc->atse_rx_irq_res != NULL) { - bus_release_resource(dev, SYS_RES_IRQ, sc->atse_rx_irq_rid, - sc->atse_rx_irq_res); - sc->atse_rx_irq_res = NULL; - } if (sc->atse_mem_res != NULL) { bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_mem_rid, sc->atse_mem_res); sc->atse_mem_res = NULL; } } int atse_detach_dev(device_t dev) { int error; error = atse_detach(dev); if (error) { /* We are basically in undefined state now. */ device_printf(dev, "atse_detach() failed: %d\n", error); return (error); } atse_detach_resources(dev); return (0); } int atse_miibus_readreg(device_t dev, int phy, int reg) { struct atse_softc *sc; + int val; sc = device_get_softc(dev); /* * We currently do not support re-mapping of MDIO space on-the-fly * but de-facto hard-code the phy#. */ - if (phy != sc->atse_phy_addr) + if (phy != sc->atse_phy_addr) { return (0); + } - return (PHY_READ_2(sc, reg)); + val = PHY_READ_2(sc, reg); + + return (val); } int atse_miibus_writereg(device_t dev, int phy, int reg, int data) { struct atse_softc *sc; sc = device_get_softc(dev); /* * We currently do not support re-mapping of MDIO space on-the-fly * but de-facto hard-code the phy#. */ - if (phy != sc->atse_phy_addr) + if (phy != sc->atse_phy_addr) { return (0); + } PHY_WRITE_2(sc, reg, data); return (0); } void atse_miibus_statchg(device_t dev) { struct atse_softc *sc; struct mii_data *mii; struct ifnet *ifp; uint32_t val4; sc = device_get_softc(dev); ATSE_LOCK_ASSERT(sc); mii = device_get_softc(sc->atse_miibus); ifp = sc->atse_ifp; if (mii == NULL || ifp == NULL || - (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { return; + } val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG); /* Assume no link. */ sc->atse_flags &= ~ATSE_FLAGS_LINK; if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == (IFM_ACTIVE | IFM_AVALID)) { switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_10_T: val4 |= BASE_CFG_COMMAND_CONFIG_ENA_10; val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED; sc->atse_flags |= ATSE_FLAGS_LINK; break; case IFM_100_TX: val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10; val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED; sc->atse_flags |= ATSE_FLAGS_LINK; break; case IFM_1000_T: val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10; val4 |= BASE_CFG_COMMAND_CONFIG_ETH_SPEED; sc->atse_flags |= ATSE_FLAGS_LINK; break; default: break; } } if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) { - /* XXX-BZ need to stop the MAC? */ + /* Need to stop the MAC? */ return; } - if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) + if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) { val4 &= ~BASE_CFG_COMMAND_CONFIG_HD_ENA; - else + } else { val4 |= BASE_CFG_COMMAND_CONFIG_HD_ENA; - /* XXX-BZ flow control? */ + } + /* flow control? */ + /* Make sure the MAC is activated. */ val4 |= BASE_CFG_COMMAND_CONFIG_TX_ENA; val4 |= BASE_CFG_COMMAND_CONFIG_RX_ENA; CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4); } -/* end */ +MODULE_DEPEND(atse, ether, 1, 1, 1); +MODULE_DEPEND(atse, miibus, 1, 1, 1); Index: head/sys/dev/altera/atse/if_atse_fdt.c =================================================================== --- head/sys/dev/altera/atse/if_atse_fdt.c (revision 332473) +++ head/sys/dev/altera/atse/if_atse_fdt.c (revision 332474) @@ -1,222 +1,147 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Bjoern A. Zeeb * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) * ("MRC2"), as part of the DARPA MRC research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include - #include #include #include #include #include /* "device miibus" required. See GENERIC if you get errors here. */ #include "miibus_if.h" static int atse_probe_fdt(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "altera,atse")) { - device_set_desc(dev, "Altera Triple-Speed Ethernet MegaCore"); - return (BUS_PROBE_DEFAULT); + if (!ofw_bus_is_compatible(dev, "altera,atse")) { + return (ENXIO); } - return (ENXIO); + + device_set_desc(dev, "Altera Triple-Speed Ethernet MegaCore"); + + return (BUS_PROBE_DEFAULT); } static int atse_attach_fdt(device_t dev) { struct atse_softc *sc; int error; sc = device_get_softc(dev); sc->atse_dev = dev; sc->atse_unit = device_get_unit(dev); /* * FDT has the list of our resources. Given we are using multiple * memory regions and possibly multiple interrupts, we need to attach * them in the order specified in .dts: * MAC, RX and RXC FIFO, TX and TXC FIFO; RX INTR, TX INTR. */ /* MAC: Avalon-MM, atse management register region. */ sc->atse_mem_rid = 0; sc->atse_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->atse_mem_rid, RF_ACTIVE); if (sc->atse_mem_res == NULL) { device_printf(dev, "failed to map memory for ctrl region\n"); - error = ENXIO; - goto err; + /* Cleanup. */ + atse_detach_resources(dev); + + return (ENXIO); } if (bootverbose) device_printf(sc->atse_dev, "MAC ctrl region at mem %p-%p\n", (void *)rman_get_start(sc->atse_mem_res), (void *)(rman_get_start(sc->atse_mem_res) + rman_get_size(sc->atse_mem_res))); - /* - * RX and RXC FIFO memory regions. - * 0x00: 2 * 32bit FIFO data, - * 0x20: 8 * 32bit FIFO ctrl, Avalon-ST Sink to Avalon-MM R-Slave. - */ - sc->atse_rx_mem_rid = 1; - sc->atse_rx_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->atse_rx_mem_rid, RF_ACTIVE); - if (sc->atse_rx_mem_res == NULL) { - device_printf(dev, "failed to map memory for RX FIFO\n"); - error = ENXIO; - goto err; - } - if (bootverbose) - device_printf(sc->atse_dev, "RX FIFO at mem %p-%p\n", - (void *)rman_get_start(sc->atse_rx_mem_res), - (void *)(rman_get_start(sc->atse_rx_mem_res) + - rman_get_size(sc->atse_rx_mem_res))); + error = atse_attach(dev); + if (error) { + /* Cleanup. */ + atse_detach_resources(dev); - sc->atse_rxc_mem_rid = 2; - sc->atse_rxc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->atse_rxc_mem_rid, RF_ACTIVE); - if (sc->atse_rxc_mem_res == NULL) { - device_printf(dev, "failed to map memory for RXC FIFO\n"); - error = ENXIO; - goto err; + return (error); } - if (bootverbose) - device_printf(sc->atse_dev, "RXC FIFO at mem %p-%p\n", - (void *)rman_get_start(sc->atse_rxc_mem_res), - (void *)(rman_get_start(sc->atse_rxc_mem_res) + - rman_get_size(sc->atse_rxc_mem_res))); - /* - * TX and TXC FIFO memory regions. - * 0x00: 2 * 32bit FIFO data, - * 0x20: 8 * 32bit FIFO ctrl, Avalon-MM W-Slave to Avalon-ST Source. - */ - sc->atse_tx_mem_rid = 3; - sc->atse_tx_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->atse_tx_mem_rid, RF_ACTIVE); - if (sc->atse_tx_mem_res == NULL) { - device_printf(dev, "failed to map memory for TX FIFO\n"); - error = ENXIO; - goto err; - } - if (bootverbose) - device_printf(sc->atse_dev, "TX FIFO at mem %p-%p\n", - (void *)rman_get_start(sc->atse_tx_mem_res), - (void *)(rman_get_start(sc->atse_tx_mem_res) + - rman_get_size(sc->atse_tx_mem_res))); - - sc->atse_txc_mem_rid = 4; - sc->atse_txc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->atse_txc_mem_rid, RF_ACTIVE); - if (sc->atse_txc_mem_res == NULL) { - device_printf(dev, "failed to map memory for TXC FIFO\n"); - error = ENXIO; - goto err; - } - if (bootverbose) - device_printf(sc->atse_dev, "TXC FIFO at mem %p-%p\n", - (void *)rman_get_start(sc->atse_txc_mem_res), - (void *)(rman_get_start(sc->atse_txc_mem_res) + - rman_get_size(sc->atse_txc_mem_res))); - - /* (Optional) RX and TX IRQ. */ - sc->atse_rx_irq_rid = 0; - sc->atse_rx_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &sc->atse_rx_irq_rid, RF_ACTIVE | RF_SHAREABLE); - sc->atse_tx_irq_rid = 1; - sc->atse_tx_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &sc->atse_tx_irq_rid, RF_ACTIVE | RF_SHAREABLE); - - error = atse_attach(dev); - if (error) - goto err; - return (0); - -err: - /* Cleanup. */ - atse_detach_resources(dev); - - return (error); } static device_method_t atse_methods_fdt[] = { /* Device interface */ DEVMETHOD(device_probe, atse_probe_fdt), DEVMETHOD(device_attach, atse_attach_fdt), DEVMETHOD(device_detach, atse_detach_dev), /* MII interface */ DEVMETHOD(miibus_readreg, atse_miibus_readreg), DEVMETHOD(miibus_writereg, atse_miibus_writereg), DEVMETHOD(miibus_statchg, atse_miibus_statchg), DEVMETHOD_END }; static driver_t atse_driver_fdt = { "atse", atse_methods_fdt, sizeof(struct atse_softc) }; DRIVER_MODULE(atse, simplebus, atse_driver_fdt, atse_devclass, 0, 0); DRIVER_MODULE(miibus, atse, miibus_driver, miibus_devclass, 0, 0); - -/* end */ Index: head/sys/dev/altera/atse/if_atse_nexus.c =================================================================== --- head/sys/dev/altera/atse/if_atse_nexus.c (revision 332473) +++ head/sys/dev/altera/atse/if_atse_nexus.c (revision 332474) @@ -1,261 +1,160 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012,2013 Bjoern A. Zeeb * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) * ("MRC2"), as part of the DARPA MRC research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_device_polling.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* "device miibus" required. See GENERIC if you get errors here. */ #include "miibus_if.h" MODULE_DEPEND(atse, ether, 1, 1, 1); MODULE_DEPEND(atse, miibus, 1, 1, 1); /* * Device routines for interacting with nexus (probe, attach, detach) & helpers. * XXX We should add suspend/resume later. */ -static int +static int __unused atse_resource_int(device_t dev, const char *resname, int *v) { int error; error = resource_int_value(device_get_name(dev), device_get_unit(dev), resname, v); if (error != 0) { /* If it does not exist, we fail, so not ingoring ENOENT. */ device_printf(dev, "could not fetch '%s' hint\n", resname); return (error); } return (0); } -static int +static int __unused atse_resource_long(device_t dev, const char *resname, long *v) { int error; error = resource_long_value(device_get_name(dev), device_get_unit(dev), resname, v); if (error != 0) { /* If it does not exist, we fail, so not ingoring ENOENT. */ device_printf(dev, "could not fetch '%s' hint\n", resname); return (error); } return (0); } static int atse_probe_nexus(device_t dev) { - struct resource *res; - long l; - int error, rid; - /* - * It is almost impossible to properly probe this device. We must - * rely on hints being set correctly. So try to get hints and - * one memory mapping. Must cleanup and do again in attach but - * should not probe successfully if not able to attach later. - */ - error = atse_resource_int(dev, "rx_irq", &rid); - error += atse_resource_long(dev, "rx_maddr", &l); - error += atse_resource_long(dev, "rx_msize", &l); - error += atse_resource_long(dev, "rxc_maddr", &l); - error += atse_resource_long(dev, "rxc_msize", &l); - error += atse_resource_int(dev, "tx_irq", &rid); - error += atse_resource_long(dev, "tx_maddr", &l); - error += atse_resource_long(dev, "tx_msize", &l); - error += atse_resource_long(dev, "txc_maddr", &l); - error += atse_resource_long(dev, "txc_msize", &l); - if (error != 0) - return (ENXIO); - - rid = 0; - res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (res == NULL) - return (ENXIO); - bus_release_resource(dev, SYS_RES_MEMORY, rid, res); - - /* Success. */ device_set_desc(dev, "Altera Triple-Speed Ethernet MegaCore"); + return (BUS_PROBE_NOWILDCARD); } static int atse_attach_nexus(device_t dev) { struct atse_softc *sc; int error; sc = device_get_softc(dev); sc->atse_dev = dev; sc->atse_unit = device_get_unit(dev); - /* Get RX and TX IRQ and FIFO information from hints. */ - error = atse_resource_int(dev, "rx_irq", &sc->atse_rx_irq); - error += atse_resource_long(dev, "rx_maddr", &sc->atse_rx_maddr); - error += atse_resource_long(dev, "rx_msize", &sc->atse_rx_msize); - error += atse_resource_long(dev, "rxc_maddr", &sc->atse_rxc_maddr); - error += atse_resource_long(dev, "rxc_msize", &sc->atse_rxc_msize); - error += atse_resource_int(dev, "tx_irq", &sc->atse_tx_irq); - error += atse_resource_long(dev, "tx_maddr", &sc->atse_tx_maddr); - error += atse_resource_long(dev, "tx_msize", &sc->atse_tx_msize); - error += atse_resource_long(dev, "txc_maddr", &sc->atse_txc_maddr); - error += atse_resource_long(dev, "txc_msize", &sc->atse_txc_msize); - if (error != 0) - return (error); - /* Avalon-MM, atse management register region. */ sc->atse_mem_rid = 0; sc->atse_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->atse_mem_rid, RF_ACTIVE); if (sc->atse_mem_res == NULL) { device_printf(dev, "failed to map memory for ctrl region\n"); return (ENXIO); } - /* - * (Optional) RX IRQ and memory mapped regions. - * 0x00: 2 * 32bit FIFO data, - * 0x20: 8 * 32bit FIFO ctrl, Avalon-ST Sink to Avalon-MM R-Slave. - */ - sc->atse_rx_irq_rid = 0; - sc->atse_rx_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, - &sc->atse_rx_irq_rid, sc->atse_rx_irq, sc->atse_rx_irq, 1, - RF_ACTIVE | RF_SHAREABLE); - - sc->atse_rx_mem_rid = 0; - sc->atse_rx_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, - &sc->atse_rx_mem_rid, sc->atse_rx_maddr, sc->atse_rx_maddr + - sc->atse_rx_msize, sc->atse_rx_msize, RF_ACTIVE); - if (sc->atse_rx_mem_res == NULL) { - device_printf(dev, "failed to map memory for RX\n"); - goto err; - } - sc->atse_rxc_mem_rid = 0; - sc->atse_rxc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, - &sc->atse_rxc_mem_rid, sc->atse_rxc_maddr, sc->atse_rxc_maddr + - sc->atse_rxc_msize, sc->atse_rxc_msize, RF_ACTIVE); - if (sc->atse_rxc_mem_res == NULL) { - device_printf(dev, "failed to map memory for RX control\n"); - goto err; - } - - /* - * (Optional) TX IRQ and memory mapped regions. - * 0x00: 2 * 32bit FIFO data, - * 0x20: 8 * 32bit FIFO ctrl, Avalon-MM W-Slave to Avalon-ST Source. - */ - sc->atse_tx_irq_rid = 0; - sc->atse_tx_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, - &sc->atse_tx_irq_rid, sc->atse_tx_irq, sc->atse_tx_irq, 1, - RF_ACTIVE | RF_SHAREABLE); - - sc->atse_tx_mem_rid = 0; - sc->atse_tx_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, - &sc->atse_tx_mem_rid, sc->atse_tx_maddr, sc->atse_tx_maddr + - sc->atse_tx_msize, sc->atse_tx_msize, RF_ACTIVE); - if (sc->atse_tx_mem_res == NULL) { - device_printf(dev, "failed to map memory for TX\n"); - goto err; + error = atse_attach(dev); + if (error) { + /* Cleanup. */ + atse_detach_resources(dev); + return (error); } - sc->atse_txc_mem_rid = 0; - sc->atse_txc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, - &sc->atse_txc_mem_rid, sc->atse_txc_maddr, sc->atse_txc_maddr + - sc->atse_txc_msize, sc->atse_txc_msize, RF_ACTIVE); - if (sc->atse_txc_mem_res == NULL) { - device_printf(dev, "failed to map memory for TX control\n"); - goto err; - } - error = atse_attach(dev); - if (error) - goto err; - return (0); - -err: - /* Cleanup. */ - atse_detach_resources(dev); - - return (error); } static device_method_t atse_methods_nexus[] = { /* Device interface */ DEVMETHOD(device_probe, atse_probe_nexus), DEVMETHOD(device_attach, atse_attach_nexus), DEVMETHOD(device_detach, atse_detach_dev), /* MII interface */ DEVMETHOD(miibus_readreg, atse_miibus_readreg), DEVMETHOD(miibus_writereg, atse_miibus_writereg), DEVMETHOD(miibus_statchg, atse_miibus_statchg), DEVMETHOD_END }; static driver_t atse_driver_nexus = { "atse", atse_methods_nexus, sizeof(struct atse_softc) }; DRIVER_MODULE(atse, nexus, atse_driver_nexus, atse_devclass, 0, 0); DRIVER_MODULE(miibus, atse, miibus_driver, miibus_devclass, 0, 0); - -/* end */ Index: head/sys/dev/altera/atse/if_atsereg.h =================================================================== --- head/sys/dev/altera/atse/if_atsereg.h (revision 332473) +++ head/sys/dev/altera/atse/if_atsereg.h (revision 332474) @@ -1,488 +1,471 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012 Bjoern A. Zeeb * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) * ("MRC2"), as part of the DARPA MRC research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_IF_ATSEREG_H #define _DEV_IF_ATSEREG_H +#include + #define ATSE_VENDOR 0x6af7 #define ATSE_DEVICE 0x00bd /* See hints file/fdt for ctrl port and Avalon FIFO addresses. */ /* Section 3. Parameter Settings. */ /* * This is a lot of options that affect the way things are synthesized. * We cannot really make them all hints and most of them might be stale. */ /* 3-1 Core Configuration */ #if 0 static const char *atse_core_core_variation[] = { [0] = "10/100/1000 Mbps Ethernet MAC only", [1] = "10/100/1000 Mbps Ethernet MAC with 1000BASE-X/SGMII PCS", [2] = "1000BASE-X/SGMII PCS only", [3] = "1000 Mbps Small MAC", [4] = "10/100 Mbps Small MAC", NULL }; static const char *atse_core_interface[] = { [0] = "MII", /* Core variation 4. */ [1] = "GMII", /* Core variation 3. */ [2] = "RGMII", /* Core variation 0,1,3. */ [3] = "MII/GMII", /* Core variation 0,1. */ NULL }; #endif #define CORE_CORE_VARIATION 1 /* atse_core_core_variation[] */ #define CORE_INTERFACE 3 /* atse_core_interface[] */ #define CORE_USE_INTERNAL_FIFO 1 #define CORE_NUMBER_OF_PORTS 1 /* Internal FIFO count. */ #define CORE_USE_TRANSCEIVER_BLOCK 1 /* SGMII PCS transceiver: * LVDS I/O. */ /* 3-2 MAC Options. */ /* Ethernet MAC Options. */ #define MAC_ENABLE_10_100_HDX_SUPPORT 0 #define MAC_ENABLE_RG_G_MII_LOOPBACK 0 #define MAC_ENABLE_SUPL_MAC_UCAST_ADDR 0 /* Supplementary MAC unicast. */ #define MAC_INCLUDE_STATISTICS_COUNTERS 0 #define MAC_STATISTICS_COUNTERS_64BIT 0 #define MAC_INCLUDE_MC_HASHTABLE 0 /* Multicast. */ #define MAC_ALIGN_PKTHDR_32BIT 1 #define MAC_ENABLE_FDX_FLOW_CTRL 0 #define MAC_ENABLE_VLAN_DETECTION 0 /* VLAN and stacked VLANs. */ #define MAC_ENABLE_MAGIC_PKT_DETECTION 0 /* MDIO Module. */ #define MAC_MDIO_INCLUDE_MDIO_MODULE 1 #define MAC_MDIO_HOST_CLOCK_DIVISOR 40 /* Not just On/Off. */ /* 3-4 FIFO Options. */ /* Width and Memory Type. */ #if 0 static char *fifo_memory_block[] = { [0] = "M4K", [1] = "M9K", [2] = "M144K", [3] = "MRAM", [4] = "AUTO", NULL }; #endif #define FIFO_MEMORY_BLOCK 4 #define FIFO_WITDH 32 /* Other: 8 bits. */ /* Depth. */ #define FIFO_DEPTH_TX 2048 /* 64 .. 64k, 2048x32bits. */ #define FIFO_DEPTH_RX 2048 /* 64 .. 64k, 2048x32bits. */ #define ATSE_TX_LIST_CNT 5 /* Certainly not bufferbloat. */ /* 3-4 PCS/Transceiver Options */ /* PCS Options. */ #define PCS_TXRX_PHY_ID 0x00000000 /* 32 bits */ #define PCS_TXRX_ENABLE_SGMII_BRIDGE 0 /* Transceiver Options. */ #define PCS_TXRX_EXP_POWER_DOWN_SIGNAL 0 /* Export power down signal. */ #define PCS_TXRX_ENABLE_DYNAMIC_RECONF 0 /* Dynamic trans. reconfig. */ #define PCS_TXRX_STARTING_CHANNEL 0 /* 0..284. */ /* -------------------------------------------------------------------------- */ /* XXX more values based on the bitmaps provided. Cleanup. */ /* See regs above. */ #define AVALON_FIFO_TX_BLOCK_DIAGRAM 0 #define AVALON_FIFO_TX_BLOCK_DIAGRAM_SHOW_SIGANLS 0 #define AVALON_FIFO_TX_PARAM_SINGLE_RESET_MODE 0 #define AVALON_FIFO_TX_BASIC_OPTS_DEPTH 16 #define AVALON_FIFO_TX_BASIC_OPTS_ALLOW_BACKPRESSURE 1 #define AVALON_FIFO_TX_BASIC_OPTS_CLOCK_SETTING "Single Clock Mode" #define AVALON_FIFO_TX_BASIC_OPTS_FIFO_IMPL "Construct FIFO from embedded memory blocks" #define AVALON_FIFO_TX_STATUS_PORT_CREATE_STATUS_INT_FOR_INPUT 1 #define AVALON_FIFO_TX_STATUS_PORT_CREATE_STATUS_INT_FOR_OUTPUT 0 #define AVALON_FIFO_TX_STATUS_PORT_ENABLE_IRQ_FOR_STATUS_PORT 1 #define AVALON_FIFO_TX_INPUT_TYPE "AVALONMM_WRITE" #define AVALON_FIFO_TX_OUTPUT_TYPE "AVALONST_SOURCE" #define AVALON_FIFO_TX_AVALON_MM_PORT_SETTINGS_DATA_WIDTH "" #define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_BITS_PER_SYMBOL 8 #define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_SYM_PER_BEAT 4 #define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_ERROR_WIDTH 1 #define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_CHANNEL_WIDTH 0 #define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_ENABLE_PACKET_DATA 1 #define AVALON_FIFO_RX_BLOCK_DIAGRAM 0 #define AVALON_FIFO_RX_BLOCK_DIAGRAM_SHOW_SIGNALS 0 #define AVALON_FIFO_RX_PARAM_SINGLE_RESET_MODE 0 #define AVALON_FIFO_RX_BASIC_OPTS_DEPTH 16 #define AVALON_FIFO_RX_BASIC_OPTS_ALLOW_BACKPRESSURE 1 #define AVALON_FIFO_RX_BASIC_OPTS_CLOCK_SETTING "Single Clock Mode" #define AVALON_FIFO_RX_BASIC_OPTS_FIFO_IMPL "Construct FIFO from embedded memory blocks" #define AVALON_FIFO_RX_STATUS_PORT_CREATE_STATUS_INT_FOR_INPUT 1 #define AVALON_FIFO_RX_STATUS_PORT_CREATE_STATUS_INT_FOR_OUTPUT 0 #define AVALON_FIFO_RX_STATUS_PORT_ENABLE_IRQ_FOR_STATUS_PORT 1 #define AVALON_FIFO_RX_INPUT_TYPE "AVALONST_SINK" #define AVALON_FIFO_RX_OUTPUT_TYPE "AVALONMM_READ" #define AVALON_FIFO_RX_AVALON_MM_PORT_SETTINGS_DATA_WIDTH "" #define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_BITS_PER_SYMBOL 8 #define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_SYM_PER_BEAT 4 #define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_ERROR_WIDTH 6 #define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_CHANNEL_WIDTH 0 #define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_ENABLE_PACKET_DATA 1 /* -------------------------------------------------------------------------- */ /* 5. Configuration Register Space. */ /* 5-1, MAC Configuration Register Space; Dword offsets. */ /* 0x00 - 0x17, Base Configuration. */ #define BASE_CONFIG_REV 0x00 /* ro, IP Core ver. */ #define BASE_CFG_REV_VER_MASK 0x0000FFFF #define BASE_CFG_REV_CUST_VERSION__MASK 0xFFFF0000 #define BASE_CFG_SCRATCH 0x01 /* rw, 0 */ #define BASE_CFG_COMMAND_CONFIG 0x02 /* rw, 0 */ #define BASE_CFG_COMMAND_CONFIG_TX_ENA (1<<0) /* rw */ #define BASE_CFG_COMMAND_CONFIG_RX_ENA (1<<1) /* rw */ #define BASE_CFG_COMMAND_CONFIG_XON_GEN (1<<2) /* rw */ #define BASE_CFG_COMMAND_CONFIG_ETH_SPEED (1<<3) /* rw */ #define BASE_CFG_COMMAND_CONFIG_PROMIS_EN (1<<4) /* rw */ #define BASE_CFG_COMMAND_CONFIG_PAD_EN (1<<5) /* rw */ #define BASE_CFG_COMMAND_CONFIG_CRC_FWD (1<<6) /* rw */ #define BASE_CFG_COMMAND_CONFIG_PAUSE_FWD (1<<7) /* rw */ #define BASE_CFG_COMMAND_CONFIG_PAUSE_IGNORE (1<<8) /* rw */ #define BASE_CFG_COMMAND_CONFIG_TX_ADDR_INS (1<<9) /* rw */ #define BASE_CFG_COMMAND_CONFIG_HD_ENA (1<<10) /* rw */ #define BASE_CFG_COMMAND_CONFIG_EXCESS_COL (1<<11) /* ro */ #define BASE_CFG_COMMAND_CONFIG_LATE_COL (1<<12) /* ro */ #define BASE_CFG_COMMAND_CONFIG_SW_RESET (1<<13) /* rw */ #define BASE_CFG_COMMAND_CONFIG_MHASH_SEL (1<<14) /* rw */ #define BASE_CFG_COMMAND_CONFIG_LOOP_ENA (1<<15) /* rw */ #define BASE_CFG_COMMAND_CONFIG_TX_ADDR_SEL (1<<16|1<<17|1<<18) /* rw */ #define BASE_CFG_COMMAND_CONFIG_MAGIC_ENA (1<<19) /* rw */ #define BASE_CFG_COMMAND_CONFIG_SLEEP (1<<20) /* rw */ #define BASE_CFG_COMMAND_CONFIG_WAKEUP (1<<21) /* ro */ #define BASE_CFG_COMMAND_CONFIG_XOFF_GEN (1<<22) /* rw */ #define BASE_CFG_COMMAND_CONFIG_CNTL_FRM_ENA (1<<23) /* rw */ #define BASE_CFG_COMMAND_CONFIG_NO_LGTH_CHECK (1<<24) /* rw */ #define BASE_CFG_COMMAND_CONFIG_ENA_10 (1<<25) /* rw */ #define BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC (1<<26) /* rw */ #define BASE_CFG_COMMAND_CONFIG_DISABLE_READ_TIMEOUT (1<<27) /* rw */ /* 28-30 Reserved. */ /* - */ #define BASE_CFG_COMMAND_CONFIG_CNT_RESET (1<<31) /* rw */ #define BASE_CFG_MAC_0 0x03 /* rw, 0 */ #define BASE_CFG_MAC_1 0x04 /* rw, 0 */ #define BASE_CFG_FRM_LENGTH 0x05 /* rw/ro, 1518 */ #define BASE_CFG_PAUSE_QUANT 0x06 /* rw, 0 */ #define BASE_CFG_RX_SECTION_EMPTY 0x07 /* rw/ro, 0 */ #define BASE_CFG_RX_SECTION_FULL 0x08 /* rw/ro, 0 */ #define BASE_CFG_TX_SECTION_EMPTY 0x09 /* rw/ro, 0 */ #define BASE_CFG_TX_SECTION_FULL 0x0A /* rw/ro, 0 */ #define BASE_CFG_RX_ALMOST_EMPTY 0x0B /* rw/ro, 0 */ #define BASE_CFG_RX_ALMOST_FULL 0x0C /* rw/ro, 0 */ #define BASE_CFG_TX_ALMOST_EMPTY 0x0D /* rw/ro, 0 */ #define BASE_CFG_TX_ALMOST_FULL 0x0E /* rw/ro, 0 */ #define BASE_CFG_MDIO_ADDR0 0x0F /* rw, 0 */ #define BASE_CFG_MDIO_ADDR1 0x10 /* rw, 1 */ #define BASE_CFG_HOLDOFF_QUANT 0x11 /* rw, 0xFFFF */ /* 0x12-0x16 Reserved. */ /* -, 0 */ #define BASE_CFG_TX_IPG_LENGTH 0x17 /* rw, 0 */ /* 0x18 - 0x38, Statistics Counters. */ #define STATS_A_MAC_ID_0 0x18 /* ro */ #define STATS_A_MAC_ID_1 0x19 /* ro */ #define STATS_A_FRAMES_TX_OK 0x1A /* ro */ #define STATS_A_FRAMES_RX_OK 0x1B /* ro */ #define STATS_A_FCS_ERRORS 0x1C /* ro */ #define STATS_A_ALIGNMENT_ERRORS 0x1D /* ro */ #define STATS_A_OCTETS_TX_OK 0x1E /* ro */ #define STATS_A_OCTETS_RX_OK 0x1F /* ro */ #define STATS_A_TX_PAUSE_MAX_CTRL_FRAME 0x20 /* ro */ #define STATS_A_RX_PAUSE_MAX_CTRL_FRAME 0x21 /* ro */ #define STATS_IF_IN_ERRORS 0x22 /* ro */ #define STATS_IF_OUT_ERRORS 0x23 /* ro */ #define STATS_IF_IN_UCAST_PKTS 0x24 /* ro */ #define STATS_IF_IN_MULTICAST_PKTS 0x25 /* ro */ #define STATS_IF_IN_BROADCAST_PKTS 0x26 /* ro */ #define STATS_IF_OUT_DISCARDS 0x27 /* ro */ #define STATS_IF_OUT_UCAST_PKTS 0x28 /* ro */ #define STATS_IF_OUT_MULTICAST_PKTS 0x29 /* ro */ #define STATS_IF_OUT_BROADCAST_PKTS 0x2A /* ro */ #define STATS_ETHER_STATS_DROP_EVENT 0x2B /* ro */ #define STATS_ETHER_STATS_OCTETS 0x2C /* ro */ #define STATS_ETHER_STATS_PKTS 0x2D /* ro */ #define STATS_ETHER_STATS_USIZE_PKTS 0x2E /* ro */ #define STATS_ETHER_STATS_OSIZE_PKTS 0x2F /* ro */ #define STATS_ETHER_STATS_PKTS_64_OCTETS 0x30 /* ro */ #define STATS_ETHER_STATS_PKTS_65_TO_127_OCTETS 0x31 /* ro */ #define STATS_ETHER_STATS_PKTS_128_TO_255_OCTETS 0x32 /* ro */ #define STATS_ETHER_STATS_PKTS_256_TO_511_OCTETS 0x33 /* ro */ #define STATS_ETHER_STATS_PKTS_512_TO_1023_OCTETS 0x34 /* ro */ #define STATS_ETHER_STATS_PKTS_1024_TO_1518_OCTETS 0x35 /* ro */ #define STATS_ETHER_STATS_PKTS_1519_TO_X_OCTETS 0x36 /* ro */ #define STATS_ETHER_STATS_JABBERS 0x37 /* ro */ #define STATS_ETHER_STATS_FRAGMENTS 0x38 /* ro */ /* 0x39, Reserved. */ /* - */ /* 0x3A, Transmit Command. */ #define TX_CMD_STAT 0x3A /* rw */ #define TX_CMD_STAT_OMIT_CRC (1<<17) #define TX_CMD_STAT_TX_SHIFT16 (1<<18) /* 0x3B, Receive Command. */ #define RX_CMD_STAT 0x3B /* rw */ #define RX_CMD_STAT_RX_SHIFT16 (1<<25) /* 0x3C - 0x3E, Extended Statistics Counters. */ #define ESTATS_MSB_A_OCTETS_TX_OK 0x3C /* ro */ #define ESTATS_MSB_A_OCTETS_RX_OK 0x3D /* ro */ #define ESTATS_MSB_ETHER_STATS_OCTETS 0x3E /* ro */ /* 0x3F, Reserved. */ /* 0x40 - 0x7F, Multicast Hash Table. */ #define MHASH_START 0x40 #define MHASH_LEN 0x3F /* 0x80 - 0x9F, MDIO Space 0 or PCS Function Configuration. */ #define MDIO_0_START 0x80 /* The following are offsets to the first PCS register at 0x80. */ /* See sys/dev/mii/mii.h. */ #define PCS_CONTROL 0x00 /* rw */ /* Bits 0:4, Reserved. */ /* - */ #define PCS_CONTROL_UNIDIRECTIONAL_ENABLE (1<<5) /* rw */ #define PCS_CONTROL_SPEED_SELECTION (1<<6|1<<13) /* ro */ #define PCS_CONTROL_COLLISION_TEST (1<<7) /* ro */ #define PCS_CONTROL_DUPLEX_MODE (1<<8) /* ro */ #define PCS_CONTROL_RESTART_AUTO_NEGOTIATION (1<<9) /* rw */ #define PCS_CONTROL_ISOLATE (1<<10) /* rw */ #define PCS_CONTROL_POWERDOWN (1<<11) /* rw */ #define PCS_CONTROL_AUTO_NEGOTIATION_ENABLE (1<<12) /* rw */ /* See bit 6 above. */ /* ro */ #define PCS_CONTROL_LOOPBACK (1<<14) /* rw */ #define PCS_CONTROL_RESET (1<<15) /* rw */ #define PCS_STATUS 0x01 /* ro */ #define PCS_STATUS_EXTENDED_CAPABILITY (1<<0) /* ro */ #define PCS_STATUS_JABBER_DETECT (1<<1) /* -, 0 */ #define PCS_STATUS_LINK_STATUS (1<<2) /* ro */ #define PCS_STATUS_AUTO_NEGOTIATION_ABILITY (1<<3) /* ro */ #define PCS_STATUS_REMOTE_FAULT (1<<4) /* -, 0 */ #define PCS_STATUS_AUTO_NEGOTIATION_COMPLETE (1<<5) /* ro */ #define PCS_STATUS_MF_PREAMBLE_SUPPRESSION (1<<6) /* -, 0 */ #define PCS_STATUS_UNIDIRECTIONAL_ABILITY (1<<7) /* ro */ #define PCS_STATUS_EXTENDED_STATUS (1<<8) /* -, 0 */ #define PCS_STATUS_100BASET2_HALF_DUPLEX (1<<9) /* ro */ #define PCS_STATUS_100BASET2_FULL_DUPLEX (1<<10) /* ro */ #define PCS_STATUS_10MBPS_HALF_DUPLEX (1<<11) /* ro */ #define PCS_STATUS_10MBPS_FULL_DUPLEX (1<<12) /* ro */ #define PCS_STATUS_100BASE_X_HALF_DUPLEX (1<<13) /* ro */ #define PCS_STATUS_100BASE_X_FULL_DUPLEX (1<<14) /* ro */ #define PCS_STATUS_100BASE_T4 (1<<15) /* ro */ #define PCS_PHY_IDENTIFIER_0 0x02 /* ro */ #define PCS_PHY_IDENTIFIER_1 0x03 /* ro */ #define PCS_DEV_ABILITY 0x04 /* rw */ /* 1000BASE-X */ /* Bits 0:4, Reserved. */ /* - */ #define PCS_DEV_ABILITY_1000BASE_X_FD (1<<5) /* rw */ #define PCS_DEV_ABILITY_1000BASE_X_HD (1<<6) /* rw */ #define PCS_DEV_ABILITY_1000BASE_X_PS1 (1<<7) /* rw */ #define PCS_DEV_ABILITY_1000BASE_X_PS2 (1<<8) /* rw */ /* Bits 9:11, Reserved. */ /* - */ #define PCS_DEV_ABILITY_1000BASE_X_RF1 (1<<12) /* rw */ #define PCS_DEV_ABILITY_1000BASE_X_RF2 (1<<13) /* rw */ #define PCS_DEV_ABILITY_1000BASE_X_ACK (1<<14) /* rw */ #define PCS_DEV_ABILITY_1000BASE_X_NP (1<<15) /* rw */ #define PCS_PARTNER_ABILITY 0x05 /* ro */ /* 1000BASE-X */ /* Bits 0:4, Reserved. */ /* - */ #define PCS_PARTNER_ABILITY_1000BASE_X_FD (1<<5) /* ro */ #define PCS_PARTNER_ABILITY_1000BASE_X_HD (1<<6) /* ro */ #define PCS_PARTNER_ABILITY_1000BASE_X_PS1 (1<<7) /* ro */ #define PCS_PARTNER_ABILITY_1000BASE_X_PS2 (1<<8) /* ro */ /* Bits 9:11, Reserved. */ /* - */ #define PCS_PARTNER_ABILITY_1000BASE_X_RF1 (1<<12) /* ro */ #define PCS_PARTNER_ABILITY_1000BASE_X_RF2 (1<<13) /* ro */ #define PCS_PARTNER_ABILITY_1000BASE_X_ACK (1<<14) /* ro */ #define PCS_PARTNER_ABILITY_1000BASE_X_NP (1<<15) /* ro */ /* SGMII */ /* Bits 0:9, Reserved. */ /* - */ #define PCS_PARTNER_ABILITY_SGMII_COPPER_SPEED0 (1<<10) /* ro */ #define PCS_PARTNER_ABILITY_SGMII_COPPER_SPEED1 (1<<11) /* ro */ #define PCS_PARTNER_ABILITY_SGMII_COPPER_DUPLEX_STATUS (1<<12) /* ro */ /* Bit 13, Reserved. */ /* - */ #define PCS_PARTNER_ABILITY_SGMII_ACK (1<<14) /* ro */ #define PCS_PARTNER_ABILITY_SGMII_COPPER_LINK_STATUS (1<<15) /* ro */ #define PCS_AN_EXPANSION 0x06 /* ro */ #define PCS_AN_EXPANSION_LINK_PARTNER_AUTO_NEGOTIATION_ABLE (1<<0) /* ro */ #define PCS_AN_EXPANSION_PAGE_RECEIVE (1<<1) /* ro */ #define PCS_AN_EXPANSION_NEXT_PAGE_ABLE (1<<2) /* -, 0 */ /* Bits 3:15, Reserved. */ /* - */ #define PCS_DEVICE_NEXT_PAGE 0x07 /* ro */ #define PCS_PARTNER_NEXT_PAGE 0x08 /* ro */ #define PCS_MASTER_SLAVE_CNTL 0x09 /* ro */ #define PCS_MASTER_SLAVE_STAT 0x0A /* ro */ /* 0x0B - 0x0E, Reserved */ /* - */ #define PCS_EXTENDED_STATUS 0x0F /* ro */ /* Specific Extended Registers. */ #define PCS_EXT_SCRATCH 0x10 /* rw */ #define PCS_EXT_REV 0x11 /* ro */ #define PCS_EXT_LINK_TIMER_0 0x12 /* rw */ #define PCS_EXT_LINK_TIMER_1 0x13 /* rw */ #define PCS_EXT_IF_MODE 0x14 /* rw */ #define PCS_EXT_IF_MODE_SGMII_ENA (1<<0) /* rw */ #define PCS_EXT_IF_MODE_USE_SGMII_AN (1<<1) /* rw */ #define PCS_EXT_IF_MODE_SGMII_SPEED1 (1<<2) /* rw */ #define PCS_EXT_IF_MODE_SGMII_SPEED0 (1<<3) /* rw */ #define PCS_EXT_IF_MODE_SGMII_DUPLEX (1<<4) /* rw */ /* Bits 5:15, Reserved. */ /* - */ #define PCS_EXT_DISABLE_READ_TIMEOUT 0x15 /* rw */ #define PCS_EXT_READ_TIMEOUT 0x16 /* r0 */ /* 0x17-0x1F, Reserved. */ /* 0xA0 - 0xBF, MDIO Space 1. */ #define MDIO_1_START 0xA0 #define ATSE_BMCR MDIO_1_START /* 0xC0 - 0xC7, Supplementary Address. */ #define SUPPL_ADDR_SMAC_0_0 0xC0 /* rw */ #define SUPPL_ADDR_SMAC_0_1 0xC1 /* rw */ #define SUPPL_ADDR_SMAC_1_0 0xC2 /* rw */ #define SUPPL_ADDR_SMAC_1_1 0xC3 /* rw */ #define SUPPL_ADDR_SMAC_2_0 0xC4 /* rw */ #define SUPPL_ADDR_SMAC_2_1 0xC5 /* rw */ #define SUPPL_ADDR_SMAC_3_0 0xC6 /* rw */ #define SUPPL_ADDR_SMAC_3_1 0xC7 /* rw */ /* 0xC8 - 0xCF, Reserved; set to zero, ignore on read. */ /* 0xD7 - 0xFF, Reserved; set to zero, ignore on read. */ /* -------------------------------------------------------------------------- */ /* DE4 Intel Strata Flash Ethernet Option Bits area. */ /* XXX-BZ this is something a loader will have to handle for us. */ #define ALTERA_ETHERNET_OPTION_BITS_OFF 0x00008000 #define ALTERA_ETHERNET_OPTION_BITS_LEN 0x00007fff /* -------------------------------------------------------------------------- */ struct atse_softc { struct ifnet *atse_ifp; - struct mbuf *atse_rx_m; - struct mbuf *atse_tx_m; - uint8_t *atse_tx_buf; struct resource *atse_mem_res; - struct resource *atse_rx_irq_res; - struct resource *atse_rx_mem_res; - struct resource *atse_rxc_mem_res; - struct resource *atse_tx_irq_res; - struct resource *atse_tx_mem_res; - struct resource *atse_txc_mem_res; device_t atse_miibus; device_t atse_dev; int atse_unit; int atse_mem_rid; - int atse_rx_irq_rid; - int atse_rx_mem_rid; - int atse_rxc_mem_rid; - int atse_tx_irq_rid; - int atse_tx_mem_rid; - int atse_txc_mem_rid; int atse_phy_addr; int atse_if_flags; - int atse_rx_irq; - int atse_tx_irq; - u_long atse_rx_maddr; - u_long atse_rx_msize; - u_long atse_tx_maddr; - u_long atse_tx_msize; - u_long atse_rxc_maddr; - u_long atse_rxc_msize; - u_long atse_txc_maddr; - u_long atse_txc_msize; - void *atse_rx_intrhand; - void *atse_tx_intrhand; bus_addr_t atse_bmcr0; bus_addr_t atse_bmcr1; uint32_t atse_flags; #define ATSE_FLAGS_LINK 0x00000001 #define ATSE_FLAGS_ERROR 0x00000002 #define ATSE_FLAGS_SOP_SEEN 0x00000004 uint8_t atse_eth_addr[ETHER_ADDR_LEN]; #define ATSE_ETH_ADDR_DEF 0x01 #define ATSE_ETH_ADDR_SUPP1 0x02 #define ATSE_ETH_ADDR_SUPP2 0x04 #define ATSE_ETH_ADDR_SUPP3 0x08 #define ATSE_ETH_ADDR_SUPP4 0x10 #define ATSE_ETH_ADDR_ALL 0x1f - uint16_t atse_watchdog_timer; - uint16_t atse_tx_m_offset; - uint16_t atse_tx_buf_len; - uint16_t atse_rx_buf_len; int16_t atse_rx_cycles; /* POLLING */ #define RX_CYCLES_IN_INTR 5 uint32_t atse_rx_err[6]; #define ATSE_RX_ERR_FIFO_THRES_EOP 0 /* FIFO threshold reached, on EOP. */ #define ATSE_RX_ERR_ELEN 1 /* Frame/payload length not valid. */ #define ATSE_RX_ERR_CRC32 2 /* CRC-32 error. */ #define ATSE_RX_ERR_FIFO_THRES_TRUNC 3 /* FIFO thresh., truncated frame. */ #define ATSE_RX_ERR_4 4 /* ? */ #define ATSE_RX_ERR_5 5 /* / */ #define ATSE_RX_ERR_MAX 6 struct callout atse_tick; struct mtx atse_mtx; + device_t dev; + + /* xDMA */ + xdma_controller_t *xdma_tx; + xdma_channel_t *xchan_tx; + void *ih_tx; + int txcount; + + xdma_controller_t *xdma_rx; + xdma_channel_t *xchan_rx; + void *ih_rx; + + struct buf_ring *br; + struct mtx br_mtx; }; int atse_attach(device_t); int atse_detach_dev(device_t); void atse_detach_resources(device_t); int atse_miibus_readreg(device_t, int, int); int atse_miibus_writereg(device_t, int, int, int); void atse_miibus_statchg(device_t); extern devclass_t atse_devclass; #endif /* _DEV_IF_ATSEREG_H */ - -/* end */ Index: head/sys/dts/mips/beripad-de4.dts =================================================================== --- head/sys/dts/mips/beripad-de4.dts (revision 332473) +++ head/sys/dts/mips/beripad-de4.dts (revision 332474) @@ -1,335 +1,336 @@ /*- * Copyright (c) 2012-2013 Robert N. M. Watson * Copyright (c) 2013 SRI International * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /dts-v1/; /* * Device names here have been largely made up on the spot, especially for the * "compatible" strings, and might want to be revised. * * For now, use 32-bit addressing as our Avalon bus is 32-bit. However, in * the future, we should likely change to 64-bit. */ / { model = "SRI/Cambridge BeriPad (DE4)"; compatible = "sri-cambridge,beripad-de4"; #address-cells = <1>; #size-cells = <1>; cpus { #address-cells = <1>; #size-cells = <1>; /* * Secondary CPUs all start disabled and use the * spin-table enable method. cpu-release-addr must be * specified for each cpu other than cpu@0. Values of * cpu-release-addr grow down from 0x100000 (kernel). */ status = "disabled"; enable-method = "spin-table"; cpu@0 { device-type = "cpu"; compatible = "sri-cambridge,beri"; reg = <0 1>; status = "okay"; }; /* cpu@1 { device-type = "cpu"; compatible = "sri-cambridge,beri"; reg = <1 1>; // XXX: should we need cached prefix? cpu-release-addr = <0xffffffff 0x800fffe0>; }; */ }; memory { device_type = "memory"; reg = <0x0 0x40000000>; // 1G at 0x0 }; cpuintc: cpuintc@0 { #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; compatible = "mti,cpu-interrupt-controller"; }; beripic0: beripic@7f804000 { compatible = "sri-cambridge,beri-pic"; interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; reg = <0x7f804000 0x400 0x7f806000 0x10 0x7f806080 0x10 0x7f806100 0x10>; interrupts = < 2 3 4 5 6 >; hard-interrupt-sources = <64>; soft-interrupt-sources = <64>; interrupt-parent = <&cpuintc>; }; /* beripic1: beripic@7f808000 { compatible = "sri-cambridge,beri-pic"; interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; reg = <0x7f808000 0x400 0x7f80a000 0x10 0x7f80a080 0x10 0x7f80a100 0x10>; interrupts = < 2 3 4 5 6 >; hard-interrupt-sources = <64>; soft-interrupt-sources = <64>; interrupt-parent = <&cpuintc>; }; */ soc { #address-cells = <1>; #size-cells = <1>; #interrupt-cells = <1>; compatible = "simple-bus", "mips,mips4k"; ranges; serial@7f002100 { compatible = "ns16550"; reg = <0x7f002100 0x20>; reg-shift = <2>; clock-frequency = <50000000>; interrupts = <6>; interrupt-parent = <&beripic0>; }; serial@7f000000 { compatible = "altera,jtag_uart-11_0"; reg = <0x7f000000 0x40>; interrupts = <0>; interrupt-parent = <&beripic0>; }; serial@7f001000 { compatible = "altera,jtag_uart-11_0"; reg = <0x7f001000 0x40>; }; serial@7f002000 { compatible = "altera,jtag_uart-11_0"; reg = <0x7f002000 0x40>; }; sdcard@7f008000 { compatible = "altera,sdcard_11_2011"; reg = <0x7f008000 0x400>; }; led@7f006000 { compatible = "sri-cambridge,de4led"; reg = <0x7f006000 0x1>; }; /* * XXX-BZ keep flash before ethernet so that atse can read the * Ethernet addresses for now. */ flash@74000000 { #address-cells = <1>; #size-cells = <1>; compatible = "cfi-flash"; reg = <0x74000000 0x4000000>; /* Board configuration */ partition@0 { reg = <0x0 0x20000>; label = "config"; }; /* Power up FPGA image */ partition@20000 { reg = <0x20000 0xc00000>; label = "fpga0"; }; /* Secondary FPGA image (on RE_CONFIGn button) */ partition@C20000 { reg = <0xc20000 0xc00000>; label = "fpga1"; }; /* Space for operating system use */ partition@1820000 { reg = <0x1820000 0x027c0000>; label = "os"; }; /* Second stage bootloader */ parition@3fe0000 { reg = <0x3fe0000 0x20000>; label = "boot"; }; }; msgdma0: msgdma@80004080 { compatible = "altr,msgdma-16.0", "altr,msgdma-1.0"; reg = <0x80004080 0x00000020>, <0x800040a0 0x00000020>; reg-names = "csr", "descriptor_slave"; interrupts = <14>; interrupt-parent = <&beripic0>; #dma-cells = <3>; }; msgdma1: msgdma@80004000 { compatible = "altr,msgdma-16.0", "altr,msgdma-1.0"; reg = <0x80004000 0x00000020>, <0x80004020 0x00000020>; reg-names = "csr", "descriptor_slave"; interrupts = <13>; interrupt-parent = <&beripic0>; #dma-cells = <3>; }; softdma0: softdma@7f007400 { compatible = "altr,softdma"; reg = < 0x7f007400 0x8 /* tx */ 0x7f007420 0x20 >; /* txc */ interrupts = <2>; interrupt-parent = <&beripic0>; #dma-cells = <3>; }; softdma1: softdma@7f007500 { compatible = "altr,softdma"; reg = < 0x7f007500 0x8 /* rx */ 0x7f007520 0x20 >; /* rxc */ interrupts = <1>; interrupt-parent = <&beripic0>; #dma-cells = <3>; }; softdma2: softdma@7f005400 { compatible = "altr,softdma"; reg = < 0x7f005400 0x8 /* tx */ 0x7f005420 0x20 >; /* txc */ interrupts = <12>; interrupt-parent = <&beripic0>; #dma-cells = <3>; }; softdma3: softdma@7f005500 { compatible = "altr,softdma"; reg = < 0x7f005500 0x8 /* rx */ 0x7f005520 0x20 >; /* rxc */ interrupts = <11>; interrupt-parent = <&beripic0>; #dma-cells = <3>; }; + ethernet@80007000 { + compatible = "altera,atse"; + reg = <0x80007000 0x400>; /* mac */ + dmas = <&msgdma0 0 0 0xffffffff>, + <&msgdma1 1 1 0xffffffff>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + ethernet@7f007000 { compatible = "altera,atse"; - // MAC, RX+RXC, TX+TXC. - reg = <0x7f007000 0x400 - 0x7f007500 0x8 - 0x7f007520 0x20 - 0x7f007400 0x8 - 0x7f007420 0x20>; - // RX, TX - interrupts = <1 2>; - interrupt-parent = <&beripic0>; + reg = <0x7f007000 0x400>; /* mac */ + dmas = <&softdma0 0 0 0xffffffff>, + <&softdma1 1 1 0xffffffff>; + dma-names = "tx", "rx"; + status = "okay"; }; ethernet@7f005000 { compatible = "altera,atse"; - // MAC, RX+RXC, TX+TXC. - reg = <0x7f005000 0x400 - 0x7f005500 0x8 - 0x7f005520 0x20 - 0x7f005400 0x8 - 0x7f005420 0x20>; - // RX, TX - interrupts = <11 12>; - interrupt-parent = <&beripic0>; + reg = <0x7f005000 0x400>; + dmas = <&softdma2 0 0 0xffffffff>, + <&softdma3 1 1 0xffffffff>; + dma-names = "tx", "rx"; + status = "disabled"; }; touchscreen@70400000 { compatible = "sri-cambridge,mtl"; panel-size = < 800 480 >; reg = <0x70400000 0x1000 0x70000000 0x177000 0x70177000 0x2000>; }; usb@0x7f100000 { compatible = "nxp,usb-isp1761"; reg = <0x7f100000 0x40000 0x7f140000 0x4>; // IRQ 4 is DC, IRQ 5 is HC. interrupts = <4 5>; interrupt-parent = <&beripic0>; }; avgen@0x7f009000 { compatible = "sri-cambridge,avgen"; reg = <0x7f009000 0x2>; sri-cambridge,width = <1>; sri-cambridge,fileio = "r"; sri-cambridge,devname = "de4bsw"; }; avgen@0x7f00a000 { compatible = "sri-cambridge,avgen"; reg = <0x7f00a000 0x14>; sri-cambridge,width = <4>; sri-cambridge,fileio = "rw"; sri-cambridge,devname = "berirom"; }; avgen@0x7f00c000 { compatible = "sri-cambridge,avgen"; reg = <0x7f00c000 0x8>; sri-cambridge,width = <4>; sri-cambridge,fileio = "rw"; sri-cambridge,devname = "de4tempfan"; }; }; }; Index: head/sys/mips/conf/BERI_DE4_BASE =================================================================== --- head/sys/mips/conf/BERI_DE4_BASE (revision 332473) +++ head/sys/mips/conf/BERI_DE4_BASE (revision 332474) @@ -1,52 +1,59 @@ # # BERI_DE4_BASE -- Kernel for the SRI/Cambridge "BERI" (Bluespec Extensible RISC # Implementation) FPGA soft core, as configured in its Terasic DE-4 reference # configuration. This kernel configration must be further specialized to # to include a root filesystem specification. # # $FreeBSD$ # #NO_UNIVERSE include "std.BERI" options NFSCL # Network Filesystem Client options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options FDT options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=beripad-de4.dts hints "BERI_DE4.hints" # Flash partitions still use hints. device altera_atse device altera_avgen device altera_jtag_uart device altera_sdcard device terasic_de4led device terasic_mtl device bpf device cfi device cfid options CFI_SUPPORT_STRATAFLASH options ATSE_CFI_HACK device vt device kbdmux device uart device miibus options DEVICE_POLLING # +# DMA support +# +device xdma +device altera_softdma +device altera_msgdma + +# # USB support # #options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE device usb device saf1761otg