diff mbox series

[net-next,05/10] net: libwx: Allocate Rx and Tx resources

Message ID 20230118065504.3075474-6-jiawenwu@trustnetic.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Wangxun interrupt and RxTx support | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 2 this patch: 2
netdev/cc_maintainers warning 4 maintainers not CCed: edumazet@google.com davem@davemloft.net pabeni@redhat.com kuba@kernel.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 454 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Jiawen Wu Jan. 18, 2023, 6:54 a.m. UTC
Setup Rx and Tx descriptors for specefic rings.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 drivers/net/ethernet/wangxun/Kconfig         |   1 +
 drivers/net/ethernet/wangxun/libwx/wx_hw.c   |   8 +
 drivers/net/ethernet/wangxun/libwx/wx_lib.c  | 299 +++++++++++++++++++
 drivers/net/ethernet/wangxun/libwx/wx_lib.h  |   2 +
 drivers/net/ethernet/wangxun/libwx/wx_type.h |  74 +++++
 5 files changed, 384 insertions(+)

Comments

kernel test robot Jan. 22, 2023, 3:05 a.m. UTC | #1
Hi Jiawen,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Jiawen-Wu/net-libwx-Add-irq-flow-functions/20230118-154258
patch link:    https://lore.kernel.org/r/20230118065504.3075474-6-jiawenwu%40trustnetic.com
patch subject: [PATCH net-next 05/10] net: libwx: Allocate Rx and Tx resources
config: mips-allyesconfig (https://download.01.org/0day-ci/archive/20230122/202301221047.SBlK8xvt-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/583ee5bbec18cbfb2f88a647db0d8d15457d2b54
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Jiawen-Wu/net-libwx-Add-irq-flow-functions/20230118-154258
        git checkout 583ee5bbec18cbfb2f88a647db0d8d15457d2b54
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=mips olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=mips SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/net/ethernet/wangxun/libwx/wx_lib.c: In function 'wx_free_rx_resources':
>> drivers/net/ethernet/wangxun/libwx/wx_lib.c:612:9: error: implicit declaration of function 'vfree'; did you mean 'kvfree'? [-Werror=implicit-function-declaration]
     612 |         vfree(rx_ring->rx_buffer_info);
         |         ^~~~~
         |         kvfree
   drivers/net/ethernet/wangxun/libwx/wx_lib.c: In function 'wx_setup_rx_resources':
>> drivers/net/ethernet/wangxun/libwx/wx_lib.c:728:35: error: implicit declaration of function 'vmalloc_node'; did you mean 'kvmalloc_node'? [-Werror=implicit-function-declaration]
     728 |         rx_ring->rx_buffer_info = vmalloc_node(size, numa_node);
         |                                   ^~~~~~~~~~~~
         |                                   kvmalloc_node
   drivers/net/ethernet/wangxun/libwx/wx_lib.c:728:33: warning: assignment to 'struct wx_rx_buffer *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     728 |         rx_ring->rx_buffer_info = vmalloc_node(size, numa_node);
         |                                 ^
>> drivers/net/ethernet/wangxun/libwx/wx_lib.c:730:43: error: implicit declaration of function 'vmalloc'; did you mean 'kvmalloc'? [-Werror=implicit-function-declaration]
     730 |                 rx_ring->rx_buffer_info = vmalloc(size);
         |                                           ^~~~~~~
         |                                           kvmalloc
   drivers/net/ethernet/wangxun/libwx/wx_lib.c:730:41: warning: assignment to 'struct wx_rx_buffer *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     730 |                 rx_ring->rx_buffer_info = vmalloc(size);
         |                                         ^
   drivers/net/ethernet/wangxun/libwx/wx_lib.c: In function 'wx_setup_tx_resources':
   drivers/net/ethernet/wangxun/libwx/wx_lib.c:810:33: warning: assignment to 'struct wx_tx_buffer *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     810 |         tx_ring->tx_buffer_info = vmalloc_node(size, numa_node);
         |                                 ^
   drivers/net/ethernet/wangxun/libwx/wx_lib.c:812:41: warning: assignment to 'struct wx_tx_buffer *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     812 |                 tx_ring->tx_buffer_info = vmalloc(size);
         |                                         ^
   cc1: some warnings being treated as errors


vim +612 drivers/net/ethernet/wangxun/libwx/wx_lib.c

   603	
   604	/**
   605	 * wx_free_rx_resources - Free Rx Resources
   606	 * @rx_ring: ring to clean the resources from
   607	 *
   608	 * Free all receive software resources
   609	 **/
   610	static void wx_free_rx_resources(struct wx_ring *rx_ring)
   611	{
 > 612		vfree(rx_ring->rx_buffer_info);
   613		rx_ring->rx_buffer_info = NULL;
   614	
   615		/* if not set, then don't free */
   616		if (!rx_ring->desc)
   617			return;
   618	
   619		dma_free_coherent(rx_ring->dev, rx_ring->size,
   620				  rx_ring->desc, rx_ring->dma);
   621	
   622		rx_ring->desc = NULL;
   623	
   624		if (rx_ring->page_pool) {
   625			page_pool_destroy(rx_ring->page_pool);
   626			rx_ring->page_pool = NULL;
   627		}
   628	}
   629	
   630	/**
   631	 * wx_free_all_rx_resources - Free Rx Resources for All Queues
   632	 * @wx: pointer to hardware structure
   633	 *
   634	 * Free all receive software resources
   635	 **/
   636	static void wx_free_all_rx_resources(struct wx *wx)
   637	{
   638		int i;
   639	
   640		for (i = 0; i < wx->num_rx_queues; i++)
   641			wx_free_rx_resources(wx->rx_ring[i]);
   642	}
   643	
   644	/**
   645	 * wx_free_tx_resources - Free Tx Resources per Queue
   646	 * @tx_ring: Tx descriptor ring for a specific queue
   647	 *
   648	 * Free all transmit software resources
   649	 **/
   650	static void wx_free_tx_resources(struct wx_ring *tx_ring)
   651	{
   652		vfree(tx_ring->tx_buffer_info);
   653		tx_ring->tx_buffer_info = NULL;
   654	
   655		/* if not set, then don't free */
   656		if (!tx_ring->desc)
   657			return;
   658	
   659		dma_free_coherent(tx_ring->dev, tx_ring->size,
   660				  tx_ring->desc, tx_ring->dma);
   661		tx_ring->desc = NULL;
   662	}
   663	
   664	/**
   665	 * wx_free_all_tx_resources - Free Tx Resources for All Queues
   666	 * @wx: pointer to hardware structure
   667	 *
   668	 * Free all transmit software resources
   669	 **/
   670	static void wx_free_all_tx_resources(struct wx *wx)
   671	{
   672		int i;
   673	
   674		for (i = 0; i < wx->num_tx_queues; i++)
   675			wx_free_tx_resources(wx->tx_ring[i]);
   676	}
   677	
   678	void wx_free_resources(struct wx *wx)
   679	{
   680		wx_free_isb_resources(wx);
   681		wx_free_all_rx_resources(wx);
   682		wx_free_all_tx_resources(wx);
   683	}
   684	EXPORT_SYMBOL(wx_free_resources);
   685	
   686	static int wx_alloc_page_pool(struct wx_ring *rx_ring)
   687	{
   688		int ret = 0;
   689	
   690		struct page_pool_params pp_params = {
   691			.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
   692			.order = 0,
   693			.pool_size = rx_ring->size,
   694			.nid = dev_to_node(rx_ring->dev),
   695			.dev = rx_ring->dev,
   696			.dma_dir = DMA_FROM_DEVICE,
   697			.offset = 0,
   698			.max_len = PAGE_SIZE,
   699		};
   700	
   701		rx_ring->page_pool = page_pool_create(&pp_params);
   702		if (IS_ERR(rx_ring->page_pool)) {
   703			rx_ring->page_pool = NULL;
   704			ret = PTR_ERR(rx_ring->page_pool);
   705		}
   706	
   707		return ret;
   708	}
   709	
   710	/**
   711	 * wx_setup_rx_resources - allocate Rx resources (Descriptors)
   712	 * @rx_ring: rx descriptor ring (for a specific queue) to setup
   713	 *
   714	 * Returns 0 on success, negative on failure
   715	 **/
   716	static int wx_setup_rx_resources(struct wx_ring *rx_ring)
   717	{
   718		struct device *dev = rx_ring->dev;
   719		int orig_node = dev_to_node(dev);
   720		int numa_node = -1;
   721		int size, ret;
   722	
   723		size = sizeof(struct wx_rx_buffer) * rx_ring->count;
   724	
   725		if (rx_ring->q_vector)
   726			numa_node = rx_ring->q_vector->numa_node;
   727	
 > 728		rx_ring->rx_buffer_info = vmalloc_node(size, numa_node);
   729		if (!rx_ring->rx_buffer_info)
 > 730			rx_ring->rx_buffer_info = vmalloc(size);
   731		if (!rx_ring->rx_buffer_info)
   732			goto err;
   733	
   734		/* Round up to nearest 4K */
   735		rx_ring->size = rx_ring->count * sizeof(union wx_rx_desc);
   736		rx_ring->size = ALIGN(rx_ring->size, 4096);
   737	
   738		set_dev_node(dev, numa_node);
   739		rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
   740						   &rx_ring->dma, GFP_KERNEL);
   741		set_dev_node(dev, orig_node);
   742		rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
   743						   &rx_ring->dma, GFP_KERNEL);
   744		if (!rx_ring->desc)
   745			goto err;
   746	
   747		ret = wx_alloc_page_pool(rx_ring);
   748		if (ret < 0) {
   749			dev_err(rx_ring->dev, "Page pool creation failed: %d\n", ret);
   750			goto err;
   751		}
   752	
   753		return 0;
   754	err:
   755		vfree(rx_ring->rx_buffer_info);
   756		rx_ring->rx_buffer_info = NULL;
   757		dev_err(dev, "Unable to allocate memory for the Rx descriptor ring\n");
   758		return -ENOMEM;
   759	}
   760
Andrew Lunn Jan. 23, 2023, 3:27 p.m. UTC | #2
> +/**
> + * wx_setup_rx_resources - allocate Rx resources (Descriptors)
> + * @rx_ring: rx descriptor ring (for a specific queue) to setup
> + *
> + * Returns 0 on success, negative on failure
> + **/
> +static int wx_setup_rx_resources(struct wx_ring *rx_ring)
> +{
> +	struct device *dev = rx_ring->dev;
> +	int orig_node = dev_to_node(dev);
> +	int numa_node = -1;
> +	int size, ret;
> +
> +	size = sizeof(struct wx_rx_buffer) * rx_ring->count;
> +
> +	if (rx_ring->q_vector)
> +		numa_node = rx_ring->q_vector->numa_node;
> +
> +	rx_ring->rx_buffer_info = vmalloc_node(size, numa_node);
> +	if (!rx_ring->rx_buffer_info)
> +		rx_ring->rx_buffer_info = vmalloc(size);
> +	if (!rx_ring->rx_buffer_info)
> +		goto err;
> +
> +	/* Round up to nearest 4K */
> +	rx_ring->size = rx_ring->count * sizeof(union wx_rx_desc);
> +	rx_ring->size = ALIGN(rx_ring->size, 4096);
> +
> +	set_dev_node(dev, numa_node);
> +	rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
> +					   &rx_ring->dma, GFP_KERNEL);
> +	set_dev_node(dev, orig_node);
> +	rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
> +					   &rx_ring->dma, GFP_KERNEL);

Is this double allocation correct?

   Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index 0922beac3ec0..c9d88673d306 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -18,6 +18,7 @@  if NET_VENDOR_WANGXUN
 
 config LIBWX
 	tristate
+	select PAGE_POOL
 	help
 	Common library for Wangxun(R) Ethernet drivers.
 
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index e969ae0d350e..b4e925ac629b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -1335,12 +1335,16 @@  static void wx_configure_tx_ring(struct wx *wx,
 {
 	u32 txdctl = WX_PX_TR_CFG_ENABLE;
 	u8 reg_idx = ring->reg_idx;
+	u64 tdba = ring->dma;
 	int ret;
 
 	/* disable queue to avoid issues while updating state */
 	wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH);
 	WX_WRITE_FLUSH(wx);
 
+	wr32(wx, WX_PX_TR_BAL(reg_idx), tdba & DMA_BIT_MASK(32));
+	wr32(wx, WX_PX_TR_BAH(reg_idx), tdba >> 32);
+
 	/* reset head and tail pointers */
 	wr32(wx, WX_PX_TR_RP(reg_idx), 0);
 	wr32(wx, WX_PX_TR_WP(reg_idx), 0);
@@ -1364,12 +1368,16 @@  static void wx_configure_rx_ring(struct wx *wx,
 				 struct wx_ring *ring)
 {
 	u16 reg_idx = ring->reg_idx;
+	u64 rdba = ring->dma;
 	u32 rxdctl;
 
 	/* disable queue to avoid issues while updating state */
 	rxdctl = rd32(wx, WX_PX_RR_CFG(reg_idx));
 	wx_disable_rx_queue(wx, ring);
 
+	wr32(wx, WX_PX_RR_BAL(reg_idx), rdba & DMA_BIT_MASK(32));
+	wr32(wx, WX_PX_RR_BAH(reg_idx), rdba >> 32);
+
 	if (ring->count == WX_MAX_RXD)
 		rxdctl |= 0 << WX_PX_RR_CFG_RR_SIZE_SHIFT;
 	else
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 0ba53ef97631..26e8391d3fe0 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -2,6 +2,7 @@ 
 /* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */
 
 #include <linux/etherdevice.h>
+#include <net/page_pool.h>
 #include <linux/iopoll.h>
 #include <linux/pci.h>
 
@@ -183,6 +184,9 @@  static int wx_alloc_q_vector(struct wx *wx,
 	wx->q_vector[v_idx] = q_vector;
 	q_vector->wx = wx;
 	q_vector->v_idx = v_idx;
+	if (cpu_online(v_idx))
+		q_vector->numa_node = cpu_to_node(v_idx);
+
 
 	/* initialize work limits */
 	q_vector->tx.work_limit = wx->tx_work_limit;
@@ -597,4 +601,299 @@  void wx_configure_vectors(struct wx *wx)
 }
 EXPORT_SYMBOL(wx_configure_vectors);
 
+/**
+ * wx_free_rx_resources - Free Rx Resources
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+static void wx_free_rx_resources(struct wx_ring *rx_ring)
+{
+	vfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+
+	/* if not set, then don't free */
+	if (!rx_ring->desc)
+		return;
+
+	dma_free_coherent(rx_ring->dev, rx_ring->size,
+			  rx_ring->desc, rx_ring->dma);
+
+	rx_ring->desc = NULL;
+
+	if (rx_ring->page_pool) {
+		page_pool_destroy(rx_ring->page_pool);
+		rx_ring->page_pool = NULL;
+	}
+}
+
+/**
+ * wx_free_all_rx_resources - Free Rx Resources for All Queues
+ * @wx: pointer to hardware structure
+ *
+ * Free all receive software resources
+ **/
+static void wx_free_all_rx_resources(struct wx *wx)
+{
+	int i;
+
+	for (i = 0; i < wx->num_rx_queues; i++)
+		wx_free_rx_resources(wx->rx_ring[i]);
+}
+
+/**
+ * wx_free_tx_resources - Free Tx Resources per Queue
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+static void wx_free_tx_resources(struct wx_ring *tx_ring)
+{
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+
+	/* if not set, then don't free */
+	if (!tx_ring->desc)
+		return;
+
+	dma_free_coherent(tx_ring->dev, tx_ring->size,
+			  tx_ring->desc, tx_ring->dma);
+	tx_ring->desc = NULL;
+}
+
+/**
+ * wx_free_all_tx_resources - Free Tx Resources for All Queues
+ * @wx: pointer to hardware structure
+ *
+ * Free all transmit software resources
+ **/
+static void wx_free_all_tx_resources(struct wx *wx)
+{
+	int i;
+
+	for (i = 0; i < wx->num_tx_queues; i++)
+		wx_free_tx_resources(wx->tx_ring[i]);
+}
+
+void wx_free_resources(struct wx *wx)
+{
+	wx_free_isb_resources(wx);
+	wx_free_all_rx_resources(wx);
+	wx_free_all_tx_resources(wx);
+}
+EXPORT_SYMBOL(wx_free_resources);
+
+static int wx_alloc_page_pool(struct wx_ring *rx_ring)
+{
+	int ret = 0;
+
+	struct page_pool_params pp_params = {
+		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
+		.order = 0,
+		.pool_size = rx_ring->size,
+		.nid = dev_to_node(rx_ring->dev),
+		.dev = rx_ring->dev,
+		.dma_dir = DMA_FROM_DEVICE,
+		.offset = 0,
+		.max_len = PAGE_SIZE,
+	};
+
+	rx_ring->page_pool = page_pool_create(&pp_params);
+	if (IS_ERR(rx_ring->page_pool)) {
+		rx_ring->page_pool = NULL;
+		ret = PTR_ERR(rx_ring->page_pool);
+	}
+
+	return ret;
+}
+
+/**
+ * wx_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int wx_setup_rx_resources(struct wx_ring *rx_ring)
+{
+	struct device *dev = rx_ring->dev;
+	int orig_node = dev_to_node(dev);
+	int numa_node = -1;
+	int size, ret;
+
+	size = sizeof(struct wx_rx_buffer) * rx_ring->count;
+
+	if (rx_ring->q_vector)
+		numa_node = rx_ring->q_vector->numa_node;
+
+	rx_ring->rx_buffer_info = vmalloc_node(size, numa_node);
+	if (!rx_ring->rx_buffer_info)
+		rx_ring->rx_buffer_info = vmalloc(size);
+	if (!rx_ring->rx_buffer_info)
+		goto err;
+
+	/* Round up to nearest 4K */
+	rx_ring->size = rx_ring->count * sizeof(union wx_rx_desc);
+	rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+	set_dev_node(dev, numa_node);
+	rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
+					   &rx_ring->dma, GFP_KERNEL);
+	set_dev_node(dev, orig_node);
+	rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
+					   &rx_ring->dma, GFP_KERNEL);
+	if (!rx_ring->desc)
+		goto err;
+
+	ret = wx_alloc_page_pool(rx_ring);
+	if (ret < 0) {
+		dev_err(rx_ring->dev, "Page pool creation failed: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+err:
+	vfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+	dev_err(dev, "Unable to allocate memory for the Rx descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * wx_setup_all_rx_resources - allocate all queues Rx resources
+ * @wx: pointer to hardware structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int wx_setup_all_rx_resources(struct wx *wx)
+{
+	int i, err = 0;
+
+	for (i = 0; i < wx->num_rx_queues; i++) {
+		err = wx_setup_rx_resources(wx->rx_ring[i]);
+		if (!err)
+			continue;
+
+		wx_err(wx, "Allocation for Rx Queue %u failed\n", i);
+		goto err_setup_rx;
+	}
+
+		return 0;
+err_setup_rx:
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		wx_free_rx_resources(wx->rx_ring[i]);
+	return err;
+}
+
+/**
+ * wx_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @tx_ring: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int wx_setup_tx_resources(struct wx_ring *tx_ring)
+{
+	struct device *dev = tx_ring->dev;
+	int orig_node = dev_to_node(dev);
+	int numa_node = -1;
+	int size;
+
+	size = sizeof(struct wx_tx_buffer) * tx_ring->count;
+
+	if (tx_ring->q_vector)
+		numa_node = tx_ring->q_vector->numa_node;
+
+	tx_ring->tx_buffer_info = vmalloc_node(size, numa_node);
+	if (!tx_ring->tx_buffer_info)
+		tx_ring->tx_buffer_info = vmalloc(size);
+	if (!tx_ring->tx_buffer_info)
+		goto err;
+
+	/* round up to nearest 4K */
+	tx_ring->size = tx_ring->count * sizeof(union wx_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+	set_dev_node(dev, numa_node);
+	tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
+					   &tx_ring->dma, GFP_KERNEL);
+	set_dev_node(dev, orig_node);
+	if (!tx_ring->desc)
+		tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
+						   &tx_ring->dma, GFP_KERNEL);
+	if (!tx_ring->desc)
+		goto err;
+
+	return 0;
+
+err:
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+	dev_err(dev, "Unable to allocate memory for the Tx descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * wx_setup_all_tx_resources - allocate all queues Tx resources
+ * @wx: pointer to private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int wx_setup_all_tx_resources(struct wx *wx)
+{
+	int i, err = 0;
+
+	for (i = 0; i < wx->num_tx_queues; i++) {
+		err = wx_setup_tx_resources(wx->tx_ring[i]);
+		if (!err)
+			continue;
+
+		wx_err(wx, "Allocation for Tx Queue %u failed\n", i);
+		goto err_setup_tx;
+	}
+
+	return 0;
+err_setup_tx:
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		wx_free_tx_resources(wx->tx_ring[i]);
+	return err;
+}
+
+int wx_setup_resources(struct wx *wx)
+{
+	int err;
+
+	/* allocate transmit descriptors */
+	err = wx_setup_all_tx_resources(wx);
+	if (err)
+		return err;
+
+	/* allocate receive descriptors */
+	err = wx_setup_all_rx_resources(wx);
+	if (err)
+		goto err_free_tx;
+
+	err = wx_setup_isb_resources(wx);
+	if (err)
+		goto err_free_rx;
+
+	return 0;
+
+err_free_rx:
+	wx_free_all_rx_resources(wx);
+err_free_tx:
+	wx_free_all_tx_resources(wx);
+
+	return err;
+}
+EXPORT_SYMBOL(wx_setup_resources);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
index 8ae657155f34..6fa95752fc42 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
@@ -16,5 +16,7 @@  int wx_setup_isb_resources(struct wx *wx);
 void wx_free_isb_resources(struct wx *wx);
 u32 wx_misc_isb(struct wx *wx, enum wx_isb_idx idx);
 void wx_configure_vectors(struct wx *wx);
+void wx_free_resources(struct wx *wx);
+int wx_setup_resources(struct wx *wx);
 
 #endif /* _NGBE_LIB_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 988878ddba47..1863c6cbc6c6 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -432,6 +432,71 @@  enum wx_reset_type {
 	WX_GLOBAL_RESET
 };
 
+/* Transmit Descriptor */
+union wx_tx_desc {
+	struct {
+		__le64 buffer_addr; /* Address of descriptor's data buf */
+		__le32 cmd_type_len;
+		__le32 olinfo_status;
+	} read;
+	struct {
+		__le64 rsvd; /* Reserved */
+		__le32 nxtseq_seed;
+		__le32 status;
+	} wb;
+};
+
+/* Receive Descriptor */
+union wx_rx_desc {
+	struct {
+		__le64 pkt_addr; /* Packet buffer address */
+		__le64 hdr_addr; /* Header buffer address */
+	} read;
+	struct {
+		struct {
+			union {
+				__le32 data;
+				struct {
+					__le16 pkt_info; /* RSS, Pkt type */
+					__le16 hdr_info; /* Splithdr, hdrlen */
+				} hs_rss;
+			} lo_dword;
+			union {
+				__le32 rss; /* RSS Hash */
+				struct {
+					__le16 ip_id; /* IP id */
+					__le16 csum; /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error; /* ext status/error */
+			__le16 length; /* Packet length */
+			__le16 vlan; /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct wx_tx_buffer {
+	union wx_tx_desc *next_to_watch;
+	struct sk_buff *skb;
+	unsigned int bytecount;
+	unsigned short gso_segs;
+	DEFINE_DMA_UNMAP_ADDR(dma);
+	DEFINE_DMA_UNMAP_LEN(len);
+};
+
+struct wx_rx_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	dma_addr_t page_dma;
+	struct page *page;
+	unsigned int page_offset;
+};
+
 /* iterator for handling rings in ring container */
 #define wx_for_each_ring(posm, headm) \
 	for (posm = (headm).ring; posm; posm = posm->next)
@@ -448,7 +513,15 @@  struct wx_ring {
 	struct wx_q_vector *q_vector;   /* backpointer to host q_vector */
 	struct net_device *netdev;      /* netdev ring belongs to */
 	struct device *dev;             /* device for DMA mapping */
+	struct page_pool *page_pool;
+	void *desc;                     /* descriptor ring memory */
+	union {
+		struct wx_tx_buffer *tx_buffer_info;
+		struct wx_rx_buffer *rx_buffer_info;
+	};
 	u8 __iomem *tail;
+	dma_addr_t dma;                 /* phys. address of descriptor ring */
+	unsigned int size;              /* length in bytes */
 
 	u16 count;                      /* amount of descriptors */
 
@@ -463,6 +536,7 @@  struct wx_ring {
 struct wx_q_vector {
 	struct wx *wx;
 	int cpu;        /* CPU for DCA */
+	int numa_node;
 	u16 v_idx;      /* index of q_vector within array, also used for
 			 * finding the bit in EICR and friends that
 			 * represents the vector for this ring