144b781cfSAndrew Turner /* 244b781cfSAndrew Turner * AMD 10Gb Ethernet driver 344b781cfSAndrew Turner * 444b781cfSAndrew Turner * This file is available to you under your choice of the following two 544b781cfSAndrew Turner * licenses: 644b781cfSAndrew Turner * 744b781cfSAndrew Turner * License 1: GPLv2 844b781cfSAndrew Turner * 944b781cfSAndrew Turner * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. 1044b781cfSAndrew Turner * 1144b781cfSAndrew Turner * This file is free software; you may copy, redistribute and/or modify 1244b781cfSAndrew Turner * it under the terms of the GNU General Public License as published by 1344b781cfSAndrew Turner * the Free Software Foundation, either version 2 of the License, or (at 1444b781cfSAndrew Turner * your option) any later version. 1544b781cfSAndrew Turner * 1644b781cfSAndrew Turner * This file is distributed in the hope that it will be useful, but 1744b781cfSAndrew Turner * WITHOUT ANY WARRANTY; without even the implied warranty of 1844b781cfSAndrew Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1944b781cfSAndrew Turner * General Public License for more details. 2044b781cfSAndrew Turner * 2144b781cfSAndrew Turner * You should have received a copy of the GNU General Public License 2244b781cfSAndrew Turner * along with this program. If not, see <http://www.gnu.org/licenses/>. 2344b781cfSAndrew Turner * 2444b781cfSAndrew Turner * This file incorporates work covered by the following copyright and 2544b781cfSAndrew Turner * permission notice: 2644b781cfSAndrew Turner * The Synopsys DWC ETHER XGMAC Software Driver and documentation 2744b781cfSAndrew Turner * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 2844b781cfSAndrew Turner * Inc. unless otherwise expressly agreed to in writing between Synopsys 2944b781cfSAndrew Turner * and you. 3044b781cfSAndrew Turner * 3144b781cfSAndrew Turner * The Software IS NOT an item of Licensed Software or Licensed Product 3244b781cfSAndrew Turner * under any End User Software License Agreement or Agreement for Licensed 3344b781cfSAndrew Turner * Product with Synopsys or any supplement thereto. Permission is hereby 3444b781cfSAndrew Turner * granted, free of charge, to any person obtaining a copy of this software 3544b781cfSAndrew Turner * annotated with this license and the Software, to deal in the Software 3644b781cfSAndrew Turner * without restriction, including without limitation the rights to use, 3744b781cfSAndrew Turner * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 3844b781cfSAndrew Turner * of the Software, and to permit persons to whom the Software is furnished 3944b781cfSAndrew Turner * to do so, subject to the following conditions: 4044b781cfSAndrew Turner * 4144b781cfSAndrew Turner * The above copyright notice and this permission notice shall be included 4244b781cfSAndrew Turner * in all copies or substantial portions of the Software. 4344b781cfSAndrew Turner * 4444b781cfSAndrew Turner * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 4544b781cfSAndrew Turner * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 4644b781cfSAndrew Turner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 4744b781cfSAndrew Turner * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 4844b781cfSAndrew Turner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4944b781cfSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5044b781cfSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5144b781cfSAndrew Turner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5244b781cfSAndrew Turner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5344b781cfSAndrew Turner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 5444b781cfSAndrew Turner * THE POSSIBILITY OF SUCH DAMAGE. 5544b781cfSAndrew Turner * 5644b781cfSAndrew Turner * 5744b781cfSAndrew Turner * License 2: Modified BSD 5844b781cfSAndrew Turner * 5944b781cfSAndrew Turner * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. 6044b781cfSAndrew Turner * All rights reserved. 6144b781cfSAndrew Turner * 6244b781cfSAndrew Turner * Redistribution and use in source and binary forms, with or without 6344b781cfSAndrew Turner * modification, are permitted provided that the following conditions are met: 6444b781cfSAndrew Turner * * Redistributions of source code must retain the above copyright 6544b781cfSAndrew Turner * notice, this list of conditions and the following disclaimer. 6644b781cfSAndrew Turner * * Redistributions in binary form must reproduce the above copyright 6744b781cfSAndrew Turner * notice, this list of conditions and the following disclaimer in the 6844b781cfSAndrew Turner * documentation and/or other materials provided with the distribution. 6944b781cfSAndrew Turner * * Neither the name of Advanced Micro Devices, Inc. nor the 7044b781cfSAndrew Turner * names of its contributors may be used to endorse or promote products 7144b781cfSAndrew Turner * derived from this software without specific prior written permission. 7244b781cfSAndrew Turner * 7344b781cfSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 7444b781cfSAndrew Turner * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7544b781cfSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 7644b781cfSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 7744b781cfSAndrew Turner * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 7844b781cfSAndrew Turner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 7944b781cfSAndrew Turner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 8044b781cfSAndrew Turner * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 8144b781cfSAndrew Turner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 8244b781cfSAndrew Turner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8344b781cfSAndrew Turner * 8444b781cfSAndrew Turner * This file incorporates work covered by the following copyright and 8544b781cfSAndrew Turner * permission notice: 8644b781cfSAndrew Turner * The Synopsys DWC ETHER XGMAC Software Driver and documentation 8744b781cfSAndrew Turner * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 8844b781cfSAndrew Turner * Inc. unless otherwise expressly agreed to in writing between Synopsys 8944b781cfSAndrew Turner * and you. 9044b781cfSAndrew Turner * 9144b781cfSAndrew Turner * The Software IS NOT an item of Licensed Software or Licensed Product 9244b781cfSAndrew Turner * under any End User Software License Agreement or Agreement for Licensed 9344b781cfSAndrew Turner * Product with Synopsys or any supplement thereto. Permission is hereby 9444b781cfSAndrew Turner * granted, free of charge, to any person obtaining a copy of this software 9544b781cfSAndrew Turner * annotated with this license and the Software, to deal in the Software 9644b781cfSAndrew Turner * without restriction, including without limitation the rights to use, 9744b781cfSAndrew Turner * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9844b781cfSAndrew Turner * of the Software, and to permit persons to whom the Software is furnished 9944b781cfSAndrew Turner * to do so, subject to the following conditions: 10044b781cfSAndrew Turner * 10144b781cfSAndrew Turner * The above copyright notice and this permission notice shall be included 10244b781cfSAndrew Turner * in all copies or substantial portions of the Software. 10344b781cfSAndrew Turner * 10444b781cfSAndrew Turner * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 10544b781cfSAndrew Turner * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 10644b781cfSAndrew Turner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 10744b781cfSAndrew Turner * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 10844b781cfSAndrew Turner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 10944b781cfSAndrew Turner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 11044b781cfSAndrew Turner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 11144b781cfSAndrew Turner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 11244b781cfSAndrew Turner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 11344b781cfSAndrew Turner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 11444b781cfSAndrew Turner * THE POSSIBILITY OF SUCH DAMAGE. 11544b781cfSAndrew Turner */ 11644b781cfSAndrew Turner 117*9c6d6488SAndrew Turner #include <sys/cdefs.h> 118*9c6d6488SAndrew Turner __FBSDID("$FreeBSD$"); 119*9c6d6488SAndrew Turner 120*9c6d6488SAndrew Turner #include <sys/param.h> 121*9c6d6488SAndrew Turner #include <sys/kernel.h> 12244b781cfSAndrew Turner 12344b781cfSAndrew Turner #include "xgbe.h" 12444b781cfSAndrew Turner #include "xgbe-common.h" 12544b781cfSAndrew Turner 126*9c6d6488SAndrew Turner static int xgbe_one_poll(struct xgbe_channel *channel, int budget); 127*9c6d6488SAndrew Turner static int xgbe_all_poll(struct xgbe_prv_data *pdata, int budget); 12844b781cfSAndrew Turner 12944b781cfSAndrew Turner static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) 13044b781cfSAndrew Turner { 13144b781cfSAndrew Turner struct xgbe_channel *channel_mem, *channel; 13244b781cfSAndrew Turner struct xgbe_ring *tx_ring, *rx_ring; 13344b781cfSAndrew Turner unsigned int count, i; 13444b781cfSAndrew Turner int ret = -ENOMEM; 13544b781cfSAndrew Turner 13644b781cfSAndrew Turner count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); 13744b781cfSAndrew Turner 138*9c6d6488SAndrew Turner channel_mem = malloc(count * sizeof(struct xgbe_channel), M_AXGBE, 139*9c6d6488SAndrew Turner M_WAITOK | M_ZERO); 140*9c6d6488SAndrew Turner tx_ring = malloc(pdata->tx_ring_count * sizeof(struct xgbe_ring), 141*9c6d6488SAndrew Turner M_AXGBE, M_WAITOK | M_ZERO); 142*9c6d6488SAndrew Turner rx_ring = malloc(pdata->rx_ring_count * sizeof(struct xgbe_ring), 143*9c6d6488SAndrew Turner M_AXGBE, M_WAITOK | M_ZERO); 14444b781cfSAndrew Turner 14544b781cfSAndrew Turner for (i = 0, channel = channel_mem; i < count; i++, channel++) { 14644b781cfSAndrew Turner snprintf(channel->name, sizeof(channel->name), "channel-%d", i); 14744b781cfSAndrew Turner channel->pdata = pdata; 14844b781cfSAndrew Turner channel->queue_index = i; 149*9c6d6488SAndrew Turner channel->dma_tag = rman_get_bustag(pdata->xgmac_res); 150*9c6d6488SAndrew Turner bus_space_subregion(channel->dma_tag, 151*9c6d6488SAndrew Turner rman_get_bushandle(pdata->xgmac_res), 152*9c6d6488SAndrew Turner DMA_CH_BASE + (DMA_CH_INC * i), DMA_CH_INC, 153*9c6d6488SAndrew Turner &channel->dma_handle); 15444b781cfSAndrew Turner 15544b781cfSAndrew Turner if (pdata->per_channel_irq) { 156*9c6d6488SAndrew Turner if (pdata->chan_irq_res[i] == NULL) 15744b781cfSAndrew Turner goto err_irq; 15844b781cfSAndrew Turner 159*9c6d6488SAndrew Turner channel->dma_irq_res = pdata->chan_irq_res[i]; 16044b781cfSAndrew Turner } 16144b781cfSAndrew Turner 16244b781cfSAndrew Turner if (i < pdata->tx_ring_count) { 16344b781cfSAndrew Turner spin_lock_init(&tx_ring->lock); 16444b781cfSAndrew Turner channel->tx_ring = tx_ring++; 16544b781cfSAndrew Turner } 16644b781cfSAndrew Turner 16744b781cfSAndrew Turner if (i < pdata->rx_ring_count) { 16844b781cfSAndrew Turner spin_lock_init(&rx_ring->lock); 16944b781cfSAndrew Turner channel->rx_ring = rx_ring++; 17044b781cfSAndrew Turner } 17144b781cfSAndrew Turner } 17244b781cfSAndrew Turner 17344b781cfSAndrew Turner pdata->channel = channel_mem; 17444b781cfSAndrew Turner pdata->channel_count = count; 17544b781cfSAndrew Turner 17644b781cfSAndrew Turner return 0; 17744b781cfSAndrew Turner 17844b781cfSAndrew Turner err_irq: 179*9c6d6488SAndrew Turner free(rx_ring, M_AXGBE); 180*9c6d6488SAndrew Turner free(tx_ring, M_AXGBE); 181*9c6d6488SAndrew Turner free(channel_mem, M_AXGBE); 18244b781cfSAndrew Turner 18344b781cfSAndrew Turner return ret; 18444b781cfSAndrew Turner } 18544b781cfSAndrew Turner 18644b781cfSAndrew Turner static void xgbe_free_channels(struct xgbe_prv_data *pdata) 18744b781cfSAndrew Turner { 18844b781cfSAndrew Turner if (!pdata->channel) 18944b781cfSAndrew Turner return; 19044b781cfSAndrew Turner 191*9c6d6488SAndrew Turner free(pdata->channel->rx_ring, M_AXGBE); 192*9c6d6488SAndrew Turner free(pdata->channel->tx_ring, M_AXGBE); 193*9c6d6488SAndrew Turner free(pdata->channel, M_AXGBE); 19444b781cfSAndrew Turner 19544b781cfSAndrew Turner pdata->channel = NULL; 19644b781cfSAndrew Turner pdata->channel_count = 0; 19744b781cfSAndrew Turner } 19844b781cfSAndrew Turner 19944b781cfSAndrew Turner static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring) 20044b781cfSAndrew Turner { 20144b781cfSAndrew Turner return (ring->rdesc_count - (ring->cur - ring->dirty)); 20244b781cfSAndrew Turner } 20344b781cfSAndrew Turner 20444b781cfSAndrew Turner static inline unsigned int xgbe_rx_dirty_desc(struct xgbe_ring *ring) 20544b781cfSAndrew Turner { 20644b781cfSAndrew Turner return (ring->cur - ring->dirty); 20744b781cfSAndrew Turner } 20844b781cfSAndrew Turner 20944b781cfSAndrew Turner static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel, 21044b781cfSAndrew Turner struct xgbe_ring *ring, unsigned int count) 21144b781cfSAndrew Turner { 21244b781cfSAndrew Turner struct xgbe_prv_data *pdata = channel->pdata; 21344b781cfSAndrew Turner 21444b781cfSAndrew Turner if (count > xgbe_tx_avail_desc(ring)) { 21544b781cfSAndrew Turner /* If we haven't notified the hardware because of xmit_more 21644b781cfSAndrew Turner * support, tell it now 21744b781cfSAndrew Turner */ 21844b781cfSAndrew Turner if (ring->tx.xmit_more) 21944b781cfSAndrew Turner pdata->hw_if.tx_start_xmit(channel, ring); 22044b781cfSAndrew Turner 221*9c6d6488SAndrew Turner return EFBIG; 22244b781cfSAndrew Turner } 22344b781cfSAndrew Turner 22444b781cfSAndrew Turner return 0; 22544b781cfSAndrew Turner } 22644b781cfSAndrew Turner 227*9c6d6488SAndrew Turner static int xgbe_calc_rx_buf_size(struct ifnet *netdev, unsigned int mtu) 22844b781cfSAndrew Turner { 22944b781cfSAndrew Turner unsigned int rx_buf_size; 23044b781cfSAndrew Turner 23144b781cfSAndrew Turner if (mtu > XGMAC_JUMBO_PACKET_MTU) { 23244b781cfSAndrew Turner return -EINVAL; 23344b781cfSAndrew Turner } 23444b781cfSAndrew Turner 23544b781cfSAndrew Turner rx_buf_size = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; 236*9c6d6488SAndrew Turner rx_buf_size = MIN(XGBE_RX_MIN_BUF_SIZE, PAGE_SIZE); 23744b781cfSAndrew Turner 23844b781cfSAndrew Turner rx_buf_size = (rx_buf_size + XGBE_RX_BUF_ALIGN - 1) & 23944b781cfSAndrew Turner ~(XGBE_RX_BUF_ALIGN - 1); 24044b781cfSAndrew Turner 24144b781cfSAndrew Turner return rx_buf_size; 24244b781cfSAndrew Turner } 24344b781cfSAndrew Turner 24444b781cfSAndrew Turner static void xgbe_enable_rx_tx_ints(struct xgbe_prv_data *pdata) 24544b781cfSAndrew Turner { 24644b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 24744b781cfSAndrew Turner struct xgbe_channel *channel; 24844b781cfSAndrew Turner enum xgbe_int int_id; 24944b781cfSAndrew Turner unsigned int i; 25044b781cfSAndrew Turner 25144b781cfSAndrew Turner channel = pdata->channel; 25244b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++, channel++) { 25344b781cfSAndrew Turner if (channel->tx_ring && channel->rx_ring) 25444b781cfSAndrew Turner int_id = XGMAC_INT_DMA_CH_SR_TI_RI; 25544b781cfSAndrew Turner else if (channel->tx_ring) 25644b781cfSAndrew Turner int_id = XGMAC_INT_DMA_CH_SR_TI; 25744b781cfSAndrew Turner else if (channel->rx_ring) 25844b781cfSAndrew Turner int_id = XGMAC_INT_DMA_CH_SR_RI; 25944b781cfSAndrew Turner else 26044b781cfSAndrew Turner continue; 26144b781cfSAndrew Turner 26244b781cfSAndrew Turner hw_if->enable_int(channel, int_id); 26344b781cfSAndrew Turner } 26444b781cfSAndrew Turner } 26544b781cfSAndrew Turner 266*9c6d6488SAndrew Turner static void xgbe_isr(void *data) 26744b781cfSAndrew Turner { 26844b781cfSAndrew Turner struct xgbe_prv_data *pdata = data; 26944b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 27044b781cfSAndrew Turner struct xgbe_channel *channel; 27144b781cfSAndrew Turner unsigned int dma_isr, dma_ch_isr; 272*9c6d6488SAndrew Turner unsigned int mac_isr; 27344b781cfSAndrew Turner unsigned int i; 27444b781cfSAndrew Turner 27544b781cfSAndrew Turner /* The DMA interrupt status register also reports MAC and MTL 27644b781cfSAndrew Turner * interrupts. So for polling mode, we just need to check for 27744b781cfSAndrew Turner * this register to be non-zero 27844b781cfSAndrew Turner */ 27944b781cfSAndrew Turner dma_isr = XGMAC_IOREAD(pdata, DMA_ISR); 28044b781cfSAndrew Turner if (!dma_isr) 281*9c6d6488SAndrew Turner return; 28244b781cfSAndrew Turner 28344b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++) { 28444b781cfSAndrew Turner if (!(dma_isr & (1 << i))) 28544b781cfSAndrew Turner continue; 28644b781cfSAndrew Turner 28744b781cfSAndrew Turner channel = pdata->channel + i; 28844b781cfSAndrew Turner 28944b781cfSAndrew Turner dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); 29044b781cfSAndrew Turner 29144b781cfSAndrew Turner /* The TI or RI interrupt bits may still be set even if using 29244b781cfSAndrew Turner * per channel DMA interrupts. Check to be sure those are not 29344b781cfSAndrew Turner * enabled before using the private data napi structure. 29444b781cfSAndrew Turner */ 29544b781cfSAndrew Turner if (!pdata->per_channel_irq && 29644b781cfSAndrew Turner (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || 29744b781cfSAndrew Turner XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI))) { 298*9c6d6488SAndrew Turner xgbe_all_poll(pdata, 16); 29944b781cfSAndrew Turner } 30044b781cfSAndrew Turner 30144b781cfSAndrew Turner if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RBU)) 30244b781cfSAndrew Turner pdata->ext_stats.rx_buffer_unavailable++; 30344b781cfSAndrew Turner 30444b781cfSAndrew Turner /* Restart the device on a Fatal Bus Error */ 30544b781cfSAndrew Turner if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, FBE)) 306*9c6d6488SAndrew Turner taskqueue_enqueue(taskqueue_thread, 307*9c6d6488SAndrew Turner &pdata->restart_work); 30844b781cfSAndrew Turner 30944b781cfSAndrew Turner /* Clear all interrupt signals */ 31044b781cfSAndrew Turner XGMAC_DMA_IOWRITE(channel, DMA_CH_SR, dma_ch_isr); 31144b781cfSAndrew Turner } 31244b781cfSAndrew Turner 31344b781cfSAndrew Turner if (XGMAC_GET_BITS(dma_isr, DMA_ISR, MACIS)) { 31444b781cfSAndrew Turner mac_isr = XGMAC_IOREAD(pdata, MAC_ISR); 31544b781cfSAndrew Turner 31644b781cfSAndrew Turner if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCTXIS)) 31744b781cfSAndrew Turner hw_if->tx_mmc_int(pdata); 31844b781cfSAndrew Turner 31944b781cfSAndrew Turner if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCRXIS)) 32044b781cfSAndrew Turner hw_if->rx_mmc_int(pdata); 32144b781cfSAndrew Turner } 32244b781cfSAndrew Turner } 32344b781cfSAndrew Turner 324*9c6d6488SAndrew Turner static void xgbe_dma_isr(void *data) 32544b781cfSAndrew Turner { 32644b781cfSAndrew Turner struct xgbe_channel *channel = data; 32744b781cfSAndrew Turner 328*9c6d6488SAndrew Turner xgbe_one_poll(channel, 16); 32944b781cfSAndrew Turner } 33044b781cfSAndrew Turner 331*9c6d6488SAndrew Turner static void xgbe_service(void *ctx, int pending) 33244b781cfSAndrew Turner { 333*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = ctx; 33444b781cfSAndrew Turner 33544b781cfSAndrew Turner pdata->phy_if.phy_status(pdata); 33644b781cfSAndrew Turner } 33744b781cfSAndrew Turner 338*9c6d6488SAndrew Turner static void xgbe_service_timer(void *data) 33944b781cfSAndrew Turner { 340*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = data; 34144b781cfSAndrew Turner 342*9c6d6488SAndrew Turner DBGPR("--> xgbe_service_timer\n"); 343*9c6d6488SAndrew Turner taskqueue_enqueue(pdata->dev_workqueue, &pdata->service_work); 34444b781cfSAndrew Turner 345*9c6d6488SAndrew Turner callout_reset(&pdata->service_timer, hz, xgbe_service_timer, pdata); 346*9c6d6488SAndrew Turner DBGPR("<-- xgbe_service_timer\n"); 34744b781cfSAndrew Turner } 34844b781cfSAndrew Turner 34944b781cfSAndrew Turner static void xgbe_init_timers(struct xgbe_prv_data *pdata) 35044b781cfSAndrew Turner { 35144b781cfSAndrew Turner 352*9c6d6488SAndrew Turner callout_init(&pdata->service_timer, 1); 35344b781cfSAndrew Turner } 35444b781cfSAndrew Turner 35544b781cfSAndrew Turner static void xgbe_start_timers(struct xgbe_prv_data *pdata) 35644b781cfSAndrew Turner { 357*9c6d6488SAndrew Turner callout_reset(&pdata->service_timer, hz, xgbe_service_timer, pdata); 35844b781cfSAndrew Turner } 35944b781cfSAndrew Turner 36044b781cfSAndrew Turner static void xgbe_stop_timers(struct xgbe_prv_data *pdata) 36144b781cfSAndrew Turner { 36244b781cfSAndrew Turner 363*9c6d6488SAndrew Turner callout_drain(&pdata->service_timer); 36444b781cfSAndrew Turner } 36544b781cfSAndrew Turner 36644b781cfSAndrew Turner void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) 36744b781cfSAndrew Turner { 36844b781cfSAndrew Turner unsigned int mac_hfr0, mac_hfr1, mac_hfr2; 36944b781cfSAndrew Turner struct xgbe_hw_features *hw_feat = &pdata->hw_feat; 37044b781cfSAndrew Turner 37144b781cfSAndrew Turner DBGPR("-->xgbe_get_all_hw_features\n"); 37244b781cfSAndrew Turner 37344b781cfSAndrew Turner mac_hfr0 = XGMAC_IOREAD(pdata, MAC_HWF0R); 37444b781cfSAndrew Turner mac_hfr1 = XGMAC_IOREAD(pdata, MAC_HWF1R); 37544b781cfSAndrew Turner mac_hfr2 = XGMAC_IOREAD(pdata, MAC_HWF2R); 37644b781cfSAndrew Turner 37744b781cfSAndrew Turner memset(hw_feat, 0, sizeof(*hw_feat)); 37844b781cfSAndrew Turner 37944b781cfSAndrew Turner hw_feat->version = XGMAC_IOREAD(pdata, MAC_VR); 38044b781cfSAndrew Turner 38144b781cfSAndrew Turner /* Hardware feature register 0 */ 38244b781cfSAndrew Turner hw_feat->gmii = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, GMIISEL); 38344b781cfSAndrew Turner hw_feat->vlhash = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, VLHASH); 38444b781cfSAndrew Turner hw_feat->sma = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SMASEL); 38544b781cfSAndrew Turner hw_feat->rwk = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, RWKSEL); 38644b781cfSAndrew Turner hw_feat->mgk = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, MGKSEL); 38744b781cfSAndrew Turner hw_feat->mmc = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, MMCSEL); 38844b781cfSAndrew Turner hw_feat->aoe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, ARPOFFSEL); 38944b781cfSAndrew Turner hw_feat->ts = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSEL); 39044b781cfSAndrew Turner hw_feat->eee = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, EEESEL); 39144b781cfSAndrew Turner hw_feat->tx_coe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TXCOESEL); 39244b781cfSAndrew Turner hw_feat->rx_coe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, RXCOESEL); 39344b781cfSAndrew Turner hw_feat->addn_mac = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, 39444b781cfSAndrew Turner ADDMACADRSEL); 39544b781cfSAndrew Turner hw_feat->ts_src = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSTSSEL); 39644b781cfSAndrew Turner hw_feat->sa_vlan_ins = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SAVLANINS); 39744b781cfSAndrew Turner 39844b781cfSAndrew Turner /* Hardware feature register 1 */ 39944b781cfSAndrew Turner hw_feat->rx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, 40044b781cfSAndrew Turner RXFIFOSIZE); 40144b781cfSAndrew Turner hw_feat->tx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, 40244b781cfSAndrew Turner TXFIFOSIZE); 40344b781cfSAndrew Turner hw_feat->adv_ts_hi = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADVTHWORD); 40444b781cfSAndrew Turner hw_feat->dma_width = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADDR64); 40544b781cfSAndrew Turner hw_feat->dcb = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DCBEN); 40644b781cfSAndrew Turner hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN); 40744b781cfSAndrew Turner hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN); 40844b781cfSAndrew Turner hw_feat->dma_debug = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DBGMEMA); 40944b781cfSAndrew Turner hw_feat->rss = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, RSSEN); 41044b781cfSAndrew Turner hw_feat->tc_cnt = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, NUMTC); 41144b781cfSAndrew Turner hw_feat->hash_table_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, 41244b781cfSAndrew Turner HASHTBLSZ); 41344b781cfSAndrew Turner hw_feat->l3l4_filter_num = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, 41444b781cfSAndrew Turner L3L4FNUM); 41544b781cfSAndrew Turner 41644b781cfSAndrew Turner /* Hardware feature register 2 */ 41744b781cfSAndrew Turner hw_feat->rx_q_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, RXQCNT); 41844b781cfSAndrew Turner hw_feat->tx_q_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, TXQCNT); 41944b781cfSAndrew Turner hw_feat->rx_ch_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, RXCHCNT); 42044b781cfSAndrew Turner hw_feat->tx_ch_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, TXCHCNT); 42144b781cfSAndrew Turner hw_feat->pps_out_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, PPSOUTNUM); 42244b781cfSAndrew Turner hw_feat->aux_snap_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, AUXSNAPNUM); 42344b781cfSAndrew Turner 42444b781cfSAndrew Turner /* Translate the Hash Table size into actual number */ 42544b781cfSAndrew Turner switch (hw_feat->hash_table_size) { 42644b781cfSAndrew Turner case 0: 42744b781cfSAndrew Turner break; 42844b781cfSAndrew Turner case 1: 42944b781cfSAndrew Turner hw_feat->hash_table_size = 64; 43044b781cfSAndrew Turner break; 43144b781cfSAndrew Turner case 2: 43244b781cfSAndrew Turner hw_feat->hash_table_size = 128; 43344b781cfSAndrew Turner break; 43444b781cfSAndrew Turner case 3: 43544b781cfSAndrew Turner hw_feat->hash_table_size = 256; 43644b781cfSAndrew Turner break; 43744b781cfSAndrew Turner } 43844b781cfSAndrew Turner 43944b781cfSAndrew Turner /* Translate the address width setting into actual number */ 44044b781cfSAndrew Turner switch (hw_feat->dma_width) { 44144b781cfSAndrew Turner case 0: 44244b781cfSAndrew Turner hw_feat->dma_width = 32; 44344b781cfSAndrew Turner break; 44444b781cfSAndrew Turner case 1: 44544b781cfSAndrew Turner hw_feat->dma_width = 40; 44644b781cfSAndrew Turner break; 44744b781cfSAndrew Turner case 2: 44844b781cfSAndrew Turner hw_feat->dma_width = 48; 44944b781cfSAndrew Turner break; 45044b781cfSAndrew Turner default: 45144b781cfSAndrew Turner hw_feat->dma_width = 32; 45244b781cfSAndrew Turner } 45344b781cfSAndrew Turner 45444b781cfSAndrew Turner /* The Queue, Channel and TC counts are zero based so increment them 45544b781cfSAndrew Turner * to get the actual number 45644b781cfSAndrew Turner */ 45744b781cfSAndrew Turner hw_feat->rx_q_cnt++; 45844b781cfSAndrew Turner hw_feat->tx_q_cnt++; 45944b781cfSAndrew Turner hw_feat->rx_ch_cnt++; 46044b781cfSAndrew Turner hw_feat->tx_ch_cnt++; 46144b781cfSAndrew Turner hw_feat->tc_cnt++; 46244b781cfSAndrew Turner 46344b781cfSAndrew Turner DBGPR("<--xgbe_get_all_hw_features\n"); 46444b781cfSAndrew Turner } 46544b781cfSAndrew Turner 46644b781cfSAndrew Turner static int xgbe_request_irqs(struct xgbe_prv_data *pdata) 46744b781cfSAndrew Turner { 46844b781cfSAndrew Turner struct xgbe_channel *channel; 46944b781cfSAndrew Turner unsigned int i; 47044b781cfSAndrew Turner int ret; 47144b781cfSAndrew Turner 472*9c6d6488SAndrew Turner ret = bus_setup_intr(pdata->dev, pdata->dev_irq_res, 473*9c6d6488SAndrew Turner INTR_MPSAFE | INTR_TYPE_NET, NULL, xgbe_isr, pdata, 474*9c6d6488SAndrew Turner &pdata->dev_irq_tag); 47544b781cfSAndrew Turner if (ret) { 47644b781cfSAndrew Turner return ret; 47744b781cfSAndrew Turner } 47844b781cfSAndrew Turner 47944b781cfSAndrew Turner if (!pdata->per_channel_irq) 48044b781cfSAndrew Turner return 0; 48144b781cfSAndrew Turner 48244b781cfSAndrew Turner channel = pdata->channel; 48344b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++, channel++) { 484*9c6d6488SAndrew Turner ret = bus_setup_intr(pdata->dev, channel->dma_irq_res, 485*9c6d6488SAndrew Turner INTR_MPSAFE | INTR_TYPE_NET, NULL, xgbe_dma_isr, channel, 486*9c6d6488SAndrew Turner &channel->dma_irq_tag); 487*9c6d6488SAndrew Turner if (ret != 0) { 48844b781cfSAndrew Turner goto err_irq; 48944b781cfSAndrew Turner } 49044b781cfSAndrew Turner } 49144b781cfSAndrew Turner 49244b781cfSAndrew Turner return 0; 49344b781cfSAndrew Turner 49444b781cfSAndrew Turner err_irq: 49544b781cfSAndrew Turner /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ 49644b781cfSAndrew Turner for (i--, channel--; i < pdata->channel_count; i--, channel--) 497*9c6d6488SAndrew Turner bus_teardown_intr(pdata->dev, channel->dma_irq_res, 498*9c6d6488SAndrew Turner channel->dma_irq_tag); 49944b781cfSAndrew Turner 500*9c6d6488SAndrew Turner bus_teardown_intr(pdata->dev, pdata->dev_irq_res, pdata->dev_irq_tag); 50144b781cfSAndrew Turner 502*9c6d6488SAndrew Turner return -ret; 50344b781cfSAndrew Turner } 50444b781cfSAndrew Turner 50544b781cfSAndrew Turner static void xgbe_free_irqs(struct xgbe_prv_data *pdata) 50644b781cfSAndrew Turner { 50744b781cfSAndrew Turner struct xgbe_channel *channel; 50844b781cfSAndrew Turner unsigned int i; 50944b781cfSAndrew Turner 510*9c6d6488SAndrew Turner bus_teardown_intr(pdata->dev, pdata->dev_irq_res, pdata->dev_irq_tag); 51144b781cfSAndrew Turner 51244b781cfSAndrew Turner if (!pdata->per_channel_irq) 51344b781cfSAndrew Turner return; 51444b781cfSAndrew Turner 51544b781cfSAndrew Turner channel = pdata->channel; 51644b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++, channel++) 517*9c6d6488SAndrew Turner bus_teardown_intr(pdata->dev, channel->dma_irq_res, 518*9c6d6488SAndrew Turner channel->dma_irq_tag); 51944b781cfSAndrew Turner } 52044b781cfSAndrew Turner 52144b781cfSAndrew Turner void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) 52244b781cfSAndrew Turner { 52344b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 52444b781cfSAndrew Turner 52544b781cfSAndrew Turner DBGPR("-->xgbe_init_tx_coalesce\n"); 52644b781cfSAndrew Turner 52744b781cfSAndrew Turner pdata->tx_usecs = XGMAC_INIT_DMA_TX_USECS; 52844b781cfSAndrew Turner pdata->tx_frames = XGMAC_INIT_DMA_TX_FRAMES; 52944b781cfSAndrew Turner 53044b781cfSAndrew Turner hw_if->config_tx_coalesce(pdata); 53144b781cfSAndrew Turner 53244b781cfSAndrew Turner DBGPR("<--xgbe_init_tx_coalesce\n"); 53344b781cfSAndrew Turner } 53444b781cfSAndrew Turner 53544b781cfSAndrew Turner void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) 53644b781cfSAndrew Turner { 53744b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 53844b781cfSAndrew Turner 53944b781cfSAndrew Turner DBGPR("-->xgbe_init_rx_coalesce\n"); 54044b781cfSAndrew Turner 54144b781cfSAndrew Turner pdata->rx_riwt = hw_if->usec_to_riwt(pdata, XGMAC_INIT_DMA_RX_USECS); 54244b781cfSAndrew Turner pdata->rx_usecs = XGMAC_INIT_DMA_RX_USECS; 54344b781cfSAndrew Turner pdata->rx_frames = XGMAC_INIT_DMA_RX_FRAMES; 54444b781cfSAndrew Turner 54544b781cfSAndrew Turner hw_if->config_rx_coalesce(pdata); 54644b781cfSAndrew Turner 54744b781cfSAndrew Turner DBGPR("<--xgbe_init_rx_coalesce\n"); 54844b781cfSAndrew Turner } 54944b781cfSAndrew Turner 55044b781cfSAndrew Turner static void xgbe_free_tx_data(struct xgbe_prv_data *pdata) 55144b781cfSAndrew Turner { 55244b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 55344b781cfSAndrew Turner struct xgbe_channel *channel; 55444b781cfSAndrew Turner struct xgbe_ring *ring; 55544b781cfSAndrew Turner struct xgbe_ring_data *rdata; 55644b781cfSAndrew Turner unsigned int i, j; 55744b781cfSAndrew Turner 55844b781cfSAndrew Turner DBGPR("-->xgbe_free_tx_data\n"); 55944b781cfSAndrew Turner 56044b781cfSAndrew Turner channel = pdata->channel; 56144b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++, channel++) { 56244b781cfSAndrew Turner ring = channel->tx_ring; 56344b781cfSAndrew Turner if (!ring) 56444b781cfSAndrew Turner break; 56544b781cfSAndrew Turner 56644b781cfSAndrew Turner for (j = 0; j < ring->rdesc_count; j++) { 56744b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, j); 56844b781cfSAndrew Turner desc_if->unmap_rdata(pdata, rdata); 56944b781cfSAndrew Turner } 57044b781cfSAndrew Turner } 57144b781cfSAndrew Turner 57244b781cfSAndrew Turner DBGPR("<--xgbe_free_tx_data\n"); 57344b781cfSAndrew Turner } 57444b781cfSAndrew Turner 57544b781cfSAndrew Turner static void xgbe_free_rx_data(struct xgbe_prv_data *pdata) 57644b781cfSAndrew Turner { 57744b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 57844b781cfSAndrew Turner struct xgbe_channel *channel; 57944b781cfSAndrew Turner struct xgbe_ring *ring; 58044b781cfSAndrew Turner struct xgbe_ring_data *rdata; 58144b781cfSAndrew Turner unsigned int i, j; 58244b781cfSAndrew Turner 58344b781cfSAndrew Turner DBGPR("-->xgbe_free_rx_data\n"); 58444b781cfSAndrew Turner 58544b781cfSAndrew Turner channel = pdata->channel; 58644b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++, channel++) { 58744b781cfSAndrew Turner ring = channel->rx_ring; 58844b781cfSAndrew Turner if (!ring) 58944b781cfSAndrew Turner break; 59044b781cfSAndrew Turner 59144b781cfSAndrew Turner for (j = 0; j < ring->rdesc_count; j++) { 59244b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, j); 59344b781cfSAndrew Turner desc_if->unmap_rdata(pdata, rdata); 59444b781cfSAndrew Turner } 59544b781cfSAndrew Turner } 59644b781cfSAndrew Turner 59744b781cfSAndrew Turner DBGPR("<--xgbe_free_rx_data\n"); 59844b781cfSAndrew Turner } 59944b781cfSAndrew Turner 60044b781cfSAndrew Turner static int xgbe_phy_init(struct xgbe_prv_data *pdata) 60144b781cfSAndrew Turner { 60244b781cfSAndrew Turner pdata->phy_link = -1; 60344b781cfSAndrew Turner pdata->phy_speed = SPEED_UNKNOWN; 60444b781cfSAndrew Turner 60544b781cfSAndrew Turner return pdata->phy_if.phy_reset(pdata); 60644b781cfSAndrew Turner } 60744b781cfSAndrew Turner 60844b781cfSAndrew Turner static int xgbe_start(struct xgbe_prv_data *pdata) 60944b781cfSAndrew Turner { 61044b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 61144b781cfSAndrew Turner struct xgbe_phy_if *phy_if = &pdata->phy_if; 61244b781cfSAndrew Turner int ret; 61344b781cfSAndrew Turner 61444b781cfSAndrew Turner DBGPR("-->xgbe_start\n"); 61544b781cfSAndrew Turner 61644b781cfSAndrew Turner hw_if->init(pdata); 61744b781cfSAndrew Turner 61844b781cfSAndrew Turner ret = phy_if->phy_start(pdata); 61944b781cfSAndrew Turner if (ret) 62044b781cfSAndrew Turner goto err_phy; 62144b781cfSAndrew Turner 62244b781cfSAndrew Turner ret = xgbe_request_irqs(pdata); 62344b781cfSAndrew Turner if (ret) 62444b781cfSAndrew Turner goto err_napi; 62544b781cfSAndrew Turner 62644b781cfSAndrew Turner hw_if->enable_tx(pdata); 62744b781cfSAndrew Turner hw_if->enable_rx(pdata); 62844b781cfSAndrew Turner 629*9c6d6488SAndrew Turner xgbe_enable_rx_tx_ints(pdata); 63044b781cfSAndrew Turner 63144b781cfSAndrew Turner xgbe_start_timers(pdata); 632*9c6d6488SAndrew Turner taskqueue_enqueue(pdata->dev_workqueue, &pdata->service_work); 63344b781cfSAndrew Turner 63444b781cfSAndrew Turner DBGPR("<--xgbe_start\n"); 63544b781cfSAndrew Turner 63644b781cfSAndrew Turner return 0; 63744b781cfSAndrew Turner 63844b781cfSAndrew Turner err_napi: 63944b781cfSAndrew Turner phy_if->phy_stop(pdata); 64044b781cfSAndrew Turner 64144b781cfSAndrew Turner err_phy: 64244b781cfSAndrew Turner hw_if->exit(pdata); 64344b781cfSAndrew Turner 64444b781cfSAndrew Turner return ret; 64544b781cfSAndrew Turner } 64644b781cfSAndrew Turner 64744b781cfSAndrew Turner static void xgbe_stop(struct xgbe_prv_data *pdata) 64844b781cfSAndrew Turner { 64944b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 65044b781cfSAndrew Turner struct xgbe_phy_if *phy_if = &pdata->phy_if; 65144b781cfSAndrew Turner 65244b781cfSAndrew Turner DBGPR("-->xgbe_stop\n"); 65344b781cfSAndrew Turner 65444b781cfSAndrew Turner xgbe_stop_timers(pdata); 655*9c6d6488SAndrew Turner taskqueue_drain_all(pdata->dev_workqueue); 65644b781cfSAndrew Turner 65744b781cfSAndrew Turner hw_if->disable_tx(pdata); 65844b781cfSAndrew Turner hw_if->disable_rx(pdata); 65944b781cfSAndrew Turner 66044b781cfSAndrew Turner xgbe_free_irqs(pdata); 66144b781cfSAndrew Turner 66244b781cfSAndrew Turner phy_if->phy_stop(pdata); 66344b781cfSAndrew Turner 66444b781cfSAndrew Turner hw_if->exit(pdata); 66544b781cfSAndrew Turner 66644b781cfSAndrew Turner DBGPR("<--xgbe_stop\n"); 66744b781cfSAndrew Turner } 66844b781cfSAndrew Turner 66944b781cfSAndrew Turner static void xgbe_restart_dev(struct xgbe_prv_data *pdata) 67044b781cfSAndrew Turner { 67144b781cfSAndrew Turner DBGPR("-->xgbe_restart_dev\n"); 67244b781cfSAndrew Turner 67344b781cfSAndrew Turner /* If not running, "restart" will happen on open */ 674*9c6d6488SAndrew Turner if ((pdata->netdev->if_drv_flags & IFF_DRV_RUNNING) == 0) 67544b781cfSAndrew Turner return; 67644b781cfSAndrew Turner 67744b781cfSAndrew Turner xgbe_stop(pdata); 67844b781cfSAndrew Turner 67944b781cfSAndrew Turner xgbe_free_tx_data(pdata); 68044b781cfSAndrew Turner xgbe_free_rx_data(pdata); 68144b781cfSAndrew Turner 68244b781cfSAndrew Turner xgbe_start(pdata); 68344b781cfSAndrew Turner 68444b781cfSAndrew Turner DBGPR("<--xgbe_restart_dev\n"); 68544b781cfSAndrew Turner } 68644b781cfSAndrew Turner 687*9c6d6488SAndrew Turner static void xgbe_restart(void *ctx, int pending) 68844b781cfSAndrew Turner { 689*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = ctx; 69044b781cfSAndrew Turner 69144b781cfSAndrew Turner xgbe_restart_dev(pdata); 69244b781cfSAndrew Turner } 69344b781cfSAndrew Turner 69444b781cfSAndrew Turner static void xgbe_packet_info(struct xgbe_prv_data *pdata, 695*9c6d6488SAndrew Turner struct xgbe_ring *ring, struct mbuf *m0, 69644b781cfSAndrew Turner struct xgbe_packet_data *packet) 69744b781cfSAndrew Turner { 698*9c6d6488SAndrew Turner struct mbuf *m; 69944b781cfSAndrew Turner unsigned int len; 70044b781cfSAndrew Turner 701*9c6d6488SAndrew Turner packet->m = m0; 70244b781cfSAndrew Turner 70344b781cfSAndrew Turner packet->rdesc_count = 0; 70444b781cfSAndrew Turner 70544b781cfSAndrew Turner packet->tx_packets = 1; 706*9c6d6488SAndrew Turner packet->tx_bytes = m_length(m0, NULL); 70744b781cfSAndrew Turner 708*9c6d6488SAndrew Turner for (m = m0; m != NULL; m = m->m_next) { 709*9c6d6488SAndrew Turner for (len = m->m_len; len != 0;) { 71044b781cfSAndrew Turner packet->rdesc_count++; 711*9c6d6488SAndrew Turner len -= MIN(len, XGBE_TX_MAX_BUF_SIZE); 71244b781cfSAndrew Turner } 71344b781cfSAndrew Turner } 71444b781cfSAndrew Turner } 71544b781cfSAndrew Turner 716*9c6d6488SAndrew Turner int xgbe_open(struct ifnet *netdev) 71744b781cfSAndrew Turner { 718*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = netdev->if_softc; 71944b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 72044b781cfSAndrew Turner int ret; 72144b781cfSAndrew Turner 72244b781cfSAndrew Turner DBGPR("-->xgbe_open\n"); 72344b781cfSAndrew Turner 72444b781cfSAndrew Turner /* Initialize the phy */ 72544b781cfSAndrew Turner ret = xgbe_phy_init(pdata); 72644b781cfSAndrew Turner if (ret) 72744b781cfSAndrew Turner return ret; 72844b781cfSAndrew Turner 72944b781cfSAndrew Turner /* Calculate the Rx buffer size before allocating rings */ 730*9c6d6488SAndrew Turner ret = xgbe_calc_rx_buf_size(netdev, if_getmtu(netdev)); 731*9c6d6488SAndrew Turner if (ret < 0) { 73244b781cfSAndrew Turner goto err_ptpclk; 733*9c6d6488SAndrew Turner } 73444b781cfSAndrew Turner pdata->rx_buf_size = ret; 73544b781cfSAndrew Turner 73644b781cfSAndrew Turner /* Allocate the channel and ring structures */ 73744b781cfSAndrew Turner ret = xgbe_alloc_channels(pdata); 738*9c6d6488SAndrew Turner if (ret) { 739*9c6d6488SAndrew Turner printf("xgbe_alloc_channels failed\n"); 74044b781cfSAndrew Turner goto err_ptpclk; 741*9c6d6488SAndrew Turner } 74244b781cfSAndrew Turner 74344b781cfSAndrew Turner /* Allocate the ring descriptors and buffers */ 74444b781cfSAndrew Turner ret = desc_if->alloc_ring_resources(pdata); 745*9c6d6488SAndrew Turner if (ret) { 746*9c6d6488SAndrew Turner printf("desc_if->alloc_ring_resources failed\n"); 74744b781cfSAndrew Turner goto err_channels; 748*9c6d6488SAndrew Turner } 74944b781cfSAndrew Turner 750*9c6d6488SAndrew Turner TASK_INIT(&pdata->service_work, 0, xgbe_service, pdata); 751*9c6d6488SAndrew Turner TASK_INIT(&pdata->restart_work, 0, xgbe_restart, pdata); 75244b781cfSAndrew Turner xgbe_init_timers(pdata); 75344b781cfSAndrew Turner 75444b781cfSAndrew Turner ret = xgbe_start(pdata); 75544b781cfSAndrew Turner if (ret) 75644b781cfSAndrew Turner goto err_rings; 75744b781cfSAndrew Turner 75844b781cfSAndrew Turner clear_bit(XGBE_DOWN, &pdata->dev_state); 75944b781cfSAndrew Turner 76044b781cfSAndrew Turner DBGPR("<--xgbe_open\n"); 76144b781cfSAndrew Turner 76244b781cfSAndrew Turner return 0; 76344b781cfSAndrew Turner 76444b781cfSAndrew Turner err_rings: 76544b781cfSAndrew Turner desc_if->free_ring_resources(pdata); 76644b781cfSAndrew Turner 76744b781cfSAndrew Turner err_channels: 76844b781cfSAndrew Turner xgbe_free_channels(pdata); 76944b781cfSAndrew Turner 77044b781cfSAndrew Turner err_ptpclk: 77144b781cfSAndrew Turner 77244b781cfSAndrew Turner return ret; 77344b781cfSAndrew Turner } 77444b781cfSAndrew Turner 775*9c6d6488SAndrew Turner int xgbe_close(struct ifnet *netdev) 77644b781cfSAndrew Turner { 777*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = netdev->if_softc; 77844b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 77944b781cfSAndrew Turner 78044b781cfSAndrew Turner DBGPR("-->xgbe_close\n"); 78144b781cfSAndrew Turner 78244b781cfSAndrew Turner /* Stop the device */ 78344b781cfSAndrew Turner xgbe_stop(pdata); 78444b781cfSAndrew Turner 78544b781cfSAndrew Turner /* Free the ring descriptors and buffers */ 78644b781cfSAndrew Turner desc_if->free_ring_resources(pdata); 78744b781cfSAndrew Turner 78844b781cfSAndrew Turner /* Free the channel and ring structures */ 78944b781cfSAndrew Turner xgbe_free_channels(pdata); 79044b781cfSAndrew Turner 79144b781cfSAndrew Turner set_bit(XGBE_DOWN, &pdata->dev_state); 79244b781cfSAndrew Turner 79344b781cfSAndrew Turner DBGPR("<--xgbe_close\n"); 79444b781cfSAndrew Turner 79544b781cfSAndrew Turner return 0; 79644b781cfSAndrew Turner } 79744b781cfSAndrew Turner 798*9c6d6488SAndrew Turner int xgbe_xmit(struct ifnet *ifp, struct mbuf *m) 79944b781cfSAndrew Turner { 800*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = ifp->if_softc; 80144b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 80244b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 80344b781cfSAndrew Turner struct xgbe_channel *channel; 80444b781cfSAndrew Turner struct xgbe_ring *ring; 80544b781cfSAndrew Turner struct xgbe_packet_data *packet; 80644b781cfSAndrew Turner int ret; 80744b781cfSAndrew Turner 808*9c6d6488SAndrew Turner M_ASSERTPKTHDR(m); 809*9c6d6488SAndrew Turner MPASS(m->m_nextpkt == NULL); 81044b781cfSAndrew Turner 811*9c6d6488SAndrew Turner if (__predict_false(test_bit(XGBE_DOWN, &pdata->dev_state) || 812*9c6d6488SAndrew Turner !pdata->phy.link)) { 813*9c6d6488SAndrew Turner m_freem(m); 814*9c6d6488SAndrew Turner return (ENETDOWN); 815*9c6d6488SAndrew Turner } 816*9c6d6488SAndrew Turner 817*9c6d6488SAndrew Turner channel = pdata->channel; 81844b781cfSAndrew Turner ring = channel->tx_ring; 81944b781cfSAndrew Turner packet = &ring->packet_data; 82044b781cfSAndrew Turner 82144b781cfSAndrew Turner /* Calculate preliminary packet info */ 82244b781cfSAndrew Turner memset(packet, 0, sizeof(*packet)); 823*9c6d6488SAndrew Turner xgbe_packet_info(pdata, ring, m, packet); 82444b781cfSAndrew Turner 82544b781cfSAndrew Turner /* Check that there are enough descriptors available */ 82644b781cfSAndrew Turner ret = xgbe_maybe_stop_tx_queue(channel, ring, packet->rdesc_count); 82744b781cfSAndrew Turner if (ret) 82844b781cfSAndrew Turner goto tx_netdev_return; 82944b781cfSAndrew Turner 830*9c6d6488SAndrew Turner if (!desc_if->map_tx_skb(channel, m)) { 83144b781cfSAndrew Turner goto tx_netdev_return; 83244b781cfSAndrew Turner } 83344b781cfSAndrew Turner 83444b781cfSAndrew Turner /* Configure required descriptor fields for transmission */ 83544b781cfSAndrew Turner hw_if->dev_xmit(channel); 83644b781cfSAndrew Turner 837*9c6d6488SAndrew Turner return 0; 83844b781cfSAndrew Turner 83944b781cfSAndrew Turner tx_netdev_return: 840*9c6d6488SAndrew Turner m_free(m); 84144b781cfSAndrew Turner 84244b781cfSAndrew Turner return 0; 84344b781cfSAndrew Turner } 84444b781cfSAndrew Turner 845*9c6d6488SAndrew Turner int xgbe_change_mtu(struct ifnet *netdev, int mtu) 84644b781cfSAndrew Turner { 847*9c6d6488SAndrew Turner struct xgbe_prv_data *pdata = netdev->if_softc; 84844b781cfSAndrew Turner int ret; 84944b781cfSAndrew Turner 85044b781cfSAndrew Turner DBGPR("-->xgbe_change_mtu\n"); 85144b781cfSAndrew Turner 85244b781cfSAndrew Turner ret = xgbe_calc_rx_buf_size(netdev, mtu); 85344b781cfSAndrew Turner if (ret < 0) 854*9c6d6488SAndrew Turner return -ret; 85544b781cfSAndrew Turner 85644b781cfSAndrew Turner pdata->rx_buf_size = ret; 857*9c6d6488SAndrew Turner netdev->if_mtu = mtu; 85844b781cfSAndrew Turner 85944b781cfSAndrew Turner xgbe_restart_dev(pdata); 86044b781cfSAndrew Turner 86144b781cfSAndrew Turner DBGPR("<--xgbe_change_mtu\n"); 86244b781cfSAndrew Turner 86344b781cfSAndrew Turner return 0; 86444b781cfSAndrew Turner } 86544b781cfSAndrew Turner 86644b781cfSAndrew Turner static void xgbe_rx_refresh(struct xgbe_channel *channel) 86744b781cfSAndrew Turner { 86844b781cfSAndrew Turner struct xgbe_prv_data *pdata = channel->pdata; 86944b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 87044b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 87144b781cfSAndrew Turner struct xgbe_ring *ring = channel->rx_ring; 87244b781cfSAndrew Turner struct xgbe_ring_data *rdata; 87344b781cfSAndrew Turner 87444b781cfSAndrew Turner while (ring->dirty != ring->cur) { 87544b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); 87644b781cfSAndrew Turner 87744b781cfSAndrew Turner /* Reset rdata values */ 87844b781cfSAndrew Turner desc_if->unmap_rdata(pdata, rdata); 87944b781cfSAndrew Turner 88044b781cfSAndrew Turner if (desc_if->map_rx_buffer(pdata, ring, rdata)) 88144b781cfSAndrew Turner break; 88244b781cfSAndrew Turner 88344b781cfSAndrew Turner hw_if->rx_desc_reset(pdata, rdata, ring->dirty); 88444b781cfSAndrew Turner 88544b781cfSAndrew Turner ring->dirty++; 88644b781cfSAndrew Turner } 88744b781cfSAndrew Turner 88844b781cfSAndrew Turner /* Make sure everything is written before the register write */ 889*9c6d6488SAndrew Turner dsb(sy); 89044b781cfSAndrew Turner 89144b781cfSAndrew Turner /* Update the Rx Tail Pointer Register with address of 89244b781cfSAndrew Turner * the last cleaned entry */ 89344b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, ring->dirty - 1); 89444b781cfSAndrew Turner XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, 895*9c6d6488SAndrew Turner lower_32_bits(rdata->rdata_paddr)); 89644b781cfSAndrew Turner } 89744b781cfSAndrew Turner 89844b781cfSAndrew Turner static int xgbe_tx_poll(struct xgbe_channel *channel) 89944b781cfSAndrew Turner { 90044b781cfSAndrew Turner struct xgbe_prv_data *pdata = channel->pdata; 90144b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 90244b781cfSAndrew Turner struct xgbe_desc_if *desc_if = &pdata->desc_if; 90344b781cfSAndrew Turner struct xgbe_ring *ring = channel->tx_ring; 90444b781cfSAndrew Turner struct xgbe_ring_data *rdata; 90544b781cfSAndrew Turner struct xgbe_ring_desc *rdesc; 90644b781cfSAndrew Turner int processed = 0; 90744b781cfSAndrew Turner unsigned int cur; 90844b781cfSAndrew Turner 90944b781cfSAndrew Turner DBGPR("-->xgbe_tx_poll\n"); 91044b781cfSAndrew Turner 91144b781cfSAndrew Turner /* Nothing to do if there isn't a Tx ring for this channel */ 91244b781cfSAndrew Turner if (!ring) 91344b781cfSAndrew Turner return 0; 91444b781cfSAndrew Turner 91544b781cfSAndrew Turner cur = ring->cur; 91644b781cfSAndrew Turner 91744b781cfSAndrew Turner /* Be sure we get ring->cur before accessing descriptor data */ 918*9c6d6488SAndrew Turner dsb(sy); 91944b781cfSAndrew Turner 92044b781cfSAndrew Turner while ((processed < XGBE_TX_DESC_MAX_PROC) && 92144b781cfSAndrew Turner (ring->dirty != cur)) { 92244b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); 92344b781cfSAndrew Turner rdesc = rdata->rdesc; 92444b781cfSAndrew Turner 92544b781cfSAndrew Turner if (!hw_if->tx_complete(rdesc)) 92644b781cfSAndrew Turner break; 92744b781cfSAndrew Turner 92844b781cfSAndrew Turner /* Make sure descriptor fields are read after reading the OWN 92944b781cfSAndrew Turner * bit */ 930*9c6d6488SAndrew Turner dsb(sy); 93144b781cfSAndrew Turner 93244b781cfSAndrew Turner /* Free the SKB and reset the descriptor for re-use */ 93344b781cfSAndrew Turner desc_if->unmap_rdata(pdata, rdata); 93444b781cfSAndrew Turner hw_if->tx_desc_reset(rdata); 93544b781cfSAndrew Turner 93644b781cfSAndrew Turner processed++; 93744b781cfSAndrew Turner ring->dirty++; 93844b781cfSAndrew Turner } 93944b781cfSAndrew Turner 94044b781cfSAndrew Turner if (!processed) 94144b781cfSAndrew Turner return 0; 94244b781cfSAndrew Turner 94344b781cfSAndrew Turner DBGPR("<--xgbe_tx_poll: processed=%d\n", processed); 94444b781cfSAndrew Turner 94544b781cfSAndrew Turner return processed; 94644b781cfSAndrew Turner } 94744b781cfSAndrew Turner 94844b781cfSAndrew Turner static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) 94944b781cfSAndrew Turner { 95044b781cfSAndrew Turner struct xgbe_prv_data *pdata = channel->pdata; 95144b781cfSAndrew Turner struct xgbe_hw_if *hw_if = &pdata->hw_if; 95244b781cfSAndrew Turner struct xgbe_ring *ring = channel->rx_ring; 95344b781cfSAndrew Turner struct xgbe_ring_data *rdata; 95444b781cfSAndrew Turner struct xgbe_packet_data *packet; 955*9c6d6488SAndrew Turner struct ifnet *ifp = pdata->netdev; 956*9c6d6488SAndrew Turner struct mbuf *m; 957*9c6d6488SAndrew Turner unsigned int incomplete, context_next, context; 95844b781cfSAndrew Turner unsigned int received = 0; 95944b781cfSAndrew Turner int packet_count = 0; 96044b781cfSAndrew Turner 96144b781cfSAndrew Turner DBGPR("-->xgbe_rx_poll: budget=%d\n", budget); 96244b781cfSAndrew Turner 96344b781cfSAndrew Turner /* Nothing to do if there isn't a Rx ring for this channel */ 96444b781cfSAndrew Turner if (!ring) 96544b781cfSAndrew Turner return 0; 96644b781cfSAndrew Turner 96744b781cfSAndrew Turner incomplete = 0; 96844b781cfSAndrew Turner context_next = 0; 96944b781cfSAndrew Turner 97044b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, ring->cur); 97144b781cfSAndrew Turner packet = &ring->packet_data; 97244b781cfSAndrew Turner while (packet_count < budget) { 97344b781cfSAndrew Turner DBGPR(" cur = %d\n", ring->cur); 97444b781cfSAndrew Turner 97544b781cfSAndrew Turner read_again: 97644b781cfSAndrew Turner rdata = XGBE_GET_DESC_DATA(ring, ring->cur); 97744b781cfSAndrew Turner 97844b781cfSAndrew Turner if (xgbe_rx_dirty_desc(ring) > (XGBE_RX_DESC_CNT >> 3)) 97944b781cfSAndrew Turner xgbe_rx_refresh(channel); 98044b781cfSAndrew Turner 98144b781cfSAndrew Turner if (hw_if->dev_read(channel)) 98244b781cfSAndrew Turner break; 98344b781cfSAndrew Turner 984*9c6d6488SAndrew Turner m = rdata->mb; 985*9c6d6488SAndrew Turner 98644b781cfSAndrew Turner received++; 98744b781cfSAndrew Turner ring->cur++; 98844b781cfSAndrew Turner 98944b781cfSAndrew Turner incomplete = XGMAC_GET_BITS(packet->attributes, 99044b781cfSAndrew Turner RX_PACKET_ATTRIBUTES, 99144b781cfSAndrew Turner INCOMPLETE); 99244b781cfSAndrew Turner context_next = XGMAC_GET_BITS(packet->attributes, 99344b781cfSAndrew Turner RX_PACKET_ATTRIBUTES, 99444b781cfSAndrew Turner CONTEXT_NEXT); 99544b781cfSAndrew Turner context = XGMAC_GET_BITS(packet->attributes, 99644b781cfSAndrew Turner RX_PACKET_ATTRIBUTES, 99744b781cfSAndrew Turner CONTEXT); 99844b781cfSAndrew Turner 99944b781cfSAndrew Turner /* Earlier error, just drain the remaining data */ 1000*9c6d6488SAndrew Turner if (incomplete || context_next) { 100144b781cfSAndrew Turner goto read_again; 1002*9c6d6488SAndrew Turner } 100344b781cfSAndrew Turner 1004*9c6d6488SAndrew Turner if (packet->errors) { 1005*9c6d6488SAndrew Turner rdata->mbuf_free = 1; 100644b781cfSAndrew Turner goto next_packet; 100744b781cfSAndrew Turner } 1008*9c6d6488SAndrew Turner rdata->mb = NULL; 100944b781cfSAndrew Turner 1010*9c6d6488SAndrew Turner m->m_pkthdr.len = rdata->rx.hdr_len + rdata->rx.len; 1011*9c6d6488SAndrew Turner if (rdata->rx.hdr_len != 0) { 1012*9c6d6488SAndrew Turner m->m_len = rdata->rx.hdr_len; 1013*9c6d6488SAndrew Turner m->m_next->m_len = rdata->rx.len; 1014*9c6d6488SAndrew Turner } else { 1015*9c6d6488SAndrew Turner m->m_len = rdata->rx.len; 1016*9c6d6488SAndrew Turner m_freem(m->m_next); 1017*9c6d6488SAndrew Turner m->m_next = NULL; 101844b781cfSAndrew Turner } 1019*9c6d6488SAndrew Turner if_setrcvif(m, ifp); 1020*9c6d6488SAndrew Turner if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 102144b781cfSAndrew Turner 1022*9c6d6488SAndrew Turner ifp->if_input(ifp, m); 102344b781cfSAndrew Turner 102444b781cfSAndrew Turner next_packet: 102544b781cfSAndrew Turner packet_count++; 102644b781cfSAndrew Turner } 102744b781cfSAndrew Turner 102844b781cfSAndrew Turner DBGPR("<--xgbe_rx_poll: packet_count = %d\n", packet_count); 102944b781cfSAndrew Turner 103044b781cfSAndrew Turner return packet_count; 103144b781cfSAndrew Turner } 103244b781cfSAndrew Turner 1033*9c6d6488SAndrew Turner static int xgbe_one_poll(struct xgbe_channel *channel, int budget) 103444b781cfSAndrew Turner { 103544b781cfSAndrew Turner int processed = 0; 103644b781cfSAndrew Turner 103744b781cfSAndrew Turner DBGPR("-->xgbe_one_poll: budget=%d\n", budget); 103844b781cfSAndrew Turner 103944b781cfSAndrew Turner /* Cleanup Tx ring first */ 104044b781cfSAndrew Turner xgbe_tx_poll(channel); 104144b781cfSAndrew Turner 104244b781cfSAndrew Turner /* Process Rx ring next */ 104344b781cfSAndrew Turner processed = xgbe_rx_poll(channel, budget); 104444b781cfSAndrew Turner 104544b781cfSAndrew Turner DBGPR("<--xgbe_one_poll: received = %d\n", processed); 104644b781cfSAndrew Turner 104744b781cfSAndrew Turner return processed; 104844b781cfSAndrew Turner } 104944b781cfSAndrew Turner 1050*9c6d6488SAndrew Turner static int xgbe_all_poll(struct xgbe_prv_data *pdata, int budget) 105144b781cfSAndrew Turner { 105244b781cfSAndrew Turner struct xgbe_channel *channel; 105344b781cfSAndrew Turner int ring_budget; 105444b781cfSAndrew Turner int processed, last_processed; 105544b781cfSAndrew Turner unsigned int i; 105644b781cfSAndrew Turner 105744b781cfSAndrew Turner DBGPR("-->xgbe_all_poll: budget=%d\n", budget); 105844b781cfSAndrew Turner 105944b781cfSAndrew Turner processed = 0; 106044b781cfSAndrew Turner ring_budget = budget / pdata->rx_ring_count; 106144b781cfSAndrew Turner do { 106244b781cfSAndrew Turner last_processed = processed; 106344b781cfSAndrew Turner 106444b781cfSAndrew Turner channel = pdata->channel; 106544b781cfSAndrew Turner for (i = 0; i < pdata->channel_count; i++, channel++) { 106644b781cfSAndrew Turner /* Cleanup Tx ring first */ 106744b781cfSAndrew Turner xgbe_tx_poll(channel); 106844b781cfSAndrew Turner 106944b781cfSAndrew Turner /* Process Rx ring next */ 107044b781cfSAndrew Turner if (ring_budget > (budget - processed)) 107144b781cfSAndrew Turner ring_budget = budget - processed; 107244b781cfSAndrew Turner processed += xgbe_rx_poll(channel, ring_budget); 107344b781cfSAndrew Turner } 107444b781cfSAndrew Turner } while ((processed < budget) && (processed != last_processed)); 107544b781cfSAndrew Turner 107644b781cfSAndrew Turner DBGPR("<--xgbe_all_poll: received = %d\n", processed); 107744b781cfSAndrew Turner 107844b781cfSAndrew Turner return processed; 107944b781cfSAndrew Turner } 1080