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