linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 00/10] Proposal for a API set for HW Buffer management
@ 2016-01-12 19:10 Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 01/10] bus: mvebu-mbus: provide api for obtaining IO and DRAM window information Gregory CLEMENT
                   ` (10 more replies)
  0 siblings, 11 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Hello,

A few weeks ago Marcin proposed a patch set including the support of
the buffer management for mvneta:
http://marc.info/?l=linux-netdev&m=144817888806131&w=2

He was asked to propose helpers in order to have common code taking
core of the hardware buffer manager. As Marcin was busy on other
topics we agreed that I would take care of it. After a few weeks, here
it is a first proposal.

The set of helpers is pretty small because I encountered issues while
trying writing more optimized helpers. The current implementation
provide a hwbm_pool structure which represents a pool with very
general members to define it: such as the number of buffers and the
size of the buffers. The structure also has a private member allowing
adding driver specific data and also a constructor called during the
allocation of a buffer.

The 3 helpers are:

- hwbm_pool_refill which allocates a new buffer and adds it in the
pool. If a constructor is provided in the hwbm_pool struct then it
will call it just after the allocation. The purpose of this
constructor is to do the hardware specific job such as informing the
hardware buffer manager of the new buffer.

- hwbm_pool_add which grows the amount of buffer in a given pool.

- hwbm_buf_free which frees a buffer calling the appropriate function
(skb_free_frag or kfree) depending of the size of the buffers of the
pool.

* At the beginning I hoped to be able to use kmem_cache objects for the
buffers pool. Indeed, for a given pool the size of the buffers is
fixed and the purpose of a SLAB allocator is to create caches, which
contains a set of objects of the same size.

However, in order to free an object from a cache we need to have a
reference to this one. As freeing the buffer is done most of the time
outside the driver there is no more reference to the cache the buffer
belonged. One solution would be to look for the buffer address in each
pool to find the slab cache, but I fear that the cost would be too
high. However, I didn't try it and maybe walking through a sorting
list would be a solution.

* I also though to add call to a ndo_free_buffer function inside the
skb_free_head. This callback would be responsible of freeing the data
buffer and in under certain circumstances with the help of a hardware
buffer manager it would only put back the buffer into the pool. Thanks
to this it would remove the cost of an allocation and of a free.

But there again we need to have a reference to the pool the buffer
belonged.



I am waiting for your feedback to consolidate this "framework".

For this RFC the interesting patches are the last 2 ones: "net:
mvneta: Use the new hwbm framework" and "net: Add a hardware buffer
management helper API". The other patches of the series are here to
let people testing the series on an Armada XP or an Armada 38x based
board.

Thanks,

Gregory

Gregory CLEMENT (3):
  bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info
  net: Add a hardware buffer management helper API
  net: mvneta: Use the new hwbm framework

Marcin Wojtas (7):
  bus: mvebu-mbus: provide api for obtaining IO and DRAM window
    information
  ARM: mvebu: enable SRAM support in mvebu_v7_defconfig
  net: mvneta: bm: add support for hardware buffer management
  ARM: mvebu: add buffer manager nodes to armada-38x.dtsi
  ARM: mvebu: enable buffer manager support on Armada 38x boards
  ARM: mvebu: add buffer manager nodes to armada-xp.dtsi
  ARM: mvebu: enable buffer manager support on Armada XP boards

 .../bindings/net/marvell-armada-370-neta.txt       |  19 +-
 .../devicetree/bindings/net/marvell-neta-bm.txt    |  49 +++
 arch/arm/boot/dts/armada-385-db-ap.dts             |  20 +-
 arch/arm/boot/dts/armada-388-db.dts                |  17 +-
 arch/arm/boot/dts/armada-388-gp.dts                |  17 +-
 arch/arm/boot/dts/armada-38x.dtsi                  |  18 +
 arch/arm/boot/dts/armada-xp-db.dts                 |  19 +-
 arch/arm/boot/dts/armada-xp-gp.dts                 |  19 +-
 arch/arm/boot/dts/armada-xp.dtsi                   |  18 +
 arch/arm/configs/mvebu_v7_defconfig                |   1 +
 drivers/bus/mvebu-mbus.c                           |  51 +++
 drivers/net/ethernet/marvell/Kconfig               |  14 +
 drivers/net/ethernet/marvell/Makefile              |   1 +
 drivers/net/ethernet/marvell/mvneta.c              | 407 +++++++++++++++--
 drivers/net/ethernet/marvell/mvneta_bm.c           | 486 +++++++++++++++++++++
 drivers/net/ethernet/marvell/mvneta_bm.h           | 162 +++++++
 include/linux/mbus.h                               |   3 +
 include/net/hwbm.h                                 |  19 +
 net/core/Makefile                                  |   2 +-
 net/core/hwbm.c                                    |  78 ++++
 20 files changed, 1364 insertions(+), 56 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/marvell-neta-bm.txt
 create mode 100644 drivers/net/ethernet/marvell/mvneta_bm.c
 create mode 100644 drivers/net/ethernet/marvell/mvneta_bm.h
 create mode 100644 include/net/hwbm.h
 create mode 100644 net/core/hwbm.c

-- 
2.5.0

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH net-next 01/10] bus: mvebu-mbus: provide api for obtaining IO and DRAM window information
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 02/10] ARM: mvebu: enable SRAM support in mvebu_v7_defconfig Gregory CLEMENT
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann, Evan Wang

From: Marcin Wojtas <mw@semihalf.com>

This commit enables finding appropriate mbus window and obtaining its
target id and attribute for given physical address in two separate
routines, both for IO and DRAM windows. This functionality
is needed for Armada XP/38x Network Controller's Buffer Manager and
PnC configuration.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>

[DRAM window information reference in LKv3.10]
Signed-off-by: Evan Wang <xswang@marvell.com>
---
 drivers/bus/mvebu-mbus.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mbus.h     |  3 +++
 2 files changed, 54 insertions(+)

diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index c43c3d2baf73..3d1c0c3880ec 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -948,6 +948,57 @@ void mvebu_mbus_get_pcie_io_aperture(struct resource *res)
 	*res = mbus_state.pcie_io_aperture;
 }
 
+int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr)
+{
+	const struct mbus_dram_target_info *dram;
+	int i;
+
+	/* Get dram info */
+	dram = mv_mbus_dram_info();
+	if (!dram) {
+		pr_err("missing DRAM information\n");
+		return -ENODEV;
+	}
+
+	/* Try to find matching DRAM window for phyaddr */
+	for (i = 0; i < dram->num_cs; i++) {
+		const struct mbus_dram_window *cs = dram->cs + i;
+
+		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size)) {
+			*target = dram->mbus_dram_target_id;
+			*attr = cs->mbus_attr;
+			return 0;
+		}
+	}
+
+	pr_err("invalid dram address 0x%x\n", phyaddr);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mvebu_mbus_get_dram_win_info);
+
+int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
+			       u8 *attr)
+{
+	int win;
+
+	for (win = 0; win < mbus_state.soc->num_wins; win++) {
+		u64 wbase;
+		int enabled;
+
+		mvebu_mbus_read_window(&mbus_state, win, &enabled, &wbase,
+				       size, target, attr, NULL);
+
+		if (!enabled)
+			continue;
+
+		if (wbase <= phyaddr && phyaddr <= wbase + *size)
+			return win;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mvebu_mbus_get_io_win_info);
+
 static __init int mvebu_mbus_debugfs_init(void)
 {
 	struct mvebu_mbus_state *s = &mbus_state;
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index 1f7bc630d225..ea34a867caa0 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -69,6 +69,9 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(vo
 int mvebu_mbus_save_cpu_target(u32 *store_addr);
 void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
 void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
+int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr);
+int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
+			       u8 *attr);
 int mvebu_mbus_add_window_remap_by_id(unsigned int target,
 				      unsigned int attribute,
 				      phys_addr_t base, size_t size,
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 02/10] ARM: mvebu: enable SRAM support in mvebu_v7_defconfig
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 01/10] bus: mvebu-mbus: provide api for obtaining IO and DRAM window information Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management Gregory CLEMENT
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

From: Marcin Wojtas <mw@semihalf.com>

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 arch/arm/configs/mvebu_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index c6729bf0a8dd..fe57e20ba200 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -58,6 +58,7 @@ CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_PXA3xx=y
 CONFIG_MTD_SPI_NOR=y
+CONFIG_SRAM=y
 CONFIG_EEPROM_AT24=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 01/10] bus: mvebu-mbus: provide api for obtaining IO and DRAM window information Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 02/10] ARM: mvebu: enable SRAM support in mvebu_v7_defconfig Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 20:12   ` Marcin Wojtas
  2016-01-12 19:10 ` [PATCH net-next 04/10] ARM: mvebu: add buffer manager nodes to armada-38x.dtsi Gregory CLEMENT
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

From: Marcin Wojtas <mw@semihalf.com>

Buffer manager (BM) is a dedicated hardware unit that can be used by all
ethernet ports of Armada XP and 38x SoC's. It allows to offload CPU on RX
path by sparing DRAM access on refilling buffer pool, hardware-based
filling of descriptor ring data and better memory utilization due to HW
arbitration for using 'short' pools for small packets.

Tests performed with A388 SoC working as a network bridge between two
packet generators showed increase of maximum processed 64B packets by
~20k (~555k packets with BM enabled vs ~535 packets without BM). Also
when pushing 1500B-packets with a line rate achieved, CPU load decreased
from around 25% without BM to 20% with BM.

BM comprise up to 4 buffer pointers' (BP) rings kept in DRAM, which
are called external BP pools - BPPE. Allocating and releasing buffer
pointers (BP) to/from BPPE is performed indirectly by write/read access
to a dedicated internal SRAM, where internal BP pools (BPPI) are placed.
BM hardware controls status of BPPE automatically, as well as assigning
proper buffers to RX descriptors. For more details please refer to
Functional Specification of Armada XP or 38x SoC.

In order to enable support for a separate hardware block, common for all
ports, a new driver has to be implemented ('mvneta_bm'). It provides
initialization sequence of address space, clocks, registers, SRAM,
empty pools' structures and also obtaining optional configuration
from DT (please refer to device tree binding documentation). mvneta_bm
exposes also a necessary API to mvneta driver, as well as a dedicated
structure with BM information (bm_priv), whose presence is used as a
flag notifying of BM usage by port. It has to be ensured that mvneta_bm
probe is executed prior to the ones in ports' driver. In case BM is not
used or its probe fails, mvneta falls back to use software buffer
management.

A sequence executed in mvneta_probe function is modified in order to have
an access to needed resources before possible port's BM initialization is
done. According to port-pools mapping provided by DT appropriate registers
are configured and the buffer pools are filled. RX path is modified
accordingly. Becaues the hardware allows a wide variety of configuration
options, following assumptions are made:
* using BM mechanisms can be selectively disabled/enabled basing
  on DT configuration among the ports
* 'long' pool's single buffer size is tied to port's MTU
* using 'long' pool by port is obligatory and it cannot be shared
* using 'short' pool for smaller packets is optional
* one 'short' pool can be shared among all ports

This commit enables hardware buffer management operation cooperating with
existing mvneta driver. New device tree binding documentation is added and
the one of mvneta is updated accordingly.

[gregory.clement@free-electrons.com: removed the suspend/resume part]

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 .../bindings/net/marvell-armada-370-neta.txt       |  19 +-
 .../devicetree/bindings/net/marvell-neta-bm.txt    |  49 ++
 drivers/net/ethernet/marvell/Kconfig               |  14 +
 drivers/net/ethernet/marvell/Makefile              |   1 +
 drivers/net/ethernet/marvell/mvneta.c              | 395 +++++++++++++--
 drivers/net/ethernet/marvell/mvneta_bm.c           | 562 +++++++++++++++++++++
 drivers/net/ethernet/marvell/mvneta_bm.h           | 167 ++++++
 7 files changed, 1153 insertions(+), 54 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/marvell-neta-bm.txt
 create mode 100644 drivers/net/ethernet/marvell/mvneta_bm.c
 create mode 100644 drivers/net/ethernet/marvell/mvneta_bm.h

diff --git a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
index aeea50c84e92..854b14ac95ae 100644
--- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
+++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
@@ -13,15 +13,30 @@ Optional properties:
   Value is presented in bytes. If not used, by default 1600B is set for
   "marvell,armada-370-neta" and 9800B for others.
 
+Optional properties (valid only for Armada XP/38x):
+
+- buffer-manager: a phandle to a buffer manager node. Please refer to
+  Documentation/devicetree/bindings/net/marvell-neta-bm.txt
+- bm,pool-long: ID of a pool, that will accept all packets of a size
+  higher than 'short' pool's threshold (if set) and up to MTU value.
+  Obligatory, when the port is supposed to use hardware
+  buffer management.
+- bm,pool-short: ID of a pool, that will be used for accepting
+  packets of a size lower than given threshold. If not set, the port
+  will use a single 'long' pool for all packets, as defined above.
+
 Example:
 
-ethernet@d0070000 {
+ethernet@70000 {
 	compatible = "marvell,armada-370-neta";
-	reg = <0xd0070000 0x2500>;
+	reg = <0x70000 0x2500>;
 	interrupts = <8>;
 	clocks = <&gate_clk 4>;
 	tx-csum-limit = <9800>
 	status = "okay";
 	phy = <&phy0>;
 	phy-mode = "rgmii-id";
+	buffer-manager = <&bm>;
+	bm,pool-long = <0>;
+	bm,pool-short = <1>;
 };
diff --git a/Documentation/devicetree/bindings/net/marvell-neta-bm.txt b/Documentation/devicetree/bindings/net/marvell-neta-bm.txt
new file mode 100644
index 000000000000..c1b1d7c3bde1
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/marvell-neta-bm.txt
@@ -0,0 +1,49 @@
+* Marvell Armada 380/XP Buffer Manager driver (BM)
+
+Required properties:
+
+- compatible: should be "marvell,armada-380-neta-bm".
+- reg: address and length of the register set for the device.
+- clocks: a pointer to the reference clock for this device.
+- internal-mem: a phandle to BM internal SRAM definition.
+
+Optional properties (port):
+
+- pool<0 : 3>,capacity: size of external buffer pointers' ring maintained
+  in DRAM. Can be set for each pool (id 0 : 3) separately. The value has
+  to be chosen between 128 and 16352 and it also has to be aligned to 32.
+  Otherwise the driver would adjust a given number or choose default if
+  not set.
+- pool<0 : 3>,pkt-size: maximum size of a packet accepted by a given buffer
+  pointers' pool (id 0 : 3). It will be taken into consideration only when pool
+  type is 'short'. For 'long' ones it would be overridden by port's MTU.
+  If not set a driver will choose a default value.
+
+In order to see how to hook the BM to a given ethernet port, please
+refer to Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt.
+
+Example:
+
+- main node:
+
+bm: bm@c8000 {
+	compatible = "marvell,armada-380-neta-bm";
+	reg = <0xc8000 0xac>;
+	clocks = <&gateclk 13>;
+	internal-mem = <&bm_bppi>;
+	status = "okay";
+	pool2,capacity = <4096>;
+	pool1,pkt-size = <512>;
+};
+
+- internal SRAM node:
+
+bm_bppi: bm-bppi {
+	compatible = "mmio-sram";
+	reg = <MBUS_ID(0x0c, 0x04) 0 0x100000>;
+	ranges = <0 MBUS_ID(0x0c, 0x04) 0 0x100000>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	clocks = <&gateclk 13>;
+	status = "okay";
+};
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index a1c862b4664d..6c8dc6d62572 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -40,11 +40,25 @@ config MVMDIO
 
 	  This driver is used by the MV643XX_ETH and MVNETA drivers.
 
+config MVNETA_BM
+	tristate "Marvell Armada 38x/XP network interface BM support"
+	depends on MVNETA
+	---help---
+	  This driver supports auxiliary block of the network
+	  interface units in the Marvell ARMADA XP and ARMADA 38x SoC
+	  family, which is called buffer manager.
+
+	  This driver, when enabled, strictly cooperates with mvneta
+	  driver and is common for all network ports of the devices,
+	  even for Armada 370 SoC, which doesn't support hardware
+	  buffer management.
+
 config MVNETA
 	tristate "Marvell Armada 370/38x/XP network interface support"
 	depends on PLAT_ORION
 	select MVMDIO
 	select FIXED_PHY
+	select MVNETA_BM
 	---help---
 	  This driver supports the network interface units in the
 	  Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile
index f6425bd2884b..ff1bffa74803 100644
--- a/drivers/net/ethernet/marvell/Makefile
+++ b/drivers/net/ethernet/marvell/Makefile
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_MVMDIO) += mvmdio.o
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+obj-$(CONFIG_MVNETA_BM) += mvneta_bm.o
 obj-$(CONFIG_MVNETA) += mvneta.o
 obj-$(CONFIG_MVPP2) += mvpp2.o
 obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index fabc8df40392..d82481cdbfbb 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -33,10 +33,15 @@
 #include <linux/phy.h>
 #include <linux/clk.h>
 #include <linux/cpu.h>
+#include "mvneta_bm.h"
 
 /* Registers */
 #define MVNETA_RXQ_CONFIG_REG(q)                (0x1400 + ((q) << 2))
 #define      MVNETA_RXQ_HW_BUF_ALLOC            BIT(0)
+#define      MVNETA_RXQ_SHORT_POOL_ID_SHIFT	4
+#define      MVNETA_RXQ_SHORT_POOL_ID_MASK	0x30
+#define      MVNETA_RXQ_LONG_POOL_ID_SHIFT	6
+#define      MVNETA_RXQ_LONG_POOL_ID_MASK	0xc0
 #define      MVNETA_RXQ_PKT_OFFSET_ALL_MASK     (0xf    << 8)
 #define      MVNETA_RXQ_PKT_OFFSET_MASK(offs)   ((offs) << 8)
 #define MVNETA_RXQ_THRESHOLD_REG(q)             (0x14c0 + ((q) << 2))
@@ -50,6 +55,9 @@
 #define MVNETA_RXQ_STATUS_UPDATE_REG(q)         (0x1500 + ((q) << 2))
 #define      MVNETA_RXQ_ADD_NON_OCCUPIED_SHIFT  16
 #define      MVNETA_RXQ_ADD_NON_OCCUPIED_MAX    255
+#define MVNETA_PORT_POOL_BUFFER_SZ_REG(pool)	(0x1700 + ((pool) << 2))
+#define      MVNETA_PORT_POOL_BUFFER_SZ_SHIFT	3
+#define      MVNETA_PORT_POOL_BUFFER_SZ_MASK	0xfff8
 #define MVNETA_PORT_RX_RESET                    0x1cc0
 #define      MVNETA_PORT_RX_DMA_RESET           BIT(0)
 #define MVNETA_PHY_ADDR                         0x2000
@@ -107,6 +115,7 @@
 #define MVNETA_GMAC_CLOCK_DIVIDER                0x24f4
 #define      MVNETA_GMAC_1MS_CLOCK_ENABLE        BIT(31)
 #define MVNETA_ACC_MODE                          0x2500
+#define MVNETA_BM_ADDRESS                        0x2504
 #define MVNETA_CPU_MAP(cpu)                      (0x2540 + ((cpu) << 2))
 #define      MVNETA_CPU_RXQ_ACCESS_ALL_MASK      0x000000ff
 #define      MVNETA_CPU_TXQ_ACCESS_ALL_MASK      0x0000ff00
@@ -253,7 +262,10 @@
 #define MVNETA_CPU_D_CACHE_LINE_SIZE    32
 #define MVNETA_TX_CSUM_DEF_SIZE		1600
 #define MVNETA_TX_CSUM_MAX_SIZE		9800
-#define MVNETA_ACC_MODE_EXT		1
+#define MVNETA_ACC_MODE_EXT1		1
+#define MVNETA_ACC_MODE_EXT2		2
+
+#define MVNETA_MAX_DECODE_WIN		6
 
 /* Timeout constants */
 #define MVNETA_TX_DISABLE_TIMEOUT_MSEC	1000
@@ -293,7 +305,8 @@
 	((addr >= txq->tso_hdrs_phys) && \
 	 (addr < txq->tso_hdrs_phys + txq->size * TSO_HEADER_SIZE))
 
-#define MVNETA_RX_BUF_SIZE(pkt_size)   ((pkt_size) + NET_SKB_PAD)
+#define MVNETA_RX_GET_BM_POOL_ID(rxd) \
+	(((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT)
 
 struct mvneta_statistic {
 	unsigned short offset;
@@ -359,6 +372,7 @@ struct mvneta_pcpu_port {
 };
 
 struct mvneta_port {
+	u8 id;
 	struct mvneta_pcpu_port __percpu	*ports;
 	struct mvneta_pcpu_stats __percpu	*stats;
 
@@ -387,6 +401,11 @@ struct mvneta_port {
 	unsigned int tx_csum_limit;
 	unsigned int use_inband_status:1;
 
+	struct mvneta_bm *bm_priv;
+	struct mvneta_bm_pool *pool_long;
+	struct mvneta_bm_pool *pool_short;
+	int bm_win_id;
+
 	u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
 
 	u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
@@ -412,6 +431,8 @@ struct mvneta_port {
 #define MVNETA_TX_L4_CSUM_NOT	BIT(31)
 
 #define MVNETA_RXD_ERR_CRC		0x0
+#define MVNETA_RXD_BM_POOL_SHIFT	13
+#define MVNETA_RXD_BM_POOL_MASK		(BIT(13) | BIT(14))
 #define MVNETA_RXD_ERR_SUMMARY		BIT(16)
 #define MVNETA_RXD_ERR_OVERRUN		BIT(17)
 #define MVNETA_RXD_ERR_LEN		BIT(18)
@@ -822,6 +843,214 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
 	mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
 }
 
+/* Enable buffer management (BM) */
+static void mvneta_rxq_bm_enable(struct mvneta_port *pp,
+				 struct mvneta_rx_queue *rxq)
+{
+	u32 val;
+
+	val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
+	val |= MVNETA_RXQ_HW_BUF_ALLOC;
+	mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
+}
+
+/* Notify HW about port's assignment of pool for bigger packets */
+static void mvneta_rxq_long_pool_set(struct mvneta_port *pp,
+				     struct mvneta_rx_queue *rxq)
+{
+	u32 val;
+
+	val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
+	val &= ~MVNETA_RXQ_LONG_POOL_ID_MASK;
+	val |= (pp->pool_long->id << MVNETA_RXQ_LONG_POOL_ID_SHIFT);
+
+	mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
+}
+
+/* Notify HW about port's assignment of pool for smaller packets */
+static void mvneta_rxq_short_pool_set(struct mvneta_port *pp,
+				      struct mvneta_rx_queue *rxq)
+{
+	u32 val;
+
+	val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
+	val &= ~MVNETA_RXQ_SHORT_POOL_ID_MASK;
+	val |= (pp->pool_short->id << MVNETA_RXQ_SHORT_POOL_ID_SHIFT);
+
+	mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
+}
+
+/* Set port's receive buffer size for assigned BM pool */
+static inline void mvneta_bm_pool_bufsize_set(struct mvneta_port *pp,
+					      int buf_size,
+					      u8 pool_id)
+{
+	u32 val;
+
+	if (!IS_ALIGNED(buf_size, 8)) {
+		dev_warn(pp->dev->dev.parent,
+			 "illegal buf_size value %d, round to %d\n",
+			 buf_size, ALIGN(buf_size, 8));
+		buf_size = ALIGN(buf_size, 8);
+	}
+
+	val = mvreg_read(pp, MVNETA_PORT_POOL_BUFFER_SZ_REG(pool_id));
+	val |= buf_size & MVNETA_PORT_POOL_BUFFER_SZ_MASK;
+	mvreg_write(pp, MVNETA_PORT_POOL_BUFFER_SZ_REG(pool_id), val);
+}
+
+/* Configure MBUS window in order to enable access BM internal SRAM */
+static int mvneta_mbus_io_win_set(struct mvneta_port *pp, u32 base, u32 wsize,
+				  u8 target, u8 attr)
+{
+	u32 win_enable, win_protect;
+	int i;
+
+	win_enable = mvreg_read(pp, MVNETA_BASE_ADDR_ENABLE);
+
+	if (pp->bm_win_id < 0) {
+		/* Find first not occupied window */
+		for (i = 0; i < MVNETA_MAX_DECODE_WIN; i++) {
+			if (win_enable & (1 << i)) {
+				pp->bm_win_id = i;
+				break;
+			}
+		}
+		if (i == MVNETA_MAX_DECODE_WIN)
+			return -ENOMEM;
+	} else {
+		i = pp->bm_win_id;
+	}
+
+	mvreg_write(pp, MVNETA_WIN_BASE(i), 0);
+	mvreg_write(pp, MVNETA_WIN_SIZE(i), 0);
+
+	if (i < 4)
+		mvreg_write(pp, MVNETA_WIN_REMAP(i), 0);
+
+	mvreg_write(pp, MVNETA_WIN_BASE(i), (base & 0xffff0000) |
+		    (attr << 8) | target);
+
+	mvreg_write(pp, MVNETA_WIN_SIZE(i), (wsize - 1) & 0xffff0000);
+
+	win_protect = mvreg_read(pp, MVNETA_ACCESS_PROTECT_ENABLE);
+	win_protect |= 3 << (2 * i);
+	mvreg_write(pp, MVNETA_ACCESS_PROTECT_ENABLE, win_protect);
+
+	win_enable &= ~(1 << i);
+	mvreg_write(pp, MVNETA_BASE_ADDR_ENABLE, win_enable);
+
+	return 0;
+}
+
+/* Assign and initialize pools for port. In case of fail
+ * buffer manager will remain disabled for current port.
+ */
+static int mvneta_bm_port_init(struct platform_device *pdev,
+			       struct mvneta_port *pp)
+{
+	struct device_node *dn = pdev->dev.of_node;
+	u32 long_pool_id, short_pool_id, wsize;
+	u8 target, attr;
+	int err;
+
+	/* Get BM window information */
+	err = mvebu_mbus_get_io_win_info(pp->bm_priv->bppi_phys_addr, &wsize,
+					 &target, &attr);
+	if (err < 0)
+		return err;
+
+	pp->bm_win_id = -1;
+
+	/* Open NETA -> BM window */
+	err = mvneta_mbus_io_win_set(pp, pp->bm_priv->bppi_phys_addr, wsize,
+				     target, attr);
+	if (err < 0) {
+		netdev_info(pp->dev, "fail to configure mbus window to BM\n");
+		return err;
+	}
+
+	if (of_property_read_u32(dn, "bm,pool-long", &long_pool_id)) {
+		netdev_info(pp->dev, "missing long pool id\n");
+		return -EINVAL;
+	}
+
+	/* Create port's long pool depending on mtu */
+	pp->pool_long = mvneta_bm_pool_use(pp->bm_priv, long_pool_id,
+					   MVNETA_BM_LONG, pp->id,
+					   MVNETA_RX_PKT_SIZE(pp->dev->mtu));
+	if (!pp->pool_long) {
+		netdev_info(pp->dev, "fail to obtain long pool for port\n");
+		return -ENOMEM;
+	}
+
+	pp->pool_long->port_map |= 1 << pp->id;
+
+	mvneta_bm_pool_bufsize_set(pp, pp->pool_long->buf_size,
+				   pp->pool_long->id);
+
+	/* If short pool id is not defined, assume using single pool */
+	if (of_property_read_u32(dn, "bm,pool-short", &short_pool_id))
+		short_pool_id = long_pool_id;
+
+	/* Create port's short pool */
+	pp->pool_short = mvneta_bm_pool_use(pp->bm_priv, short_pool_id,
+					    MVNETA_BM_SHORT, pp->id,
+					    MVNETA_BM_SHORT_PKT_SIZE);
+	if (!pp->pool_short) {
+		netdev_info(pp->dev, "fail to obtain short pool for port\n");
+		mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_long, 1 << pp->id);
+		return -ENOMEM;
+	}
+
+	if (short_pool_id != long_pool_id) {
+		pp->pool_short->port_map |= 1 << pp->id;
+		mvneta_bm_pool_bufsize_set(pp, pp->pool_short->buf_size,
+					   pp->pool_short->id);
+	}
+
+	return 0;
+}
+
+/* Update settings of a pool for bigger packets */
+static void mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
+{
+	struct mvneta_bm_pool *bm_pool = pp->pool_long;
+	int num;
+
+	/* Release all buffers from long pool */
+	mvneta_bm_bufs_free(pp->bm_priv, bm_pool, 1 << pp->id);
+	if (bm_pool->buf_num) {
+		WARN(1, "cannot free all buffers in pool %d\n",
+		     bm_pool->id);
+		goto bm_mtu_err;
+	}
+
+	bm_pool->pkt_size = MVNETA_RX_PKT_SIZE(mtu);
+	bm_pool->buf_size = MVNETA_RX_BUF_SIZE(bm_pool->pkt_size);
+	bm_pool->frag_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
+			  SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(bm_pool->pkt_size));
+
+	/* Fill entire long pool */
+	num = mvneta_bm_bufs_add(pp->bm_priv, bm_pool, bm_pool->size);
+	if (num != bm_pool->size) {
+		WARN(1, "pool %d: %d of %d allocated\n",
+		     bm_pool->id, num, bm_pool->size);
+		goto bm_mtu_err;
+	}
+	mvneta_bm_pool_bufsize_set(pp, bm_pool->buf_size, bm_pool->id);
+
+	return;
+
+bm_mtu_err:
+	mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_long, 1 << pp->id);
+	mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_short, 1 << pp->id);
+
+	pp->bm_priv = NULL;
+	mvreg_write(pp, MVNETA_ACC_MODE, MVNETA_ACC_MODE_EXT1);
+	netdev_info(pp->dev, "fail to update MTU, fall back to software BM\n");
+}
+
 /* Start the Ethernet port RX and TX activity */
 static void mvneta_port_up(struct mvneta_port *pp)
 {
@@ -1109,9 +1338,17 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
 	mvreg_write(pp, MVNETA_PORT_RX_RESET, 0);
 
 	/* Set Port Acceleration Mode */
-	val = MVNETA_ACC_MODE_EXT;
+	if (pp->bm_priv)
+		/* HW buffer management + legacy parser */
+		val = MVNETA_ACC_MODE_EXT2;
+	else
+		/* SW buffer management + legacy parser */
+		val = MVNETA_ACC_MODE_EXT1;
 	mvreg_write(pp, MVNETA_ACC_MODE, val);
 
+	if (pp->bm_priv)
+		mvreg_write(pp, MVNETA_BM_ADDRESS, pp->bm_priv->bppi_phys_addr);
+
 	/* Update val of portCfg register accordingly with all RxQueue types */
 	val = MVNETA_PORT_CONFIG_DEFL_VALUE(pp->rxq_def);
 	mvreg_write(pp, MVNETA_PORT_CONFIG, val);
@@ -1478,23 +1715,7 @@ static void mvneta_txq_done(struct mvneta_port *pp,
 	}
 }
 
-static void *mvneta_frag_alloc(const struct mvneta_port *pp)
-{
-	if (likely(pp->frag_size <= PAGE_SIZE))
-		return netdev_alloc_frag(pp->frag_size);
-	else
-		return kmalloc(pp->frag_size, GFP_ATOMIC);
-}
-
-static void mvneta_frag_free(const struct mvneta_port *pp, void *data)
-{
-	if (likely(pp->frag_size <= PAGE_SIZE))
-		skb_free_frag(data);
-	else
-		kfree(data);
-}
-
-/* Refill processing */
+/* Refill processing for SW buffer management */
 static int mvneta_rx_refill(struct mvneta_port *pp,
 			    struct mvneta_rx_desc *rx_desc)
 
@@ -1502,7 +1723,7 @@ static int mvneta_rx_refill(struct mvneta_port *pp,
 	dma_addr_t phys_addr;
 	void *data;
 
-	data = mvneta_frag_alloc(pp);
+	data = mvneta_frag_alloc(pp->frag_size);
 	if (!data)
 		return -ENOMEM;
 
@@ -1510,7 +1731,7 @@ static int mvneta_rx_refill(struct mvneta_port *pp,
 				   MVNETA_RX_BUF_SIZE(pp->pkt_size),
 				   DMA_FROM_DEVICE);
 	if (unlikely(dma_mapping_error(pp->dev->dev.parent, phys_addr))) {
-		mvneta_frag_free(pp, data);
+		mvneta_frag_free(pp->frag_size, data);
 		return -ENOMEM;
 	}
 
@@ -1556,17 +1777,20 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
 	int rx_done, i;
 
 	rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq);
+	if (rx_done)
+		mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
+
+	if (pp->bm_priv)
+		return;
+
 	for (i = 0; i < rxq->size; i++) {
 		struct mvneta_rx_desc *rx_desc = rxq->descs + i;
 		void *data = (void *)rx_desc->buf_cookie;
 
 		dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr,
 				 MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
-		mvneta_frag_free(pp, data);
+		mvneta_frag_free(pp->frag_size, data);
 	}
-
-	if (rx_done)
-		mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
 }
 
 /* Main rx processing */
@@ -1578,6 +1802,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
 	int rx_done;
 	u32 rcvd_pkts = 0;
 	u32 rcvd_bytes = 0;
+	bool bm_in_use;
 
 	/* Get number of received packets */
 	rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq);
@@ -1587,23 +1812,35 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
 
 	rx_done = 0;
 
+	bm_in_use = pp->bm_priv ? true : false;
+
 	/* Fairness NAPI loop */
 	while (rx_done < rx_todo) {
 		struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq);
+		struct mvneta_bm_pool *bm_pool = NULL;
 		struct sk_buff *skb;
 		unsigned char *data;
 		dma_addr_t phys_addr;
-		u32 rx_status;
+		u32 rx_status, frag_size;
 		int rx_bytes, err;
+		u8 pool_id;
 
 		rx_done++;
 		rx_status = rx_desc->status;
 		rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
 		data = (unsigned char *)rx_desc->buf_cookie;
 		phys_addr = rx_desc->buf_phys_addr;
+		if (bm_in_use) {
+			pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc);
+			bm_pool = &pp->bm_priv->bm_pools[pool_id];
+		}
 
 		if (!mvneta_rxq_desc_is_first_last(rx_status) ||
 		    (rx_status & MVNETA_RXD_ERR_SUMMARY)) {
+			/* Return the buffer to the pool */
+			if (bm_in_use)
+				mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
+						      rx_desc->buf_phys_addr);
 		err_drop_frame:
 			dev->stats.rx_errors++;
 			mvneta_rx_error(pp, rx_desc);
@@ -1633,25 +1870,38 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
 			rcvd_pkts++;
 			rcvd_bytes += rx_bytes;
 
+			/* Return the buffer to the pool */
+			if (bm_in_use)
+				mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
+						      rx_desc->buf_phys_addr);
+
 			/* leave the descriptor and buffer untouched */
 			continue;
 		}
 
 		/* Refill processing */
-		err = mvneta_rx_refill(pp, rx_desc);
+		err = bm_in_use ? mvneta_bm_pool_refill(pp->bm_priv, bm_pool) :
+				  mvneta_rx_refill(pp, rx_desc);
 		if (err) {
 			netdev_err(dev, "Linux processing - Can't refill\n");
 			rxq->missed++;
 			goto err_drop_frame;
 		}
 
-		skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size);
+		frag_size = bm_in_use ? bm_pool->frag_size : pp->frag_size;
+
+		skb = build_skb(data, frag_size > PAGE_SIZE ? 0 : frag_size);
 
 		/* After refill old buffer has to be unmapped regardless
 		 * the skb is successfully built or not.
 		 */
-		dma_unmap_single(dev->dev.parent, phys_addr,
-				 MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
+		if (bm_in_use)
+			dma_unmap_single(&pp->bm_priv->pdev->dev, phys_addr,
+					 bm_pool->buf_size, DMA_FROM_DEVICE);
+		else
+			dma_unmap_single(dev->dev.parent, phys_addr,
+					 MVNETA_RX_BUF_SIZE(pp->pkt_size),
+					 DMA_FROM_DEVICE);
 
 		if (!skb)
 			goto err_drop_frame;
@@ -2346,9 +2596,17 @@ static int mvneta_rxq_init(struct mvneta_port *pp,
 	mvneta_rx_pkts_coal_set(pp, rxq, rxq->pkts_coal);
 	mvneta_rx_time_coal_set(pp, rxq, rxq->time_coal);
 
-	/* Fill RXQ with buffers from RX pool */
-	mvneta_rxq_buf_size_set(pp, rxq, MVNETA_RX_BUF_SIZE(pp->pkt_size));
-	mvneta_rxq_bm_disable(pp, rxq);
+	if (!pp->bm_priv) {
+		/* Fill RXQ with buffers from RX pool */
+		mvneta_rxq_buf_size_set(pp, rxq,
+					MVNETA_RX_BUF_SIZE(pp->pkt_size));
+		mvneta_rxq_bm_disable(pp, rxq);
+	} else {
+		mvneta_rxq_bm_enable(pp, rxq);
+		mvneta_rxq_long_pool_set(pp, rxq);
+		mvneta_rxq_short_pool_set(pp, rxq);
+	}
+
 	mvneta_rxq_fill(pp, rxq, rxq->size);
 
 	return 0;
@@ -2650,6 +2908,9 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu)
 	dev->mtu = mtu;
 
 	if (!netif_running(dev)) {
+		if (pp->bm_priv)
+			mvneta_bm_update_mtu(pp, mtu);
+
 		netdev_update_features(dev);
 		return 0;
 	}
@@ -2662,6 +2923,9 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu)
 	mvneta_cleanup_txqs(pp);
 	mvneta_cleanup_rxqs(pp);
 
+	if (pp->bm_priv)
+		mvneta_bm_update_mtu(pp, mtu);
+
 	pp->pkt_size = MVNETA_RX_PKT_SIZE(dev->mtu);
 	pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) +
 	                SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
@@ -3538,6 +3802,7 @@ static int mvneta_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct device_node *dn = pdev->dev.of_node;
 	struct device_node *phy_node;
+	struct device_node *bm_node;
 	struct mvneta_port *pp;
 	struct net_device *dev;
 	const char *dt_mac_addr;
@@ -3665,26 +3930,51 @@ static int mvneta_probe(struct platform_device *pdev)
 
 	pp->tx_csum_limit = tx_csum_limit;
 
+	dram_target_info = mv_mbus_dram_info();
+	if (dram_target_info)
+		mvneta_conf_mbus_windows(pp, dram_target_info);
+
 	pp->tx_ring_size = MVNETA_MAX_TXD;
 	pp->rx_ring_size = MVNETA_MAX_RXD;
 
 	pp->dev = dev;
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
+	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+	dev->hw_features |= dev->features;
+	dev->vlan_features |= dev->features;
+	dev->priv_flags |= IFF_UNICAST_FLT;
+	dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
+
+	err = register_netdev(dev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to register\n");
+		goto err_free_stats;
+	}
+
+	pp->id = dev->ifindex;
+
+	/* Obtain access to BM resources if enabled and already initialized */
+	bm_node = of_parse_phandle(dn, "buffer-manager", 0);
+	if (bm_node && bm_node->data) {
+		pp->bm_priv = bm_node->data;
+		err = mvneta_bm_port_init(pdev, pp);
+		if (err < 0) {
+			dev_info(&pdev->dev, "use SW buffer management\n");
+			pp->bm_priv = NULL;
+		}
+	}
+
 	err = mvneta_init(&pdev->dev, pp);
 	if (err < 0)
-		goto err_free_stats;
+		goto err_netdev;
 
 	err = mvneta_port_power_up(pp, phy_mode);
 	if (err < 0) {
 		dev_err(&pdev->dev, "can't power up port\n");
-		goto err_free_stats;
+		goto err_netdev;
 	}
 
-	dram_target_info = mv_mbus_dram_info();
-	if (dram_target_info)
-		mvneta_conf_mbus_windows(pp, dram_target_info);
-
 	for_each_present_cpu(cpu) {
 		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 
@@ -3692,18 +3982,6 @@ static int mvneta_probe(struct platform_device *pdev)
 		port->pp = pp;
 	}
 
-	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
-	dev->hw_features |= dev->features;
-	dev->vlan_features |= dev->features;
-	dev->priv_flags |= IFF_UNICAST_FLT;
-	dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
-
-	err = register_netdev(dev);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to register\n");
-		goto err_free_stats;
-	}
-
 	netdev_info(dev, "Using %s mac address %pM\n", mac_from,
 		    dev->dev_addr);
 
@@ -3719,6 +3997,13 @@ static int mvneta_probe(struct platform_device *pdev)
 
 	return 0;
 
+err_netdev:
+	unregister_netdev(dev);
+	if (pp->bm_priv) {
+		mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_long, 1 << pp->id);
+		mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_short,
+				       1 << pp->id);
+	}
 err_free_stats:
 	free_percpu(pp->stats);
 err_free_ports:
@@ -3748,6 +4033,12 @@ static int mvneta_remove(struct platform_device *pdev)
 	of_node_put(pp->phy_node);
 	free_netdev(dev);
 
+	if (pp->bm_priv) {
+		mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_long, 1 << pp->id);
+		mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_short,
+				       1 << pp->id);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c
new file mode 100644
index 000000000000..ff7e73c6d31c
--- /dev/null
+++ b/drivers/net/ethernet/marvell/mvneta_bm.c
@@ -0,0 +1,562 @@
+/*
+ * Driver for Marvell NETA network controller Buffer Manager.
+ *
+ * Copyright (C) 2015 Marvell
+ *
+ * Marcin Wojtas <mw@semihalf.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/genalloc.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mbus.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include "mvneta_bm.h"
+
+#define MVNETA_BM_DRIVER_NAME "mvneta_bm"
+#define MVNETA_BM_DRIVER_VERSION "1.0"
+
+static void mvneta_bm_write(struct mvneta_bm *priv, u32 offset, u32 data)
+{
+	writel(data, priv->reg_base + offset);
+}
+
+static u32 mvneta_bm_read(struct mvneta_bm *priv, u32 offset)
+{
+	return readl(priv->reg_base + offset);
+}
+
+static void mvneta_bm_pool_enable(struct mvneta_bm *priv, int pool_id)
+{
+	u32 val;
+
+	val = mvneta_bm_read(priv, MVNETA_BM_POOL_BASE_REG(pool_id));
+	val |= MVNETA_BM_POOL_ENABLE_MASK;
+	mvneta_bm_write(priv, MVNETA_BM_POOL_BASE_REG(pool_id), val);
+
+	/* Clear BM cause register */
+	mvneta_bm_write(priv, MVNETA_BM_INTR_CAUSE_REG, 0);
+}
+
+static void mvneta_bm_pool_disable(struct mvneta_bm *priv, int pool_id)
+{
+	u32 val;
+
+	val = mvneta_bm_read(priv, MVNETA_BM_POOL_BASE_REG(pool_id));
+	val &= ~MVNETA_BM_POOL_ENABLE_MASK;
+	mvneta_bm_write(priv, MVNETA_BM_POOL_BASE_REG(pool_id), val);
+}
+
+static inline void mvneta_bm_config_set(struct mvneta_bm *priv, u32 mask)
+{
+	u32 val;
+
+	val = mvneta_bm_read(priv, MVNETA_BM_CONFIG_REG);
+	val |= mask;
+	mvneta_bm_write(priv, MVNETA_BM_CONFIG_REG, val);
+}
+
+static inline void mvneta_bm_config_clear(struct mvneta_bm *priv, u32 mask)
+{
+	u32 val;
+
+	val = mvneta_bm_read(priv, MVNETA_BM_CONFIG_REG);
+	val &= ~mask;
+	mvneta_bm_write(priv, MVNETA_BM_CONFIG_REG, val);
+}
+
+static void mvneta_bm_pool_target_set(struct mvneta_bm *priv, int pool_id,
+				      u8 target_id, u8 attr)
+{
+	u32 val;
+
+	val = mvneta_bm_read(priv, MVNETA_BM_XBAR_POOL_REG(pool_id));
+	val &= ~MVNETA_BM_TARGET_ID_MASK(pool_id);
+	val &= ~MVNETA_BM_XBAR_ATTR_MASK(pool_id);
+	val |= MVNETA_BM_TARGET_ID_VAL(pool_id, target_id);
+	val |= MVNETA_BM_XBAR_ATTR_VAL(pool_id, attr);
+
+	mvneta_bm_write(priv, MVNETA_BM_XBAR_POOL_REG(pool_id), val);
+}
+
+void *mvneta_frag_alloc(unsigned int frag_size)
+{
+	if (likely(frag_size <= PAGE_SIZE))
+		return netdev_alloc_frag(frag_size);
+	else
+		return kmalloc(frag_size, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(mvneta_frag_alloc);
+
+void mvneta_frag_free(unsigned int frag_size, void *data)
+{
+	if (likely(frag_size <= PAGE_SIZE))
+		skb_free_frag(data);
+	else
+		kfree(data);
+}
+EXPORT_SYMBOL_GPL(mvneta_frag_free);
+
+/* Allocate skb for BM pool */
+void *mvneta_buf_alloc(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
+		       dma_addr_t *buf_phys_addr)
+{
+	void *buf;
+	dma_addr_t phys_addr;
+
+	buf = mvneta_frag_alloc(bm_pool->frag_size);
+	if (!buf)
+		return NULL;
+
+	/* In order to update buf_cookie field of RX descriptor properly,
+	 * BM hardware expects buf virtual address to be placed in the
+	 * first four bytes of mapped buffer.
+	 */
+	*(u32 *)buf = (u32)buf;
+	phys_addr = dma_map_single(&priv->pdev->dev, buf, bm_pool->buf_size,
+				   DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(&priv->pdev->dev, phys_addr))) {
+		mvneta_frag_free(bm_pool->frag_size, buf);
+		return NULL;
+	}
+	*buf_phys_addr = phys_addr;
+
+	return buf;
+}
+
+/* Refill processing for HW buffer management */
+int mvneta_bm_pool_refill(struct mvneta_bm *priv,
+			  struct mvneta_bm_pool *bm_pool)
+{
+	dma_addr_t buf_phys_addr;
+	void *buf;
+
+	buf = mvneta_buf_alloc(priv, bm_pool, &buf_phys_addr);
+	if (!buf)
+		return -ENOMEM;
+
+	mvneta_bm_pool_put_bp(priv, bm_pool, buf_phys_addr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mvneta_bm_pool_refill);
+
+/* Allocate buffers for the pool */
+int mvneta_bm_bufs_add(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
+		       int buf_num)
+{
+	int err, i;
+
+	if (bm_pool->buf_num == bm_pool->size) {
+		dev_dbg(&priv->pdev->dev, "pool %d already filled\n",
+			bm_pool->id);
+		return bm_pool->buf_num;
+	}
+
+	if (buf_num < 0 ||
+	    (buf_num + bm_pool->buf_num > bm_pool->size)) {
+		dev_err(&priv->pdev->dev,
+			"cannot allocate %d buffers for pool %d\n",
+			buf_num, bm_pool->id);
+		return 0;
+	}
+
+	for (i = 0; i < buf_num; i++) {
+		err = mvneta_bm_pool_refill(priv, bm_pool);
+		if (err < 0)
+			break;
+	}
+
+	/* Update BM driver with number of buffers added to pool */
+	bm_pool->buf_num += i;
+
+	dev_dbg(&priv->pdev->dev,
+		"%s pool %d: pkt_size=%4d, buf_size=%4d, frag_size=%4d\n",
+		bm_pool->type == MVNETA_BM_SHORT ? "short" : "long",
+		bm_pool->id, bm_pool->pkt_size, bm_pool->buf_size,
+		bm_pool->frag_size);
+
+	dev_dbg(&priv->pdev->dev,
+		"%s pool %d: %d of %d buffers added\n",
+		bm_pool->type == MVNETA_BM_SHORT ? "short" : "long",
+		bm_pool->id, i, buf_num);
+
+	return i;
+}
+
+/* Create pool */
+static int mvneta_bm_pool_create(struct mvneta_bm *priv,
+				 struct mvneta_bm_pool *bm_pool)
+{
+	struct platform_device *pdev = priv->pdev;
+	u8 target_id, attr;
+	int size_bytes, err;
+
+	size_bytes = sizeof(u32) * bm_pool->size;
+	bm_pool->virt_addr = dma_alloc_coherent(&pdev->dev, size_bytes,
+						&bm_pool->phys_addr,
+						GFP_KERNEL);
+	if (!bm_pool->virt_addr)
+		return -ENOMEM;
+
+	if (!IS_ALIGNED((u32)bm_pool->virt_addr, MVNETA_BM_POOL_PTR_ALIGN)) {
+		dma_free_coherent(&pdev->dev, size_bytes, bm_pool->virt_addr,
+				  bm_pool->phys_addr);
+		dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n",
+			bm_pool->id, MVNETA_BM_POOL_PTR_ALIGN);
+		return -ENOMEM;
+	}
+
+	err = mvebu_mbus_get_dram_win_info(bm_pool->phys_addr, &target_id,
+					   &attr);
+	if (err < 0) {
+		dma_free_coherent(&pdev->dev, size_bytes, bm_pool->virt_addr,
+				  bm_pool->phys_addr);
+		return err;
+	}
+
+	/* Set pool address */
+	mvneta_bm_write(priv, MVNETA_BM_POOL_BASE_REG(bm_pool->id),
+			bm_pool->phys_addr);
+
+	mvneta_bm_pool_target_set(priv, bm_pool->id, target_id,  attr);
+	mvneta_bm_pool_enable(priv, bm_pool->id);
+
+	return 0;
+}
+
+/* Notify the driver that BM pool is being used as specific type and return the
+ * pool pointer on success
+ */
+struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
+					  enum mvneta_bm_type type, u8 port_id,
+					  int pkt_size)
+{
+	struct mvneta_bm_pool *new_pool = &priv->bm_pools[pool_id];
+	int num, err;
+
+	if (new_pool->type == MVNETA_BM_LONG &&
+	    new_pool->port_map != 1 << port_id) {
+		dev_err(&priv->pdev->dev,
+			"long pool cannot be shared by the ports\n");
+		return NULL;
+	}
+
+	if (new_pool->type == MVNETA_BM_SHORT && new_pool->type != type) {
+		dev_err(&priv->pdev->dev,
+			"mixing pools' types between the ports is forbidden\n");
+		return NULL;
+	}
+
+	if (new_pool->pkt_size == 0 || type != MVNETA_BM_SHORT)
+		new_pool->pkt_size = pkt_size;
+
+	/* Allocate buffers in case BM pool hasn't been used yet */
+	if (new_pool->type == MVNETA_BM_FREE) {
+		new_pool->type = type;
+		new_pool->buf_size = MVNETA_RX_BUF_SIZE(new_pool->pkt_size);
+		new_pool->frag_size =
+			SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(new_pool->pkt_size)) +
+			SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+		/* Create new pool */
+		err = mvneta_bm_pool_create(priv, new_pool);
+		if (err) {
+			dev_err(&priv->pdev->dev, "fail to create pool %d\n",
+				new_pool->id);
+			return NULL;
+		}
+
+		/* Allocate buffers for this pool */
+		num = mvneta_bm_bufs_add(priv, new_pool, new_pool->size);
+		if (num != new_pool->size) {
+			WARN(1, "pool %d: %d of %d allocated\n",
+			     new_pool->id, num, new_pool->size);
+			return NULL;
+		}
+	}
+
+	return new_pool;
+}
+EXPORT_SYMBOL_GPL(mvneta_bm_pool_use);
+
+/* Free all buffers from the pool */
+void mvneta_bm_bufs_free(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
+			 u8 port_map)
+{
+	int i;
+
+	bm_pool->port_map &= ~port_map;
+	if (bm_pool->port_map)
+		return;
+
+	mvneta_bm_config_set(priv, MVNETA_BM_EMPTY_LIMIT_MASK);
+
+	for (i = 0; i < bm_pool->buf_num; i++) {
+		dma_addr_t buf_phys_addr;
+		u32 *vaddr;
+
+		/* Get buffer physical address (indirect access) */
+		buf_phys_addr = mvneta_bm_pool_get_bp(priv, bm_pool);
+
+		/* Work-around to the problems when destroying the pool,
+		 * when it occurs that a read access to BPPI returns 0.
+		 */
+		if (buf_phys_addr == 0)
+			continue;
+
+		vaddr = phys_to_virt(buf_phys_addr);
+		if (!vaddr)
+			break;
+
+		dma_unmap_single(&priv->pdev->dev, buf_phys_addr,
+				 bm_pool->buf_size, DMA_FROM_DEVICE);
+		mvneta_frag_free(bm_pool->frag_size, vaddr);
+	}
+
+	mvneta_bm_config_clear(priv, MVNETA_BM_EMPTY_LIMIT_MASK);
+
+	/* Update BM driver with number of buffers removed from pool */
+	bm_pool->buf_num -= i;
+}
+
+/* Cleanup pool */
+void mvneta_bm_pool_destroy(struct mvneta_bm *priv,
+			    struct mvneta_bm_pool *bm_pool, u8 port_map)
+{
+	bm_pool->port_map &= ~port_map;
+	if (bm_pool->port_map)
+		return;
+
+	bm_pool->type = MVNETA_BM_FREE;
+
+	mvneta_bm_bufs_free(priv, bm_pool, port_map);
+	if (bm_pool->buf_num)
+		WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
+
+	if (bm_pool->virt_addr) {
+		dma_free_coherent(&priv->pdev->dev, sizeof(u32) * bm_pool->size,
+				  bm_pool->virt_addr, bm_pool->phys_addr);
+		bm_pool->virt_addr = NULL;
+	}
+
+	mvneta_bm_pool_disable(priv, bm_pool->id);
+}
+EXPORT_SYMBOL_GPL(mvneta_bm_pool_destroy);
+
+static void mvneta_bm_pools_init(struct mvneta_bm *priv)
+{
+	struct device_node *dn = priv->pdev->dev.of_node;
+	struct mvneta_bm_pool *bm_pool;
+	char prop[15];
+	u32 size;
+	int i;
+
+	/* Activate BM unit */
+	mvneta_bm_write(priv, MVNETA_BM_COMMAND_REG, MVNETA_BM_START_MASK);
+
+	/* Create all pools with maximum size */
+	for (i = 0; i < MVNETA_BM_POOLS_NUM; i++) {
+		bm_pool = &priv->bm_pools[i];
+		bm_pool->id = i;
+		bm_pool->type = MVNETA_BM_FREE;
+
+		/* Reset read pointer */
+		mvneta_bm_write(priv, MVNETA_BM_POOL_READ_PTR_REG(i), 0);
+
+		/* Reset write pointer */
+		mvneta_bm_write(priv, MVNETA_BM_POOL_WRITE_PTR_REG(i), 0);
+
+		/* Configure pool size according to DT or use default value */
+		sprintf(prop, "pool%d,capacity", i);
+		if (of_property_read_u32(dn, prop, &size)) {
+			size = MVNETA_BM_POOL_CAP_DEF;
+		} else if (size > MVNETA_BM_POOL_CAP_MAX) {
+			dev_warn(&priv->pdev->dev,
+				 "Illegal pool %d capacity %d, set to %d\n",
+				 i, size, MVNETA_BM_POOL_CAP_MAX);
+			size = MVNETA_BM_POOL_CAP_MAX;
+		} else if (size < MVNETA_BM_POOL_CAP_MIN) {
+			dev_warn(&priv->pdev->dev,
+				 "Illegal pool %d capacity %d, set to %d\n",
+				 i, size, MVNETA_BM_POOL_CAP_MIN);
+			size = MVNETA_BM_POOL_CAP_MIN;
+		} else if (!IS_ALIGNED(size, MVNETA_BM_POOL_CAP_ALIGN)) {
+			dev_warn(&priv->pdev->dev,
+				 "Illegal pool %d capacity %d, round to %d\n",
+				 i, size, ALIGN(size,
+				 MVNETA_BM_POOL_CAP_ALIGN));
+			size = ALIGN(size, MVNETA_BM_POOL_CAP_ALIGN);
+		}
+		bm_pool->size = size;
+
+		mvneta_bm_write(priv, MVNETA_BM_POOL_SIZE_REG(i),
+				bm_pool->size);
+
+		/* Obtain custom pkt_size from DT */
+		sprintf(prop, "pool%d,pkt-size", i);
+		if (of_property_read_u32(dn, prop, &bm_pool->pkt_size))
+			bm_pool->pkt_size = 0;
+	}
+}
+
+static void mvneta_bm_default_set(struct mvneta_bm *priv)
+{
+	u32 val;
+
+	/* Mask BM all interrupts */
+	mvneta_bm_write(priv, MVNETA_BM_INTR_MASK_REG, 0);
+
+	/* Clear BM cause register */
+	mvneta_bm_write(priv, MVNETA_BM_INTR_CAUSE_REG, 0);
+
+	/* Set BM configuration register */
+	val = mvneta_bm_read(priv, MVNETA_BM_CONFIG_REG);
+
+	/* Reduce MaxInBurstSize from 32 BPs to 16 BPs */
+	val &= ~MVNETA_BM_MAX_IN_BURST_SIZE_MASK;
+	val |= MVNETA_BM_MAX_IN_BURST_SIZE_16BP;
+	mvneta_bm_write(priv, MVNETA_BM_CONFIG_REG, val);
+}
+
+static int mvneta_bm_init(struct mvneta_bm *priv)
+{
+	mvneta_bm_default_set(priv);
+
+	/* Allocate and initialize BM pools structures */
+	priv->bm_pools = devm_kcalloc(&priv->pdev->dev, MVNETA_BM_POOLS_NUM,
+				      sizeof(struct mvneta_bm_pool),
+				      GFP_KERNEL);
+	if (!priv->bm_pools)
+		return -ENOMEM;
+
+	mvneta_bm_pools_init(priv);
+
+	return 0;
+}
+
+static int mvneta_bm_get_sram(struct device_node *dn,
+			      struct mvneta_bm *priv)
+{
+	priv->bppi_pool = of_gen_pool_get(dn, "internal-mem", 0);
+	if (!priv->bppi_pool)
+		return -ENOMEM;
+
+	priv->bppi_virt_addr = gen_pool_dma_alloc(priv->bppi_pool,
+						  MVNETA_BM_BPPI_SIZE,
+						  &priv->bppi_phys_addr);
+	if (!priv->bppi_virt_addr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void mvneta_bm_put_sram(struct mvneta_bm *priv)
+{
+	gen_pool_free(priv->bppi_pool, priv->bppi_phys_addr,
+		      MVNETA_BM_BPPI_SIZE);
+}
+
+static int mvneta_bm_probe(struct platform_device *pdev)
+{
+	struct device_node *dn = pdev->dev.of_node;
+	struct mvneta_bm *priv;
+	struct resource *res;
+	int err;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct mvneta_bm), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->reg_base))
+		return PTR_ERR(priv->reg_base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+	err = clk_prepare_enable(priv->clk);
+	if (err < 0)
+		return err;
+
+	err = mvneta_bm_get_sram(dn, priv);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to allocate internal memory\n");
+		goto err_clk;
+	}
+
+	priv->pdev = pdev;
+
+	/* Initialize buffer manager internals */
+	err = mvneta_bm_init(priv);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to initialize controller\n");
+		goto err_sram;
+	}
+
+	dn->data = priv;
+	platform_set_drvdata(pdev, priv);
+
+	dev_info(&pdev->dev, "Buffer Manager for network controller enabled\n");
+
+	return 0;
+
+err_sram:
+	mvneta_bm_put_sram(priv);
+err_clk:
+	clk_disable_unprepare(priv->clk);
+	return err;
+}
+
+static int mvneta_bm_remove(struct platform_device *pdev)
+{
+	struct mvneta_bm *priv = platform_get_drvdata(pdev);
+	u8 all_ports_map = 0xff;
+	int i = 0;
+
+	for (i = 0; i < MVNETA_BM_POOLS_NUM; i++) {
+		struct mvneta_bm_pool *bm_pool = &priv->bm_pools[i];
+
+		mvneta_bm_pool_destroy(priv, bm_pool, all_ports_map);
+	}
+
+	mvneta_bm_put_sram(priv);
+
+	/* Dectivate BM unit */
+	mvneta_bm_write(priv, MVNETA_BM_COMMAND_REG, MVNETA_BM_STOP_MASK);
+
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+static const struct of_device_id mvneta_bm_match[] = {
+	{ .compatible = "marvell,armada-380-neta-bm" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mvneta_bm_match);
+
+static struct platform_driver mvneta_bm_driver = {
+	.probe = mvneta_bm_probe,
+	.remove = mvneta_bm_remove,
+	.driver = {
+		.name = MVNETA_BM_DRIVER_NAME,
+		.of_match_table = mvneta_bm_match,
+	},
+};
+
+module_platform_driver(mvneta_bm_driver);
+
+MODULE_DESCRIPTION("Marvell NETA Buffer Manager Driver - www.marvell.com");
+MODULE_AUTHOR("Marcin Wojtas <mw@semihalf.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/marvell/mvneta_bm.h b/drivers/net/ethernet/marvell/mvneta_bm.h
new file mode 100644
index 000000000000..f2449b843577
--- /dev/null
+++ b/drivers/net/ethernet/marvell/mvneta_bm.h
@@ -0,0 +1,167 @@
+/*
+ * Driver for Marvell NETA network controller Buffer Manager.
+ *
+ * Copyright (C) 2015 Marvell
+ *
+ * Marcin Wojtas <mw@semihalf.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _MVNETA_BM_H_
+#define _MVNETA_BM_H_
+
+/* BM Configuration Register */
+#define MVNETA_BM_CONFIG_REG			0x0
+#define    MVNETA_BM_STATUS_MASK		0x30
+#define    MVNETA_BM_ACTIVE_MASK		BIT(4)
+#define    MVNETA_BM_MAX_IN_BURST_SIZE_MASK	0x60000
+#define    MVNETA_BM_MAX_IN_BURST_SIZE_16BP	BIT(18)
+#define    MVNETA_BM_EMPTY_LIMIT_MASK		BIT(19)
+
+/* BM Activation Register */
+#define MVNETA_BM_COMMAND_REG			0x4
+#define    MVNETA_BM_START_MASK			BIT(0)
+#define    MVNETA_BM_STOP_MASK			BIT(1)
+#define    MVNETA_BM_PAUSE_MASK			BIT(2)
+
+/* BM Xbar interface Register */
+#define MVNETA_BM_XBAR_01_REG			0x8
+#define MVNETA_BM_XBAR_23_REG			0xc
+#define MVNETA_BM_XBAR_POOL_REG(pool)		\
+		(((pool) < 2) ? MVNETA_BM_XBAR_01_REG : MVNETA_BM_XBAR_23_REG)
+#define     MVNETA_BM_TARGET_ID_OFFS(pool)	(((pool) & 1) ? 16 : 0)
+#define     MVNETA_BM_TARGET_ID_MASK(pool)	\
+		(0xf << MVNETA_BM_TARGET_ID_OFFS(pool))
+#define     MVNETA_BM_TARGET_ID_VAL(pool, id)	\
+		((id) << MVNETA_BM_TARGET_ID_OFFS(pool))
+#define     MVNETA_BM_XBAR_ATTR_OFFS(pool)	(((pool) & 1) ? 20 : 4)
+#define     MVNETA_BM_XBAR_ATTR_MASK(pool)	\
+		(0xff << MVNETA_BM_XBAR_ATTR_OFFS(pool))
+#define     MVNETA_BM_XBAR_ATTR_VAL(pool, attr)	\
+		((attr) << MVNETA_BM_XBAR_ATTR_OFFS(pool))
+
+/* Address of External Buffer Pointers Pool Register */
+#define MVNETA_BM_POOL_BASE_REG(pool)		(0x10 + ((pool) << 4))
+#define     MVNETA_BM_POOL_ENABLE_MASK		BIT(0)
+
+/* External Buffer Pointers Pool RD pointer Register */
+#define MVNETA_BM_POOL_READ_PTR_REG(pool)	(0x14 + ((pool) << 4))
+#define     MVNETA_BM_POOL_SET_READ_PTR_MASK	0xfffc
+#define     MVNETA_BM_POOL_GET_READ_PTR_OFFS	16
+#define     MVNETA_BM_POOL_GET_READ_PTR_MASK	0xfffc0000
+
+/* External Buffer Pointers Pool WR pointer */
+#define MVNETA_BM_POOL_WRITE_PTR_REG(pool)	(0x18 + ((pool) << 4))
+#define     MVNETA_BM_POOL_SET_WRITE_PTR_OFFS	0
+#define     MVNETA_BM_POOL_SET_WRITE_PTR_MASK	0xfffc
+#define     MVNETA_BM_POOL_GET_WRITE_PTR_OFFS	16
+#define     MVNETA_BM_POOL_GET_WRITE_PTR_MASK	0xfffc0000
+
+/* External Buffer Pointers Pool Size Register */
+#define MVNETA_BM_POOL_SIZE_REG(pool)		(0x1c + ((pool) << 4))
+#define     MVNETA_BM_POOL_SIZE_MASK		0x3fff
+
+/* BM Interrupt Cause Register */
+#define MVNETA_BM_INTR_CAUSE_REG		(0x50)
+
+/* BM interrupt Mask Register */
+#define MVNETA_BM_INTR_MASK_REG			(0x54)
+
+/* Other definitions */
+#define MVNETA_BM_SHORT_PKT_SIZE		256
+#define MVNETA_BM_POOLS_NUM			4
+#define MVNETA_BM_POOL_CAP_MIN			128
+#define MVNETA_BM_POOL_CAP_DEF			2048
+#define MVNETA_BM_POOL_CAP_MAX			\
+		(16 * 1024 - MVNETA_BM_POOL_CAP_ALIGN)
+#define MVNETA_BM_POOL_CAP_ALIGN		32
+#define MVNETA_BM_POOL_PTR_ALIGN		32
+
+#define MVNETA_BM_POOL_ACCESS_OFFS		8
+
+#define MVNETA_BM_BPPI_SIZE			0x100000
+
+#define MVNETA_RX_BUF_SIZE(pkt_size)   ((pkt_size) + NET_SKB_PAD)
+
+enum mvneta_bm_type {
+	MVNETA_BM_FREE,
+	MVNETA_BM_LONG,
+	MVNETA_BM_SHORT
+};
+
+struct mvneta_bm {
+	void __iomem *reg_base;
+	struct clk *clk;
+	struct platform_device *pdev;
+
+	struct gen_pool *bppi_pool;
+	/* BPPI virtual base address */
+	void __iomem *bppi_virt_addr;
+	/* BPPI physical base address */
+	dma_addr_t bppi_phys_addr;
+
+	/* BM pools */
+	struct mvneta_bm_pool *bm_pools;
+};
+
+struct mvneta_bm_pool {
+	/* Pool number in the range 0-3 */
+	u8 id;
+	enum mvneta_bm_type type;
+
+	/* Buffer Pointers Pool External (BPPE) size in number of bytes */
+	int size;
+	/* Number of buffers used by this pool */
+	int buf_num;
+	/* Pool buffer size */
+	int buf_size;
+	/* Packet size */
+	int pkt_size;
+	/* Single frag size */
+	u32 frag_size;
+
+	/* BPPE virtual base address */
+	u32 *virt_addr;
+	/* BPPE physical base address */
+	dma_addr_t phys_addr;
+
+	/* Ports using BM pool */
+	u8 port_map;
+
+	struct mvneta_bm *priv;
+};
+
+/* Declarations and definitions */
+void *mvneta_frag_alloc(unsigned int frag_size);
+void mvneta_frag_free(unsigned int frag_size, void *data);
+void mvneta_bm_pool_destroy(struct mvneta_bm *priv,
+			    struct mvneta_bm_pool *bm_pool, u8 port_map);
+void mvneta_bm_bufs_free(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
+			 u8 port_map);
+int mvneta_bm_bufs_add(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
+		       int buf_num);
+int mvneta_bm_pool_refill(struct mvneta_bm *priv,
+			  struct mvneta_bm_pool *bm_pool);
+struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
+					  enum mvneta_bm_type type, u8 port_id,
+					  int pkt_size);
+
+static inline void mvneta_bm_pool_put_bp(struct mvneta_bm *priv,
+					 struct mvneta_bm_pool *bm_pool,
+					 dma_addr_t buf_phys_addr)
+{
+	writel_relaxed(buf_phys_addr, priv->bppi_virt_addr +
+		       (bm_pool->id << MVNETA_BM_POOL_ACCESS_OFFS));
+}
+
+static inline u32 mvneta_bm_pool_get_bp(struct mvneta_bm *priv,
+					struct mvneta_bm_pool *bm_pool)
+{
+	return readl_relaxed(priv->bppi_virt_addr +
+			     (bm_pool->id << MVNETA_BM_POOL_ACCESS_OFFS));
+}
+
+#endif
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 04/10] ARM: mvebu: add buffer manager nodes to armada-38x.dtsi
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (2 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 05/10] ARM: mvebu: enable buffer manager support on Armada 38x boards Gregory CLEMENT
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

From: Marcin Wojtas <mw@semihalf.com>

Armada 38x network controller supports hardware buffer management (BM).
Since it is now enabled in mvneta driver, appropriate nodes can be added
to armada-38x.dtsi - for the actual common BM unit (bm@c8000) and its
internal SRAM (bm-bppi), which is used for indirect access to buffer
pointer ring residing in DRAM.

Pools - ports mapping, bm-bppi entry in 'soc' node's ranges and optional
parameters are supposed to be set in board files.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 arch/arm/boot/dts/armada-38x.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index e8b7f6726772..1b7d690d8e10 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -540,6 +540,14 @@
 				status = "disabled";
 			};
 
+			bm: bm@c8000 {
+				compatible = "marvell,armada-380-neta-bm";
+				reg = <0xc8000 0xac>;
+				clocks = <&gateclk 13>;
+				internal-mem = <&bm_bppi>;
+				status = "disabled";
+			};
+
 			sata@e0000 {
 				compatible = "marvell,armada-380-ahci";
 				reg = <0xe0000 0x2000>;
@@ -618,6 +626,16 @@
 			#size-cells = <1>;
 			ranges = <0 MBUS_ID(0x09, 0x15) 0 0x800>;
 		};
+
+		bm_bppi: bm-bppi {
+			compatible = "mmio-sram";
+			reg = <MBUS_ID(0x0c, 0x04) 0 0x100000>;
+			ranges = <0 MBUS_ID(0x0c, 0x04) 0 0x100000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&gateclk 13>;
+			status = "disabled";
+		};
 	};
 
 	clocks {
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 05/10] ARM: mvebu: enable buffer manager support on Armada 38x boards
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (3 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 04/10] ARM: mvebu: add buffer manager nodes to armada-38x.dtsi Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 06/10] ARM: mvebu: add buffer manager nodes to armada-xp.dtsi Gregory CLEMENT
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

From: Marcin Wojtas <mw@semihalf.com>

Since mvneta driver supports using hardware buffer management (BM), in
order to use it, board files have to be adjusted accordingly. This commit
enables BM on:
* A385-DB-AP - each port has its own pool for long and common pool for
short packets,
* A388-DB - to each port unique 'short' and 'long' pools are mapped,
* A388-GP - same as above.

Moreover appropriate entry is added to 'soc' node ranges, as well as "okay"
status for 'bm' and 'bm-bppi' (internal SRAM) nodes.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 arch/arm/boot/dts/armada-385-db-ap.dts | 20 +++++++++++++++++++-
 arch/arm/boot/dts/armada-388-db.dts    | 17 ++++++++++++++++-
 arch/arm/boot/dts/armada-388-gp.dts    | 17 ++++++++++++++++-
 3 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts
index acd5b1519edb..5f9451be21ff 100644
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
@@ -61,7 +61,8 @@
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 
 		internal-regs {
 			spi1: spi@10680 {
@@ -138,12 +139,18 @@
 				status = "okay";
 				phy = <&phy2>;
 				phy-mode = "sgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <1>;
+				bm,pool-short = <3>;
 			};
 
 			ethernet@34000 {
 				status = "okay";
 				phy = <&phy1>;
 				phy-mode = "sgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <2>;
+				bm,pool-short = <3>;
 			};
 
 			ethernet@70000 {
@@ -157,6 +164,13 @@
 				status = "okay";
 				phy = <&phy0>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <0>;
+				bm,pool-short = <3>;
+			};
+
+			bm@c8000 {
+				status = "okay";
 			};
 
 			nfc: flash@d0000 {
@@ -178,6 +192,10 @@
 			};
 		};
 
+		bm-bppi {
+			status = "okay";
+		};
+
 		pcie-controller {
 			status = "okay";
 
diff --git a/arch/arm/boot/dts/armada-388-db.dts b/arch/arm/boot/dts/armada-388-db.dts
index ff47af57f091..ea93ed727030 100644
--- a/arch/arm/boot/dts/armada-388-db.dts
+++ b/arch/arm/boot/dts/armada-388-db.dts
@@ -66,7 +66,8 @@
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 
 		internal-regs {
 			spi@10600 {
@@ -99,6 +100,9 @@
 				status = "okay";
 				phy = <&phy1>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <2>;
+				bm,pool-short = <3>;
 			};
 
 			usb@58000 {
@@ -109,6 +113,9 @@
 				status = "okay";
 				phy = <&phy0>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <0>;
+				bm,pool-short = <1>;
 			};
 
 			mdio@72004 {
@@ -129,6 +136,10 @@
 				status = "okay";
 			};
 
+			bm@c8000 {
+				status = "okay";
+			};
+
 			flash@d0000 {
 				status = "okay";
 				num-cs = <1>;
@@ -169,6 +180,10 @@
 			};
 		};
 
+		bm-bppi {
+			status = "okay";
+		};
+
 		pcie-controller {
 			status = "okay";
 			/*
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index a633be3defda..0a3bd7fba488 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -60,7 +60,8 @@
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 
 		internal-regs {
 			spi@10600 {
@@ -133,6 +134,9 @@
 				status = "okay";
 				phy = <&phy1>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <2>;
+				bm,pool-short = <3>;
 			};
 
 			/* CON4 */
@@ -152,6 +156,9 @@
 				status = "okay";
 				phy = <&phy0>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <0>;
+				bm,pool-short = <1>;
 			};
 
 
@@ -186,6 +193,10 @@
 				};
 			};
 
+			bm@c8000 {
+				status = "okay";
+			};
+
 			sata@e0000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&sata2_pins>, <&sata3_pins>;
@@ -240,6 +251,10 @@
 			};
 		};
 
+		bm-bppi {
+			status = "okay";
+		};
+
 		pcie-controller {
 			status = "okay";
 			/*
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 06/10] ARM: mvebu: add buffer manager nodes to armada-xp.dtsi
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (4 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 05/10] ARM: mvebu: enable buffer manager support on Armada 38x boards Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 07/10] ARM: mvebu: enable buffer manager support on Armada XP boards Gregory CLEMENT
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

From: Marcin Wojtas <mw@semihalf.com>

Armada XP network controller supports hardware buffer management (BM).
Since it is now enabled in mvneta driver, appropriate nodes can be added
to armada-xp.dtsi - for the actual common BM unit (bm@c0000) and its
internal SRAM (bm-bppi), which is used for indirect access to buffer
pointer ring residing in DRAM.

Pools - ports mapping, bm-bppi entry in 'soc' node's ranges and optional
parameters are supposed to be set in board files.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 arch/arm/boot/dts/armada-xp.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index be23196829bb..bd459360d7a6 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -253,6 +253,14 @@
 				marvell,crypto-sram-size = <0x800>;
 			};
 
+			bm: bm@c0000 {
+				compatible = "marvell,armada-380-neta-bm";
+				reg = <0xc0000 0xac>;
+				clocks = <&gateclk 13>;
+				internal-mem = <&bm_bppi>;
+				status = "disabled";
+			};
+
 			xor@f0900 {
 				compatible = "marvell,orion-xor";
 				reg = <0xF0900 0x100
@@ -291,6 +299,16 @@
 			#size-cells = <1>;
 			ranges = <0 MBUS_ID(0x09, 0x05) 0 0x800>;
 		};
+
+		bm_bppi: bm-bppi {
+			compatible = "mmio-sram";
+			reg = <MBUS_ID(0x0c, 0x04) 0 0x100000>;
+			ranges = <0 MBUS_ID(0x0c, 0x04) 0 0x100000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&gateclk 13>;
+			status = "disabled";
+		};
 	};
 
 	clocks {
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 07/10] ARM: mvebu: enable buffer manager support on Armada XP boards
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (5 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 06/10] ARM: mvebu: add buffer manager nodes to armada-xp.dtsi Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 19:10 ` [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info Gregory CLEMENT
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

From: Marcin Wojtas <mw@semihalf.com>

Since mvneta driver supports using hardware buffer management (BM), in
order to use it, board files have to be adjusted accordingly. This commit
enables BM on AXP-DB and AXP-GP in same manner - because number of ports
on those boards is the same as number of possible pools, each port is
supposed to use single pool for all kind of packets.

Moreover appropriate entry is added to 'soc' node ranges, as well as "okay"
status for 'bm' and 'bm-bppi' (internal SRAM) nodes.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 arch/arm/boot/dts/armada-xp-db.dts | 19 ++++++++++++++++++-
 arch/arm/boot/dts/armada-xp-gp.dts | 19 ++++++++++++++++++-
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index f774101416a5..30657302305d 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -77,7 +77,8 @@
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
 			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
 			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000
+			  MBUS_ID(0x0c, 0x04) 0 0 0xf1200000 0x100000>;
 
 		devbus-bootcs {
 			status = "okay";
@@ -181,21 +182,33 @@
 				status = "okay";
 				phy = <&phy0>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <0>;
 			};
 			ethernet@74000 {
 				status = "okay";
 				phy = <&phy1>;
 				phy-mode = "rgmii-id";
+				buffer-manager = <&bm>;
+				bm,pool-long = <1>;
 			};
 			ethernet@30000 {
 				status = "okay";
 				phy = <&phy2>;
 				phy-mode = "sgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <2>;
 			};
 			ethernet@34000 {
 				status = "okay";
 				phy = <&phy3>;
 				phy-mode = "sgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <3>;
+			};
+
+			bm@c0000 {
+				status = "okay";
 			};
 
 			mvsdio@d4000 {
@@ -230,5 +243,9 @@
 				};
 			};
 		};
+
+		bm-bppi {
+			status = "okay";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 4878d7353069..a1ded01d0c07 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -96,7 +96,8 @@
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
 			  MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
 			  MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
-			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
+			  MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000
+			  MBUS_ID(0x0c, 0x04) 0 0 0xf1200000 0x100000>;
 
 		devbus-bootcs {
 			status = "okay";
@@ -196,21 +197,29 @@
 				status = "okay";
 				phy = <&phy0>;
 				phy-mode = "qsgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <0>;
 			};
 			ethernet@74000 {
 				status = "okay";
 				phy = <&phy1>;
 				phy-mode = "qsgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <1>;
 			};
 			ethernet@30000 {
 				status = "okay";
 				phy = <&phy2>;
 				phy-mode = "qsgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <2>;
 			};
 			ethernet@34000 {
 				status = "okay";
 				phy = <&phy3>;
 				phy-mode = "qsgmii";
+				buffer-manager = <&bm>;
+				bm,pool-long = <3>;
 			};
 
 			/* Front-side USB slot */
@@ -235,6 +244,10 @@
 				};
 			};
 
+			bm@c0000 {
+				status = "okay";
+			};
+
 			nand@d0000 {
 				status = "okay";
 				num-cs = <1>;
@@ -243,5 +256,9 @@
 				nand-on-flash-bbt;
 			};
 		};
+
+		bm-bppi {
+			status = "okay";
+		};
 	};
 };
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (6 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 07/10] ARM: mvebu: enable buffer manager support on Armada XP boards Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 21:42   ` Marcin Wojtas
  2016-01-14 14:00   ` David Laight
  2016-01-12 19:10 ` [PATCH net-next 09/10] net: Add a hardware buffer management helper API Gregory CLEMENT
                   ` (2 subsequent siblings)
  10 siblings, 2 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/bus/mvebu-mbus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 3d1c0c3880ec..214bb964165b 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -964,7 +964,7 @@ int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr)
 	for (i = 0; i < dram->num_cs; i++) {
 		const struct mbus_dram_window *cs = dram->cs + i;
 
-		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size)) {
+		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size - 1)) {
 			*target = dram->mbus_dram_target_id;
 			*attr = cs->mbus_attr;
 			return 0;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 09/10] net: Add a hardware buffer management helper API
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (7 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-27 20:02   ` Florian Fainelli
  2016-01-12 19:10 ` [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework Gregory CLEMENT
  2016-01-12 20:52 ` [PATCH net-next 00/10] Proposal for a API set for HW Buffer management David Miller
  10 siblings, 1 reply; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

This basic implementation allows to share code between driver using
hardware buffer management. As the code is hardware agnostic, there is
few helpers, most of the optimization brought by the an HW BM has to be
done at driver level.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 include/net/hwbm.h | 19 +++++++++++++
 net/core/Makefile  |  2 +-
 net/core/hwbm.c    | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 include/net/hwbm.h
 create mode 100644 net/core/hwbm.c

diff --git a/include/net/hwbm.h b/include/net/hwbm.h
new file mode 100644
index 000000000000..898ccd2fb58d
--- /dev/null
+++ b/include/net/hwbm.h
@@ -0,0 +1,19 @@
+#ifndef _HWBM_H
+#define _HWBM_H
+
+struct hwbm_pool {
+	/* Size of the buffers managed */
+	int size;
+	/* Number of buffers currently used by this pool */
+	int buf_num;
+	/* constructor called during alocation */
+	int (*construct)(struct hwbm_pool *bm_pool, void *buf);
+	/* private data */
+	void *priv;
+};
+
+void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf);
+int hwbm_pool_refill(struct hwbm_pool *bm_pool);
+int hwbm_pool_add(struct hwbm_pool *bm_pool, int buf_num);
+
+#endif /* _HWBM_H */
diff --git a/net/core/Makefile b/net/core/Makefile
index 0b835de04de3..df81bf11f072 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
 obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
-			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o
+			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o hwbm.o
 
 obj-$(CONFIG_XFRM) += flow.o
 obj-y += net-sysfs.o
diff --git a/net/core/hwbm.c b/net/core/hwbm.c
new file mode 100644
index 000000000000..d5d40d63cb34
--- /dev/null
+++ b/net/core/hwbm.c
@@ -0,0 +1,78 @@
+/* Support for hardware buffer manager.
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/skbuff.h>
+#include <net/hwbm.h>
+
+void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf)
+{
+	if (likely(bm_pool->size <= PAGE_SIZE))
+		skb_free_frag(buf);
+	else
+		kfree(buf);
+}
+EXPORT_SYMBOL_GPL(hwbm_buf_free);
+
+/* Refill processing for HW buffer management */
+int hwbm_pool_refill(struct hwbm_pool *bm_pool)
+{
+	void *buf;
+	int frag_size = bm_pool->size;
+
+	if (likely(frag_size <= PAGE_SIZE))
+		buf = netdev_alloc_frag(frag_size);
+	else
+		buf = kmalloc(frag_size, GFP_ATOMIC);
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (bm_pool->construct)
+		if (bm_pool->construct(bm_pool, buf)) {
+			hwbm_buf_free(bm_pool, buf);
+			return -ENOMEM;
+		}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hwbm_pool_refill);
+
+int hwbm_pool_add(struct hwbm_pool *bm_pool, int buf_num)
+{
+	int err, i;
+
+	if (bm_pool->buf_num == bm_pool->size) {
+		pr_debug("pool already filled\n");
+		return bm_pool->buf_num;
+	}
+
+	if (buf_num + bm_pool->buf_num > bm_pool->size) {
+		pr_debug("cannot allocate %d buffers for pool\n",
+			 buf_num);
+		return 0;
+	}
+
+	for (i = 0; i < buf_num; i++) {
+		err = hwbm_pool_refill(bm_pool);
+		if (err < 0)
+			break;
+	}
+
+	/* Update BM driver with number of buffers added to pool */
+	bm_pool->buf_num += i;
+
+	pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);
+
+	return i;
+}
+EXPORT_SYMBOL_GPL(hwbm_pool_add);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (8 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 09/10] net: Add a hardware buffer management helper API Gregory CLEMENT
@ 2016-01-12 19:10 ` Gregory CLEMENT
  2016-01-12 22:40   ` Marcin Wojtas
  2016-01-12 20:52 ` [PATCH net-next 00/10] Proposal for a API set for HW Buffer management David Miller
  10 siblings, 1 reply; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-12 19:10 UTC (permalink / raw)
  To: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, linux-arm-kernel, Lior Amsalem, Nadav Haklai,
	Marcin Wojtas, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Now that the hardware buffer management framework had been introduced,
let's use it.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/net/ethernet/marvell/mvneta.c    |  44 +++++++---
 drivers/net/ethernet/marvell/mvneta_bm.c | 140 +++++++------------------------
 drivers/net/ethernet/marvell/mvneta_bm.h |  11 +--
 3 files changed, 67 insertions(+), 128 deletions(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index d82481cdbfbb..d32291c4e5aa 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -33,6 +33,7 @@
 #include <linux/phy.h>
 #include <linux/clk.h>
 #include <linux/cpu.h>
+#include <net/hwbm.h>
 #include "mvneta_bm.h"
 
 /* Registers */
@@ -1016,11 +1017,12 @@ static int mvneta_bm_port_init(struct platform_device *pdev,
 static void mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
 {
 	struct mvneta_bm_pool *bm_pool = pp->pool_long;
+	struct hwbm_pool *hwbm_pool = &bm_pool->hwbm_pool;
 	int num;
 
 	/* Release all buffers from long pool */
 	mvneta_bm_bufs_free(pp->bm_priv, bm_pool, 1 << pp->id);
-	if (bm_pool->buf_num) {
+	if (hwbm_pool->buf_num) {
 		WARN(1, "cannot free all buffers in pool %d\n",
 		     bm_pool->id);
 		goto bm_mtu_err;
@@ -1028,14 +1030,14 @@ static void mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
 
 	bm_pool->pkt_size = MVNETA_RX_PKT_SIZE(mtu);
 	bm_pool->buf_size = MVNETA_RX_BUF_SIZE(bm_pool->pkt_size);
-	bm_pool->frag_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
+	hwbm_pool->size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
 			  SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(bm_pool->pkt_size));
 
 	/* Fill entire long pool */
-	num = mvneta_bm_bufs_add(pp->bm_priv, bm_pool, bm_pool->size);
-	if (num != bm_pool->size) {
+	num = hwbm_pool_add(hwbm_pool, hwbm_pool->size);
+	if (num != hwbm_pool->size) {
 		WARN(1, "pool %d: %d of %d allocated\n",
-		     bm_pool->id, num, bm_pool->size);
+		     bm_pool->id, num, hwbm_pool->size);
 		goto bm_mtu_err;
 	}
 	mvneta_bm_pool_bufsize_set(pp, bm_pool->buf_size, bm_pool->id);
@@ -1715,6 +1717,14 @@ static void mvneta_txq_done(struct mvneta_port *pp,
 	}
 }
 
+void *mvneta_frag_alloc(unsigned int frag_size)
+{
+	if (likely(frag_size <= PAGE_SIZE))
+		return netdev_alloc_frag(frag_size);
+	else
+		return kmalloc(frag_size, GFP_ATOMIC);
+}
+
 /* Refill processing for SW buffer management */
 static int mvneta_rx_refill(struct mvneta_port *pp,
 			    struct mvneta_rx_desc *rx_desc)
@@ -1770,6 +1780,14 @@ static u32 mvneta_skb_tx_csum(struct mvneta_port *pp, struct sk_buff *skb)
 	return MVNETA_TX_L4_CSUM_NOT;
 }
 
+void mvneta_frag_free(unsigned int frag_size, void *data)
+{
+	if (likely(frag_size <= PAGE_SIZE))
+		skb_free_frag(data);
+	else
+		kfree(data);
+}
+
 /* Drop packets received by the RXQ and free buffers */
 static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
 				 struct mvneta_rx_queue *rxq)
@@ -1880,7 +1898,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
 		}
 
 		/* Refill processing */
-		err = bm_in_use ? mvneta_bm_pool_refill(pp->bm_priv, bm_pool) :
+		err = bm_in_use ? hwbm_pool_refill(&bm_pool->hwbm_pool) :
 				  mvneta_rx_refill(pp, rx_desc);
 		if (err) {
 			netdev_err(dev, "Linux processing - Can't refill\n");
@@ -1888,7 +1906,8 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
 			goto err_drop_frame;
 		}
 
-		frag_size = bm_in_use ? bm_pool->frag_size : pp->frag_size;
+		frag_size = bm_in_use ? bm_pool->hwbm_pool.size :
+					pp->frag_size;
 
 		skb = build_skb(data, frag_size > PAGE_SIZE ? 0 : frag_size);
 
@@ -3946,11 +3965,6 @@ static int mvneta_probe(struct platform_device *pdev)
 	dev->priv_flags |= IFF_UNICAST_FLT;
 	dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
 
-	err = register_netdev(dev);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to register\n");
-		goto err_free_stats;
-	}
 
 	pp->id = dev->ifindex;
 
@@ -3965,6 +3979,12 @@ static int mvneta_probe(struct platform_device *pdev)
 		}
 	}
 
+	err = register_netdev(dev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to register\n");
+		goto err_free_stats;
+	}
+
 	err = mvneta_init(&pdev->dev, pp);
 	if (err < 0)
 		goto err_netdev;
diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c
index ff7e73c6d31c..66a08910b5bf 100644
--- a/drivers/net/ethernet/marvell/mvneta_bm.c
+++ b/drivers/net/ethernet/marvell/mvneta_bm.c
@@ -10,16 +10,17 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/kernel.h>
+#include <linux/clk.h>
 #include <linux/genalloc.h>
-#include <linux/platform_device.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/mbus.h>
 #include <linux/module.h>
-#include <linux/io.h>
+#include <linux/netdevice.h>
 #include <linux/of.h>
-#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <net/hwbm.h>
 #include "mvneta_bm.h"
 
 #define MVNETA_BM_DRIVER_NAME "mvneta_bm"
@@ -88,35 +89,13 @@ static void mvneta_bm_pool_target_set(struct mvneta_bm *priv, int pool_id,
 	mvneta_bm_write(priv, MVNETA_BM_XBAR_POOL_REG(pool_id), val);
 }
 
-void *mvneta_frag_alloc(unsigned int frag_size)
-{
-	if (likely(frag_size <= PAGE_SIZE))
-		return netdev_alloc_frag(frag_size);
-	else
-		return kmalloc(frag_size, GFP_ATOMIC);
-}
-EXPORT_SYMBOL_GPL(mvneta_frag_alloc);
-
-void mvneta_frag_free(unsigned int frag_size, void *data)
+int mvneta_bm_construct(struct hwbm_pool *hwbm_pool, void *buf)
 {
-	if (likely(frag_size <= PAGE_SIZE))
-		skb_free_frag(data);
-	else
-		kfree(data);
-}
-EXPORT_SYMBOL_GPL(mvneta_frag_free);
-
-/* Allocate skb for BM pool */
-void *mvneta_buf_alloc(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
-		       dma_addr_t *buf_phys_addr)
-{
-	void *buf;
+	struct mvneta_bm_pool *bm_pool =
+		(struct mvneta_bm_pool *)hwbm_pool->priv;
+	struct mvneta_bm *priv = bm_pool->priv;
 	dma_addr_t phys_addr;
 
-	buf = mvneta_frag_alloc(bm_pool->frag_size);
-	if (!buf)
-		return NULL;
-
 	/* In order to update buf_cookie field of RX descriptor properly,
 	 * BM hardware expects buf virtual address to be placed in the
 	 * first four bytes of mapped buffer.
@@ -124,74 +103,13 @@ void *mvneta_buf_alloc(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 	*(u32 *)buf = (u32)buf;
 	phys_addr = dma_map_single(&priv->pdev->dev, buf, bm_pool->buf_size,
 				   DMA_FROM_DEVICE);
-	if (unlikely(dma_mapping_error(&priv->pdev->dev, phys_addr))) {
-		mvneta_frag_free(bm_pool->frag_size, buf);
-		return NULL;
-	}
-	*buf_phys_addr = phys_addr;
-
-	return buf;
-}
-
-/* Refill processing for HW buffer management */
-int mvneta_bm_pool_refill(struct mvneta_bm *priv,
-			  struct mvneta_bm_pool *bm_pool)
-{
-	dma_addr_t buf_phys_addr;
-	void *buf;
-
-	buf = mvneta_buf_alloc(priv, bm_pool, &buf_phys_addr);
-	if (!buf)
+	if (unlikely(dma_mapping_error(&priv->pdev->dev, phys_addr)))
 		return -ENOMEM;
 
-	mvneta_bm_pool_put_bp(priv, bm_pool, buf_phys_addr);
-
+	mvneta_bm_pool_put_bp(priv, bm_pool, phys_addr);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(mvneta_bm_pool_refill);
-
-/* Allocate buffers for the pool */
-int mvneta_bm_bufs_add(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
-		       int buf_num)
-{
-	int err, i;
-
-	if (bm_pool->buf_num == bm_pool->size) {
-		dev_dbg(&priv->pdev->dev, "pool %d already filled\n",
-			bm_pool->id);
-		return bm_pool->buf_num;
-	}
-
-	if (buf_num < 0 ||
-	    (buf_num + bm_pool->buf_num > bm_pool->size)) {
-		dev_err(&priv->pdev->dev,
-			"cannot allocate %d buffers for pool %d\n",
-			buf_num, bm_pool->id);
-		return 0;
-	}
-
-	for (i = 0; i < buf_num; i++) {
-		err = mvneta_bm_pool_refill(priv, bm_pool);
-		if (err < 0)
-			break;
-	}
-
-	/* Update BM driver with number of buffers added to pool */
-	bm_pool->buf_num += i;
 
-	dev_dbg(&priv->pdev->dev,
-		"%s pool %d: pkt_size=%4d, buf_size=%4d, frag_size=%4d\n",
-		bm_pool->type == MVNETA_BM_SHORT ? "short" : "long",
-		bm_pool->id, bm_pool->pkt_size, bm_pool->buf_size,
-		bm_pool->frag_size);
-
-	dev_dbg(&priv->pdev->dev,
-		"%s pool %d: %d of %d buffers added\n",
-		bm_pool->type == MVNETA_BM_SHORT ? "short" : "long",
-		bm_pool->id, i, buf_num);
-
-	return i;
-}
 
 /* Create pool */
 static int mvneta_bm_pool_create(struct mvneta_bm *priv,
@@ -200,8 +118,7 @@ static int mvneta_bm_pool_create(struct mvneta_bm *priv,
 	struct platform_device *pdev = priv->pdev;
 	u8 target_id, attr;
 	int size_bytes, err;
-
-	size_bytes = sizeof(u32) * bm_pool->size;
+	size_bytes = sizeof(u32) * bm_pool->hwbm_pool.size;
 	bm_pool->virt_addr = dma_alloc_coherent(&pdev->dev, size_bytes,
 						&bm_pool->phys_addr,
 						GFP_KERNEL);
@@ -262,11 +179,16 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
 
 	/* Allocate buffers in case BM pool hasn't been used yet */
 	if (new_pool->type == MVNETA_BM_FREE) {
+		struct hwbm_pool *hwbm_pool = &new_pool->hwbm_pool;
+
+		new_pool->priv = priv;
 		new_pool->type = type;
 		new_pool->buf_size = MVNETA_RX_BUF_SIZE(new_pool->pkt_size);
-		new_pool->frag_size =
+		hwbm_pool->size =
 			SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(new_pool->pkt_size)) +
 			SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+		hwbm_pool->construct = mvneta_bm_construct;
+		hwbm_pool->priv = new_pool;
 
 		/* Create new pool */
 		err = mvneta_bm_pool_create(priv, new_pool);
@@ -277,10 +199,10 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
 		}
 
 		/* Allocate buffers for this pool */
-		num = mvneta_bm_bufs_add(priv, new_pool, new_pool->size);
-		if (num != new_pool->size) {
+		num = hwbm_pool_add(hwbm_pool, hwbm_pool->size);
+		if (num != hwbm_pool->size) {
 			WARN(1, "pool %d: %d of %d allocated\n",
-			     new_pool->id, num, new_pool->size);
+			     new_pool->id, num, hwbm_pool->size);
 			return NULL;
 		}
 	}
@@ -301,7 +223,7 @@ void mvneta_bm_bufs_free(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 
 	mvneta_bm_config_set(priv, MVNETA_BM_EMPTY_LIMIT_MASK);
 
-	for (i = 0; i < bm_pool->buf_num; i++) {
+	for (i = 0; i < bm_pool->hwbm_pool.buf_num; i++) {
 		dma_addr_t buf_phys_addr;
 		u32 *vaddr;
 
@@ -320,19 +242,20 @@ void mvneta_bm_bufs_free(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 
 		dma_unmap_single(&priv->pdev->dev, buf_phys_addr,
 				 bm_pool->buf_size, DMA_FROM_DEVICE);
-		mvneta_frag_free(bm_pool->frag_size, vaddr);
+		hwbm_buf_free(&bm_pool->hwbm_pool, vaddr);
 	}
 
 	mvneta_bm_config_clear(priv, MVNETA_BM_EMPTY_LIMIT_MASK);
 
 	/* Update BM driver with number of buffers removed from pool */
-	bm_pool->buf_num -= i;
+	bm_pool->hwbm_pool.buf_num -= i;
 }
 
 /* Cleanup pool */
 void mvneta_bm_pool_destroy(struct mvneta_bm *priv,
 			    struct mvneta_bm_pool *bm_pool, u8 port_map)
 {
+	struct hwbm_pool *hwbm_pool = &bm_pool->hwbm_pool;
 	bm_pool->port_map &= ~port_map;
 	if (bm_pool->port_map)
 		return;
@@ -340,11 +263,12 @@ void mvneta_bm_pool_destroy(struct mvneta_bm *priv,
 	bm_pool->type = MVNETA_BM_FREE;
 
 	mvneta_bm_bufs_free(priv, bm_pool, port_map);
-	if (bm_pool->buf_num)
+	if (hwbm_pool->buf_num)
 		WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
 
 	if (bm_pool->virt_addr) {
-		dma_free_coherent(&priv->pdev->dev, sizeof(u32) * bm_pool->size,
+		dma_free_coherent(&priv->pdev->dev,
+				  sizeof(u32) * hwbm_pool->size,
 				  bm_pool->virt_addr, bm_pool->phys_addr);
 		bm_pool->virt_addr = NULL;
 	}
@@ -397,10 +321,10 @@ static void mvneta_bm_pools_init(struct mvneta_bm *priv)
 				 MVNETA_BM_POOL_CAP_ALIGN));
 			size = ALIGN(size, MVNETA_BM_POOL_CAP_ALIGN);
 		}
-		bm_pool->size = size;
+		bm_pool->hwbm_pool.size = size;
 
 		mvneta_bm_write(priv, MVNETA_BM_POOL_SIZE_REG(i),
-				bm_pool->size);
+				bm_pool->hwbm_pool.size);
 
 		/* Obtain custom pkt_size from DT */
 		sprintf(prop, "pool%d,pkt-size", i);
diff --git a/drivers/net/ethernet/marvell/mvneta_bm.h b/drivers/net/ethernet/marvell/mvneta_bm.h
index f2449b843577..ea08736d8cb4 100644
--- a/drivers/net/ethernet/marvell/mvneta_bm.h
+++ b/drivers/net/ethernet/marvell/mvneta_bm.h
@@ -108,20 +108,15 @@ struct mvneta_bm {
 };
 
 struct mvneta_bm_pool {
+	struct hwbm_pool hwbm_pool;
 	/* Pool number in the range 0-3 */
 	u8 id;
 	enum mvneta_bm_type type;
 
-	/* Buffer Pointers Pool External (BPPE) size in number of bytes */
-	int size;
-	/* Number of buffers used by this pool */
-	int buf_num;
-	/* Pool buffer size */
-	int buf_size;
 	/* Packet size */
 	int pkt_size;
-	/* Single frag size */
-	u32 frag_size;
+	/* Size of the buffer acces through DMA*/
+	u32 buf_size;
 
 	/* BPPE virtual base address */
 	u32 *virt_addr;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management
  2016-01-12 19:10 ` [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management Gregory CLEMENT
@ 2016-01-12 20:12   ` Marcin Wojtas
  2016-01-13 17:38     ` Gregory CLEMENT
  2016-02-12 18:04     ` Gregory CLEMENT
  0 siblings, 2 replies; 24+ messages in thread
From: Marcin Wojtas @ 2016-01-12 20:12 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Hi Gregory,

I have two remarks to my own code. Please let me know before patch v2,
I will provide you with corrected version (I already did it locally).

> @@ -1556,17 +1777,20 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
>         int rx_done, i;
>
>         rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq);
> +       if (rx_done)
> +               mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
> +
> +       if (pp->bm_priv)
> +               return;
> +

This is wrong - buffers that are supposed to be dropped should return
to bm_pool.

> @@ -1587,23 +1812,35 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
>
>         rx_done = 0;
>
> +       bm_in_use = pp->bm_priv ? true : false;
> +
>         /* Fairness NAPI loop */
>         while (rx_done < rx_todo) {
>                 struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq);
> +               struct mvneta_bm_pool *bm_pool = NULL;
>                 struct sk_buff *skb;
>                 unsigned char *data;
>                 dma_addr_t phys_addr;
> -               u32 rx_status;
> +               u32 rx_status, frag_size;
>                 int rx_bytes, err;
> +               u8 pool_id;
>
>                 rx_done++;
>                 rx_status = rx_desc->status;
>                 rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
>                 data = (unsigned char *)rx_desc->buf_cookie;
>                 phys_addr = rx_desc->buf_phys_addr;
> +               if (bm_in_use) {
> +                       pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc);
> +                       bm_pool = &pp->bm_priv->bm_pools[pool_id];
> +               }
>
>                 if (!mvneta_rxq_desc_is_first_last(rx_status) ||
>                     (rx_status & MVNETA_RXD_ERR_SUMMARY)) {
> +                       /* Return the buffer to the pool */
> +                       if (bm_in_use)
> +                               mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
> +                                                     rx_desc->buf_phys_addr);
>                 err_drop_frame:
>                         dev->stats.rx_errors++;
>                         mvneta_rx_error(pp, rx_desc);
> @@ -1633,25 +1870,38 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
>                         rcvd_pkts++;
>                         rcvd_bytes += rx_bytes;
>
> +                       /* Return the buffer to the pool */
> +                       if (bm_in_use)
> +                               mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
> +                                                     rx_desc->buf_phys_addr);
> +
>                         /* leave the descriptor and buffer untouched */
>                         continue;
>                 }
>
>                 /* Refill processing */
> -               err = mvneta_rx_refill(pp, rx_desc);
> +               err = bm_in_use ? mvneta_bm_pool_refill(pp->bm_priv, bm_pool) :
> +                                 mvneta_rx_refill(pp, rx_desc);
>                 if (err) {
>                         netdev_err(dev, "Linux processing - Can't refill\n");
>                         rxq->missed++;
>                         goto err_drop_frame;

Wrong - on refill fail, original buffer should be returned to bm_pool.
Same case is, when netdev_alloc_skb_ip_align fail inside copybreak
(this should also be fixed).

Best regards,
Marcin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 00/10] Proposal for a API set for HW Buffer management
  2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
                   ` (9 preceding siblings ...)
  2016-01-12 19:10 ` [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework Gregory CLEMENT
@ 2016-01-12 20:52 ` David Miller
  2016-01-13 17:36   ` Gregory CLEMENT
  10 siblings, 1 reply; 24+ messages in thread
From: David Miller @ 2016-01-12 20:52 UTC (permalink / raw)
  To: gregory.clement
  Cc: linux-kernel, netdev, thomas.petazzoni, f.fainelli, jason,
	andrew, sebastian.hesselbarth, linux-arm-kernel, alior, nadavh,
	mw, simon.guinot, ezequiel.garcia, maxime.ripard,
	boris.brezillon, linux, w, arnd


If you are going to contribute to netdev you must follow the mailing
list and make not of important announcements such as:

http://marc.info/?l=linux-netdev&m=145248145925834&w=2

Thank you.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info
  2016-01-12 19:10 ` [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info Gregory CLEMENT
@ 2016-01-12 21:42   ` Marcin Wojtas
  2016-01-14 14:00   ` David Laight
  1 sibling, 0 replies; 24+ messages in thread
From: Marcin Wojtas @ 2016-01-12 21:42 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Gregory,



2016-01-12 20:10 GMT+01:00 Gregory CLEMENT <gregory.clement@free-electrons.com>:
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
>  drivers/bus/mvebu-mbus.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
> index 3d1c0c3880ec..214bb964165b 100644
> --- a/drivers/bus/mvebu-mbus.c
> +++ b/drivers/bus/mvebu-mbus.c
> @@ -964,7 +964,7 @@ int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr)
>         for (i = 0; i < dram->num_cs; i++) {
>                 const struct mbus_dram_window *cs = dram->cs + i;
>
> -               if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size)) {
> +               if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size - 1)) {
>                         *target = dram->mbus_dram_target_id;
>                         *attr = cs->mbus_attr;
>                         return 0;
> --

Except for a typo in the commit log, the fix is good.
If you wish you can add
Reviewed-by: Marcin Wojtas <mw@semihalf.com>

Best regards,
Marcin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework
  2016-01-12 19:10 ` [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework Gregory CLEMENT
@ 2016-01-12 22:40   ` Marcin Wojtas
  2016-01-13 17:47     ` Gregory CLEMENT
  0 siblings, 1 reply; 24+ messages in thread
From: Marcin Wojtas @ 2016-01-12 22:40 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Hi Gregory,

A quick remark below. All changes look fine to me at a first look, but
I will test and dig more into code soon.

>
> @@ -3946,11 +3965,6 @@ static int mvneta_probe(struct platform_device *pdev)
>         dev->priv_flags |= IFF_UNICAST_FLT;
>         dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
>
> -       err = register_netdev(dev);
> -       if (err < 0) {
> -               dev_err(&pdev->dev, "failed to register\n");
> -               goto err_free_stats;
> -       }

The purpose of shifting register_netdev() was to be able to obtain
pp->id from net_device, before mvneta_bm_port_init is called. It is
needed for proper port - pool mapping control.

>
>         pp->id = dev->ifindex;
>
> @@ -3965,6 +3979,12 @@ static int mvneta_probe(struct platform_device *pdev)
>                 }
>         }
>
> +       err = register_netdev(dev);
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to register\n");
> +               goto err_free_stats;
> +       }
> +
>         err = mvneta_init(&pdev->dev, pp);
>         if (err < 0)
>                 goto err_netdev;

Best regards,
Marcin

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 00/10] Proposal for a API set for HW Buffer management
  2016-01-12 20:52 ` [PATCH net-next 00/10] Proposal for a API set for HW Buffer management David Miller
@ 2016-01-13 17:36   ` Gregory CLEMENT
  2016-01-13 19:53     ` David Miller
  0 siblings, 1 reply; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-13 17:36 UTC (permalink / raw)
  To: David Miller
  Cc: linux-kernel, netdev, thomas.petazzoni, f.fainelli, jason,
	andrew, sebastian.hesselbarth, linux-arm-kernel, alior, nadavh,
	mw, simon.guinot, ezequiel.garcia, maxime.ripard,
	boris.brezillon, linux, w, arnd

Hi David,
 
 On mar., janv. 12 2016, David Miller <davem@davemloft.net> wrote:

> If you are going to contribute to netdev you must follow the mailing
> list and make not of important announcements such as:
>
> http://marc.info/?l=linux-netdev&m=145248145925834&w=2

I perfectly understand that you are busy during this merge
window. However, I didn't expect a feedback from you but more from the
others who were involved previously on this topic. Moreover, at this
stage I don't expect a deep review but more to start a discussion about
this topic in order to submit a better proposal when the net-ext will be
opened.

I realize that I should not have put you as main recipient. It was
because your address is part of my netdev alias.

Sorry for the inconvenience,

Gregory

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management
  2016-01-12 20:12   ` Marcin Wojtas
@ 2016-01-13 17:38     ` Gregory CLEMENT
  2016-02-12 18:04     ` Gregory CLEMENT
  1 sibling, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-13 17:38 UTC (permalink / raw)
  To: Marcin Wojtas
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Hi Marcin,
 
 On mar., janv. 12 2016, Marcin Wojtas <mw@semihalf.com> wrote:

> Hi Gregory,
>
> I have two remarks to my own code. Please let me know before patch v2,
> I will provide you with corrected version (I already did it locally).

OK I will asked your version before the next submitting.

Thanks,

Gregory

>
>> @@ -1556,17 +1777,20 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
>>         int rx_done, i;
>>
>>         rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq);
>> +       if (rx_done)
>> +               mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
>> +
>> +       if (pp->bm_priv)
>> +               return;
>> +
>
> This is wrong - buffers that are supposed to be dropped should return
> to bm_pool.
>
>> @@ -1587,23 +1812,35 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
>>
>>         rx_done = 0;
>>
>> +       bm_in_use = pp->bm_priv ? true : false;
>> +
>>         /* Fairness NAPI loop */
>>         while (rx_done < rx_todo) {
>>                 struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq);
>> +               struct mvneta_bm_pool *bm_pool = NULL;
>>                 struct sk_buff *skb;
>>                 unsigned char *data;
>>                 dma_addr_t phys_addr;
>> -               u32 rx_status;
>> +               u32 rx_status, frag_size;
>>                 int rx_bytes, err;
>> +               u8 pool_id;
>>
>>                 rx_done++;
>>                 rx_status = rx_desc->status;
>>                 rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
>>                 data = (unsigned char *)rx_desc->buf_cookie;
>>                 phys_addr = rx_desc->buf_phys_addr;
>> +               if (bm_in_use) {
>> +                       pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc);
>> +                       bm_pool = &pp->bm_priv->bm_pools[pool_id];
>> +               }
>>
>>                 if (!mvneta_rxq_desc_is_first_last(rx_status) ||
>>                     (rx_status & MVNETA_RXD_ERR_SUMMARY)) {
>> +                       /* Return the buffer to the pool */
>> +                       if (bm_in_use)
>> +                               mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
>> +                                                     rx_desc->buf_phys_addr);
>>                 err_drop_frame:
>>                         dev->stats.rx_errors++;
>>                         mvneta_rx_error(pp, rx_desc);
>> @@ -1633,25 +1870,38 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
>>                         rcvd_pkts++;
>>                         rcvd_bytes += rx_bytes;
>>
>> +                       /* Return the buffer to the pool */
>> +                       if (bm_in_use)
>> +                               mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
>> +                                                     rx_desc->buf_phys_addr);
>> +
>>                         /* leave the descriptor and buffer untouched */
>>                         continue;
>>                 }
>>
>>                 /* Refill processing */
>> -               err = mvneta_rx_refill(pp, rx_desc);
>> +               err = bm_in_use ? mvneta_bm_pool_refill(pp->bm_priv, bm_pool) :
>> +                                 mvneta_rx_refill(pp, rx_desc);
>>                 if (err) {
>>                         netdev_err(dev, "Linux processing - Can't refill\n");
>>                         rxq->missed++;
>>                         goto err_drop_frame;
>
> Wrong - on refill fail, original buffer should be returned to bm_pool.
> Same case is, when netdev_alloc_skb_ip_align fail inside copybreak
> (this should also be fixed).
>
> Best regards,
> Marcin

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework
  2016-01-12 22:40   ` Marcin Wojtas
@ 2016-01-13 17:47     ` Gregory CLEMENT
  0 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-13 17:47 UTC (permalink / raw)
  To: Marcin Wojtas
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Hi Marcin,
 
 On mar., janv. 12 2016, Marcin Wojtas <mw@semihalf.com> wrote:

> Hi Gregory,
>
> A quick remark below. All changes look fine to me at a first look, but
> I will test and dig more into code soon.

Great! A test would be nice because I have just did basic tests: mainly an
iperf.

>
>>
>> @@ -3946,11 +3965,6 @@ static int mvneta_probe(struct platform_device *pdev)
>>         dev->priv_flags |= IFF_UNICAST_FLT;
>>         dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
>>
>> -       err = register_netdev(dev);
>> -       if (err < 0) {
>> -               dev_err(&pdev->dev, "failed to register\n");
>> -               goto err_free_stats;
>> -       }
>
> The purpose of shifting register_netdev() was to be able to obtain
> pp->id from net_device, before mvneta_bm_port_init is called. It is
> needed for proper port - pool mapping control.

I can revert this change, initially I moved this chunk because I wanted
to add a netdev_ops before registering it and this netdev_op depend on
the bm support. As for now I don't have this this netdev_op this change
is pointless. But if in future I need it, then I will look for how to do
it in a different way.

Thanks,


>
>>
>>         pp->id = dev->ifindex;
>>
>> @@ -3965,6 +3979,12 @@ static int mvneta_probe(struct platform_device *pdev)
>>                 }
>>         }
>>
>> +       err = register_netdev(dev);
>> +       if (err < 0) {
>> +               dev_err(&pdev->dev, "failed to register\n");
>> +               goto err_free_stats;
>> +       }
>> +
>>         err = mvneta_init(&pdev->dev, pp);
>>         if (err < 0)
>>                 goto err_netdev;
>
> Best regards,
> Marcin

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 00/10] Proposal for a API set for HW Buffer management
  2016-01-13 17:36   ` Gregory CLEMENT
@ 2016-01-13 19:53     ` David Miller
  0 siblings, 0 replies; 24+ messages in thread
From: David Miller @ 2016-01-13 19:53 UTC (permalink / raw)
  To: gregory.clement
  Cc: linux-kernel, netdev, thomas.petazzoni, f.fainelli, jason,
	andrew, sebastian.hesselbarth, linux-arm-kernel, alior, nadavh,
	mw, simon.guinot, ezequiel.garcia, maxime.ripard,
	boris.brezillon, linux, w, arnd

From: Gregory CLEMENT <gregory.clement@free-electrons.com>
Date: Wed, 13 Jan 2016 18:36:54 +0100

> I perfectly understand that you are busy during this merge
> window. However, I didn't expect a feedback from you but more from the
> others who were involved previously on this topic.

When a patch is submitted with "net-next" in the Subject line and
no "RFC" or other indication like that, it means you think the
patch is ready for me to consider applying to my tree.

You have to communicate properly in your Subject line tags if you
want me to interpret your changes one way or another.

And quite frankly, I really don't even want to see a lot of RFC
networking changes posted when the merge window is open, I only want
to see bug fixes and people concentrating on that instead of future
work.

Thanks.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info
  2016-01-12 19:10 ` [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info Gregory CLEMENT
  2016-01-12 21:42   ` Marcin Wojtas
@ 2016-01-14 14:00   ` David Laight
  2016-02-16 16:18     ` Gregory CLEMENT
  1 sibling, 1 reply; 24+ messages in thread
From: David Laight @ 2016-01-14 14:00 UTC (permalink / raw)
  To: 'Gregory CLEMENT',
	David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas,
	Simon Guinot, Ezequiel Garcia, Maxime Ripard, Boris BREZILLON,
	Russell King - ARM Linux, Willy Tarreau, Arnd Bergmann

From: Gregory CLEMENT
> Sent: 12 January 2016 19:11
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
>  drivers/bus/mvebu-mbus.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
> index 3d1c0c3880ec..214bb964165b 100644
> --- a/drivers/bus/mvebu-mbus.c
> +++ b/drivers/bus/mvebu-mbus.c
> @@ -964,7 +964,7 @@ int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr)
>  	for (i = 0; i < dram->num_cs; i++) {
>  		const struct mbus_dram_window *cs = dram->cs + i;
> 
> -		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size)) {
> +		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size - 1)) {

Wouldn't it be better to change the line to:
> +		if (cs->base <= phyaddr && phyaddr < (cs->base + cs->size)) {

	David

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 09/10] net: Add a hardware buffer management helper API
  2016-01-12 19:10 ` [PATCH net-next 09/10] net: Add a hardware buffer management helper API Gregory CLEMENT
@ 2016-01-27 20:02   ` Florian Fainelli
  2016-01-29 18:36     ` Gregory CLEMENT
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Fainelli @ 2016-01-27 20:02 UTC (permalink / raw)
  To: Gregory CLEMENT, David S. Miller, linux-kernel, netdev, Thomas Petazzoni
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas,
	Simon Guinot, Ezequiel Garcia, Maxime Ripard, Boris BREZILLON,
	Russell King - ARM Linux, Willy Tarreau, Arnd Bergmann

On 12/01/16 11:10, Gregory CLEMENT wrote:
> This basic implementation allows to share code between driver using
> hardware buffer management. As the code is hardware agnostic, there is
> few helpers, most of the optimization brought by the an HW BM has to be
> done at driver level.
> 
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
>  include/net/hwbm.h | 19 +++++++++++++
>  net/core/Makefile  |  2 +-
>  net/core/hwbm.c    | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 98 insertions(+), 1 deletion(-)
>  create mode 100644 include/net/hwbm.h
>  create mode 100644 net/core/hwbm.c
> 
> diff --git a/include/net/hwbm.h b/include/net/hwbm.h
> new file mode 100644
> index 000000000000..898ccd2fb58d
> --- /dev/null
> +++ b/include/net/hwbm.h
> @@ -0,0 +1,19 @@
> +#ifndef _HWBM_H
> +#define _HWBM_H
> +
> +struct hwbm_pool {
> +	/* Size of the buffers managed */
> +	int size;
> +	/* Number of buffers currently used by this pool */
> +	int buf_num;
> +	/* constructor called during alocation */
> +	int (*construct)(struct hwbm_pool *bm_pool, void *buf);

Having the buffer size might be handy too.

> +	/* private data */
> +	void *priv;
> +};
> +
> +void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf);
> +int hwbm_pool_refill(struct hwbm_pool *bm_pool);
> +int hwbm_pool_add(struct hwbm_pool *bm_pool, int buf_num);
> +
> +#endif /* _HWBM_H */
> diff --git a/net/core/Makefile b/net/core/Makefile
> index 0b835de04de3..df81bf11f072 100644
> --- a/net/core/Makefile
> +++ b/net/core/Makefile
> @@ -9,7 +9,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
>  
>  obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
>  			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
> -			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o
> +			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o hwbm.o

Not everybody will want this built in by default, we probably need a
hidden config symbol here.

>  
>  obj-$(CONFIG_XFRM) += flow.o
>  obj-y += net-sysfs.o
> diff --git a/net/core/hwbm.c b/net/core/hwbm.c
> new file mode 100644
> index 000000000000..d5d40d63cb34
> --- /dev/null
> +++ b/net/core/hwbm.c
> @@ -0,0 +1,78 @@
> +/* Support for hardware buffer manager.
> + *
> + * Copyright (C) 2016 Marvell
> + *
> + * Gregory CLEMENT <gregory.clement@free-electrons.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + */
> +#include <linux/kernel.h>
> +#include <linux/printk.h>
> +#include <linux/skbuff.h>
> +#include <net/hwbm.h>
> +
> +void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf)
> +{
> +	if (likely(bm_pool->size <= PAGE_SIZE))
> +		skb_free_frag(buf);
> +	else
> +		kfree(buf);
> +}
> +EXPORT_SYMBOL_GPL(hwbm_buf_free);
> +
> +/* Refill processing for HW buffer management */
> +int hwbm_pool_refill(struct hwbm_pool *bm_pool)
> +{
> +	void *buf;
> +	int frag_size = bm_pool->size;

Reverse christmas tree declaration looks a bit nicer.

> +
> +	if (likely(frag_size <= PAGE_SIZE))
> +		buf = netdev_alloc_frag(frag_size);
> +	else
> +		buf = kmalloc(frag_size, GFP_ATOMIC);

Maybe we should allow the caller to specify a gfp_t, just in case
GFP_ATOMIC is not good enough.

> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	if (bm_pool->construct)
> +		if (bm_pool->construct(bm_pool, buf)) {
> +			hwbm_buf_free(bm_pool, buf);
> +			return -ENOMEM;
> +		}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hwbm_pool_refill);
> +
> +int hwbm_pool_add(struct hwbm_pool *bm_pool, int buf_num)

unsigned int buf_num

> +{
> +	int err, i;
> +
> +	if (bm_pool->buf_num == bm_pool->size) {
> +		pr_debug("pool already filled\n");
> +		return bm_pool->buf_num;
> +	}
> +
> +	if (buf_num + bm_pool->buf_num > bm_pool->size) {
> +		pr_debug("cannot allocate %d buffers for pool\n",
> +			 buf_num);
> +		return 0;
> +	}

buf_num is under caller control, and potentially hardware control
indirectly, what if I make this arbitrary big and wrap around?

> +
> +	for (i = 0; i < buf_num; i++) {
> +		err = hwbm_pool_refill(bm_pool);
> +		if (err < 0)
> +			break;
> +	}

If we fail refiling here, should not we propagate the error back to the
caller?

> +
> +	/* Update BM driver with number of buffers added to pool */
> +	bm_pool->buf_num += i;
> +
> +	pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);

No locking or atomic operations here? What if two CPUs call into this
function?

> +
> +	return i;
> +}
> +EXPORT_SYMBOL_GPL(hwbm_pool_add);
> 


-- 
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 09/10] net: Add a hardware buffer management helper API
  2016-01-27 20:02   ` Florian Fainelli
@ 2016-01-29 18:36     ` Gregory CLEMENT
  0 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-01-29 18:36 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	linux-arm-kernel, Lior Amsalem, Nadav Haklai, Marcin Wojtas,
	Simon Guinot, Ezequiel Garcia, Maxime Ripard, Boris BREZILLON,
	Russell King - ARM Linux, Willy Tarreau, Arnd Bergmann

Hi Florian,

thanks for your review!
 
 On mer., janv. 27 2016, Florian Fainelli <f.fainelli@gmail.com> wrote:

> On 12/01/16 11:10, Gregory CLEMENT wrote:
>> This basic implementation allows to share code between driver using
>> hardware buffer management. As the code is hardware agnostic, there is
>> few helpers, most of the optimization brought by the an HW BM has to be
>> done at driver level.
>> 
>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>> ---
>>  include/net/hwbm.h | 19 +++++++++++++
>>  net/core/Makefile  |  2 +-
>>  net/core/hwbm.c    | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 98 insertions(+), 1 deletion(-)
>>  create mode 100644 include/net/hwbm.h
>>  create mode 100644 net/core/hwbm.c
>> 
>> diff --git a/include/net/hwbm.h b/include/net/hwbm.h
>> new file mode 100644
>> index 000000000000..898ccd2fb58d
>> --- /dev/null
>> +++ b/include/net/hwbm.h
>> @@ -0,0 +1,19 @@
>> +#ifndef _HWBM_H
>> +#define _HWBM_H
>> +
>> +struct hwbm_pool {
>> +	/* Size of the buffers managed */
>> +	int size;
>> +	/* Number of buffers currently used by this pool */
>> +	int buf_num;
>> +	/* constructor called during alocation */
>> +	int (*construct)(struct hwbm_pool *bm_pool, void *buf);
>
> Having the buffer size might be handy too.
>
>> +	/* private data */
>> +	void *priv;
>> +};
>> +
>> +void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf);
>> +int hwbm_pool_refill(struct hwbm_pool *bm_pool);
>> +int hwbm_pool_add(struct hwbm_pool *bm_pool, int buf_num);
>> +
>> +#endif /* _HWBM_H */
>> diff --git a/net/core/Makefile b/net/core/Makefile
>> index 0b835de04de3..df81bf11f072 100644
>> --- a/net/core/Makefile
>> +++ b/net/core/Makefile
>> @@ -9,7 +9,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
>>  
>>  obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
>>  			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
>> -			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o
>> +			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o hwbm.o
>
> Not everybody will want this built in by default, we probably need a
> hidden config symbol here.

I copied what was done for TSO, but I agree to not build it by default.

>
>>  
>>  obj-$(CONFIG_XFRM) += flow.o
>>  obj-y += net-sysfs.o
>> diff --git a/net/core/hwbm.c b/net/core/hwbm.c
>> new file mode 100644
>> index 000000000000..d5d40d63cb34
>> --- /dev/null
>> +++ b/net/core/hwbm.c
>> @@ -0,0 +1,78 @@
>> +/* Support for hardware buffer manager.
>> + *
>> + * Copyright (C) 2016 Marvell
>> + *
>> + * Gregory CLEMENT <gregory.clement@free-electrons.com>
>> + *
>> + *  This program is free software; you can redistribute it and/or modify
>> + *  it under the terms of the GNU General Public License as published by
>> + *  the Free Software Foundation; either version 2 of the License, or
>> + *  (at your option) any later version.
>> + */
>> +#include <linux/kernel.h>
>> +#include <linux/printk.h>
>> +#include <linux/skbuff.h>
>> +#include <net/hwbm.h>
>> +
>> +void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf)
>> +{
>> +	if (likely(bm_pool->size <= PAGE_SIZE))
>> +		skb_free_frag(buf);
>> +	else
>> +		kfree(buf);
>> +}
>> +EXPORT_SYMBOL_GPL(hwbm_buf_free);
>> +
>> +/* Refill processing for HW buffer management */
>> +int hwbm_pool_refill(struct hwbm_pool *bm_pool)
>> +{
>> +	void *buf;
>> +	int frag_size = bm_pool->size;
>
> Reverse christmas tree declaration looks a bit nicer.

First time I heard about it :) I though it was something related to the
tree algorithms until I visualized it!

My logical here was first uninitialized variable then the initialized
ones. But I don't have a strong opinion about it so I can change it.

>
>> +
>> +	if (likely(frag_size <= PAGE_SIZE))
>> +		buf = netdev_alloc_frag(frag_size);
>> +	else
>> +		buf = kmalloc(frag_size, GFP_ATOMIC);
>
> Maybe we should allow the caller to specify a gfp_t, just in case
> GFP_ATOMIC is not good enough.

Good idea.

>
>> +
>> +	if (!buf)
>> +		return -ENOMEM;
>> +
>> +	if (bm_pool->construct)
>> +		if (bm_pool->construct(bm_pool, buf)) {
>> +			hwbm_buf_free(bm_pool, buf);
>> +			return -ENOMEM;
>> +		}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(hwbm_pool_refill);
>> +
>> +int hwbm_pool_add(struct hwbm_pool *bm_pool, int buf_num)
>
> unsigned int buf_num

OK

>
>> +{
>> +	int err, i;
>> +
>> +	if (bm_pool->buf_num == bm_pool->size) {
>> +		pr_debug("pool already filled\n");
>> +		return bm_pool->buf_num;
>> +	}
>> +
>> +	if (buf_num + bm_pool->buf_num > bm_pool->size) {
>> +		pr_debug("cannot allocate %d buffers for pool\n",
>> +			 buf_num);
>> +		return 0;
>> +	}
>
> buf_num is under caller control, and potentially hardware control
> indirectly, what if I make this arbitrary big and wrap around?

We could test if ((buf_num + bm_pool->buf_num)<bm_pool->buf_num. I
failed to find a better way to detect a wrapping.


>
>> +
>> +	for (i = 0; i < buf_num; i++) {
>> +		err = hwbm_pool_refill(bm_pool);
>> +		if (err < 0)
>> +			break;
>> +	}
>
> If we fail refiling here, should not we propagate the error back to the
> caller?

We return the number of we actually managed to add. So, if it fails we
return less buffer than expected, as for a read in userspace. Is it not
a good indication of what happened?

>
>> +
>> +	/* Update BM driver with number of buffers added to pool */
>> +	bm_pool->buf_num += i;
>> +
>> +	pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);
>
> No locking or atomic operations here? What if two CPUs call into this
> function?

Indeed it could be a problem, I will see how to handle this in the next
version.

Thanks again,

Gregory

>
>> +
>> +	return i;
>> +}
>> +EXPORT_SYMBOL_GPL(hwbm_pool_add);
>> 
>
>
> -- 
> Florian

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management
  2016-01-12 20:12   ` Marcin Wojtas
  2016-01-13 17:38     ` Gregory CLEMENT
@ 2016-02-12 18:04     ` Gregory CLEMENT
  1 sibling, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-02-12 18:04 UTC (permalink / raw)
  To: Marcin Wojtas
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Simon Guinot, Ezequiel Garcia, Maxime Ripard,
	Boris BREZILLON, Russell King - ARM Linux, Willy Tarreau,
	Arnd Bergmann

Hi Marcin,
 
 On mar., janv. 12 2016, Marcin Wojtas <mw@semihalf.com> wrote:

> Hi Gregory,
>
> I have two remarks to my own code. Please let me know before patch v2,
> I will provide you with corrected version (I already did it locally).

I resumled my work on the subject yestaerdy, and I just remebered this
email now.

Could you provide the correct version of your patches?

Thanks!

>
>> @@ -1556,17 +1777,20 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
>>         int rx_done, i;
>>
>>         rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq);
>> +       if (rx_done)
>> +               mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
>> +
>> +       if (pp->bm_priv)
>> +               return;
>> +
>
> This is wrong - buffers that are supposed to be dropped should return
> to bm_pool.
>
>> @@ -1587,23 +1812,35 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
>>
>>         rx_done = 0;
>>
>> +       bm_in_use = pp->bm_priv ? true : false;
>> +
>>         /* Fairness NAPI loop */
>>         while (rx_done < rx_todo) {
>>                 struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq);
>> +               struct mvneta_bm_pool *bm_pool = NULL;
>>                 struct sk_buff *skb;
>>                 unsigned char *data;
>>                 dma_addr_t phys_addr;
>> -               u32 rx_status;
>> +               u32 rx_status, frag_size;
>>                 int rx_bytes, err;
>> +               u8 pool_id;
>>
>>                 rx_done++;
>>                 rx_status = rx_desc->status;
>>                 rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
>>                 data = (unsigned char *)rx_desc->buf_cookie;
>>                 phys_addr = rx_desc->buf_phys_addr;
>> +               if (bm_in_use) {
>> +                       pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc);
>> +                       bm_pool = &pp->bm_priv->bm_pools[pool_id];
>> +               }
>>
>>                 if (!mvneta_rxq_desc_is_first_last(rx_status) ||
>>                     (rx_status & MVNETA_RXD_ERR_SUMMARY)) {
>> +                       /* Return the buffer to the pool */
>> +                       if (bm_in_use)
>> +                               mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
>> +                                                     rx_desc->buf_phys_addr);
>>                 err_drop_frame:
>>                         dev->stats.rx_errors++;
>>                         mvneta_rx_error(pp, rx_desc);
>> @@ -1633,25 +1870,38 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
>>                         rcvd_pkts++;
>>                         rcvd_bytes += rx_bytes;
>>
>> +                       /* Return the buffer to the pool */
>> +                       if (bm_in_use)
>> +                               mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
>> +                                                     rx_desc->buf_phys_addr);
>> +
>>                         /* leave the descriptor and buffer untouched */
>>                         continue;
>>                 }
>>
>>                 /* Refill processing */
>> -               err = mvneta_rx_refill(pp, rx_desc);
>> +               err = bm_in_use ? mvneta_bm_pool_refill(pp->bm_priv, bm_pool) :
>> +                                 mvneta_rx_refill(pp, rx_desc);
>>                 if (err) {
>>                         netdev_err(dev, "Linux processing - Can't refill\n");
>>                         rxq->missed++;
>>                         goto err_drop_frame;
>
> Wrong - on refill fail, original buffer should be returned to bm_pool.
> Same case is, when netdev_alloc_skb_ip_align fail inside copybreak
> (this should also be fixed).
>
> Best regards,
> Marcin

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info
  2016-01-14 14:00   ` David Laight
@ 2016-02-16 16:18     ` Gregory CLEMENT
  0 siblings, 0 replies; 24+ messages in thread
From: Gregory CLEMENT @ 2016-02-16 16:18 UTC (permalink / raw)
  To: David Laight
  Cc: David S. Miller, linux-kernel, netdev, Thomas Petazzoni,
	Florian Fainelli, Jason Cooper, Andrew Lunn,
	Sebastian Hesselbarth, linux-arm-kernel, Lior Amsalem,
	Nadav Haklai, Marcin Wojtas, Simon Guinot, Ezequiel Garcia,
	Maxime Ripard, Boris BREZILLON, Russell King - ARM Linux,
	Willy Tarreau, Arnd Bergmann

Hi David,
 
 On jeu., janv. 14 2016, David Laight <David.Laight@ACULAB.COM> wrote:

> From: Gregory CLEMENT
>> Sent: 12 January 2016 19:11
>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>> ---
>>  drivers/bus/mvebu-mbus.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
>> index 3d1c0c3880ec..214bb964165b 100644
>> --- a/drivers/bus/mvebu-mbus.c
>> +++ b/drivers/bus/mvebu-mbus.c
>> @@ -964,7 +964,7 @@ int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr)
>>  	for (i = 0; i < dram->num_cs; i++) {
>>  		const struct mbus_dram_window *cs = dram->cs + i;
>> 
>> -		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size)) {
>> +		if (cs->base <= phyaddr && phyaddr <= (cs->base + cs->size - 1)) {
>
> Wouldn't it be better to change the line to:
>> +		if (cs->base <= phyaddr && phyaddr < (cs->base +
>cs->size)) {

It doesn't work if there is 4GB of memory in this case we can have
cs->base + cs->size which wrap to 0 and the test fails. It was exactly
what happened on Armada XP GP board.

Gregory

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2016-02-16 16:41 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-12 19:10 [PATCH net-next 00/10] Proposal for a API set for HW Buffer management Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 01/10] bus: mvebu-mbus: provide api for obtaining IO and DRAM window information Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 02/10] ARM: mvebu: enable SRAM support in mvebu_v7_defconfig Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 03/10] net: mvneta: bm: add support for hardware buffer management Gregory CLEMENT
2016-01-12 20:12   ` Marcin Wojtas
2016-01-13 17:38     ` Gregory CLEMENT
2016-02-12 18:04     ` Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 04/10] ARM: mvebu: add buffer manager nodes to armada-38x.dtsi Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 05/10] ARM: mvebu: enable buffer manager support on Armada 38x boards Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 06/10] ARM: mvebu: add buffer manager nodes to armada-xp.dtsi Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 07/10] ARM: mvebu: enable buffer manager support on Armada XP boards Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 08/10] bus: mvenus-mbus: Fix size test for mvebu_mbus_get_dram_win_info Gregory CLEMENT
2016-01-12 21:42   ` Marcin Wojtas
2016-01-14 14:00   ` David Laight
2016-02-16 16:18     ` Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 09/10] net: Add a hardware buffer management helper API Gregory CLEMENT
2016-01-27 20:02   ` Florian Fainelli
2016-01-29 18:36     ` Gregory CLEMENT
2016-01-12 19:10 ` [PATCH net-next 10/10] net: mvneta: Use the new hwbm framework Gregory CLEMENT
2016-01-12 22:40   ` Marcin Wojtas
2016-01-13 17:47     ` Gregory CLEMENT
2016-01-12 20:52 ` [PATCH net-next 00/10] Proposal for a API set for HW Buffer management David Miller
2016-01-13 17:36   ` Gregory CLEMENT
2016-01-13 19:53     ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).