From 9ccd41bc542748ecdfbd239af847b0e1ea4ad1f1225dab3e759987156129af92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 10 May 2026 22:25:46 +0800 Subject: [PATCH] Got dpa_app working --- alpine/install-packages.sh | 4 +- docker/ask.Dockerfile | 8 +- docs/vendor-resources.md | 68 ++++++ kernel-build/dts/mono-gateway-dk-sdk.dts | 31 +-- kernel-build/dts/mono-gateway-dk.dts | 4 +- ...-allow-xml-config-path-env-overrides.patch | 2 +- .../0002-cdx-harden-fman-port-lookup.patch | 152 +++++++++++++ ...free-of-userspace-dist-info-pointers.patch | 120 ++++++++++ ...stash-userspace-fman-nested-pointers.patch | 205 ++++++++++++++++++ 9 files changed, 571 insertions(+), 23 deletions(-) create mode 100644 patches/ask/dpa/0002-cdx-harden-fman-port-lookup.patch create mode 100644 patches/ask/dpa/0003-cdx-avoid-kfree-of-userspace-dist-info-pointers.patch create mode 100644 patches/ask/dpa/0004-cdx-stash-userspace-fman-nested-pointers.patch diff --git a/alpine/install-packages.sh b/alpine/install-packages.sh index d5679c3..d924634 100755 --- a/alpine/install-packages.sh +++ b/alpine/install-packages.sh @@ -9,9 +9,9 @@ apk add alpine-base \ # For diagnotics apk add \ - iproute2 iproute2-ss curl bind-tools procps strace tcpdump lsof jq binutils \ + iproute2 iproute2-ss curl bind-tools procps strace tcpdump lsof jq gdb binutils \ openssl conntrack-tools ethtool findmnt kmod coreutils util-linux zstd libcap-utils \ - iotop sysstat + iotop sysstat dtc echo '[ -x /bin/bash ] && exec /bin/bash -l' >> "/root/.profile" # Compat layer for kubelet for now. Will look into building it myself later. If needed diff --git a/docker/ask.Dockerfile b/docker/ask.Dockerfile index 4e42dd8..5302e61 100644 --- a/docker/ask.Dockerfile +++ b/docker/ask.Dockerfile @@ -248,7 +248,7 @@ RUN make -C "${ASK_DIR}/cmm" \ PKG_CONFIG_PATH="${SYSROOT}/lib/pkgconfig" && \ make -C "${ASK_DIR}/dpa_app" \ CC="aarch64-linux-musl-gcc -static" \ - CFLAGS="-DDPAA_DEBUG_ENABLE -DNCSW_LINUX \ + CFLAGS="-DDPAA_DEBUG_ENABLE -DLS1043 -DNCSW_LINUX -D__STDC_LIMIT_MACROS \ -I/src/fmc/source \ -I${ASK_DIR}/cdx \ -I/src/fmlib/include/fmd \ @@ -265,8 +265,8 @@ RUN mkdir -p /out/ASK/dist && \ mkdir -p /out/ASK/bin && \ cp /src/fmc/source/fmc /out/ASK/bin/ && \ cp "${ASK_DIR}/cmm/src/cmm" /out/ASK/bin/ && \ - cp "${ASK_DIR}/dpa_app/dpa_app" /out/ASK/bin/ && \ - aarch64-linux-musl-strip /out/ASK/bin/fmc /out/ASK/bin/cmm /out/ASK/bin/dpa_app + cp "${ASK_DIR}/dpa_app/dpa_app" /out/ASK/bin/ +# aarch64-linux-musl-strip /out/ASK/bin/fmc /out/ASK/bin/cmm /out/ASK/bin/dpa_app # in-tree Linux kernel modules RUN mkdir -p /out/rootfs && \ @@ -282,7 +282,7 @@ RUN KERNEL_VER=$(ls /out/rootfs/lib/modules/) && \ RUN mkdir -p /out/rootfs-cfg/etc/dpa && \ cp -r "${ASK_DIR}/dpa_app/files/etc/"* /out/rootfs-cfg/etc/dpa/ && \ cp "${ASK_DIR}/config/gateway-dk/cdx_cfg.xml" /out/rootfs-cfg/etc/dpa/ && \ - cp -r /src/fmc/etc /out/rootfs-cfg/etc + cp -r /src/fmc/etc/* /out/rootfs-cfg/etc FROM scratch AS export diff --git a/docs/vendor-resources.md b/docs/vendor-resources.md index 41d6ee1..01bda09 100644 --- a/docs/vendor-resources.md +++ b/docs/vendor-resources.md @@ -1,3 +1,6 @@ +## ASK +The most important one is vendor's ASK. Which provides all the required resources to build the device-specific kernel + ## Updating build.env You can find the latest package versions in here * [kernel](https://github.com/nxp-qoriq/linux/archive/refs/tags/) @@ -10,3 +13,68 @@ You can find the latest package versions in here https://github.com/we-are-mono/OpenWRT-ASK/tree/mono-25.12.0-rc3/target/linux/layerscape/files/arch/arm64/boot/dts/freescale * We need both `mono-gateway-dk-sdk.dts` and `mono-gateway-dk.dts` since the sdk one includes the non-sdk one. * The actual dts being used is the `mono-gateway-dk-sdk.dts` + +## Testing dpa_app +Run this on the gateway device +```bash +while true; do nc -l -p 1234 -e sh; done +``` + +Run this script on your dev machine +```bash +#!/bin/bash +FILES=" +bin/dpa_app +rootfs-cfg/etc/dpa/cdx_cfg.xml +rootfs-cfg/etc/dpa/cdx_pcd.xml +rootfs-cfg/etc/dpa/cdx_sp.xml +rootfs-cfg/etc/dpa/cdx_cfg_ls1046_rdb.xml +rootfs-cfg/etc/fmc/config/hxs_pdl_v3.xml +rootfs-cfg/etc/fmc/config/cfgdata.xsd +rootfs-cfg/etc/fmc/config/netpcd.xsd +" + +SIZE=$( + tar -C ./out/ASK -czf - $FILES | wc -c +) + +( + echo 'set -eu' + + echo 'rm -rf /var/dpa-test' + echo 'mkdir -p /var/dpa-test/bin' + echo 'mkdir -p /etc/dpa' + echo 'mkdir -p /etc/fmc/config' + + echo 'base64 -d > /tmp/dpa-test.tar.gz <<'"'"'EOF'"'"'' + tar -C ./out/ASK -czf - $FILES | pv -s "$SIZE" | base64 + echo 'EOF' + + echo 'tar -xzf /tmp/dpa-test.tar.gz -C /var/dpa-test' + + echo 'cp /var/dpa-test/bin/dpa_app /var/dpa_app' + echo 'cp /var/dpa-test/rootfs-cfg/etc/dpa/cdx_cfg.xml /etc/dpa/cdx_cfg.xml' + echo 'cp /var/dpa-test/rootfs-cfg/etc/dpa/cdx_pcd.xml /etc/dpa/cdx_pcd.xml' + echo 'cp /var/dpa-test/rootfs-cfg/etc/dpa/cdx_sp.xml /etc/dpa/cdx_sp.xml' + echo 'cp /var/dpa-test/rootfs-cfg/etc/fmc/config/hxs_pdl_v3.xml /etc/fmc/config/hxs_pdl_v3.xml' + echo 'cp /var/dpa-test/rootfs-cfg/etc/fmc/config/cfgdata.xsd /etc/fmc/config/cfgdata.xsd' + echo 'cp /var/dpa-test/rootfs-cfg/etc/fmc/config/netpcd.xsd /etc/fmc/config/netpcd.xsd' + + echo 'chmod +x /var/dpa_app' + + echo 'export CDX_CFG_FILE=/etc/dpa/cdx_cfg.xml' + echo 'export CDX_PCD_FILE=/etc/dpa/cdx_pcd.xml' + echo 'export CDX_SP_FILE=/etc/dpa/cdx_sp.xml' + echo 'export CDX_PDL_FILE=/etc/fmc/config/hxs_pdl_v3.xml' + + echo 'echo "CDX_CFG_FILE=$CDX_CFG_FILE"' + echo 'echo "CDX_PCD_FILE=$CDX_PCD_FILE"' + echo 'echo "CDX_SP_FILE=$CDX_SP_FILE"' + echo 'echo "CDX_PDL_FILE=$CDX_PDL_FILE"' + + echo 'ls -l /var/dpa_app /etc/dpa /etc/fmc/config' + echo 'echo Running /var/dpa_app' + echo '/var/dpa_app' + echo 'echo exit=$?' +) | nc 10.0.0.10 1234 +``` diff --git a/kernel-build/dts/mono-gateway-dk-sdk.dts b/kernel-build/dts/mono-gateway-dk-sdk.dts index 8ea2c5b..0c1ac11 100644 --- a/kernel-build/dts/mono-gateway-dk-sdk.dts +++ b/kernel-build/dts/mono-gateway-dk-sdk.dts @@ -263,22 +263,23 @@ * ethernet@8 = enet6 = MAC9 (10G) */ - ethernet@8 { - compatible = "fsl,dpa-ethernet-init"; - fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; - fsl,qman-frame-queues-rx = <0x5c 1 0x5d 1>; - fsl,qman-frame-queues-tx = <0x7c 1 0x7d 1>; - }; + ethernet@8 { + compatible = "fsl,dpa-ethernet"; + /delete-property/ fsl,bman-buffer-pools; + /delete-property/ fsl,qman-frame-queues-rx; + /delete-property/ fsl,qman-frame-queues-tx; + dma-coherent; + }; /* Add MAC10 - not in qoriq-dpaa-eth.dtsi */ - ethernet@9 { - compatible = "fsl,dpa-ethernet-init"; - fsl,fman-mac = <&enet7>; - fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; - fsl,qman-frame-queues-rx = <0x5e 1 0x5f 1>; - fsl,qman-frame-queues-tx = <0x7e 1 0x7f 1>; - dma-coherent; - }; + ethernet@9 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet7>; + /delete-property/ fsl,bman-buffer-pools; + /delete-property/ fsl,qman-frame-queues-rx; + /delete-property/ fsl,qman-frame-queues-tx; + dma-coherent; + }; }; &fman0 { @@ -336,12 +337,14 @@ }; ethernet@f0000 { + status = "okay"; /delete-property/ managed; fixed-link = <0 1 10000 0 0>; phy-connection-type = "xgmii"; }; ethernet@f2000 { + status = "okay"; /delete-property/ managed; fixed-link = <0 1 10000 0 0>; phy-connection-type = "xgmii"; diff --git a/kernel-build/dts/mono-gateway-dk.dts b/kernel-build/dts/mono-gateway-dk.dts index d2d7aea..df7c1ae 100644 --- a/kernel-build/dts/mono-gateway-dk.dts +++ b/kernel-build/dts/mono-gateway-dk.dts @@ -500,14 +500,14 @@ status = "okay"; }; - fm1_mac9: ethernet@f0000 { /* 10GEC1 */ + fm0_mac9: ethernet@f0000 { /* 10GEC1 */ sfp = <&sfp_xfi0>; phy-connection-type = "10gbase-r"; managed = "in-band-status"; pcs-handle-names = "xfi"; /* Match enet7 for consistency */ }; - fm1_mac10: ethernet@f2000 { /* 10GEC2 */ + fm0_mac10: ethernet@f2000 { /* 10GEC2 */ sfp = <&sfp_xfi1>; phy-connection-type = "10gbase-r"; managed = "in-band-status"; diff --git a/patches/ask/dpa/0001-dpa-app-allow-xml-config-path-env-overrides.patch b/patches/ask/dpa/0001-dpa-app-allow-xml-config-path-env-overrides.patch index 4ae1766..786f022 100644 --- a/patches/ask/dpa/0001-dpa-app-allow-xml-config-path-env-overrides.patch +++ b/patches/ask/dpa/0001-dpa-app-allow-xml-config-path-env-overrides.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: monok8s Date: Sun, 10 May 2026 00:00:00 +0000 -Subject: [PATCH] dpa_app: allow XML config paths to be overridden by env +Subject: [PATCH 1/4] dpa_app: allow XML config paths to be overridden by env Keep the vendor default XML paths, but allow deployments to override them without patching the binary or placing board-specific XML files directly diff --git a/patches/ask/dpa/0002-cdx-harden-fman-port-lookup.patch b/patches/ask/dpa/0002-cdx-harden-fman-port-lookup.patch new file mode 100644 index 0000000..9cede6a --- /dev/null +++ b/patches/ask/dpa/0002-cdx-harden-fman-port-lookup.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: monok8s +Date: Sun, 10 May 2026 00:00:00 +0000 +Subject: [PATCH 2/4] cdx: harden FMAN port lookup + +The DPA userspace loader passes FMC-derived port metadata into the CDX +ioctl. If an Ethernet netdev has a partially initialized DPAA private +structure, find_osdev_by_fman_params() can dereference a missing mac_dev +or FM wrapper pointer while trying to match the FMC port. + +Add lookup diagnostics and hard NULL guards so a mismatched board +model returns -ENODEV instead of oopsing the kernel. +--- + cdx/devman.c | 85 +++++++++++++++++++++++++++++++++++++-------------- + cdx/dpa_cfg.c | 18 ++++++++--- + 2 files changed, 76 insertions(+), 27 deletions(-) + +diff -urN a/cdx/devman.c b/cdx/devman.c +--- a/cdx/devman.c 2026-05-10 00:32:28.745375897 +0000 ++++ b/cdx/devman.c 2026-05-10 00:32:29.834300280 +0000 +@@ -396,39 +396,74 @@ + uint32_t speed) + { + struct net_device *device; +- struct dpa_priv_s *priv; +- struct mac_device *macdev; ++ ++ DPA_INFO("%s::lookup fm %u port %u speed %uG\n", ++ __func__, fm_idx, port_idx, speed); + + device = first_net_device(&init_net); +- while(1) { +- if (!device) +- break; +- if (device->type == ARPHRD_ETHER) { +- t_LnxWrpFmDev *p_LnxWrpFmDev; +- priv = netdev_priv(device); +- macdev = priv->mac_dev; +- if (macdev) { +- p_LnxWrpFmDev = (t_LnxWrpFmDev*)macdev->fm; +- if (speed == 10) { +- //10 gig interfaces upports only SUPPORTED_10000baseT_Full +- /*DGW board has 2 fixed-link interfaces +- 1 - (eth2)(xDSL)1G Fixed link interface linked to rgmii-txid +- 2 - eth5(G.fast)- 1G Fixed link interface linked to sgmii and +- connected to 10G link of the board. +- sgmii - considered as 1000baseT_Full and this has cell_index = 0*/ +- +- if ( (!macdev->fixed_link) && (macdev->if_support != SUPPORTED_10000baseT_Full) ) +- goto next_device; +- } +- if ((fm_idx == p_LnxWrpFmDev->id) && +- (port_idx == macdev->cell_index)) +- return device; +- } ++ while (device) { ++ struct dpa_priv_s *priv; ++ struct mac_device *macdev; ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ ++ if (device->type != ARPHRD_ETHER) ++ goto next_device; ++ ++ priv = netdev_priv(device); ++ if (!priv) { ++ DPA_INFO("%s::skip %s: null private data\n", ++ __func__, device->name); ++ goto next_device; ++ } ++ ++ macdev = priv->mac_dev; ++ if (!macdev) { ++ DPA_INFO("%s::skip %s: null mac_dev\n", ++ __func__, device->name); ++ goto next_device; ++ } ++ ++ if (!macdev->fm) { ++ DPA_INFO("%s::skip %s: null mac_dev->fm cell_index %u max_speed %u fixed_link %u if_support 0x%x\n", ++ __func__, device->name, macdev->cell_index, ++ macdev->max_speed, macdev->fixed_link, ++ macdev->if_support); ++ goto next_device; + } ++ ++ p_LnxWrpFmDev = (t_LnxWrpFmDev *)macdev->fm; ++ DPA_INFO("%s::candidate %s fm %u cell_index %u max_speed %u fixed_link %u if_support 0x%x\n", ++ __func__, device->name, p_LnxWrpFmDev->id, ++ macdev->cell_index, macdev->max_speed, ++ macdev->fixed_link, macdev->if_support); ++ ++ if (speed == 10) { ++ //10 gig interfaces upports only SUPPORTED_10000baseT_Full ++ /*DGW board has 2 fixed-link interfaces ++ 1 - (eth2)(xDSL)1G Fixed link interface linked to rgmii-txid ++ 2 - eth5(G.fast)- 1G Fixed link interface linked to sgmii and ++ connected to 10G link of the board. ++ sgmii - considered as 1000baseT_Full and this has cell_index = 0*/ ++ ++ if ((!macdev->fixed_link) && ++ (macdev->if_support != SUPPORTED_10000baseT_Full)) ++ goto next_device; ++ } ++ ++ if ((fm_idx == p_LnxWrpFmDev->id) && ++ (port_idx == macdev->cell_index)) { ++ DPA_INFO("%s::matched %s for fm %u port %u speed %uG\n", ++ __func__, device->name, fm_idx, port_idx, speed); ++ return device; ++ } ++ + next_device: + device = next_net_device(device); + } +- return device; ++ ++ DPA_ERROR("%s::no OS device found for fm %u port %u speed %uG\n", ++ __func__, fm_idx, port_idx, speed); ++ return NULL; + } + + +diff -urN a/cdx/dpa_cfg.c b/cdx/dpa_cfg.c +--- a/cdx/dpa_cfg.c 2026-05-10 00:32:28.757992164 +0000 ++++ b/cdx/dpa_cfg.c 2026-05-10 00:32:51.954850425 +0000 +@@ -301,15 +301,21 @@ + struct net_device *dev; + + if (port_info->type) { ++ DPA_INFO("%s::mapping user port %s fm %u index %u portid %u type %uG\n", ++ __func__, port_info->name, port_info->fm_index, ++ port_info->index, port_info->portid, port_info->type); + dev = find_osdev_by_fman_params(port_info->fm_index, + port_info->index, port_info->type); + if (!dev) { +- DPA_ERROR("%s::could not map port %s\n", +- __func__, port_info->name); +- return -EIO; +- } else { +- strcpy(port_info->name, dev->name); ++ DPA_ERROR("%s::could not map port %s fm %u index %u portid %u type %uG\n", ++ __func__, port_info->name, ++ port_info->fm_index, port_info->index, ++ port_info->portid, port_info->type); ++ return -ENODEV; + } ++ DPA_INFO("%s::mapped user port %s to netdev %s\n", ++ __func__, port_info->name, dev->name); ++ strscpy(port_info->name, dev->name, sizeof(port_info->name)); + } + #ifdef DPA_CFG_DEBUG + DPA_INFO("%s::port %s, fmindex %d, port index %d, port id %d\n", diff --git a/patches/ask/dpa/0003-cdx-avoid-kfree-of-userspace-dist-info-pointers.patch b/patches/ask/dpa/0003-cdx-avoid-kfree-of-userspace-dist-info-pointers.patch new file mode 100644 index 0000000..c6b0f5d --- /dev/null +++ b/patches/ask/dpa/0003-cdx-avoid-kfree-of-userspace-dist-info-pointers.patch @@ -0,0 +1,120 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: monok8s +Date: Sun, 10 May 2026 00:00:00 +0000 +Subject: [PATCH 3/4] cdx: avoid kfree of userspace dist_info pointers + +get_port_info() copies an array of cdx_port_info from userspace. At that +point each cdx_port_info.dist_info field is still a userspace pointer. +However release_cfg_info() treats any non-NULL dist_info as a kernel +allocation and kfree()s it on error paths. + +If a later step fails before get_dist_info() has replaced every dist_info +with a kernel allocation, release_cfg_info() can kfree a raw userspace +pointer and oops in kfree()/virt_to_folio(). + +Stash the userspace dist_info pointers in a temporary array, clear the +kernel-side cdx_port_info.dist_info fields immediately after copy_from_user(), +and pass the saved userspace pointer explicitly to get_dist_info(). This +keeps release_cfg_info() safe on partial-initialization failures. +--- + cdx/dpa_cfg.c | 47 +++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 37 insertions(+), 10 deletions(-) + +diff -urN a/cdx/dpa_cfg.c b/cdx/dpa_cfg.c +--- a/cdx/dpa_cfg.c 2026-05-10 00:46:34.295813594 +0000 ++++ b/cdx/dpa_cfg.c 2026-05-10 00:46:35.558487337 +0000 +@@ -169,11 +169,10 @@ + } + + //allocate and copy distribution info from uspace +-static int get_dist_info(struct cdx_port_info *port_info) ++static int get_dist_info(struct cdx_port_info *port_info, void *uspace_info) + { + uint32_t mem_size; + struct cdx_dist_info *dist_info; +- void *uspace_info; + + #ifdef DPA_CFG_DEBUG + DPA_INFO("%s::port %s dist %d\n", __func__, +@@ -187,7 +186,6 @@ + return -ENOMEM; + } + memset(dist_info, 0, mem_size); +- uspace_info = port_info->dist_info; + port_info->dist_info = dist_info; + if (copy_from_user(dist_info, uspace_info, + mem_size)) { +@@ -273,6 +271,7 @@ + { + struct cdx_port_info *port_info; + void *uspace_info; ++ void **uspace_dist_info; + uint32_t mem_size; + uint32_t ii; + +@@ -289,13 +288,40 @@ + return -ENOMEM; + } + memset(port_info, 0, mem_size); ++ ++ uspace_dist_info = kcalloc(finfo->max_ports, sizeof(*uspace_dist_info), ++ GFP_KERNEL); ++ if (!uspace_dist_info) { ++ DPA_ERROR("%s::memalloc for uspace_dist_info failed\n", ++ __func__); ++ kfree(port_info); ++ return -ENOMEM; ++ } ++ + uspace_info = finfo->portinfo; + finfo->portinfo = port_info; + if (copy_from_user(port_info, uspace_info, mem_size)) { + DPA_ERROR("%s::Read port_info failed\n", + __func__); ++ finfo->portinfo = NULL; ++ kfree(uspace_dist_info); ++ kfree(port_info); + return -EIO; + } ++ ++ /* ++ * port_info has just been copied from userspace, so each dist_info ++ * member is still a userspace pointer. release_cfg_info() kfree()s ++ * non-NULL dist_info members, therefore keeping those raw userspace ++ * pointers in the kernel copy turns any later error path into an ++ * invalid kfree(). Stash the userspace pointers separately and clear ++ * the struct fields until get_dist_info() replaces them with real ++ * kernel allocations. ++ */ ++ for (ii = 0; ii < finfo->max_ports; ii++) { ++ uspace_dist_info[ii] = port_info[ii].dist_info; ++ port_info[ii].dist_info = NULL; ++ } + //put the linux name for the port + for (ii = 0; ii < finfo->max_ports; ii++) { + struct net_device *dev; +@@ -311,6 +337,7 @@ + __func__, port_info->name, + port_info->fm_index, port_info->index, + port_info->portid, port_info->type); ++ kfree(uspace_dist_info); + return -ENODEV; + } + DPA_INFO("%s::mapped user port %s to netdev %s\n", +@@ -330,11 +357,14 @@ + for (ii = 0; ii < finfo->max_ports; ii++) { + int retval; + //get dist info for this port +- retval = get_dist_info(port_info); +- if (retval) ++ retval = get_dist_info(port_info, uspace_dist_info[ii]); ++ if (retval) { ++ kfree(uspace_dist_info); + return retval; ++ } + port_info++; + } ++ kfree(uspace_dist_info); + return 0; + } + diff --git a/patches/ask/dpa/0004-cdx-stash-userspace-fman-nested-pointers.patch b/patches/ask/dpa/0004-cdx-stash-userspace-fman-nested-pointers.patch new file mode 100644 index 0000000..2344959 --- /dev/null +++ b/patches/ask/dpa/0004-cdx-stash-userspace-fman-nested-pointers.patch @@ -0,0 +1,205 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: monok8s +Date: Sun, 10 May 2026 00:00:00 +0000 +Subject: [PATCH 4/4] cdx: stash userspace fman nested pointers before cleanup + +cdx_ioc_set_dpa_params() copies struct cdx_fman_info from userspace. +The nested portinfo and tbl_info members are userspace pointers at that +point, but release_cfg_info() treats non-NULL nested pointers as +kernel-owned allocations. + +If setup fails before get_port_info() or get_cctbl_info() replaces those +members with kernel allocations, the error path can kfree a userspace +address and panic in kfree()/virt_to_folio(). + +Stash the userspace pointers in temporary arrays, clear the nested +members in fman_info immediately, and pass the stashed pointers into the +copy helpers explicitly. Also route early setup failures through the same +cleanup path so partial state is released consistently. +--- +diff --git a/cdx/dpa_cfg.c b/cdx/dpa_cfg.c +index c678d5d..55b910d 100644 +--- a/cdx/dpa_cfg.c ++++ b/cdx/dpa_cfg.c +@@ -267,10 +267,9 @@ static void *get_dist_info_by_fman_params(struct cdx_fman_info *finfo, uint32_t + #endif //CDX_RTP_RELAY + + //allocate and copy port releated info from uspace +-static int get_port_info(struct cdx_fman_info *finfo) ++static int get_port_info(struct cdx_fman_info *finfo, void *uspace_info) + { + struct cdx_port_info *port_info; +- void *uspace_info; + void **uspace_dist_info; + uint32_t mem_size; + uint32_t ii; +@@ -298,7 +297,6 @@ static int get_port_info(struct cdx_fman_info *finfo) + return -ENOMEM; + } + +- uspace_info = finfo->portinfo; + finfo->portinfo = port_info; + if (copy_from_user(port_info, uspace_info, mem_size)) { + DPA_ERROR("%s::Read port_info failed\n", +@@ -355,7 +353,7 @@ static int get_port_info(struct cdx_fman_info *finfo) + } + port_info = finfo->portinfo; + for (ii = 0; ii < finfo->max_ports; ii++) { +- int retval; ++ int retval = 0; + //get dist info for this port + retval = get_dist_info(port_info, uspace_dist_info[ii]); + if (retval) { +@@ -369,11 +367,10 @@ static int get_port_info(struct cdx_fman_info *finfo) + } + + //allocate and copy cc table infor from uspace +-static int get_cctbl_info(struct cdx_fman_info *finfo) ++static int get_cctbl_info(struct cdx_fman_info *finfo, void *uspace_info) + { + struct table_info *tbl_info; + uint32_t mem_size; +- void *uspace_info; + + //allocate table information area + mem_size = (sizeof(struct table_info) * finfo->num_tables); +@@ -384,7 +381,6 @@ static int get_cctbl_info(struct cdx_fman_info *finfo) + return -ENOMEM; + } + memset(tbl_info, 0, mem_size); +- uspace_info = finfo->tbl_info; + finfo->tbl_info = tbl_info; + //copy table related info from user space + if (copy_from_user(tbl_info, (void *)uspace_info, mem_size)) { +@@ -625,9 +621,11 @@ int cdx_ioc_set_dpa_params(unsigned long args) + { + struct cdx_ctrl_set_dpa_params params; + struct cdx_fman_info *finfo; ++ void **uspace_port_info = NULL; ++ void **uspace_tbl_info = NULL; + uint32_t ii; + uint32_t mem_size; +- int retval; ++ int retval = 0; + + if (copy_from_user(¶ms, (void *)args, + sizeof(struct cdx_ctrl_set_dpa_params))) { +@@ -655,6 +653,35 @@ int cdx_ioc_set_dpa_params(unsigned long args) + retval = -EIO; + goto err_ret; + } ++ uspace_port_info = kcalloc(num_fmans, sizeof(*uspace_port_info), ++ GFP_KERNEL); ++ uspace_tbl_info = kcalloc(num_fmans, sizeof(*uspace_tbl_info), ++ GFP_KERNEL); ++ if (!uspace_port_info || !uspace_tbl_info) { ++ DPA_ERROR("%s::unable to allocate user pointer stash\n", ++ __func__); ++ for (ii = 0; ii < num_fmans; ii++) { ++ fman_info[ii].portinfo = NULL; ++ fman_info[ii].tbl_info = NULL; ++ } ++ retval = -ENOMEM; ++ goto err_ret; ++ } ++ ++ /* ++ * fman_info is copied from userspace. Its nested portinfo and ++ * tbl_info members are userspace pointers until get_port_info() and ++ * get_cctbl_info() replace them with kernel allocations. Never leave ++ * raw userspace pointers in fman_info, because release_cfg_info() owns ++ * and frees non-NULL nested pointers on error paths. ++ */ ++ for (ii = 0; ii < num_fmans; ii++) { ++ uspace_port_info[ii] = fman_info[ii].portinfo; ++ uspace_tbl_info[ii] = fman_info[ii].tbl_info; ++ fman_info[ii].portinfo = NULL; ++ fman_info[ii].tbl_info = NULL; ++ } ++ + if (copy_from_user(&ipr_info, (void *)params.ipr_info, + sizeof(struct cdx_ipr_info))) { + DPA_ERROR("%s::Read iprv_info failed\n", +@@ -665,22 +688,26 @@ int cdx_ioc_set_dpa_params(unsigned long args) + //init the fman handles + finfo = fman_info; + for (ii = 0; ii < num_fmans; ii++) { +- if (cdxdrv_get_fman_handles(finfo)) +- return -1; ++ if (cdxdrv_get_fman_handles(finfo)) { ++ retval = -EIO; ++ goto err_ret; ++ } + finfo++; + } + finfo = fman_info; + //init interface stats module +- if (cdxdrv_init_stats(finfo->muram_handle)) +- return -1; ++ if (cdxdrv_init_stats(finfo->muram_handle)) { ++ retval = -EIO; ++ goto err_ret; ++ } + + for (ii = 0; ii < num_fmans; ii++) { + //get port info +- retval = get_port_info(finfo); ++ retval = get_port_info(finfo, uspace_port_info[ii]); + if (retval) + goto err_ret; + //get cc table info +- retval = get_cctbl_info(finfo); ++ retval = get_cctbl_info(finfo, uspace_tbl_info[ii]); + if (retval) + goto err_ret; + finfo++; +@@ -727,29 +754,43 @@ int cdx_ioc_set_dpa_params(unsigned long args) + finfo++; + } + +- if (cdx_create_port_fqs()) +- return -1; ++ if (cdx_create_port_fqs()) { ++ retval = -EIO; ++ goto err_ret; ++ } + //create cp rate limit policier profiles + if (cdxdrv_create_missaction_policer_profiles(fman_info)) { ++ retval = -EIO; + goto err_ret; + } + #ifdef ENABLE_INGRESS_QOS + if (cdxdrv_create_ingress_qos_policer_profiles(fman_info)) { ++ retval = -EIO; + goto err_ret; + } + #endif + #ifdef ENABLE_EGRESS_QOS +- if(ceetm_init_cq_plcr()) ++ if(ceetm_init_cq_plcr()) { ++ retval = -EIO; + goto err_ret; ++ } + #endif + //init the fman and its ports + for (ii = 0; ii < num_fmans; ii++) { +- if (cdxdrv_set_miss_action(ii)) ++ if (cdxdrv_set_miss_action(ii)) { ++ retval = -EIO; + goto err_ret; ++ } + } + display_dpa_cfg(); ++ kfree(uspace_port_info); ++ kfree(uspace_tbl_info); + return 0; + err_ret: ++ DPA_ERROR("%s::error path retval %d, releasing partial DPA cfg\n", ++ __func__, retval); ++ kfree(uspace_port_info); ++ kfree(uspace_tbl_info); + release_cfg_info(); + return retval; + } +-- +2.39.5