18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * AMD 10Gb Ethernet driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is available to you under your choice of the following two 58c2ecf20Sopenharmony_ci * licenses: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * License 1: GPLv2 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2014 Advanced Micro Devices, Inc. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 138c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at 148c2ecf20Sopenharmony_ci * your option) any later version. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 198c2ecf20Sopenharmony_ci * General Public License for more details. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 228c2ecf20Sopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 258c2ecf20Sopenharmony_ci * permission notice: 268c2ecf20Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 278c2ecf20Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 288c2ecf20Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 298c2ecf20Sopenharmony_ci * and you. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 328c2ecf20Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 338c2ecf20Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 348c2ecf20Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 358c2ecf20Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 368c2ecf20Sopenharmony_ci * without restriction, including without limitation the rights to use, 378c2ecf20Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 388c2ecf20Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 398c2ecf20Sopenharmony_ci * to do so, subject to the following conditions: 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included 428c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 458c2ecf20Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 468c2ecf20Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 478c2ecf20Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 488c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 498c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 508c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 518c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 528c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 538c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 548c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * License 2: Modified BSD 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Copyright (c) 2014 Advanced Micro Devices, Inc. 608c2ecf20Sopenharmony_ci * All rights reserved. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 638c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 648c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 658c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 668c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 678c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 688c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 698c2ecf20Sopenharmony_ci * * Neither the name of Advanced Micro Devices, Inc. nor the 708c2ecf20Sopenharmony_ci * names of its contributors may be used to endorse or promote products 718c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 748c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 758c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 768c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 778c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 788c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 798c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 808c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 818c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 828c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 858c2ecf20Sopenharmony_ci * permission notice: 868c2ecf20Sopenharmony_ci * The Synopsys DWC ETHER XGMAC Software Driver and documentation 878c2ecf20Sopenharmony_ci * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 888c2ecf20Sopenharmony_ci * Inc. unless otherwise expressly agreed to in writing between Synopsys 898c2ecf20Sopenharmony_ci * and you. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * The Software IS NOT an item of Licensed Software or Licensed Product 928c2ecf20Sopenharmony_ci * under any End User Software License Agreement or Agreement for Licensed 938c2ecf20Sopenharmony_ci * Product with Synopsys or any supplement thereto. Permission is hereby 948c2ecf20Sopenharmony_ci * granted, free of charge, to any person obtaining a copy of this software 958c2ecf20Sopenharmony_ci * annotated with this license and the Software, to deal in the Software 968c2ecf20Sopenharmony_ci * without restriction, including without limitation the rights to use, 978c2ecf20Sopenharmony_ci * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 988c2ecf20Sopenharmony_ci * of the Software, and to permit persons to whom the Software is furnished 998c2ecf20Sopenharmony_ci * to do so, subject to the following conditions: 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included 1028c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 1058c2ecf20Sopenharmony_ci * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1068c2ecf20Sopenharmony_ci * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 1078c2ecf20Sopenharmony_ci * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 1088c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1098c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1108c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1118c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1128c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1138c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1148c2ecf20Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGE. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#include "xgbe.h" 1188c2ecf20Sopenharmony_ci#include "xgbe-common.h" 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void xgbe_unmap_rdata(struct xgbe_prv_data *, struct xgbe_ring_data *); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void xgbe_free_ring(struct xgbe_prv_data *pdata, 1238c2ecf20Sopenharmony_ci struct xgbe_ring *ring) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct xgbe_ring_data *rdata; 1268c2ecf20Sopenharmony_ci unsigned int i; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (!ring) 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (ring->rdata) { 1328c2ecf20Sopenharmony_ci for (i = 0; i < ring->rdesc_count; i++) { 1338c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, i); 1348c2ecf20Sopenharmony_ci xgbe_unmap_rdata(pdata, rdata); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci kfree(ring->rdata); 1388c2ecf20Sopenharmony_ci ring->rdata = NULL; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (ring->rx_hdr_pa.pages) { 1428c2ecf20Sopenharmony_ci dma_unmap_page(pdata->dev, ring->rx_hdr_pa.pages_dma, 1438c2ecf20Sopenharmony_ci ring->rx_hdr_pa.pages_len, DMA_FROM_DEVICE); 1448c2ecf20Sopenharmony_ci put_page(ring->rx_hdr_pa.pages); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci ring->rx_hdr_pa.pages = NULL; 1478c2ecf20Sopenharmony_ci ring->rx_hdr_pa.pages_len = 0; 1488c2ecf20Sopenharmony_ci ring->rx_hdr_pa.pages_offset = 0; 1498c2ecf20Sopenharmony_ci ring->rx_hdr_pa.pages_dma = 0; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (ring->rx_buf_pa.pages) { 1538c2ecf20Sopenharmony_ci dma_unmap_page(pdata->dev, ring->rx_buf_pa.pages_dma, 1548c2ecf20Sopenharmony_ci ring->rx_buf_pa.pages_len, DMA_FROM_DEVICE); 1558c2ecf20Sopenharmony_ci put_page(ring->rx_buf_pa.pages); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ring->rx_buf_pa.pages = NULL; 1588c2ecf20Sopenharmony_ci ring->rx_buf_pa.pages_len = 0; 1598c2ecf20Sopenharmony_ci ring->rx_buf_pa.pages_offset = 0; 1608c2ecf20Sopenharmony_ci ring->rx_buf_pa.pages_dma = 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (ring->rdesc) { 1648c2ecf20Sopenharmony_ci dma_free_coherent(pdata->dev, 1658c2ecf20Sopenharmony_ci (sizeof(struct xgbe_ring_desc) * 1668c2ecf20Sopenharmony_ci ring->rdesc_count), 1678c2ecf20Sopenharmony_ci ring->rdesc, ring->rdesc_dma); 1688c2ecf20Sopenharmony_ci ring->rdesc = NULL; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void xgbe_free_ring_resources(struct xgbe_prv_data *pdata) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct xgbe_channel *channel; 1758c2ecf20Sopenharmony_ci unsigned int i; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci DBGPR("-->xgbe_free_ring_resources\n"); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++) { 1808c2ecf20Sopenharmony_ci channel = pdata->channel[i]; 1818c2ecf20Sopenharmony_ci xgbe_free_ring(pdata, channel->tx_ring); 1828c2ecf20Sopenharmony_ci xgbe_free_ring(pdata, channel->rx_ring); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci DBGPR("<--xgbe_free_ring_resources\n"); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void *xgbe_alloc_node(size_t size, int node) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci void *mem; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci mem = kzalloc_node(size, GFP_KERNEL, node); 1938c2ecf20Sopenharmony_ci if (!mem) 1948c2ecf20Sopenharmony_ci mem = kzalloc(size, GFP_KERNEL); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return mem; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void *xgbe_dma_alloc_node(struct device *dev, size_t size, 2008c2ecf20Sopenharmony_ci dma_addr_t *dma, int node) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci void *mem; 2038c2ecf20Sopenharmony_ci int cur_node = dev_to_node(dev); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci set_dev_node(dev, node); 2068c2ecf20Sopenharmony_ci mem = dma_alloc_coherent(dev, size, dma, GFP_KERNEL); 2078c2ecf20Sopenharmony_ci set_dev_node(dev, cur_node); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!mem) 2108c2ecf20Sopenharmony_ci mem = dma_alloc_coherent(dev, size, dma, GFP_KERNEL); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return mem; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int xgbe_init_ring(struct xgbe_prv_data *pdata, 2168c2ecf20Sopenharmony_ci struct xgbe_ring *ring, unsigned int rdesc_count) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci size_t size; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!ring) 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Descriptors */ 2248c2ecf20Sopenharmony_ci size = rdesc_count * sizeof(struct xgbe_ring_desc); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ring->rdesc_count = rdesc_count; 2278c2ecf20Sopenharmony_ci ring->rdesc = xgbe_dma_alloc_node(pdata->dev, size, &ring->rdesc_dma, 2288c2ecf20Sopenharmony_ci ring->node); 2298c2ecf20Sopenharmony_ci if (!ring->rdesc) 2308c2ecf20Sopenharmony_ci return -ENOMEM; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Descriptor information */ 2338c2ecf20Sopenharmony_ci size = rdesc_count * sizeof(struct xgbe_ring_data); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ring->rdata = xgbe_alloc_node(size, ring->node); 2368c2ecf20Sopenharmony_ci if (!ring->rdata) 2378c2ecf20Sopenharmony_ci return -ENOMEM; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 2408c2ecf20Sopenharmony_ci "rdesc=%p, rdesc_dma=%pad, rdata=%p, node=%d\n", 2418c2ecf20Sopenharmony_ci ring->rdesc, &ring->rdesc_dma, ring->rdata, ring->node); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct xgbe_channel *channel; 2498c2ecf20Sopenharmony_ci unsigned int i; 2508c2ecf20Sopenharmony_ci int ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++) { 2538c2ecf20Sopenharmony_ci channel = pdata->channel[i]; 2548c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "%s - Tx ring:\n", 2558c2ecf20Sopenharmony_ci channel->name); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = xgbe_init_ring(pdata, channel->tx_ring, 2588c2ecf20Sopenharmony_ci pdata->tx_desc_count); 2598c2ecf20Sopenharmony_ci if (ret) { 2608c2ecf20Sopenharmony_ci netdev_alert(pdata->netdev, 2618c2ecf20Sopenharmony_ci "error initializing Tx ring\n"); 2628c2ecf20Sopenharmony_ci goto err_ring; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "%s - Rx ring:\n", 2668c2ecf20Sopenharmony_ci channel->name); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = xgbe_init_ring(pdata, channel->rx_ring, 2698c2ecf20Sopenharmony_ci pdata->rx_desc_count); 2708c2ecf20Sopenharmony_ci if (ret) { 2718c2ecf20Sopenharmony_ci netdev_alert(pdata->netdev, 2728c2ecf20Sopenharmony_ci "error initializing Rx ring\n"); 2738c2ecf20Sopenharmony_ci goto err_ring; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cierr_ring: 2808c2ecf20Sopenharmony_ci xgbe_free_ring_resources(pdata); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int xgbe_alloc_pages(struct xgbe_prv_data *pdata, 2868c2ecf20Sopenharmony_ci struct xgbe_page_alloc *pa, int alloc_order, 2878c2ecf20Sopenharmony_ci int node) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct page *pages = NULL; 2908c2ecf20Sopenharmony_ci dma_addr_t pages_dma; 2918c2ecf20Sopenharmony_ci gfp_t gfp; 2928c2ecf20Sopenharmony_ci int order; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciagain: 2958c2ecf20Sopenharmony_ci order = alloc_order; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Try to obtain pages, decreasing order if necessary */ 2988c2ecf20Sopenharmony_ci gfp = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN; 2998c2ecf20Sopenharmony_ci while (order >= 0) { 3008c2ecf20Sopenharmony_ci pages = alloc_pages_node(node, gfp, order); 3018c2ecf20Sopenharmony_ci if (pages) 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci order--; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* If we couldn't get local pages, try getting from anywhere */ 3088c2ecf20Sopenharmony_ci if (!pages && (node != NUMA_NO_NODE)) { 3098c2ecf20Sopenharmony_ci node = NUMA_NO_NODE; 3108c2ecf20Sopenharmony_ci goto again; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!pages) 3148c2ecf20Sopenharmony_ci return -ENOMEM; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Map the pages */ 3178c2ecf20Sopenharmony_ci pages_dma = dma_map_page(pdata->dev, pages, 0, 3188c2ecf20Sopenharmony_ci PAGE_SIZE << order, DMA_FROM_DEVICE); 3198c2ecf20Sopenharmony_ci if (dma_mapping_error(pdata->dev, pages_dma)) { 3208c2ecf20Sopenharmony_ci put_page(pages); 3218c2ecf20Sopenharmony_ci return -ENOMEM; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci pa->pages = pages; 3258c2ecf20Sopenharmony_ci pa->pages_len = PAGE_SIZE << order; 3268c2ecf20Sopenharmony_ci pa->pages_offset = 0; 3278c2ecf20Sopenharmony_ci pa->pages_dma = pages_dma; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void xgbe_set_buffer_data(struct xgbe_buffer_data *bd, 3338c2ecf20Sopenharmony_ci struct xgbe_page_alloc *pa, 3348c2ecf20Sopenharmony_ci unsigned int len) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci get_page(pa->pages); 3378c2ecf20Sopenharmony_ci bd->pa = *pa; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci bd->dma_base = pa->pages_dma; 3408c2ecf20Sopenharmony_ci bd->dma_off = pa->pages_offset; 3418c2ecf20Sopenharmony_ci bd->dma_len = len; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci pa->pages_offset += len; 3448c2ecf20Sopenharmony_ci if ((pa->pages_offset + len) > pa->pages_len) { 3458c2ecf20Sopenharmony_ci /* This data descriptor is responsible for unmapping page(s) */ 3468c2ecf20Sopenharmony_ci bd->pa_unmap = *pa; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Get a new allocation next time */ 3498c2ecf20Sopenharmony_ci pa->pages = NULL; 3508c2ecf20Sopenharmony_ci pa->pages_len = 0; 3518c2ecf20Sopenharmony_ci pa->pages_offset = 0; 3528c2ecf20Sopenharmony_ci pa->pages_dma = 0; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata, 3578c2ecf20Sopenharmony_ci struct xgbe_ring *ring, 3588c2ecf20Sopenharmony_ci struct xgbe_ring_data *rdata) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int ret; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!ring->rx_hdr_pa.pages) { 3638c2ecf20Sopenharmony_ci ret = xgbe_alloc_pages(pdata, &ring->rx_hdr_pa, 0, ring->node); 3648c2ecf20Sopenharmony_ci if (ret) 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (!ring->rx_buf_pa.pages) { 3698c2ecf20Sopenharmony_ci ret = xgbe_alloc_pages(pdata, &ring->rx_buf_pa, 3708c2ecf20Sopenharmony_ci PAGE_ALLOC_COSTLY_ORDER, ring->node); 3718c2ecf20Sopenharmony_ci if (ret) 3728c2ecf20Sopenharmony_ci return ret; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Set up the header page info */ 3768c2ecf20Sopenharmony_ci xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa, 3778c2ecf20Sopenharmony_ci XGBE_SKB_ALLOC_SIZE); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Set up the buffer page info */ 3808c2ecf20Sopenharmony_ci xgbe_set_buffer_data(&rdata->rx.buf, &ring->rx_buf_pa, 3818c2ecf20Sopenharmony_ci pdata->rx_buf_size); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct xgbe_hw_if *hw_if = &pdata->hw_if; 3898c2ecf20Sopenharmony_ci struct xgbe_channel *channel; 3908c2ecf20Sopenharmony_ci struct xgbe_ring *ring; 3918c2ecf20Sopenharmony_ci struct xgbe_ring_data *rdata; 3928c2ecf20Sopenharmony_ci struct xgbe_ring_desc *rdesc; 3938c2ecf20Sopenharmony_ci dma_addr_t rdesc_dma; 3948c2ecf20Sopenharmony_ci unsigned int i, j; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci DBGPR("-->xgbe_wrapper_tx_descriptor_init\n"); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++) { 3998c2ecf20Sopenharmony_ci channel = pdata->channel[i]; 4008c2ecf20Sopenharmony_ci ring = channel->tx_ring; 4018c2ecf20Sopenharmony_ci if (!ring) 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci rdesc = ring->rdesc; 4058c2ecf20Sopenharmony_ci rdesc_dma = ring->rdesc_dma; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci for (j = 0; j < ring->rdesc_count; j++) { 4088c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, j); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci rdata->rdesc = rdesc; 4118c2ecf20Sopenharmony_ci rdata->rdesc_dma = rdesc_dma; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci rdesc++; 4148c2ecf20Sopenharmony_ci rdesc_dma += sizeof(struct xgbe_ring_desc); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ring->cur = 0; 4188c2ecf20Sopenharmony_ci ring->dirty = 0; 4198c2ecf20Sopenharmony_ci memset(&ring->tx, 0, sizeof(ring->tx)); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci hw_if->tx_desc_init(channel); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci DBGPR("<--xgbe_wrapper_tx_descriptor_init\n"); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct xgbe_hw_if *hw_if = &pdata->hw_if; 4308c2ecf20Sopenharmony_ci struct xgbe_channel *channel; 4318c2ecf20Sopenharmony_ci struct xgbe_ring *ring; 4328c2ecf20Sopenharmony_ci struct xgbe_ring_desc *rdesc; 4338c2ecf20Sopenharmony_ci struct xgbe_ring_data *rdata; 4348c2ecf20Sopenharmony_ci dma_addr_t rdesc_dma; 4358c2ecf20Sopenharmony_ci unsigned int i, j; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci DBGPR("-->xgbe_wrapper_rx_descriptor_init\n"); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++) { 4408c2ecf20Sopenharmony_ci channel = pdata->channel[i]; 4418c2ecf20Sopenharmony_ci ring = channel->rx_ring; 4428c2ecf20Sopenharmony_ci if (!ring) 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci rdesc = ring->rdesc; 4468c2ecf20Sopenharmony_ci rdesc_dma = ring->rdesc_dma; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci for (j = 0; j < ring->rdesc_count; j++) { 4498c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, j); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci rdata->rdesc = rdesc; 4528c2ecf20Sopenharmony_ci rdata->rdesc_dma = rdesc_dma; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (xgbe_map_rx_buffer(pdata, ring, rdata)) 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci rdesc++; 4588c2ecf20Sopenharmony_ci rdesc_dma += sizeof(struct xgbe_ring_desc); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci ring->cur = 0; 4628c2ecf20Sopenharmony_ci ring->dirty = 0; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci hw_if->rx_desc_init(channel); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci DBGPR("<--xgbe_wrapper_rx_descriptor_init\n"); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic void xgbe_unmap_rdata(struct xgbe_prv_data *pdata, 4718c2ecf20Sopenharmony_ci struct xgbe_ring_data *rdata) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci if (rdata->skb_dma) { 4748c2ecf20Sopenharmony_ci if (rdata->mapped_as_page) { 4758c2ecf20Sopenharmony_ci dma_unmap_page(pdata->dev, rdata->skb_dma, 4768c2ecf20Sopenharmony_ci rdata->skb_dma_len, DMA_TO_DEVICE); 4778c2ecf20Sopenharmony_ci } else { 4788c2ecf20Sopenharmony_ci dma_unmap_single(pdata->dev, rdata->skb_dma, 4798c2ecf20Sopenharmony_ci rdata->skb_dma_len, DMA_TO_DEVICE); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci rdata->skb_dma = 0; 4828c2ecf20Sopenharmony_ci rdata->skb_dma_len = 0; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (rdata->skb) { 4868c2ecf20Sopenharmony_ci dev_kfree_skb_any(rdata->skb); 4878c2ecf20Sopenharmony_ci rdata->skb = NULL; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (rdata->rx.hdr.pa.pages) 4918c2ecf20Sopenharmony_ci put_page(rdata->rx.hdr.pa.pages); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (rdata->rx.hdr.pa_unmap.pages) { 4948c2ecf20Sopenharmony_ci dma_unmap_page(pdata->dev, rdata->rx.hdr.pa_unmap.pages_dma, 4958c2ecf20Sopenharmony_ci rdata->rx.hdr.pa_unmap.pages_len, 4968c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4978c2ecf20Sopenharmony_ci put_page(rdata->rx.hdr.pa_unmap.pages); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (rdata->rx.buf.pa.pages) 5018c2ecf20Sopenharmony_ci put_page(rdata->rx.buf.pa.pages); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (rdata->rx.buf.pa_unmap.pages) { 5048c2ecf20Sopenharmony_ci dma_unmap_page(pdata->dev, rdata->rx.buf.pa_unmap.pages_dma, 5058c2ecf20Sopenharmony_ci rdata->rx.buf.pa_unmap.pages_len, 5068c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 5078c2ecf20Sopenharmony_ci put_page(rdata->rx.buf.pa_unmap.pages); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci memset(&rdata->tx, 0, sizeof(rdata->tx)); 5118c2ecf20Sopenharmony_ci memset(&rdata->rx, 0, sizeof(rdata->rx)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci rdata->mapped_as_page = 0; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (rdata->state_saved) { 5168c2ecf20Sopenharmony_ci rdata->state_saved = 0; 5178c2ecf20Sopenharmony_ci rdata->state.skb = NULL; 5188c2ecf20Sopenharmony_ci rdata->state.len = 0; 5198c2ecf20Sopenharmony_ci rdata->state.error = 0; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct xgbe_prv_data *pdata = channel->pdata; 5268c2ecf20Sopenharmony_ci struct xgbe_ring *ring = channel->tx_ring; 5278c2ecf20Sopenharmony_ci struct xgbe_ring_data *rdata; 5288c2ecf20Sopenharmony_ci struct xgbe_packet_data *packet; 5298c2ecf20Sopenharmony_ci skb_frag_t *frag; 5308c2ecf20Sopenharmony_ci dma_addr_t skb_dma; 5318c2ecf20Sopenharmony_ci unsigned int start_index, cur_index; 5328c2ecf20Sopenharmony_ci unsigned int offset, tso, vlan, datalen, len; 5338c2ecf20Sopenharmony_ci unsigned int i; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci DBGPR("-->xgbe_map_tx_skb: cur = %d\n", ring->cur); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci offset = 0; 5388c2ecf20Sopenharmony_ci start_index = ring->cur; 5398c2ecf20Sopenharmony_ci cur_index = ring->cur; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci packet = &ring->packet_data; 5428c2ecf20Sopenharmony_ci packet->rdesc_count = 0; 5438c2ecf20Sopenharmony_ci packet->length = 0; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, 5468c2ecf20Sopenharmony_ci TSO_ENABLE); 5478c2ecf20Sopenharmony_ci vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, 5488c2ecf20Sopenharmony_ci VLAN_CTAG); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Save space for a context descriptor if needed */ 5518c2ecf20Sopenharmony_ci if ((tso && (packet->mss != ring->tx.cur_mss)) || 5528c2ecf20Sopenharmony_ci (vlan && (packet->vlan_ctag != ring->tx.cur_vlan_ctag))) 5538c2ecf20Sopenharmony_ci cur_index++; 5548c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, cur_index); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (tso) { 5578c2ecf20Sopenharmony_ci /* Map the TSO header */ 5588c2ecf20Sopenharmony_ci skb_dma = dma_map_single(pdata->dev, skb->data, 5598c2ecf20Sopenharmony_ci packet->header_len, DMA_TO_DEVICE); 5608c2ecf20Sopenharmony_ci if (dma_mapping_error(pdata->dev, skb_dma)) { 5618c2ecf20Sopenharmony_ci netdev_alert(pdata->netdev, "dma_map_single failed\n"); 5628c2ecf20Sopenharmony_ci goto err_out; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci rdata->skb_dma = skb_dma; 5658c2ecf20Sopenharmony_ci rdata->skb_dma_len = packet->header_len; 5668c2ecf20Sopenharmony_ci netif_dbg(pdata, tx_queued, pdata->netdev, 5678c2ecf20Sopenharmony_ci "skb header: index=%u, dma=%pad, len=%u\n", 5688c2ecf20Sopenharmony_ci cur_index, &skb_dma, packet->header_len); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci offset = packet->header_len; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci packet->length += packet->header_len; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci cur_index++; 5758c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, cur_index); 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Map the (remainder of the) packet */ 5798c2ecf20Sopenharmony_ci for (datalen = skb_headlen(skb) - offset; datalen; ) { 5808c2ecf20Sopenharmony_ci len = min_t(unsigned int, datalen, XGBE_TX_MAX_BUF_SIZE); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci skb_dma = dma_map_single(pdata->dev, skb->data + offset, len, 5838c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5848c2ecf20Sopenharmony_ci if (dma_mapping_error(pdata->dev, skb_dma)) { 5858c2ecf20Sopenharmony_ci netdev_alert(pdata->netdev, "dma_map_single failed\n"); 5868c2ecf20Sopenharmony_ci goto err_out; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci rdata->skb_dma = skb_dma; 5898c2ecf20Sopenharmony_ci rdata->skb_dma_len = len; 5908c2ecf20Sopenharmony_ci netif_dbg(pdata, tx_queued, pdata->netdev, 5918c2ecf20Sopenharmony_ci "skb data: index=%u, dma=%pad, len=%u\n", 5928c2ecf20Sopenharmony_ci cur_index, &skb_dma, len); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci datalen -= len; 5958c2ecf20Sopenharmony_ci offset += len; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci packet->length += len; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci cur_index++; 6008c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, cur_index); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 6048c2ecf20Sopenharmony_ci netif_dbg(pdata, tx_queued, pdata->netdev, 6058c2ecf20Sopenharmony_ci "mapping frag %u\n", i); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i]; 6088c2ecf20Sopenharmony_ci offset = 0; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci for (datalen = skb_frag_size(frag); datalen; ) { 6118c2ecf20Sopenharmony_ci len = min_t(unsigned int, datalen, 6128c2ecf20Sopenharmony_ci XGBE_TX_MAX_BUF_SIZE); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci skb_dma = skb_frag_dma_map(pdata->dev, frag, offset, 6158c2ecf20Sopenharmony_ci len, DMA_TO_DEVICE); 6168c2ecf20Sopenharmony_ci if (dma_mapping_error(pdata->dev, skb_dma)) { 6178c2ecf20Sopenharmony_ci netdev_alert(pdata->netdev, 6188c2ecf20Sopenharmony_ci "skb_frag_dma_map failed\n"); 6198c2ecf20Sopenharmony_ci goto err_out; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci rdata->skb_dma = skb_dma; 6228c2ecf20Sopenharmony_ci rdata->skb_dma_len = len; 6238c2ecf20Sopenharmony_ci rdata->mapped_as_page = 1; 6248c2ecf20Sopenharmony_ci netif_dbg(pdata, tx_queued, pdata->netdev, 6258c2ecf20Sopenharmony_ci "skb frag: index=%u, dma=%pad, len=%u\n", 6268c2ecf20Sopenharmony_ci cur_index, &skb_dma, len); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci datalen -= len; 6298c2ecf20Sopenharmony_ci offset += len; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci packet->length += len; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci cur_index++; 6348c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, cur_index); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Save the skb address in the last entry. We always have some data 6398c2ecf20Sopenharmony_ci * that has been mapped so rdata is always advanced past the last 6408c2ecf20Sopenharmony_ci * piece of mapped data - use the entry pointed to by cur_index - 1. 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, cur_index - 1); 6438c2ecf20Sopenharmony_ci rdata->skb = skb; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Save the number of descriptor entries used */ 6468c2ecf20Sopenharmony_ci packet->rdesc_count = cur_index - start_index; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci DBGPR("<--xgbe_map_tx_skb: count=%u\n", packet->rdesc_count); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return packet->rdesc_count; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cierr_out: 6538c2ecf20Sopenharmony_ci while (start_index < cur_index) { 6548c2ecf20Sopenharmony_ci rdata = XGBE_GET_DESC_DATA(ring, start_index++); 6558c2ecf20Sopenharmony_ci xgbe_unmap_rdata(pdata, rdata); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci DBGPR("<--xgbe_map_tx_skb: count=0\n"); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_civoid xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci DBGPR("-->xgbe_init_function_ptrs_desc\n"); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci desc_if->alloc_ring_resources = xgbe_alloc_ring_resources; 6688c2ecf20Sopenharmony_ci desc_if->free_ring_resources = xgbe_free_ring_resources; 6698c2ecf20Sopenharmony_ci desc_if->map_tx_skb = xgbe_map_tx_skb; 6708c2ecf20Sopenharmony_ci desc_if->map_rx_buffer = xgbe_map_rx_buffer; 6718c2ecf20Sopenharmony_ci desc_if->unmap_rdata = xgbe_unmap_rdata; 6728c2ecf20Sopenharmony_ci desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init; 6738c2ecf20Sopenharmony_ci desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci DBGPR("<--xgbe_init_function_ptrs_desc\n"); 6768c2ecf20Sopenharmony_ci} 677