All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add support for WASP SoC on AVM router boards
@ 2022-07-21 19:34 Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 1/3] dt-bindings: vendor-prefixes: Add AVM Daniel Kestrel
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Daniel Kestrel @ 2022-07-21 19:34 UTC (permalink / raw)
  Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring, Daniel Kestrel,
	linux-remoteproc, devicetree, linux-kernel

There is a popular set of Lantiq xrx200 router boards by AVM in
Germany (AVM Fritzbox 3390, 3490, 5490, 5491 and 7490) which
have the strange implementation of having the wifi cards
connected to a separate memory only ATH79 based SoC. It has no
persistent storage and no access to any resource on the Lantiq
host, but is connect to the Lantiq GSWIP switch on an additional
fixed internal network port.
This kernel module is to support booting the secondary SoC called
Wireless Assistant Support Processor (WASP).
After turning it on, a small network boot firmware is sent to
the SoC by using mdio and when it is started, an initramfs
linux image is sent to the SoC using raw ethernet frames.

The whole procedure takes about 6 seconds, if there is no error.
So far tested on 3490, 5490 and 7490 devices based on OpenWrt, 3390
takes about 20 seconds.

Patch 1/3 adds the vendor name
Patch 2/3 adds the dt-bindings
Patch 3/3 adds the remoteproc driver

To build and run, there is OpenWrt PR 5075.

Please review.

Changes in v3:
  - Replace generic avm,fritzboxx490-wasp with actual device names for
    device tree documentation and change the driver to accept them
  - Add maxItems to device tree documentation
  - Change example in the device tree documentation
  - Fix wait time to make the Wasp upload work for 3390 more reliable
  - Enable the SOC on driver load, use reset instead of disable/enable
    while driver is loaded and disable on unloading the driver
  - Change some messages printed to adhere to standards (e.g. remove !)

Changes in v2:
  - Remove firmware names from dt-binding and add as kmod parameters
  - Rename other bindings with vender prefix and fix gpios suffix
  - Change descriptions in dt-binding
  - Replace/Remove asynch load of firmware with request_firmware_direct
  - Fix comments to use the errno define instead of the number
  - Implement wait loops with read_poll_timeout() macro
  - Wrap read_poll_timeout() macro in function saving 6k module size
  - Return -ETIMEDOUT for all errors returned by read_poll_timeout
  - Replace mdio writes/reads with mdiobus_write and mdiobus_read and add
    return codes and their handling
  - Remove mutex for mdiobus_lock and add return code checking for mdio ops
  - Replaced the mdio register array with directly specifying registers
  - As a result of the previous 3 changes remove the functions for mdio
  - Consolidate error messages for mdio writes into a single one saved 1k
    for module size
  - Replaced mdelay with usleep_range saved 0,7k module size
  - Remove unneeded include <linux/interrupt.h> and <linux/error.h>
  - Wrap all blocks with {} and fix some indentation errors
  - Change const len in to size_t in avm_wasp_netboot_write_chunk
  - Make all methods static to fix kernel bot warning
  - Change read variable name in avm_wasp_load_initramfs_image
  - Change ssize_t variables to size_t in avm_wasp_load_initramfs_image
  - avm_wasp_netboot_write_chunk change for loop for 2 byte divisibility
  - Change uint32_t to u32
  - Change int count = -1 to u32 with U32_MAX initialisation
  - Add check for firmware len divisable by 4
  - Replace big endian bit shift operations with be32_to_cpu
  - Change loop to write 14 byte firmware chuncks like suggested
  - Change WASP_CHUNK_SIZE to ARRAY_SIZE(mac_data) for readability
  - Change int done to boolean
  - Change unsigned ints to u32
  - Change int to size_t for send_len
  - Use int for numbytes because kernel_recvmsg returns error or number
  - Two sockets are not needed, so reduce to one socket usage
  - Remove struct timeval definition, replace with __kernel_old_timeval
  - __kernel_old_timeval is depracated, but arch mips is 32bit platform
  - Replace &avmwasp->pdev->dev with local dev
  - Check if wasp network interface is up and fail if not in start method
  - Remove setsockopt for SO_REUSEADDR and SO_BINDTODEVICE
  - Remove packet_counter
  - Move firmware and firmware_end out of RESP_DISCOVER to make sure that
    they are initialized if RESP_DISCOVER is not happening first
  - indend break;
  - Move second half of the send/receive paket while loop to RESP_OK and
    let RESP_DISCOVER fall through
  - Remove bringing up the wasp network interface
  - Check if wasp network interface is up in probe and defer if not
  - Remove the check for the root device and replace it with match data
    for WASP device identification
  - Move of_read and find of mdio bus to rproc_start but delete reference
    after using it in the rproc_start method
  - Replace dev_set_drvdata with platform_set_drvdata
  - Remove avm_wasp_rproc_boot_addr because its not needed and move
    setting the fw struct pointer to avm_wasp_rproc_load
  - Move avm_wasp.h definitions to kernel module

Reported-by: kernel test robot <lkp@intel.com>

Daniel Kestrel (3):
  dt-bindings: vendor-prefixes: Add AVM
  dt-bindings: remoteproc: Add AVM WASP
  remoteproc: Add AVM WASP driver

 .../bindings/remoteproc/avm,wasp-rproc.yaml   |   61 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 drivers/remoteproc/Kconfig                    |   10 +
 drivers/remoteproc/Makefile                   |    1 +
 drivers/remoteproc/avm_wasp.c                 | 1056 +++++++++++++++++
 5 files changed, 1130 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/avm,wasp-rproc.yaml
 create mode 100644 drivers/remoteproc/avm_wasp.c

-- 
2.17.1


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

* [PATCH v3 1/3] dt-bindings: vendor-prefixes: Add AVM
  2022-07-21 19:34 [PATCH v3 0/3] Add support for WASP SoC on AVM router boards Daniel Kestrel
@ 2022-07-21 19:34 ` Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 2/3] dt-bindings: remoteproc: Add AVM WASP Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 3/3] remoteproc: Add AVM WASP driver Daniel Kestrel
  2 siblings, 0 replies; 5+ messages in thread
From: Daniel Kestrel @ 2022-07-21 19:34 UTC (permalink / raw)
  Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring, Daniel Kestrel,
	linux-remoteproc, devicetree, linux-kernel

Add vendor prefix for AVM Computersysteme Vertriebs GmbH (http://www.avm.de/en)

Signed-off-by: Daniel Kestrel <kestrelseventyfour@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 294093d45a23..0be52bb27f2b 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -153,6 +153,8 @@ patternProperties:
     description: avia semiconductor
   "^avic,.*":
     description: Shanghai AVIC Optoelectronics Co., Ltd.
+  "^avm,.*":
+    description: AVM Computersysteme Vertriebs GmbH
   "^avnet,.*":
     description: Avnet, Inc.
   "^awinic,.*":
-- 
2.17.1


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

* [PATCH v3 2/3] dt-bindings: remoteproc: Add AVM WASP
  2022-07-21 19:34 [PATCH v3 0/3] Add support for WASP SoC on AVM router boards Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 1/3] dt-bindings: vendor-prefixes: Add AVM Daniel Kestrel
@ 2022-07-21 19:34 ` Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 3/3] remoteproc: Add AVM WASP driver Daniel Kestrel
  2 siblings, 0 replies; 5+ messages in thread
From: Daniel Kestrel @ 2022-07-21 19:34 UTC (permalink / raw)
  Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring, Daniel Kestrel,
	linux-remoteproc, devicetree, linux-kernel

AVM Fritzbox router boards may contain an additional ATH79
based SoC that has the wifi cards connected.
This patch adds bindings for this remote processor.

Signed-off-by: Daniel Kestrel <kestrelseventyfour@gmail.com>
---
 .../bindings/remoteproc/avm,wasp-rproc.yaml   | 61 +++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/avm,wasp-rproc.yaml

diff --git a/Documentation/devicetree/bindings/remoteproc/avm,wasp-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/avm,wasp-rproc.yaml
new file mode 100644
index 000000000000..e8618706a34f
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/avm,wasp-rproc.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/avm,wasp-rproc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AVM WASP processor controller bindings
+
+maintainers:
+  - Daniel Kestrel <kestrelseventyfour@gmail.com>
+
+description: |
+  This document defines the bindings for the remoteproc component that loads and
+  boots firmwares on the AVM Wireless Assistant Support Processor (WASP) SoC
+  that is attached to some AVM Fritzbox devices (3390, 3490, 5490, 5491, 7490).
+
+properties:
+  compatible:
+    enum:
+      - avm,fritzbox3390-wasp
+      - avm,fritzbox3490-wasp
+      - avm,fritzbox5490-wasp
+      - avm,fritzbox5491-wasp
+      - avm,fritzbox7490-wasp
+
+  avm,wasp-mdio:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Lantiq GSWIP switch mdio.
+
+  avm,wasp-port:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Network port, where the WASP SoC is connected to.
+
+  avm,reset-gpios:
+    description: Reset gpio of the WASP SoC.
+    maxItems: 1
+
+  avm,startup-gpios:
+    description: Startup gpio of the WASP SoC.
+    maxItems: 1
+
+required:
+  - compatible
+  - avm,wasp-mdio
+  - avm,wasp-port
+  - avm,reset-gpios
+  - avm,startup-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    remoteproc {
+        compatible = "avm,fritzbox7490-wasp";
+        avm,wasp-mdio = <&gswip_mdio>;
+        avm,wasp-port = <&port5>;
+        avm,reset-gpios = <&gpio 34 GPIO_ACTIVE_HIGH>;
+        avm,startup-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>;
+    };
-- 
2.17.1


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

* [PATCH v3 3/3] remoteproc: Add AVM WASP driver
  2022-07-21 19:34 [PATCH v3 0/3] Add support for WASP SoC on AVM router boards Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 1/3] dt-bindings: vendor-prefixes: Add AVM Daniel Kestrel
  2022-07-21 19:34 ` [PATCH v3 2/3] dt-bindings: remoteproc: Add AVM WASP Daniel Kestrel
@ 2022-07-21 19:34 ` Daniel Kestrel
  2022-07-22 15:44   ` kernel test robot
  2 siblings, 1 reply; 5+ messages in thread
From: Daniel Kestrel @ 2022-07-21 19:34 UTC (permalink / raw)
  Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring, Daniel Kestrel,
	linux-remoteproc, devicetree, linux-kernel

Some AVM Fritzbox router boards (3390, 3490, 5490, 5491, 7490),
that are Lantiq XRX200 based, have a memory only ATH79 based
WASP (Wireless Assistant Support Processor) SoC that has wifi
cards connected to it. It does not share anything with the
Lantiq host and has no persistent storage. It has an mdio based
connection for bringing up a small network boot firmware and is
connected to the Lantiq GSWIP switch via gigabit ethernet. This
is used to load an initramfs linux image to it, after the
network boot firmware was started.

In order to initialize this remote processor we need to:
- power on the SoC using startup gpio
- reset the SoC using the reset gpio
- send the network boot firmware using mdio
- send the linux image using raw ethernet frames

This driver allows to start and stop the WASP SoC.

Signed-off-by: Daniel Kestrel <kestrelseventyfour@gmail.com>
Tested-by: Timo Dorfner <timo.capa@gmail.com> # tested on Fritzbox 7490
---
 drivers/remoteproc/Kconfig    |   10 +
 drivers/remoteproc/Makefile   |    1 +
 drivers/remoteproc/avm_wasp.c | 1056 +++++++++++++++++++++++++++++++++
 3 files changed, 1067 insertions(+)
 create mode 100644 drivers/remoteproc/avm_wasp.c

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 166019786653..a761186c5171 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,16 @@ config REMOTEPROC_CDEV
 
 	  It's safe to say N if you don't want to use this interface.
 
+config AVM_WASP_REMOTEPROC
+	tristate "AVM WASP remoteproc support"
+	depends on NET_DSA_LANTIQ_GSWIP
+	help
+	  Say y here to support booting the secondary SoC ATH79 target
+	  called Wireless Assistant Support Processor (WASP) that some
+	  AVM Fritzbox devices (3390, 3490, 5490, 5491, 7490) have built in.
+
+	  It's safe to say N here.
+
 config IMX_REMOTEPROC
 	tristate "i.MX remoteproc support"
 	depends on ARCH_MXC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 5478c7cb9e07..0ae175c6722f 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -11,6 +11,7 @@ remoteproc-y				+= remoteproc_sysfs.o
 remoteproc-y				+= remoteproc_virtio.o
 remoteproc-y				+= remoteproc_elf_loader.o
 obj-$(CONFIG_REMOTEPROC_CDEV)		+= remoteproc_cdev.o
+obj-$(CONFIG_AVM_WASP_REMOTEPROC)	+= avm_wasp.o
 obj-$(CONFIG_IMX_REMOTEPROC)		+= imx_rproc.o
 obj-$(CONFIG_IMX_DSP_REMOTEPROC)	+= imx_dsp_rproc.o
 obj-$(CONFIG_INGENIC_VPU_RPROC)		+= ingenic_rproc.o
diff --git a/drivers/remoteproc/avm_wasp.c b/drivers/remoteproc/avm_wasp.c
new file mode 100644
index 000000000000..fa35d9589164
--- /dev/null
+++ b/drivers/remoteproc/avm_wasp.c
@@ -0,0 +1,1056 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AVM WASP Remote Processor driver
+ *
+ * Copyright (c) 2019-2020 Andreas Böhler
+ * Copyright (c) 2021-2022 Daniel Kestrel
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/timekeeping.h>
+#include <net/sock.h>
+#include <asm-generic/gpio.h>
+
+#include "remoteproc_internal.h"
+
+#define WASP_CHUNK_SIZE			14
+#define WASP_ADDR			0x07
+#define WASP_TIMEOUT_COUNT		1000
+#define WASP_WAIT_TIMEOUT_COUNT		20
+#define WASP_CHECK_LEN_DIVBY4_MASK	0x3
+
+#define WASP_WRITE_SLEEP_US		20000
+#define WASP_WAIT_SLEEP_US_LOW		50000
+#define WASP_WAIT_SLEEP_US		100000
+#define WASP_POLL_SLEEP_US		200
+
+#define WASP_RESP_RETRY			0x0102
+#define WASP_RESP_OK			0x0002
+#define WASP_RESP_WAIT			0x0401
+#define WASP_RESP_COMPLETED		0x0000
+#define WASP_RESP_READY_TO_START	0x0202
+#define WASP_RESP_STARTING		0x00c9
+
+#define WASP_CMD_SET_PARAMS		0x0c01
+#define WASP_CMD_SET_CHECKSUM_3390	0x0801
+#define WASP_CMD_SET_CHECKSUM_X490	0x0401
+#define WASP_CMD_SET_DATA		0x0e01
+#define WASP_CMD_START_FIRMWARE_3390	0x0201
+#define WASP_CMD_START_FIRMWARE_X490	0x0001
+#define WASP_CMD_START_FIRMWARE2_X490	0x0101
+
+static const u32 start_addr = 0xbd003000;
+static const u32 exec_addr = 0xbd003000;
+
+static const char mac_data[WASP_CHUNK_SIZE] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0x04, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+enum {
+	MODEL_3390,
+	MODEL_X490,
+	MODEL_UNKNOWN
+} m_model = MODEL_UNKNOWN;
+
+#define ETH_TYPE_ATH_ECPS_FRAME		0x88bd
+#define ETH_BUF_SIZE			1056
+#define ETH_SEND_LOOP_TIMEOUT_SECS	60
+#define ETH_MAX_DATA_SIZE		1028
+#define ETH_DATA_SIZE			1024
+#define ETH_WASP_PACKET_ID		0x1200
+
+#define CMD_FIRMWARE_DATA		0x0104
+#define CMD_START_FIRMWARE		0xd400
+
+#define RESP_DISCOVER			0x0000
+#define RESP_OK				0x0100
+#define RESP_STARTING			0x0200
+#define RESP_ERROR			0x0300
+
+static const u32 m_load_addr = 0x81a00000;
+
+static char wasp_mac[] = {0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
+
+struct wasp_packet {
+	struct ethhdr eh;
+	struct __packed {
+		u16	packet_start;
+		u8	pad_one[5];
+		u16	command;
+		u16	response;
+		u16	counter;
+		u8	pad_two;
+	} hdr;
+	u8	payload[ETH_MAX_DATA_SIZE];
+} __packed;
+
+static char *firmware = "ath9k-eeprom-ahb-18100000.wmac.bin";
+module_param(firmware, charp, 0444);
+MODULE_PARM_DESC(firmware,
+		 "Filename of the ath9k eeprom to be loaded");
+
+static char *caldata = "ath10k/cal-pci-0000:00:00.0.bin";
+module_param(caldata, charp, 0444);
+MODULE_PARM_DESC(caldata,
+		 "Filename of the ath10k caldata to be loaded");
+
+static char *netboot = "netboot.fw";
+module_param(netboot, charp, 0444);
+MODULE_PARM_DESC(netboot,
+		 "Filename of the network boot firmware for WASP");
+
+static char *image = "wasp-image.bin";
+module_param(image, charp, 0444);
+MODULE_PARM_DESC(image,
+		 "Filename of the linux image to be loaded to WASP");
+
+/**
+ * struct avm_wasp_rproc - avmwasp remote processor priv
+ * @rproc: rproc handle
+ * @pdev: pointer to platform device
+ * @fw_blob: pointer to load and save any firmware
+ * @linux_blob: pointer to access initramfs image
+ * @mdio_bus: pointer to mii_bus of gswip device for gpio
+ * @startup_gpio: store WASP startup gpio descriptor
+ * @reset_gpio: store WASP reset gpio descriptor
+ * @loader_port: store name of the port wasp is connected to
+ * @buffer: recv buffer for feedback from WASP
+ * @ifindex: interface index used for WASP communication
+ */
+struct avm_wasp_rproc {
+	struct rproc *rproc;
+	struct platform_device *pdev;
+	const struct firmware *fw_blob, *linux_blob;
+	struct mii_bus *mdio_bus;
+	struct gpio_desc *startup_gpio, *reset_gpio;
+	char *loader_port;
+	char buffer[ETH_BUF_SIZE];
+	int ifindex;
+};
+
+/**
+ * avm_wasp_netboot_mdio_write_u32_split() - write 32bit value
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ * @mdio_reg: register start value for two mdio registers to write to
+ * @value: value to be written to the register
+ *
+ * As the mdio registers are 16bit, this function writes a 32bit value
+ * to two subsequent mdio registers starting with the specified register
+ * for the mdio address that is used for the connection to the WASP SoC
+ *
+ * Return: 0 on Success, -ETIMEDOUT if avm_wasp_netboot_mdio_write fails
+ */
+static int avm_wasp_netboot_mdio_write_u32_split(struct avm_wasp_rproc *avmwasp,
+						 u32 mdio_reg, const u32 value)
+{
+	struct device *dev = &avmwasp->pdev->dev;
+	int ret;
+
+	ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, mdio_reg,
+			    ((value & 0xffff0000) >> 16));
+	if (ret < 0)
+		goto err;
+
+	ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, mdio_reg + 2,
+			    (value & 0x0000ffff));
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	dev_err(dev, "mdio split write failed\n");
+	return ret;
+}
+
+/**
+ * avm_wasp_read_poll_timeout() - wrap read_poll_timeout_macro
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ * @udelay: microseconds to wait after read
+ * @utimeout: timeout value in microseconds
+ * @checkval: value to be checked against
+ *
+ * This function checks checkval against the WASP mdio status register,
+ * waits udelay before repeating the read and times out after utimeout.
+ * Separate function because every other use of read_poll_timeout makes
+ * the kernel module around half a kB larger.
+ *
+ * Return: 0 when checkval was read or -ETIMEDOUT if not
+ */
+static int avm_wasp_read_poll_timeout(struct avm_wasp_rproc *avmwasp,
+				      u32 udelay, u32 utimeout, u32 checkval)
+{
+	u32 val;
+
+	return read_poll_timeout(mdiobus_read, val,
+				 (val == checkval), udelay, utimeout, false,
+				 avmwasp->mdio_bus, WASP_ADDR, 0x0);
+}
+
+/**
+ * avm_wasp_netboot_write_header() - write header to WASP
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ * @start_addr: address where to load the firmware to on WASP
+ * @len: length of the network boot firmware
+ * @exec_addr: address where to start execution on WASP
+ *
+ * Writes the header to WASP using mdio to initiate the start of
+ * transferring the network boot firmware to WASP
+ *
+ * Return: 0 on Success, -ETIMEDOUT if writing header failed based on return
+ * code from WASP or the write methods
+ */
+static int avm_wasp_netboot_write_header(struct avm_wasp_rproc *avmwasp,
+					 const u32 start_addr, const u32 len,
+					 const u32 exec_addr)
+{
+	struct device *dev = &avmwasp->pdev->dev;
+	int ret;
+
+	ret = avm_wasp_netboot_mdio_write_u32_split(avmwasp, 0x2, start_addr);
+	if (ret < 0)
+		goto err;
+
+	ret = avm_wasp_netboot_mdio_write_u32_split(avmwasp, 0x6, len);
+	if (ret < 0)
+		goto err;
+
+	ret = avm_wasp_netboot_mdio_write_u32_split(avmwasp, 0xA, exec_addr);
+	if (ret < 0)
+		goto err;
+
+	ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, 0x0,
+			    WASP_CMD_SET_PARAMS);
+	if (ret < 0)
+		goto err;
+
+	ret = avm_wasp_read_poll_timeout(avmwasp, WASP_POLL_SLEEP_US,
+					 WASP_TIMEOUT_COUNT * WASP_POLL_SLEEP_US,
+					 WASP_RESP_OK);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	dev_err(dev, "mdio write for header failed\n");
+	return ret;
+}
+
+/**
+ * avm_wasp_netboot_write_checksum() - write checksum to WASP
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ * @checksum: calculated checksum value to be sent to WASP
+ *
+ * Writes the calculated checksum for the given network boot firmware
+ * to WASP using mdio as the second step
+ *
+ * Return: 0 on Success, -ETIMEDOUT if writing checksum failed based on
+ * return code from WASP or the write methods
+ */
+static int avm_wasp_netboot_write_checksum(struct avm_wasp_rproc *avmwasp,
+					   const u32 checksum)
+{
+	struct device *dev = &avmwasp->pdev->dev;
+	int ret;
+
+	ret = avm_wasp_netboot_mdio_write_u32_split(avmwasp, 0x2, checksum);
+	if (ret < 0)
+		goto err;
+
+	if (m_model == MODEL_3390) {
+		ret = avm_wasp_netboot_mdio_write_u32_split(avmwasp, 0x6, 0x0000);
+		if (ret < 0)
+			goto err;
+
+		ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_SET_CHECKSUM_3390);
+	} else if (m_model == MODEL_X490) {
+		ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_SET_CHECKSUM_X490);
+	}
+	if (ret < 0)
+		goto err;
+
+	ret = avm_wasp_read_poll_timeout(avmwasp, WASP_POLL_SLEEP_US,
+					 WASP_TIMEOUT_COUNT * WASP_POLL_SLEEP_US,
+					 WASP_RESP_OK);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	dev_err(dev, "mdio write for checksum failed\n");
+	return ret;
+}
+
+/**
+ * avm_wasp_netboot_write_chunk() - write chunk of data to WASP
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ * @data: pointer to data
+ * @len: length of data (should not exceed 14 bytes)
+ *
+ * Writes up to 14 bytes of data into the 7 16bit mdio registers
+ * to WASP using mdio
+ *
+ * Return: 0 on Success, -EFAULT if data length is more than 14 bytes or
+ * -ETIMEDOUT if writing the data failed based on return code from WASP
+ * or the write methods
+ */
+static int avm_wasp_netboot_write_chunk(struct avm_wasp_rproc *avmwasp,
+					const char *data, size_t len)
+{
+	struct device *dev = &avmwasp->pdev->dev;
+	int i, ret;
+
+	if (len > WASP_CHUNK_SIZE || !data)
+		return -EFAULT;
+
+	for (i = 0; i < len && ret >= 0; i += 2)
+		ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, i + 2,
+				    *((u16 *)(data + i)));
+	if (ret < 0)
+		goto err;
+
+	ret = mdiobus_write(avmwasp->mdio_bus, WASP_ADDR, 0x0, WASP_CMD_SET_DATA);
+	if (ret < 0)
+		goto err;
+
+	ret = avm_wasp_read_poll_timeout(avmwasp, WASP_POLL_SLEEP_US,
+					 WASP_TIMEOUT_COUNT * WASP_POLL_SLEEP_US,
+					 WASP_RESP_OK);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	dev_err(dev, "mdio write for data chunk failed\n");
+	return ret;
+}
+
+/**
+ * avm_wasp_netboot_calc_checksum() - calculate netboot firmware checksum
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ *
+ * Calculates the checksum by using the firmware in fw_blob from the private
+ * avm_wasp_rproc structure
+ *
+ * Return: Calculated checksum
+ */
+static u32 avm_wasp_netboot_calc_checksum(struct avm_wasp_rproc *avmwasp)
+{
+	u32 checksum = U32_MAX, count = U32_MAX, cs;
+	const u8 *firmware, *firmware_end;
+
+	firmware = avmwasp->fw_blob->data;
+	firmware_end = firmware + avmwasp->fw_blob->size;
+
+	while (firmware < firmware_end) {
+		cs = be32_to_cpu(*(u32 *)firmware);
+		checksum = checksum - cs;
+		count++;
+		firmware += 4;
+	}
+
+	checksum = checksum - count;
+	return checksum;
+}
+
+/**
+ * avm_wasp_netboot_load_firmware() - load netboot firmware to WASP
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ *
+ * First the status is checked if poweron and reset were successful.
+ * Implements the process to send header, checksum and the firmware
+ * blob in 14 byte chunks to the WASP processor using mdio
+ * Includes checks between the steps and sending commands to start
+ * the network boot firmware
+ *
+ * Return: 0 on Success, -ENODEV if WASP not ready after reset,
+ * -ETIMEDOUT if there was a timeout on polling or
+ * -EFAULT if other errors have occurred
+ */
+static int avm_wasp_netboot_load_firmware(struct avm_wasp_rproc *avmwasp)
+{
+	struct device *dev = &avmwasp->pdev->dev;
+	struct mii_bus *mdio_bus = avmwasp->mdio_bus;
+	const u8 *firmware, *firmware_end;
+	int regval, regval2, ret, cont = 1;
+	u32 checksum, left;
+
+	ret = avm_wasp_read_poll_timeout(avmwasp, WASP_WAIT_SLEEP_US,
+					 WASP_WAIT_TIMEOUT_COUNT *
+					 WASP_WAIT_SLEEP_US, WASP_RESP_OK);
+	if (ret) {
+		dev_err(dev, "error WASP processor not in ready status\n");
+		return -ENODEV;
+	}
+
+	firmware = avmwasp->fw_blob->data;
+	firmware_end = firmware + avmwasp->fw_blob->size;
+
+	if ((avmwasp->fw_blob->size & WASP_CHECK_LEN_DIVBY4_MASK) ||
+	    avmwasp->fw_blob->size > U16_MAX) {
+		dev_err(dev, "error network boot firmware size\n");
+		return -EFAULT;
+	}
+
+	ret = avm_wasp_netboot_write_header(avmwasp, start_addr,
+					    avmwasp->fw_blob->size,
+					    exec_addr);
+	if (ret < 0)
+		return ret;
+
+	checksum = avm_wasp_netboot_calc_checksum(avmwasp);
+	ret = avm_wasp_netboot_write_checksum(avmwasp, checksum);
+
+	if (ret < 0)
+		return ret;
+
+	while (firmware < firmware_end) {
+		left = firmware_end - firmware;
+		if (left > WASP_CHUNK_SIZE)
+			left = WASP_CHUNK_SIZE;
+		ret = avm_wasp_netboot_write_chunk(avmwasp, firmware, left);
+		if (ret < 0)
+			return ret;
+
+		firmware += left;
+	}
+
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+
+	if (m_model == MODEL_3390)
+		ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_START_FIRMWARE_3390);
+	else if (m_model == MODEL_X490)
+		ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_START_FIRMWARE_X490);
+	if (ret < 0) {
+		dev_err(dev, "writing command failed\n");
+		return ret;
+	}
+
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+
+	ret = avm_wasp_read_poll_timeout(avmwasp, WASP_WAIT_SLEEP_US,
+					 WASP_WAIT_TIMEOUT_COUNT *
+					 WASP_WAIT_SLEEP_US,
+					 WASP_RESP_READY_TO_START);
+	if (ret) {
+		dev_err(dev, "timed out waiting for WASP ready to start\n");
+		return ret;
+	}
+
+	if (m_model == MODEL_3390)
+		ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_START_FIRMWARE_3390);
+	else if (m_model == MODEL_X490)
+		ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_SET_CHECKSUM_X490);
+	if (ret < 0) {
+		dev_err(dev, "writing command failed\n");
+		return ret;
+	}
+
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+
+	if (m_model == MODEL_3390) {
+		ret = avm_wasp_read_poll_timeout(avmwasp, WASP_WAIT_SLEEP_US,
+						 WASP_WAIT_TIMEOUT_COUNT *
+						 WASP_WAIT_SLEEP_US * 10,
+						 WASP_RESP_OK);
+		if (ret) {
+			dev_err(dev, "timed out waiting for WASP OK\n");
+			return ret;
+		}
+		if (avm_wasp_netboot_write_chunk(avmwasp, mac_data,
+						 ARRAY_SIZE(mac_data)) < 0) {
+			dev_err(dev, "error sending MAC address\n");
+			return -EFAULT;
+		}
+	} else if (m_model == MODEL_X490) {
+		while (cont) {
+			ret = avm_wasp_read_poll_timeout(avmwasp,
+							 WASP_WAIT_SLEEP_US,
+							 WASP_WAIT_TIMEOUT_COUNT *
+							 WASP_WAIT_SLEEP_US,
+							 WASP_RESP_OK);
+			if (ret) {
+				dev_err(dev,
+					"timed out waiting for WASP OK\n");
+				return ret;
+			}
+			regval = mdiobus_read(mdio_bus, WASP_ADDR, 0x2);
+			if (regval < 0) {
+				dev_err(dev, "mdio read failed\n");
+				return ret;
+			}
+			regval2 = mdiobus_read(mdio_bus, WASP_ADDR, 0x4);
+			if (regval2 < 0) {
+				dev_err(dev, "mdio read failed\n");
+				return ret;
+			}
+			ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x0,
+					    WASP_CMD_SET_CHECKSUM_X490);
+			if (ret < 0) {
+				dev_err(dev, "writing command failed\n");
+				return ret;
+			}
+
+			if (regval == 0 && regval2 != 0)
+				cont = regval2;
+			else
+				cont--;
+		}
+
+		ret = avm_wasp_read_poll_timeout(avmwasp,
+						 WASP_POLL_SLEEP_US,
+						 WASP_TIMEOUT_COUNT *
+						 WASP_POLL_SLEEP_US,
+						 WASP_RESP_OK);
+		if (ret) {
+			dev_err(dev,
+				"error waiting for checksum OK response\n");
+			return ret;
+		}
+
+		ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x2, 0x00);
+		if (ret < 0) {
+			dev_err(dev, "mdio write failed\n");
+			return ret;
+		}
+		ret = mdiobus_write(mdio_bus, WASP_ADDR, 0x0,
+				    WASP_CMD_START_FIRMWARE2_X490);
+		if (ret < 0) {
+			dev_err(dev, "writing command failed\n");
+			return ret;
+		}
+
+		regval = mdiobus_read(mdio_bus, WASP_ADDR, 0x0);
+		if (regval != WASP_RESP_OK) {
+			dev_err(dev,
+				"error starting WASP network boot: 0x%x\n",
+				regval);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * avm_wasp_load_initramfs_image() - load initramfs image to WASP
+ * @avmwasp: pointer to drivers private avm_wasp_rproc structure
+ *
+ * Uses the lan port specified from DT to load the initramfs to
+ * WASP after the network boot firmware was successfully started.
+ * Communication is done by using raw sockets.
+ * There are several commands and status values which are checked.
+ * First a discovery packet is received and then each data packet
+ * is acknowledged by the WASP network boot firmware.
+ * First packet needs to prepend the load address and last packet
+ * needs to append the execution address.
+ *
+ * Return: 0 on Success, -EFAULT if errors with the WASP send protocol
+ * have occurred, -EAGAIN if the wasp network interface is down or the
+ * error returned from the failed operating system function or service
+ */
+static int avm_wasp_load_initramfs_image(struct avm_wasp_rproc *avmwasp)
+{
+	bool done = false;
+	int ret;
+	u32 num_chunks, chunk_counter;
+	short interface_flags;
+	const u8 *firmware, *firmware_end;
+	struct device *dev = &avmwasp->pdev->dev;
+	struct kvec socket_kvec;
+	struct msghdr socket_msghdr;
+	struct net_device *send_netdev;
+	struct sockaddr send_sock_addr;
+	struct sockaddr_ll send_socket_address;
+	struct socket *wasp_socket;
+	struct wasp_packet *packet = (struct wasp_packet *)
+			(avmwasp->buffer);
+	struct __kernel_old_timeval timeout;
+	time64_t start_time, current_time;
+
+	if (!avmwasp->linux_blob) {
+		dev_err(dev, "error accessing initramfs image\n");
+		goto err;
+	}
+
+	firmware = avmwasp->linux_blob->data;
+	firmware_end = firmware + avmwasp->linux_blob->size;
+
+	ret = sock_create_kern(&init_net, PF_PACKET, SOCK_RAW,
+			       htons(ETH_TYPE_ATH_ECPS_FRAME),
+			       &wasp_socket);
+	if (ret < 0) {
+		dev_err(dev, "error opening recv socket: %d\n", ret);
+		goto err;
+	}
+
+	timeout.tv_sec = 10;
+	timeout.tv_usec = 0;
+	ret = sock_setsockopt(wasp_socket, SOL_SOCKET, SO_RCVTIMEO_OLD,
+			      KERNEL_SOCKPTR(&timeout), sizeof(timeout));
+	if (ret < 0) {
+		dev_err(dev, "error SO_RCVTIMEO recv socket: %d\n", ret);
+		goto err_socket;
+	}
+
+	ret = sock_setsockopt(wasp_socket, SOL_SOCKET, SO_SNDTIMEO_OLD,
+			      KERNEL_SOCKPTR(&timeout), sizeof(timeout));
+	if (ret < 0) {
+		dev_err(dev, "error SO_SNDTIMEO send socket: %d\n", ret);
+		goto err_socket;
+	}
+
+	rcu_read_lock();
+	send_netdev = dev_get_by_name_rcu(sock_net(wasp_socket->sk),
+					  avmwasp->loader_port);
+	if (send_netdev)
+		interface_flags = (short)dev_get_flags(send_netdev);
+	rcu_read_unlock();
+
+	if (IS_ERR_OR_NULL(send_netdev)) {
+		dev_err(dev, "error accessing net device\n");
+		ret = -ENODEV;
+		goto err_socket;
+	}
+
+	if (!(interface_flags & IFF_UP && interface_flags & IFF_RUNNING)) {
+		dev_err(dev, "error wasp interface %s is down\n",
+			avmwasp->loader_port);
+		ret = -EAGAIN;
+		goto err_socket;
+	}
+
+	avmwasp->ifindex = send_netdev->ifindex;
+	ret = dev_get_mac_address(&send_sock_addr, &init_net,
+				  avmwasp->loader_port);
+	if (ret < 0) {
+		dev_err(dev, "error getting mac address: %d\n", ret);
+		goto err_socket;
+	}
+
+	send_socket_address.sll_halen = ETH_ALEN;
+	send_socket_address.sll_ifindex = avmwasp->ifindex;
+	memset(&socket_msghdr, 0, sizeof(socket_msghdr));
+	socket_msghdr.msg_name = (struct sockaddr *)&send_socket_address;
+	socket_msghdr.msg_namelen = sizeof(struct sockaddr_ll);
+
+	start_time = ktime_get_seconds();
+
+	while (!done) {
+		current_time = ktime_get_seconds();
+		if ((current_time - start_time) > ETH_SEND_LOOP_TIMEOUT_SECS) {
+			dev_err(dev,
+				"waiting for packet from WASP timed out\n");
+			ret = -ETIMEDOUT;
+			goto err_socket;
+		}
+
+		socket_kvec.iov_base = avmwasp->buffer;
+		socket_kvec.iov_len = ETH_BUF_SIZE;
+		ret = kernel_recvmsg(wasp_socket,
+				     &socket_msghdr, &socket_kvec, 1,
+				     ETH_BUF_SIZE, 0);
+
+		if (ret < 0) {
+			dev_err(dev,
+				"error receiving any packet or timeout: %d\n",
+				ret);
+			goto err_socket;
+		}
+
+		if (ret < (sizeof(struct ethhdr) + sizeof(packet->hdr))) {
+			dev_err(dev,
+				"packet too small, discard and continue\n");
+			continue;
+		}
+
+		if (packet->eh.h_proto != ETH_TYPE_ATH_ECPS_FRAME)
+			continue;
+
+		memcpy(wasp_mac, packet->eh.h_source, sizeof(wasp_mac));
+
+		if (packet->hdr.packet_start == ETH_WASP_PACKET_ID) {
+			switch (packet->hdr.response) {
+			case RESP_DISCOVER:
+				chunk_counter = 1;
+				num_chunks = DIV_ROUND_UP(avmwasp->linux_blob->size,
+							  ETH_DATA_SIZE);
+				fallthrough;
+			case RESP_OK:
+				memcpy(packet->eh.h_dest, wasp_mac, sizeof(packet->eh.h_dest));
+				packet->eh.h_proto = ETH_TYPE_ATH_ECPS_FRAME;
+				memcpy(packet->eh.h_source, send_sock_addr.sa_data,
+				       sizeof(packet->eh.h_source));
+
+				if (firmware < firmware_end) {
+					size_t bytestosend, send_len;
+					u32 data_offset = 0;
+
+					if (chunk_counter == 1) {
+						memcpy(packet->payload,
+						       &m_load_addr,
+						       sizeof(m_load_addr));
+						data_offset = sizeof(m_load_addr);
+					}
+
+					if ((firmware_end - firmware) >=
+					     ETH_DATA_SIZE)
+						bytestosend = ETH_DATA_SIZE;
+					else
+						bytestosend = firmware_end -
+									firmware;
+					memcpy(&packet->payload[data_offset],
+					       firmware, bytestosend);
+					firmware = firmware + ETH_DATA_SIZE;
+
+					packet->hdr.packet_start =
+							ETH_WASP_PACKET_ID;
+					if (chunk_counter == num_chunks) {
+						packet->hdr.response =
+							CMD_START_FIRMWARE;
+						memcpy(&packet->payload
+						       [data_offset + bytestosend],
+						       &m_load_addr,
+						       sizeof(m_load_addr));
+						bytestosend += sizeof(m_load_addr);
+					} else {
+						packet->hdr.command =
+							CMD_FIRMWARE_DATA;
+					}
+					packet->hdr.counter =
+							(chunk_counter - 1) * 4;
+
+					send_len = sizeof(struct ethhdr)
+						+ sizeof(packet->hdr) + bytestosend +
+						data_offset;
+
+					socket_kvec.iov_len = send_len;
+					socket_kvec.iov_base = avmwasp->buffer;
+
+					ret = kernel_sendmsg(wasp_socket,
+							     &socket_msghdr,
+							     &socket_kvec,
+							     1, send_len);
+					if (ret < 0) {
+						dev_err(dev,
+							"error sending to WASP %d\n",
+							ret);
+						goto err_socket;
+					}
+
+					chunk_counter++;
+				}
+				break;
+			case RESP_ERROR:
+				dev_err(dev,
+					"received an WASP error packet\n");
+				ret = -EFAULT;
+				goto err_socket;
+			case RESP_STARTING:
+				done = true;
+				ret = 0;
+				continue;
+				break;
+			default:
+				dev_err(dev, "unknown packet, continue\n");
+				continue;
+				break;
+			}
+		}
+	}
+
+err_socket:
+	wasp_socket->ops->release(wasp_socket);
+err:
+	return ret;
+}
+
+/**
+ * avm_wasp_rproc_start() - start the remote processor
+ * @rproc: pointer to the rproc structure
+ *
+ * Starts the remote processor by initiating the reset process using
+ * the reset_gpio.
+ * As the first step, the network boot firmware is tried to be loaded
+ * and started.
+ * As a second step, the initramfs image is tried to be loaded
+ * and started.
+ *
+ * Return: 0 on Success, -ENODEV or return code from the called function
+ * if any other error occurred in the process of starting and loading
+ * the firmware files to the WASP processor
+ */
+static int avm_wasp_rproc_start(struct rproc *rproc)
+{
+	struct avm_wasp_rproc *avmwasp = rproc->priv;
+	struct device *dev = &avmwasp->pdev->dev;
+	u32 phandle;
+	int ret;
+
+	gpiod_set_value(avmwasp->reset_gpio, 0);
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+	gpiod_set_value(avmwasp->reset_gpio, 1);
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+
+	ret = request_firmware_direct((const struct firmware **)
+				      &avmwasp->fw_blob, netboot, dev);
+	if (ret) {
+		dev_err(dev, "could not load network boot firmware\n");
+		goto err;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "avm,wasp-mdio", &phandle);
+	if (ret) {
+		dev_err(dev, "no wasp-netboot-mdio given\n");
+		goto err_release_fw;
+	} else {
+		struct device_node *mdio_node =
+					of_find_node_by_phandle(phandle);
+
+		if (!mdio_node) {
+			dev_err(dev, "get wasp-netboot-mdio failed\n");
+			ret = -ENODEV;
+			goto err_release_fw;
+		} else {
+			avmwasp->mdio_bus = of_mdio_find_bus(mdio_node);
+			of_node_put(mdio_node);
+			if (!avmwasp->mdio_bus) {
+				dev_err(dev, "mdio bus not found\n");
+				ret = -ENODEV;
+				goto err_release_fw;
+			}
+		}
+	}
+
+	ret = avm_wasp_netboot_load_firmware(avmwasp);
+	if (ret)
+		goto err_put_device;
+
+	ret = avm_wasp_load_initramfs_image(avmwasp);
+
+err_put_device:
+	put_device(&avmwasp->mdio_bus->dev);
+err_release_fw:
+	release_firmware(avmwasp->fw_blob);
+err:
+	return ret;
+}
+
+/**
+ * avm_wasp_rproc_stop() - stop the remote processor
+ * @rproc: pointer to the rproc structure
+ *
+ * To stop the remote processor the reset gpio is used
+ *
+ * Return: 0 on Success
+ */
+static int avm_wasp_rproc_stop(struct rproc *rproc)
+{
+	struct avm_wasp_rproc *avmwasp = rproc->priv;
+
+	gpiod_set_value(avmwasp->reset_gpio, 0);
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+	gpiod_set_value(avmwasp->reset_gpio, 1);
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+
+	return 0;
+}
+
+/**
+ * avm_wasp_rproc_load() - noop to avoid the ELF binary defaults
+ * @rproc: pointer to the rproc structure
+ * @fw: pointer to firmware struct
+ *
+ * If a load function is not defined in the rproc_ops, then all the settings
+ * like checking the firmware binary will default to ELF checks, which fail
+ * in case of the bootable and compressed initramfs image for WASP.
+ * This function stores the initramfs image that is loaded by the remote
+ * processor framework during boot process into the priv for access by
+ * the initramfs load function avm_wasp_load_initramfs_image().
+ *
+ * Return: Always 0
+ */
+static int avm_wasp_rproc_load(struct rproc *rproc, const struct firmware *fw)
+{
+	struct avm_wasp_rproc *avmwasp = rproc->priv;
+
+	avmwasp->linux_blob = fw;
+
+	return 0;
+}
+
+static const struct rproc_ops avm_wasp_rproc_ops = {
+	.start		= avm_wasp_rproc_start,
+	.stop		= avm_wasp_rproc_stop,
+	.load		= avm_wasp_rproc_load,
+};
+
+static int avm_wasp_rproc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct avm_wasp_rproc *avmwasp;
+	struct rproc *rproc;
+	struct net_device *netdev;
+	int ret;
+	short interface_flags;
+	const u32 *match_data;
+	u32 phandle;
+
+	match_data = of_device_get_match_data(dev);
+	if (IS_ERR_OR_NULL(match_data)) {
+		dev_err_probe(dev, PTR_ERR(match_data),
+			      "model specific data is not defined\n");
+		ret = -ENODEV;
+		goto err;
+	}
+	m_model = *match_data;
+
+	rproc = devm_rproc_alloc(dev, "avm,wasp", &avm_wasp_rproc_ops,
+				 image, sizeof(*avmwasp));
+	if (!rproc) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	rproc->auto_boot = true;
+
+	avmwasp = rproc->priv;
+	avmwasp->rproc = rproc;
+	avmwasp->pdev = pdev;
+
+	ret = request_firmware((const struct firmware **)&avmwasp->fw_blob,
+			       firmware, dev);
+	if (ret)
+		dev_err(dev, "could not load ath9k firmware\n");
+	release_firmware(avmwasp->fw_blob);
+
+	if (m_model == MODEL_X490) {
+		ret = request_firmware((const struct firmware **)
+				       &avmwasp->fw_blob, caldata, dev);
+		if (ret)
+			dev_err(dev, "could not load ath10k caldata\n");
+		release_firmware(avmwasp->fw_blob);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "avm,wasp-port",
+				   &phandle);
+	if (ret) {
+		dev_err(dev, "no wasp-port given\n");
+		goto err;
+	} else {
+		struct device_node *child = of_find_node_by_phandle(phandle);
+
+		if (!child) {
+			dev_err(dev, "get wasp-port node failed\n");
+			ret = -ENODEV;
+			goto err;
+		} else {
+			ret = of_property_read_string(child, "label",
+						      (const char **)
+						      &avmwasp->loader_port);
+			of_node_put(child);
+			if (ret) {
+				dev_err(dev, "get wasp-port label failed\n");
+				goto err;
+			}
+		}
+	}
+
+	rcu_read_lock();
+	netdev = dev_get_by_name_rcu(&init_net, avmwasp->loader_port);
+	if (netdev)
+		interface_flags = (short)dev_get_flags(netdev);
+	rcu_read_unlock();
+
+	if (IS_ERR_OR_NULL(netdev)) {
+		dev_err_probe(dev, PTR_ERR(netdev),
+			      "error accessing net device\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (!(interface_flags & IFF_UP && interface_flags & IFF_RUNNING)) {
+		dev_err(dev, "error wasp interface %s down\n",
+			avmwasp->loader_port);
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+
+	avmwasp->startup_gpio = devm_gpiod_get(dev, "avm,startup",
+					       GPIOD_OUT_LOW);
+	if (IS_ERR(avmwasp->startup_gpio)) {
+		ret = dev_err_probe(dev, PTR_ERR(avmwasp->startup_gpio),
+				    "failed to get startup gpio\n");
+		goto err;
+	}
+
+	avmwasp->reset_gpio = devm_gpiod_get(dev, "avm,reset", GPIOD_OUT_LOW);
+	if (IS_ERR(avmwasp->reset_gpio)) {
+		ret = dev_err_probe(dev, PTR_ERR(avmwasp->reset_gpio),
+				    "failed to get reset gpio\n");
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, rproc);
+
+	ret = devm_rproc_add(dev, rproc);
+	if (ret) {
+		dev_err(dev, "rproc_add failed\n");
+		goto err;
+	}
+
+	gpiod_set_value(avmwasp->startup_gpio, 1);
+	usleep_range(WASP_WAIT_SLEEP_US_LOW, WASP_WAIT_SLEEP_US);
+
+err:
+	return ret;
+}
+
+static int avm_wasp_rproc_remove(struct platform_device *pdev)
+{
+	struct rproc *rproc = platform_get_drvdata(pdev);
+	struct avm_wasp_rproc *avmwasp = rproc->priv;
+
+	gpiod_set_value(avmwasp->startup_gpio, 0);
+
+	return 0;
+}
+
+static const u32 model_3390 = MODEL_3390;
+static const u32 model_x490 = MODEL_X490;
+
+static const struct of_device_id avm_wasp_rproc_of_match[] = {
+	{ .compatible = "avm,fritzbox3390-wasp", .data = &model_3390 },
+	{ .compatible = "avm,fritzbox3490-wasp", .data = &model_x490 },
+	{ .compatible = "avm,fritzbox5490-wasp", .data = &model_x490 },
+	{ .compatible = "avm,fritzbox5491-wasp", .data = &model_x490 },
+	{ .compatible = "avm,fritzbox7490-wasp", .data = &model_x490 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, avm_wasp_rproc_of_match);
+
+static struct platform_driver avm_wasp_rproc_driver = {
+	.probe = avm_wasp_rproc_probe,
+	.remove = avm_wasp_rproc_remove,
+	.driver = {
+		.name = "avm_wasp_rproc",
+		.of_match_table = avm_wasp_rproc_of_match,
+	},
+};
+
+module_platform_driver(avm_wasp_rproc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("AVM WASP remote processor boot driver");
+MODULE_AUTHOR("Daniel Kestrel <kestrelseventyfour@gmail.com>");
-- 
2.17.1


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

* Re: [PATCH v3 3/3] remoteproc: Add AVM WASP driver
  2022-07-21 19:34 ` [PATCH v3 3/3] remoteproc: Add AVM WASP driver Daniel Kestrel
@ 2022-07-22 15:44   ` kernel test robot
  0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2022-07-22 15:44 UTC (permalink / raw)
  To: Daniel Kestrel
  Cc: llvm, kbuild-all, Bjorn Andersson, Mathieu Poirier, Rob Herring,
	Daniel Kestrel, linux-remoteproc, devicetree, linux-kernel

Hi Daniel,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on remoteproc/rproc-next]
[also build test WARNING on robh/for-next linus/master v5.19-rc7 next-20220721]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Daniel-Kestrel/Add-support-for-WASP-SoC-on-AVM-router-boards/20220722-033724
base:   git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20220722/202207222313.GAofKYST-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 72686d68c137551cce816416190a18d45b4d4e2a)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/b737a00511b74767e3eb13b2ddfba8e6dfe8e5c2
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Daniel-Kestrel/Add-support-for-WASP-SoC-on-AVM-router-boards/20220722-033724
        git checkout b737a00511b74767e3eb13b2ddfba8e6dfe8e5c2
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/remoteproc/

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

All warnings (new ones prefixed by >>):

>> drivers/remoteproc/avm_wasp.c:582:6: warning: variable 'ret' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
           if (!avmwasp->linux_blob) {
               ^~~~~~~~~~~~~~~~~~~~
   drivers/remoteproc/avm_wasp.c:776:9: note: uninitialized use occurs here
           return ret;
                  ^~~
   drivers/remoteproc/avm_wasp.c:582:2: note: remove the 'if' if its condition is always false
           if (!avmwasp->linux_blob) {
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/remoteproc/avm_wasp.c:566:9: note: initialize the variable 'ret' to silence this warning
           int ret;
                  ^
                   = 0
   1 warning generated.


vim +582 drivers/remoteproc/avm_wasp.c

   545	
   546	/**
   547	 * avm_wasp_load_initramfs_image() - load initramfs image to WASP
   548	 * @avmwasp: pointer to drivers private avm_wasp_rproc structure
   549	 *
   550	 * Uses the lan port specified from DT to load the initramfs to
   551	 * WASP after the network boot firmware was successfully started.
   552	 * Communication is done by using raw sockets.
   553	 * There are several commands and status values which are checked.
   554	 * First a discovery packet is received and then each data packet
   555	 * is acknowledged by the WASP network boot firmware.
   556	 * First packet needs to prepend the load address and last packet
   557	 * needs to append the execution address.
   558	 *
   559	 * Return: 0 on Success, -EFAULT if errors with the WASP send protocol
   560	 * have occurred, -EAGAIN if the wasp network interface is down or the
   561	 * error returned from the failed operating system function or service
   562	 */
   563	static int avm_wasp_load_initramfs_image(struct avm_wasp_rproc *avmwasp)
   564	{
   565		bool done = false;
   566		int ret;
   567		u32 num_chunks, chunk_counter;
   568		short interface_flags;
   569		const u8 *firmware, *firmware_end;
   570		struct device *dev = &avmwasp->pdev->dev;
   571		struct kvec socket_kvec;
   572		struct msghdr socket_msghdr;
   573		struct net_device *send_netdev;
   574		struct sockaddr send_sock_addr;
   575		struct sockaddr_ll send_socket_address;
   576		struct socket *wasp_socket;
   577		struct wasp_packet *packet = (struct wasp_packet *)
   578				(avmwasp->buffer);
   579		struct __kernel_old_timeval timeout;
   580		time64_t start_time, current_time;
   581	
 > 582		if (!avmwasp->linux_blob) {
   583			dev_err(dev, "error accessing initramfs image\n");
   584			goto err;
   585		}
   586	
   587		firmware = avmwasp->linux_blob->data;
   588		firmware_end = firmware + avmwasp->linux_blob->size;
   589	
   590		ret = sock_create_kern(&init_net, PF_PACKET, SOCK_RAW,
   591				       htons(ETH_TYPE_ATH_ECPS_FRAME),
   592				       &wasp_socket);
   593		if (ret < 0) {
   594			dev_err(dev, "error opening recv socket: %d\n", ret);
   595			goto err;
   596		}
   597	
   598		timeout.tv_sec = 10;
   599		timeout.tv_usec = 0;
   600		ret = sock_setsockopt(wasp_socket, SOL_SOCKET, SO_RCVTIMEO_OLD,
   601				      KERNEL_SOCKPTR(&timeout), sizeof(timeout));
   602		if (ret < 0) {
   603			dev_err(dev, "error SO_RCVTIMEO recv socket: %d\n", ret);
   604			goto err_socket;
   605		}
   606	
   607		ret = sock_setsockopt(wasp_socket, SOL_SOCKET, SO_SNDTIMEO_OLD,
   608				      KERNEL_SOCKPTR(&timeout), sizeof(timeout));
   609		if (ret < 0) {
   610			dev_err(dev, "error SO_SNDTIMEO send socket: %d\n", ret);
   611			goto err_socket;
   612		}
   613	
   614		rcu_read_lock();
   615		send_netdev = dev_get_by_name_rcu(sock_net(wasp_socket->sk),
   616						  avmwasp->loader_port);
   617		if (send_netdev)
   618			interface_flags = (short)dev_get_flags(send_netdev);
   619		rcu_read_unlock();
   620	
   621		if (IS_ERR_OR_NULL(send_netdev)) {
   622			dev_err(dev, "error accessing net device\n");
   623			ret = -ENODEV;
   624			goto err_socket;
   625		}
   626	
   627		if (!(interface_flags & IFF_UP && interface_flags & IFF_RUNNING)) {
   628			dev_err(dev, "error wasp interface %s is down\n",
   629				avmwasp->loader_port);
   630			ret = -EAGAIN;
   631			goto err_socket;
   632		}
   633	
   634		avmwasp->ifindex = send_netdev->ifindex;
   635		ret = dev_get_mac_address(&send_sock_addr, &init_net,
   636					  avmwasp->loader_port);
   637		if (ret < 0) {
   638			dev_err(dev, "error getting mac address: %d\n", ret);
   639			goto err_socket;
   640		}
   641	
   642		send_socket_address.sll_halen = ETH_ALEN;
   643		send_socket_address.sll_ifindex = avmwasp->ifindex;
   644		memset(&socket_msghdr, 0, sizeof(socket_msghdr));
   645		socket_msghdr.msg_name = (struct sockaddr *)&send_socket_address;
   646		socket_msghdr.msg_namelen = sizeof(struct sockaddr_ll);
   647	
   648		start_time = ktime_get_seconds();
   649	
   650		while (!done) {
   651			current_time = ktime_get_seconds();
   652			if ((current_time - start_time) > ETH_SEND_LOOP_TIMEOUT_SECS) {
   653				dev_err(dev,
   654					"waiting for packet from WASP timed out\n");
   655				ret = -ETIMEDOUT;
   656				goto err_socket;
   657			}
   658	
   659			socket_kvec.iov_base = avmwasp->buffer;
   660			socket_kvec.iov_len = ETH_BUF_SIZE;
   661			ret = kernel_recvmsg(wasp_socket,
   662					     &socket_msghdr, &socket_kvec, 1,
   663					     ETH_BUF_SIZE, 0);
   664	
   665			if (ret < 0) {
   666				dev_err(dev,
   667					"error receiving any packet or timeout: %d\n",
   668					ret);
   669				goto err_socket;
   670			}
   671	
   672			if (ret < (sizeof(struct ethhdr) + sizeof(packet->hdr))) {
   673				dev_err(dev,
   674					"packet too small, discard and continue\n");
   675				continue;
   676			}
   677	
   678			if (packet->eh.h_proto != ETH_TYPE_ATH_ECPS_FRAME)
   679				continue;
   680	
   681			memcpy(wasp_mac, packet->eh.h_source, sizeof(wasp_mac));
   682	
   683			if (packet->hdr.packet_start == ETH_WASP_PACKET_ID) {
   684				switch (packet->hdr.response) {
   685				case RESP_DISCOVER:
   686					chunk_counter = 1;
   687					num_chunks = DIV_ROUND_UP(avmwasp->linux_blob->size,
   688								  ETH_DATA_SIZE);
   689					fallthrough;
   690				case RESP_OK:
   691					memcpy(packet->eh.h_dest, wasp_mac, sizeof(packet->eh.h_dest));
   692					packet->eh.h_proto = ETH_TYPE_ATH_ECPS_FRAME;
   693					memcpy(packet->eh.h_source, send_sock_addr.sa_data,
   694					       sizeof(packet->eh.h_source));
   695	
   696					if (firmware < firmware_end) {
   697						size_t bytestosend, send_len;
   698						u32 data_offset = 0;
   699	
   700						if (chunk_counter == 1) {
   701							memcpy(packet->payload,
   702							       &m_load_addr,
   703							       sizeof(m_load_addr));
   704							data_offset = sizeof(m_load_addr);
   705						}
   706	
   707						if ((firmware_end - firmware) >=
   708						     ETH_DATA_SIZE)
   709							bytestosend = ETH_DATA_SIZE;
   710						else
   711							bytestosend = firmware_end -
   712										firmware;
   713						memcpy(&packet->payload[data_offset],
   714						       firmware, bytestosend);
   715						firmware = firmware + ETH_DATA_SIZE;
   716	
   717						packet->hdr.packet_start =
   718								ETH_WASP_PACKET_ID;
   719						if (chunk_counter == num_chunks) {
   720							packet->hdr.response =
   721								CMD_START_FIRMWARE;
   722							memcpy(&packet->payload
   723							       [data_offset + bytestosend],
   724							       &m_load_addr,
   725							       sizeof(m_load_addr));
   726							bytestosend += sizeof(m_load_addr);
   727						} else {
   728							packet->hdr.command =
   729								CMD_FIRMWARE_DATA;
   730						}
   731						packet->hdr.counter =
   732								(chunk_counter - 1) * 4;
   733	
   734						send_len = sizeof(struct ethhdr)
   735							+ sizeof(packet->hdr) + bytestosend +
   736							data_offset;
   737	
   738						socket_kvec.iov_len = send_len;
   739						socket_kvec.iov_base = avmwasp->buffer;
   740	
   741						ret = kernel_sendmsg(wasp_socket,
   742								     &socket_msghdr,
   743								     &socket_kvec,
   744								     1, send_len);
   745						if (ret < 0) {
   746							dev_err(dev,
   747								"error sending to WASP %d\n",
   748								ret);
   749							goto err_socket;
   750						}
   751	
   752						chunk_counter++;
   753					}
   754					break;
   755				case RESP_ERROR:
   756					dev_err(dev,
   757						"received an WASP error packet\n");
   758					ret = -EFAULT;
   759					goto err_socket;
   760				case RESP_STARTING:
   761					done = true;
   762					ret = 0;
   763					continue;
   764					break;
   765				default:
   766					dev_err(dev, "unknown packet, continue\n");
   767					continue;
   768					break;
   769				}
   770			}
   771		}
   772	
   773	err_socket:
   774		wasp_socket->ops->release(wasp_socket);
   775	err:
   776		return ret;
   777	}
   778	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

end of thread, other threads:[~2022-07-22 15:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-21 19:34 [PATCH v3 0/3] Add support for WASP SoC on AVM router boards Daniel Kestrel
2022-07-21 19:34 ` [PATCH v3 1/3] dt-bindings: vendor-prefixes: Add AVM Daniel Kestrel
2022-07-21 19:34 ` [PATCH v3 2/3] dt-bindings: remoteproc: Add AVM WASP Daniel Kestrel
2022-07-21 19:34 ` [PATCH v3 3/3] remoteproc: Add AVM WASP driver Daniel Kestrel
2022-07-22 15:44   ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.