* Re: [PATCH net-next v6 14/15] dt-bindings: net: add onsemi's S2500
From: Krzysztof Kozlowski @ 2026-06-30 6:29 UTC (permalink / raw)
To: Selvamani Rajagopal
Cc: Andrew Lunn, Piergiorgio Beruto, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Parthiban Veerasooran, Richard Cochran, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Simon Horman, Jonathan Corbet,
Shuah Khan, netdev, linux-kernel, devicetree, linux-doc,
Jerry Ray
In-Reply-To: <20260629-s2500-mac-phy-support-v6-14-18ce79500371@onsemi.com>
On Mon, Jun 29, 2026 at 10:23:44AM -0700, Selvamani Rajagopal wrote:
> Add YAML device tree binding for the onsemi S2500 IEEE 802.3cg
No improvements.
So not only you ignored review comment but you also ignored actual
review tag.
Don't worry, we can ignore your patches as well.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 3/3] drm/xe/xe_ras: Add error-event support for CRI
From: Tauro, Riana @ 2026-06-30 6:26 UTC (permalink / raw)
To: Raag Jadav
Cc: intel-xe, dri-devel, netdev, aravind.iddamsetty, anshuman.gupta,
rodrigo.vivi, joonas.lahtinen, kuba, simona.vetter, airlied,
pratik.bari, joshua.santosh.ranjan, ashwin.kumar.kulkarni,
shubham.kumar, ravi.kishore.koppuravuri, maarten.lankhorst,
mallesh.koujalagi, soham.purkait
In-Reply-To: <akNSDXcXa0mtwR5r@black.igk.intel.com>
On 30-06-2026 10:50, Raag Jadav wrote:
> On Mon, Jun 22, 2026 at 03:47:20PM +0530, Riana Tauro wrote:
>> Add error-event support for Correctable errors in CRI.
>> error-event is reported to userspace for all errors that crossed
>> threshold on receiving an interrupt for correctable errors.
> ...
>
>> +static void ras_send_error_event(struct xe_device *xe, u8 severity, u8 component)
>> +{
>> + u8 drm_severity, drm_component;
>> + u32 value;
>> + int ret;
>> +
>> + drm_severity = xe_to_drm_ras_severity(severity);
>> + if (drm_severity == DRM_XE_RAS_ERR_SEV_MAX)
>> + return;
>> +
>> + drm_component = xe_to_drm_ras_component(component);
>> + if (drm_component == DRM_XE_RAS_ERR_COMP_MAX)
>> + return;
>> +
>> + ret = xe_ras_get_counter(xe, severity, component, &value);
>> + if (ret)
>> + return;
>> +
>> + xe_drm_ras_event(xe, drm_component, drm_severity, value, GFP_KERNEL);
>> +}
>> +
>> void xe_ras_counter_threshold_crossed(struct xe_device *xe,
>> struct xe_sysctrl_event_response *response)
>> {
>> @@ -152,6 +203,8 @@ void xe_ras_counter_threshold_crossed(struct xe_device *xe,
>> severity = errors[id].common.severity;
>> component = errors[id].common.component;
>>
>> + ras_send_error_event(xe, severity, component);
> We already have error-value as part of the event, so this looks like
> a lot of redundant duplicate events if threshold is set high enough.
Yeah makes sense based on testing. Will add it once per error type.
Thanks
Riana
> I'm wondering if we use a local variable as a bitmap for components
> (which we set here) and only send event for_each_set_bit() after the
> loop?
>
> Raag
>
>> xe_warn(xe, "[RAS]: %s %s detected\n",
>> comp_to_str(component), sev_to_str(severity));
>> }
>> --
>> 2.47.1
>>
^ permalink raw reply
* [PATCH v2 2/2] octeontx2-af: Add RSS hashing support based on RoCEv2 header
From: nshettyj @ 2026-06-30 6:21 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, lcherian, gakula, hkelam, sbhatta, andrew+netdev, davem,
edumazet, kuba, pabeni, Kiran Kumar K, Nitin Shetty J
In-Reply-To: <20260630062145.2533816-1-nshettyj@marvell.com>
From: Kiran Kumar K <kirankumark@marvell.com>
Add NIX_FLOW_KEY_TYPE_ROCEV2 flow key type to support RSS hashing on
the RoCEv2 destination Queue Pair (QP) field, allowing RoCEv2 traffic
to be distributed across receive queues.
Signed-off-by: Kiran Kumar K <kirankumark@marvell.com>
Signed-off-by: Nitin Shetty J <nshettyj@marvell.com>
---
v2:
- Fixed coding style.
---
drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 1 +
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 83f0da3a93fb..f87cdf1b971d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -1268,6 +1268,7 @@ struct nix_rss_flowkey_cfg {
#define NIX_FLOW_KEY_TYPE_IPV4_PROTO BIT(21)
#define NIX_FLOW_KEY_TYPE_AH BIT(22)
#define NIX_FLOW_KEY_TYPE_ESP BIT(23)
+#define NIX_FLOW_KEY_TYPE_ROCEV2 BIT(24)
#define NIX_FLOW_KEY_TYPE_L4_DST_ONLY BIT(28)
#define NIX_FLOW_KEY_TYPE_L4_SRC_ONLY BIT(29)
#define NIX_FLOW_KEY_TYPE_L3_DST_ONLY BIT(30)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 144076e161c6..8e3bb47eb3ba 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -4305,6 +4305,13 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
keyoff_marker = false;
}
break;
+ case NIX_FLOW_KEY_TYPE_ROCEV2:
+ field->hdr_offset = 5;
+ field->bytesm1 = 2; /* Destination QP */
+ field->ltype_mask = 0xF;
+ field->lid = NPC_LID_LE;
+ field->ltype_match = NPC_LT_LE_ROCEV2;
+ break;
}
field->ena = 1;
--
2.48.1
^ permalink raw reply related
* [PATCH v2 1/2] octeontx2-af: reserve 4 PKINDs for skip-size custom use
From: nshettyj @ 2026-06-30 6:21 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, lcherian, gakula, hkelam, sbhatta, andrew+netdev, davem,
edumazet, kuba, pabeni, Kiran Kumar K, Nitin Shetty J
In-Reply-To: <20260630062145.2533816-1-nshettyj@marvell.com>
From: Kiran Kumar K <kirankumark@marvell.com>
The NPC block uses PKINDs to determine how incoming packets are
parsed. Reserve PKINDs 46-49 (NPC_RX_SKIP_SIZE_PKIND) for
configurable L2 skip-size use in the first pass, and PKINDs 50-53
(NPC_RX_CPT_SKIP_SIZE_PKIND) for the second pass where packets
carry a CPT (Cryptographic Accelerator Unit) header.
Add npc_set_skip_size_pkind() to program NPC_AF_PKINDX_ACTION0
for these reserved PKINDs with a user-supplied ptr_advance value
representing the L2 size to skip. For the corresponding CPT PKINDs
(pkind + 4), additionally configure the var_len_offset, var_len_mask,
var_len_shift, and var_len_right fields so the NPC can extract the
inner payload length from the CPT header.
Update rvu_npc_set_parse_mode() to accept a new skip_size argument
and dispatch to npc_set_skip_size_pkind() when the requested PKIND
falls in the newly reserved range. Extend the npc_set_pkind mbox
message struct with a skip_size field so PF/VF drivers can supply
this value at run time.
Advance NPC_UNRESERVED_PKIND_COUNT to NPC_RX_SKIP_SIZE_PKIND to
reflect the updated reservation boundary.
Signed-off-by: Kiran Kumar K <kirankumark@marvell.com>
Signed-off-by: Nitin Shetty J <nshettyj@marvell.com>
---
v2:
- Fixed coding style.
---
.../net/ethernet/marvell/octeontx2/af/mbox.h | 1 +
.../net/ethernet/marvell/octeontx2/af/npc.h | 4 +-
.../net/ethernet/marvell/octeontx2/af/rvu.h | 2 +-
.../ethernet/marvell/octeontx2/af/rvu_nix.c | 2 +-
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 43 +++++++++++++++++--
5 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 714e47f68d93..83f0da3a93fb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -803,6 +803,7 @@ struct npc_set_pkind {
*/
u8 var_len_off_mask; /* Mask for length with in offset */
u8 shift_dir; /* shift direction to get length of the header at var_len_off */
+ u8 skip_size; /* l2 size to skip */
};
/* NPA mbox message formats */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
index eaed172f1606..719b3618eeb5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
@@ -161,10 +161,12 @@ enum npc_kpu_lh_ltype {
* Software assigns pkind for each incoming port such as CGX
* Ethernet interfaces, LBK interfaces, etc.
*/
-#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_CPT_HDR_PTP_PKIND
+#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_SKIP_SIZE_PKIND
enum npc_pkind_type {
NPC_RX_LBK_PKIND = 0ULL,
+ NPC_RX_SKIP_SIZE_PKIND = 46ULL,
+ NPC_RX_CPT_SKIP_SIZE_PKIND = 50ULL,
NPC_RX_CPT_HDR_PTP_PKIND = 54ULL,
NPC_RX_CUSTOM_PRE_L2_PKIND = 55ULL,
NPC_RX_VLAN_EXDSA_PKIND = 56ULL,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 7f3505ae6860..c5610f242687 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -1181,7 +1181,7 @@ void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool ena);
int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
u64 pkind, u8 var_len_off, u8 var_len_off_mask,
- u8 shift_dir);
+ u8 shift_dir, u8 skip_size);
int rvu_get_hwvf(struct rvu *rvu, int pcifunc);
/* CN10K MCS */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 0297c7ab0614..144076e161c6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -5392,7 +5392,7 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf)
/* reset HW config done for Switch headers */
rvu_npc_set_parse_mode(rvu, pcifunc, OTX2_PRIV_FLAGS_DEFAULT,
- (PKIND_TX | PKIND_RX), 0, 0, 0, 0);
+ (PKIND_TX | PKIND_RX), 0, 0, 0, 0, 0);
/* Disabling CGX and NPC config done for PTP */
if (pfvf->hw_rx_tstamp_en) {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c7bc0b3a29b9..08b83de9beb4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -4194,10 +4194,40 @@ npc_set_var_len_offset_pkind(struct rvu *rvu, u16 pcifunc, u64 pkind,
return 0;
}
+static int npc_set_skip_size_pkind(struct rvu *rvu, u16 pcifunc, u64 pkind,
+ u8 skip_size)
+{
+ struct npc_kpu_action0 *act0;
+ int blkaddr;
+ u64 val;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, pcifunc);
+ if (blkaddr < 0) {
+ dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
+ return -EINVAL;
+ }
+
+ val = rvu_read64(rvu, blkaddr, NPC_AF_PKINDX_ACTION0(pkind));
+ act0 = (struct npc_kpu_action0 *)&val;
+ act0->ptr_advance = skip_size;
+ rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_ACTION0(pkind), val);
+
+ /* Update CPT_HR new PKIND */
+ val = rvu_read64(rvu, blkaddr, NPC_AF_PKINDX_ACTION0(pkind + 4));
+ act0 = (struct npc_kpu_action0 *)&val;
+ act0->ptr_advance = (skip_size + 40);
+ act0->next_state = NPC_S_KPU1_CPT_HDR;
+ act0->var_len_offset = (skip_size + 6);
+ act0->var_len_mask = 0xe0;
+ act0->var_len_shift = 0x5;
+ act0->var_len_right = 0x1;
+ rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_ACTION0(pkind + 4), val);
+ return 0;
+}
+
int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
u64 pkind, u8 var_len_off, u8 var_len_off_mask,
- u8 shift_dir)
-
+ u8 shift_dir, u8 skip_size)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
int blkaddr, nixlf, rc, intf_mode;
@@ -4218,6 +4248,12 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
shift_dir);
if (rc)
return rc;
+ } else if (pkind >= NPC_RX_SKIP_SIZE_PKIND &&
+ pkind <= NPC_RX_SKIP_SIZE_PKIND + 3) {
+ rc = npc_set_skip_size_pkind(rvu, pcifunc, pkind,
+ skip_size);
+ if (rc)
+ return rc;
}
rxpkind = pkind;
txpkind = pkind;
@@ -4254,7 +4290,8 @@ int rvu_mbox_handler_npc_set_pkind(struct rvu *rvu, struct npc_set_pkind *req,
{
return rvu_npc_set_parse_mode(rvu, req->hdr.pcifunc, req->mode,
req->dir, req->pkind, req->var_len_off,
- req->var_len_off_mask, req->shift_dir);
+ req->var_len_off_mask, req->shift_dir,
+ req->skip_size);
}
int rvu_mbox_handler_npc_read_base_steer_rule(struct rvu *rvu,
--
2.48.1
^ permalink raw reply related
* Re: [PATCH net-next v11 1/7] dt-bindings: phy: document the serdes PHY on sa8255p
From: Krzysztof Kozlowski @ 2026-06-30 6:22 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Vinod Koul, Giuseppe Cavallaro, Chen-Yu Tsai, Jernej Skrabec,
Neil Armstrong, Kevin Hilman, Jerome Brunet, Shawn Guo,
Fabio Estevam, Jan Petrous, s32, Mohd Ayaan Anwar, Romain Gantois,
Geert Uytterhoeven, Magnus Damm, Maxime Ripard,
Christophe Roullier, Bartosz Golaszewski, Radu Rendec,
linux-arm-msm, devicetree, linux-kernel, netdev, linux-stm32,
linux-arm-kernel, Drew Fustini, linux-sunxi, linux-amlogic,
linux-mips, imx, linux-renesas-soc, linux-rockchip, sophgo,
linux-riscv, Bartosz Golaszewski
In-Reply-To: <20260629-qcom-sa8255p-emac-v11-1-1b7fb95b51f9@oss.qualcomm.com>
On Mon, Jun 29, 2026 at 01:28:47PM +0200, Bartosz Golaszewski wrote:
> Describe the SGMII/SerDes PHY present on the Qualcomm sa8255p platforms.
> This is essentially the same hardware as sa8775p rev3 but the PHY is
> managed by firmware over SCMI.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
> .../bindings/phy/qcom,sa8255p-dwmac-sgmii-phy.yaml | 51 ++++++++++++++++++++++
> 1 file changed, 51 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/phy/qcom,sa8255p-dwmac-sgmii-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sa8255p-dwmac-sgmii-phy.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..4cea6926d1c28872ea7b7aad53088dbbcb74fa99
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom,sa8255p-dwmac-sgmii-phy.yaml
> @@ -0,0 +1,51 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/qcom,sa8255p-dwmac-sgmii-phy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm SerDes/SGMII ethernet PHY controller (firmware managed)
> +
> +maintainers:
> + - Bartosz Golaszewski <brgl@kernel.org>
> +
> +description:
> + The SerDes PHY sits between the MAC and the external PHY and provides
> + separate Rx Tx lines.
> +
> +properties:
> + compatible:
> + const: qcom,sa8255p-dwmac-sgmii-phy
> +
> + reg:
> + items:
> + - description: serdes
> +
> + power-domains:
> + maxItems: 1
> +
> + power-domain-names:
> + items:
> + - const: serdes
Drop names. Not useful if it repeats the device block name.
With this:
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH net-next 0/2] octeontx2-af: NPC parser and RSS improvements
From: nshettyj @ 2026-06-30 6:21 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, lcherian, gakula, hkelam, sbhatta, andrew+netdev, davem,
edumazet, kuba, pabeni, Kiran Kumar K
From: Kiran Kumar K <kirankumark@marvell.com>
This series extends the Marvell OcteonTX2 admin-function driver with two
improvements to the NPC (Network Parser CAM) block. The NPC parses packets
received by or transmitted from the NIX, and its matching CAM (MCAM)
selects which VFs, queues, or output ports handle each packet.
Patch 1 reserves a new range of PKINDs (46-53) to support configurable
L2 skip-size parsing. Packets arriving with variable length L2 headers
or a CPT (Cryptographic Accelerator Unit) pre-header can be steered
to one of four skip-size PKINDs so the NPC advances past the right number
of bytes before starting protocol classification. The mbox interface is
extended with a skip_size field so PF/VF drivers can program the desired
L2 offset at run time without rebuilding firmware.
Patch 2 adds a NIX_FLOW_KEY_TYPE_ROCEV2 flow-key type so the RSS engine
can distribute RoCEv2 traffic across receive queues using the destination
Queue Pair (QP) field. Without this, all RoCEv2 flows hash the same
way and land on a single queue.
Both changes target the admin-function driver to improve overall hardware
parsing infrastructure.
Changelog:
v2:
- Fixed coding style in patch 1 and patch 2.
Kiran Kumar K (2):
octeontx2-af: reserve 4 PKINDs for skip-size custom use
octeontx2-af: Add RSS hashing support based on RoCEv2 header
.../net/ethernet/marvell/octeontx2/af/mbox.h | 2 +
.../net/ethernet/marvell/octeontx2/af/npc.h | 4 +-
.../net/ethernet/marvell/octeontx2/af/rvu.h | 2 +-
.../ethernet/marvell/octeontx2/af/rvu_nix.c | 9 +++-
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 43 +++++++++++++++++--
5 files changed, 54 insertions(+), 6 deletions(-)
--
2.48.1
^ permalink raw reply
* [syzbot] [bpf?] BUG: using smp_processor_id() in preemptible code in bpf_mem_cache_free_rcu
From: syzbot @ 2026-06-30 6:20 UTC (permalink / raw)
To: andrii, ast, bpf, daniel, eddyz87, emil, jolsa, linux-kernel,
martin.lau, memxor, netdev, song, syzkaller-bugs, yonghong.song
Hello,
syzbot found the following issue on:
HEAD commit: e771677c937d Merge tag 'for-linus-iommufd' of git://git.ke..
git tree: bpf
console output: https://syzkaller.appspot.com/x/log.txt?x=144f8aae580000
kernel config: https://syzkaller.appspot.com/x/.config?x=1ce9592ed82f8125
dashboard link: https://syzkaller.appspot.com/bug?extid=fd7e415d891073b83e1f
compiler: Debian clang version 22.1.6 (++20260514074242+fc4aad7b5db3-1~exp1~20260514074407.73), Debian LLD 22.1.6
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=124c12ae580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=13b89986580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/5c69b301ec25/disk-e771677c.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/8267811b5065/vmlinux-e771677c.xz
kernel image: https://storage.googleapis.com/syzbot-assets/bcc54586e6c4/bzImage-e771677c.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+fd7e415d891073b83e1f@syzkaller.appspotmail.com
BUG: using smp_processor_id() in preemptible [00000000] code: syz.0.17/5820
caller is bpf_mem_cache_free_rcu+0x48/0xc0 kernel/bpf/memalloc.c:954
CPU: 1 UID: 0 PID: 5820 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47
bpf_mem_cache_free_rcu+0x48/0xc0 kernel/bpf/memalloc.c:954
rhtab_delete_elem+0x185a/0x1b30 kernel/bpf/hashtab.c:2969
__rhtab_map_lookup_and_delete_batch+0x935/0xcb0 kernel/bpf/hashtab.c:3349
bpf_map_do_batch+0x445/0x630 kernel/bpf/syscall.c:-1
__sys_bpf+0x906/0xd90 kernel/bpf/syscall.c:-1
__do_sys_bpf kernel/bpf/syscall.c:6537 [inline]
__se_sys_bpf kernel/bpf/syscall.c:6534 [inline]
__x64_sys_bpf+0xba/0xd0 kernel/bpf/syscall.c:6534
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fce2819ce59
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffcea2ad4b8 EFLAGS: 00000246 ORIG_RAX: 0000000000000141
RAX: ffffffffffffffda RBX: 00007fce28415fa0 RCX: 00007fce2819ce59
RDX: 0000000000000038 RSI: 00002000000018c0 RDI: 0000000000000019
RBP: 00007fce28232d6f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fce28415fac R14: 00007fce28415fa0 R15: 00007fce28415fa0
</TASK>
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* Re: [PATCH 4/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Krzysztof Kozlowski @ 2026-06-30 6:18 UTC (permalink / raw)
To: Konrad Dybcio, George Moussalem
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <0e0fb3af-968f-46d2-be6c-18b76c7d2a1a@oss.qualcomm.com>
On 26/06/2026 13:30, Konrad Dybcio wrote:
> On 6/26/26 1:20 PM, George Moussalem wrote:
>> On 6/26/26 14:53, Krzysztof Kozlowski wrote:
>>> On Thu, Jun 25, 2026 at 06:10:08PM +0400, George Moussalem wrote:
>>>> Document the Qualcomm IPQ5018 Bluetooth controller.
>>>>
>>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>>> ---
>
> [...]
>
>>>> + compatible = "qcom,ipq5018-bt";
>>>> +
>>>> + qcom,ipc = <&apcs_glb 8 23>;
>>>> + interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
>>>
>>> No firmware to load?
>>
>> firmware is loaded by the remoteproc in patch 1
>>
>>>
>>> It feels like remoteproc node split is fake. The property qcom,rproc is
>>> even more supporting that case. Shouldn't this be simply one device -
>>> bluetooth? What sort of two devices do you have exactly? How can I
>>> identify them in the hardware?
>>
>> I wasn't sure how to represent the HW. Should I make this bluetooth node
>> a childnode of the rproc? Essentially, this is the transport layer
>> (using shared memory space and IPC/interrupt).
>>
>> Most QCA BT controllers are also childnodes of a serdev/uart node as
>> they use serdev for transport.
>>
>> From what I understand, it's simply BT firmware running on this
>> dedicated M0 core in the SoC itself connected to an RF.
>
> Seems like this rhymes with the WPSS remoteproc +ATH1xK_AHB situation
> - the Q6 core power sequences and manages the wireless controller,
> while Linux gets to drive the device as it would if it were connected
> over PCIe/ UART respectively, just with MMIO writes instead.
But the ATH (except the MMIO for remoteproc bringup) are physically
connected over other bus, like PCIe and UART.
What is here?
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v6] net: mvneta_bm: add suspend/resume support to prevent crash after resume
From: Yun Zhou @ 2026-06-30 6:03 UTC (permalink / raw)
To: marcin.s.wojtas, andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-kernel, yun.zhou
The mvneta driver uses the hardware Buffer Manager (BM) for RX buffer
allocation. During suspend, mvneta disables its clock, causing BM to
lose all buffer address state. On resume, mvneta_bm_port_init() re-
attaches the BM pool to the NIC, but BM hardware returns stale/garbage
buffer addresses. When NAPI poll processes these buffers, DMA cache
sync hits an invalid virtual address causing a kernel panic:
Unable to handle kernel paging request at virtual address b0000080
PC is at v7_dma_inv_range
Call trace:
v7_dma_inv_range from arch_sync_dma_for_cpu+0x94/0x158
arch_sync_dma_for_cpu from __dma_sync_single_for_cpu+0xc4/0x15c
__dma_sync_single_for_cpu from mvneta_rx_swbm+0x6c8/0xf48
mvneta_rx_swbm from mvneta_poll+0x6fc/0x70c
mvneta_poll from __napi_poll.constprop.0+0x2c/0x1e0
__napi_poll.constprop.0 from net_rx_action+0x160/0x2c4
net_rx_action from handle_softirqs+0xd8/0x2b8
handle_softirqs from run_ksoftirqd+0x30/0x94
run_ksoftirqd from smpboot_thread_fn+0x100/0x204
smpboot_thread_fn from kthread+0xf4/0x110
kthread from ret_from_fork+0x14/0x28
Fix by adding suspend/resume callbacks to the BM driver:
- suspend: drain all buffers (with DMA unmapping), free the BPPE
regions, and reset pool state to FREE before stopping BM and gating
the clock.
- resume: enable the clock, reinitialize BM defaults, and restore pool
read/write pointers and size registers. Pool allocation and buffer
refill are handled by mvneta_resume() through the normal
mvneta_bm_port_init() path, which sees pools as FREE and performs
full initialization identical to probe.
Add a device_link (DL_FLAG_AUTOREMOVE_CONSUMER) in mvneta_probe to
guarantee BM resumes before mvneta and suspends after mvneta. If the
link cannot be created, fall back to SW buffer management to avoid a
potential crash on resume due to unordered PM transitions.
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
---
v6:
- Add mutex_destroy() before setting type = FREE in suspend, pairing
with mutex_init() in mvneta_bm_pool_use() on resume. This avoids
re-initializing an active lockdep class.
- NULL-out bm_pool->virt_addr in mvneta_bm_pool_create() error paths
to fix a pre-existing dangling pointer that could cause double-free
in suspend.
v5:
- Call mvneta_bm_pool_disable() per pool before dma_free_coherent()
in suspend, matching mvneta_bm_pool_destroy() ordering. This also
ensures ENABLE_MASK is cleared before BM START on resume.
- Guard dma_free_coherent() with if (bm_pool->virt_addr) to defend
against a partially-failed mvneta_bm_pool_create() leaving a stale
pointer.
v4:
- On device_link_add() failure, fall back to SW buffer management
(destroy pools, put BM reference, clear bm_priv) instead of merely
emitting a warning. Without the link, suspend/resume ordering is
not guaranteed and the original crash can still occur.
v3:
- Restore per-pool POOL_SIZE_REG, POOL_READ_PTR_REG, and
POOL_WRITE_PTR_REG in resume, since clock gating loses all BM
register state.
- Check device_link_add() return value and emit dev_warn on failure.
- Replace SIMPLE_DEV_PM_OPS (deprecated) with
DEFINE_SIMPLE_DEV_PM_OPS and pm_sleep_ptr(), removing the
#ifdef CONFIG_PM_SLEEP guard.
- Add dev_warn in suspend if not all buffers could be freed.
v2:
- Drain buffers via mvneta_bm_bufs_free() in suspend instead of only
stopping BM and gating the clock. This ensures proper DMA unmapping
and avoids buffer leaks.
- Free the BPPE DMA-coherent region in suspend so that resume takes
the full probe-time initialization path (alloc + fill), eliminating
the need to modify mvneta_bm_pool_create().
- Reset pool type to MVNETA_BM_FREE in suspend so mvneta_bm_pool_use()
correctly re-creates and refills pools on resume.
- Check clk_prepare_enable() return value in resume.
- Add device_link between mvneta (consumer) and mvneta_bm (supplier)
to guarantee correct suspend/resume ordering.
drivers/net/ethernet/marvell/mvneta.c | 18 ++++++
drivers/net/ethernet/marvell/mvneta_bm.c | 72 ++++++++++++++++++++++++
2 files changed, 90 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 744d6585a949..543e566425c1 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -5678,6 +5678,24 @@ static int mvneta_probe(struct platform_device *pdev)
"use SW buffer management\n");
mvneta_bm_put(pp->bm_priv);
pp->bm_priv = NULL;
+ } else if (!device_link_add(&pdev->dev,
+ &pp->bm_priv->pdev->dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER)) {
+ /*
+ * Link guarantees BM resumes before mvneta.
+ * Without it, BM may not be ready when
+ * mvneta_bm_port_init() runs on resume,
+ * causing stale buffer addresses and a crash.
+ * Fall back to SW management to be safe.
+ */
+ dev_warn(&pdev->dev,
+ "failed to link to BM, use SW buffer management\n");
+ 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);
+ mvneta_bm_put(pp->bm_priv);
+ pp->bm_priv = NULL;
}
}
/* Set RX packet offset correction for platforms, whose
diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c
index 6bb380494919..e0c693c0a910 100644
--- a/drivers/net/ethernet/marvell/mvneta_bm.c
+++ b/drivers/net/ethernet/marvell/mvneta_bm.c
@@ -129,6 +129,7 @@ static int mvneta_bm_pool_create(struct mvneta_bm *priv,
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);
+ bm_pool->virt_addr = NULL;
dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n",
bm_pool->id, MVNETA_BM_POOL_PTR_ALIGN);
return -ENOMEM;
@@ -139,6 +140,7 @@ static int mvneta_bm_pool_create(struct mvneta_bm *priv,
if (err < 0) {
dma_free_coherent(&pdev->dev, size_bytes, bm_pool->virt_addr,
bm_pool->phys_addr);
+ bm_pool->virt_addr = NULL;
return err;
}
@@ -477,6 +479,75 @@ static void mvneta_bm_remove(struct platform_device *pdev)
clk_disable_unprepare(priv->clk);
}
+static int mvneta_bm_suspend(struct device *dev)
+{
+ struct mvneta_bm *priv = dev_get_drvdata(dev);
+ int i;
+
+ /* Drain buffers and free pool resources while BM is still clocked */
+ for (i = 0; i < MVNETA_BM_POOLS_NUM; i++) {
+ struct mvneta_bm_pool *bm_pool = &priv->bm_pools[i];
+ int size_bytes;
+
+ if (bm_pool->type == MVNETA_BM_FREE)
+ continue;
+
+ mvneta_bm_bufs_free(priv, bm_pool, bm_pool->port_map);
+ if (bm_pool->hwbm_pool.buf_num)
+ dev_warn(&priv->pdev->dev,
+ "pool %d: %d buffers not freed\n",
+ bm_pool->id, bm_pool->hwbm_pool.buf_num);
+
+ mvneta_bm_pool_disable(priv, bm_pool->id);
+
+ if (bm_pool->virt_addr) {
+ size_bytes = sizeof(u32) * bm_pool->hwbm_pool.size;
+ dma_free_coherent(&priv->pdev->dev, size_bytes,
+ bm_pool->virt_addr,
+ bm_pool->phys_addr);
+ bm_pool->virt_addr = NULL;
+ }
+ /*
+ * Safe to destroy: device_link guarantees all mvneta ports
+ * have already suspended, so no hwbm_pool_add() can be in
+ * progress holding buf_lock. Pairs with mutex_init() in
+ * mvneta_bm_pool_use() on resume.
+ */
+ mutex_destroy(&bm_pool->hwbm_pool.buf_lock);
+ bm_pool->type = MVNETA_BM_FREE;
+ }
+
+ mvneta_bm_write(priv, MVNETA_BM_COMMAND_REG, MVNETA_BM_STOP_MASK);
+ clk_disable_unprepare(priv->clk);
+ return 0;
+}
+
+static int mvneta_bm_resume(struct device *dev)
+{
+ struct mvneta_bm *priv = dev_get_drvdata(dev);
+ int i, err;
+
+ err = clk_prepare_enable(priv->clk);
+ if (err)
+ return err;
+
+ /* Reinitialize BM hardware; pools are refilled by mvneta_resume() */
+ mvneta_bm_default_set(priv);
+
+ /* Restore pool registers lost during clock gating */
+ for (i = 0; i < MVNETA_BM_POOLS_NUM; i++) {
+ mvneta_bm_write(priv, MVNETA_BM_POOL_READ_PTR_REG(i), 0);
+ mvneta_bm_write(priv, MVNETA_BM_POOL_WRITE_PTR_REG(i), 0);
+ mvneta_bm_write(priv, MVNETA_BM_POOL_SIZE_REG(i),
+ priv->bm_pools[i].hwbm_pool.size);
+ }
+
+ mvneta_bm_write(priv, MVNETA_BM_COMMAND_REG, MVNETA_BM_START_MASK);
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(mvneta_bm_pm_ops, mvneta_bm_suspend, mvneta_bm_resume);
+
static const struct of_device_id mvneta_bm_match[] = {
{ .compatible = "marvell,armada-380-neta-bm" },
{ }
@@ -489,6 +560,7 @@ static struct platform_driver mvneta_bm_driver = {
.driver = {
.name = MVNETA_BM_DRIVER_NAME,
.of_match_table = mvneta_bm_match,
+ .pm = pm_sleep_ptr(&mvneta_bm_pm_ops),
},
};
--
2.43.0
^ permalink raw reply related
* RE: [PATCH net v2 0/2] Fix to possible skb leak due to race condtion in tx path
From: Selvamani Rajagopal @ 2026-06-30 5:57 UTC (permalink / raw)
To: Parthiban.Veerasooran@microchip.com
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
andrew@lunn.ch, andrew+netdev@lunn.ch, Piergiorgio Beruto,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com
In-Reply-To: <d3d382c6-5ae4-486f-89a4-885584d863c4@microchip.com>
> -----Original Message-----
> From: Parthiban.Veerasooran@microchip.com <Parthiban.Veerasooran@microchip.com>
> Subject: Re: [PATCH net v2 0/2] Fix to possible skb leak due to race condtion in tx path
>
>
>
> I performed a one-hour quick test using two instances of the LAN8651
> MAC-PHY Click (Test Case 2), and it ran without any crashes. Thank you
> for the fixes.
Great. Appreciate your help. Thanks
>
> Best regards,
> Parthiban V
> >
> > ---
^ permalink raw reply
* Re: [PATCH net-next v1] tcp/dccp: avoid parity split for socket-local bind range
From: luoxuanqiang @ 2026-06-30 5:56 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: Eric Dumazet, Neal Cardwell, netdev, David S . Miller,
Jakub Kicinski, Paolo Abeni, Simon Horman, luoxuanqiang
In-Reply-To: <CAAVpQUA+yKA773dtgr2E=mu4SbMCjWZk83sFYrWS6f1sDphdRQ@mail.gmail.com>
在 2026/6/30 02:21, Kuniyuki Iwashima 写道:
> On Fri, Jun 26, 2026 at 7:00 PM luoxuanqiang <xuanqiang.luo@linux.dev> wrote:
>>> 2026年6月27日 07:40,Kuniyuki Iwashima <kuniyu@google.com> 写道:
>>>
>>> On Fri, Jun 26, 2026 at 2:40 AM <xuanqiang.luo@linux.dev> wrote:
>>>> From: luoxuanqiang <luoxuanqiang@kylinos.cn>
>>>>
>>>> IP_LOCAL_PORT_RANGE lets applications override the netns ephemeral port
>>>> range on a per-socket basis. __inet_hash_connect() already treats such a
>>>> range as an explicit application partition and scans it with step 1 [1].
>>>>
>>>> Do the same in inet_csk_find_open_port():
>>> What's the use case of IP_LOCAL_PORT_RANGE + bind(, 0)
>>> without IP_BIND_ADDRESS_NO_PORT ?
>> Hi Kuniyuki,
>>
>> Thanks for the question!
>>
>> The use case is when an application wants to restrict ephemeral port
>> allocation to a socket-local IP_LOCAL_PORT_RANGE, but still needs
>> bind(..., 0) to allocate and reserve a local port immediately.
> IP_LOCAL_PORT_RANGE was introduced for connect().
>
> Unlike connect(), bind() occupies the port without SO_REUSEADDR/PORT,
> so I don't think the step 1 or 2 makes any difference.
>
Hi Kuniyuki,
That's a fair point — bind() takes exclusive ownership of the port
without SO_REUSEADDR/PORT, so the parity split only changes the scan
order, not the set of ports bind() can pick. Correctness-wise there is
no difference between step 1 and step 2 here.
There are a couple of smaller things that made me think it is still
worth aligning the two paths, though:
- inet_csk_find_open_port() already consumes the narrowed range from
IP_LOCAL_PORT_RANGE since commit 91d0b78c5177f ("inet: Add
IP_LOCAL_PORT_RANGE socket option"), so the bind path isn't
insulated from the option. It just didn't pick up the relaxed scan
step that __inet_hash_connect() got in commit 207184853dbdb
("tcp/dccp: change source port selection at connect() time"). Eric
even noted at the end of that commit:
"A similar change can be done in inet_csk_find_open_port() if
needed."
So this felt more like completing the companion change than adding
something new.
- The entropy argument from commit 207184853dbdb applies equally here:
the parity split drops one bit of the 16-bit sport for RSS hashing.
Whether the port came from connect() or bind() doesn't matter to the
NIC, and losing that bit hurts more when the application has already
shrunk its port space with IP_LOCAL_PORT_RANGE.
- When IP_BIND_ADDRESS_NO_PORT is not set, plain bind(, 0) reserves a
port immediately through inet_csk_find_open_port(). If the same
application also uses connect() on other sockets within the same
IP_LOCAL_PORT_RANGE, connect() now scans the full range while bind()
still biases toward odd ports — so the parity heuristic works against
itself inside the application's own partition.
Does that make sense, or am I over-thinking the consistency angle?
Thanks,
Xuanqiang
>> IP_BIND_ADDRESS_NO_PORT is useful when the application can defer port
>> allocation until connect(), but it changes this behavior: bind(..., 0)
>> does not reserve a port in that case. So it is not a replacement for
>> applications that need the local port before connect(), for example to
>> publish it to another component or set up local policy.
>>
>> This patch is also intended to keep the bind(..., 0) path consistent with
>> Eric's earlier change in __inet_hash_connect().
>>
>> Thanks,
>> Xuanqiang
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/2] bpf, sockmap: disallow update and delete from tc, xdp and flow_dissector
From: John Fastabend @ 2026-06-30 5:47 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Sechang Lim, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, David S . Miller,
Jakub Kicinski, Jesper Dangaard Brouer, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Stanislav Fomichev,
Emil Tsalapatis, Lorenz Bauer, Jakub Sitnicki, Jiayuan Chen,
Shuah Khan, bpf, netdev, linux-kselftest, linux-kernel
In-Reply-To: <DJLQSC87KCSV.314DTZAWRNA8C@gmail.com>
On Mon, Jun 29, 2026 at 11:24:49AM -0700, Alexei Starovoitov wrote:
>On Mon Jun 29, 2026 at 10:27 AM PDT, Sechang Lim wrote:
>> sock_map_update_common() and __sock_map_delete() hold stab->lock and call
>> sock_map_unref() -> sock_map_del_link(), which takes sk_callback_lock for
>> write. That gives the order stab->lock -> sk_callback_lock.
>>
>> The reverse order comes from the SK_SKB stream parser.
>> sk_psock_strp_data_ready() holds sk_callback_lock for read, and after the
>> verdict tcp_bpf_strp_read_sock() acks the consumed data inline via
>> __tcp_cleanup_rbuf(). The ACK goes out egress, where a sched_cls program
>> deletes from the sockmap and takes stab->lock:
>>
>> WARNING: possible circular locking dependency detected
>> ------------------------------------------------------
>> syz.9.8824 is trying to acquire lock:
>> (&stab->lock){+.-.}-{3:3}, at: __sock_map_delete net/core/sock_map.c:421
>> but task is already holding lock:
>> (clock-AF_INET){++.-}-{3:3}, at: sk_psock_strp_data_ready net/core/skmsg.c:1173
>>
>> -> #1 (clock-AF_INET){++.-}-{3:3}:
>> _raw_write_lock_bh
>> sock_map_del_link net/core/sock_map.c:167
>> sock_map_unref net/core/sock_map.c:184
>> sock_map_update_common net/core/sock_map.c:509
>> sock_map_update_elem_sys net/core/sock_map.c:588
>> map_update_elem kernel/bpf/syscall.c:1805
>>
>> -> #0 (&stab->lock){+.-.}-{3:3}:
>> _raw_spin_lock_bh
>> __sock_map_delete net/core/sock_map.c:421
>> sock_map_delete_elem net/core/sock_map.c:452
>> bpf_prog_06044d24140080b6
>> tcx_run net/core/dev.c:4451
>> sch_handle_egress net/core/dev.c:4541
>> __dev_queue_xmit net/core/dev.c:4808
>> ...
>> tcp_bpf_strp_read_sock net/ipv4/tcp_bpf.c:701
>> strp_data_ready net/strparser/strparser.c:402
>> sk_psock_strp_data_ready net/core/skmsg.c:1174
>> tcp_data_queue net/ipv4/tcp_input.c:5661
>>
>> Possible unsafe locking scenario:
>>
>> CPU0 CPU1
>> ---- ----
>> rlock(clock-AF_INET);
>> lock(&stab->lock);
>> lock(clock-AF_INET);
>> lock(&stab->lock);
>>
>> *** DEADLOCK ***
>>
>> A tc, xdp or flow_dissector program has no reason to update or delete a
>> sockmap, and redirect does not go through here. Drop them from
>> may_update_sockmap() so the verifier rejects it. It also closes the
>> matching sockhash inversion.
>>
>> Suggested-by: John Fastabend <john.fastabend@gmail.com>
>> Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com>
>
>John,
>
>please ack.
Hi Sechang,
I think we additionally need to also block BPF_PROG_TYPE_SOCKET_FILTER?
Did you check this case I guess the same case is possible there?
Then another patch needs to restrict BPF_SOCK_OPS users. For that
we need to block BPF_SOCK_OPS_HDR_OPT_LEN_CB and BPF_SOCK_OPS_WRITE_*.
Let me know if you want to do those as well. Let me know if you want
to do both patches or just the prog blocking above with the possible
addition of SOCKET_FILTER. I didn't search very hard so probably need
to check all the BPF_SOCK_OPS_* to find the valid cases.
Thanks,
John
^ permalink raw reply
* Re: [PATCH net-next 2/2] powerpc: remove ehea driver references
From: Christophe Leroy (CS GROUP) @ 2026-06-30 5:43 UTC (permalink / raw)
To: David Christensen, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Michael Ellerman, Nicholas Piggin
Cc: netdev, linuxppc-dev, linux-kernel
In-Reply-To: <20260629211343.3712775-3-drc@linux.ibm.com>
Le 29/06/2026 à 23:13, David Christensen a écrit :
> [Vous ne recevez pas souvent de courriers de drc@linux.ibm.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ]
>
> Follow-on cleanup after the removal of the IBM eHEA driver in commit
> f721e8ffa92a ("ehea: remove the ehea driver").
>
> Remove the CONFIG_IBM_EHEA entry from ppc64_defconfig and the
> EXPORT_SYMBOL_GPL(walk_system_ram_range) export from arch/powerpc/mm/mem.c
> that was only needed by the ehea driver.
>
> Signed-off-by: David Christensen <drc@linux.ibm.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
> arch/powerpc/configs/ppc64_defconfig | 1 -
> arch/powerpc/mm/mem.c | 6 ------
> 2 files changed, 7 deletions(-)
>
> diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
> index f795b74602ec..1eb8e3457e8b 100644
> --- a/arch/powerpc/configs/ppc64_defconfig
> +++ b/arch/powerpc/configs/ppc64_defconfig
> @@ -210,7 +210,6 @@ CONFIG_BNX2X=m
> CONFIG_CHELSIO_T1=m
> CONFIG_BE2NET=m
> CONFIG_IBMVETH=m
> -CONFIG_EHEA=m
> CONFIG_IBMVNIC=m
> CONFIG_E100=y
> CONFIG_E1000=y
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 4c1afab91996..b617b69452cd 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -371,12 +371,6 @@ int devmem_is_allowed(unsigned long pfn)
> }
> #endif /* CONFIG_STRICT_DEVMEM */
>
> -/*
> - * This is defined in kernel/resource.c but only powerpc needs to export it, for
> - * the EHEA driver. Drop this when drivers/net/ethernet/ibm/ehea is removed.
> - */
> -EXPORT_SYMBOL_GPL(walk_system_ram_range);
> -
> #ifdef CONFIG_EXECMEM
> static struct execmem_info execmem_info __ro_after_init;
>
> --
> 2.47.3
>
^ permalink raw reply
* Re: [PATCH net-next 1/2] ehea: remove the ehea driver
From: Christophe Leroy (CS GROUP) @ 2026-06-30 5:42 UTC (permalink / raw)
To: David Christensen, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Michael Ellerman, Nicholas Piggin
Cc: netdev, linuxppc-dev, linux-kernel
In-Reply-To: <20260629211343.3712775-2-drc@linux.ibm.com>
Le 29/06/2026 à 23:13, David Christensen a écrit :
> [Vous ne recevez pas souvent de courriers de drc@linux.ibm.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ]
>
> The IBM eHEA (Ethernet Host Ethernet Adapter) driver has been orphaned
> since April 2024 with no active maintainer. The hardware was last
> supported on IBM POWER7 systems which reached end-of-support in
> December 2020. The driver has received no functional updates since
> October 2022, with all subsequent changes being mechanical API
> migrations affecting the entire kernel tree.
>
> A search of lore.kernel.org for the last 24 months reveals no user
> reports, no objections to the orphan status, and no maintenance
> discussions indicating active hardware deployment.
>
> The code is preserved in git history and can be restored if a
> maintainer steps forward to take ownership.
>
> Signed-off-by: David Christensen <drc@linux.ibm.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
> MAINTAINERS | 5 -
> drivers/net/ethernet/ibm/Kconfig | 9 -
> drivers/net/ethernet/ibm/Makefile | 1 -
> drivers/net/ethernet/ibm/ehea/Makefile | 7 -
> drivers/net/ethernet/ibm/ehea/ehea.h | 477 ---
> drivers/net/ethernet/ibm/ehea/ehea_ethtool.c | 277 --
> drivers/net/ethernet/ibm/ehea/ehea_hw.h | 253 --
> drivers/net/ethernet/ibm/ehea/ehea_main.c | 3581 ------------------
> drivers/net/ethernet/ibm/ehea/ehea_phyp.c | 612 ---
> drivers/net/ethernet/ibm/ehea/ehea_phyp.h | 433 ---
> drivers/net/ethernet/ibm/ehea/ehea_qmr.c | 999 -----
> drivers/net/ethernet/ibm/ehea/ehea_qmr.h | 390 --
> 12 files changed, 7044 deletions(-)
> delete mode 100644 drivers/net/ethernet/ibm/ehea/Makefile
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea.h
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_hw.h
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_main.c
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_phyp.c
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_phyp.h
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_qmr.c
> delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_qmr.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 15011f5752a9..ee4ee7b8e947 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9498,11 +9498,6 @@ S: Orphan
> W: http://aeschi.ch.eu.org/efs/
> F: fs/efs/
>
> -EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
> -L: netdev@vger.kernel.org
> -S: Orphan
> -F: drivers/net/ethernet/ibm/ehea/
> -
> ELM327 CAN NETWORK DRIVER
> M: Max Staudt <max@enpas.org>
> L: linux-can@vger.kernel.org
> diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig
> index 4f4b23465c47..8e55faac2035 100644
> --- a/drivers/net/ethernet/ibm/Kconfig
> +++ b/drivers/net/ethernet/ibm/Kconfig
> @@ -42,15 +42,6 @@ config IBMVETH_KUNIT_TEST
>
> source "drivers/net/ethernet/ibm/emac/Kconfig"
>
> -config EHEA
> - tristate "eHEA Ethernet support"
> - depends on IBMEBUS && SPARSEMEM
> - help
> - This driver supports the IBM pSeries eHEA ethernet adapter.
> -
> - To compile the driver as a module, choose M here. The module
> - will be called ehea.
> -
> config IBMVNIC
> tristate "IBM Virtual NIC support"
> depends on PPC_PSERIES
> diff --git a/drivers/net/ethernet/ibm/Makefile b/drivers/net/ethernet/ibm/Makefile
> index 1d17d0c33d4d..c7e5d891c946 100644
> --- a/drivers/net/ethernet/ibm/Makefile
> +++ b/drivers/net/ethernet/ibm/Makefile
> @@ -6,4 +6,3 @@
> obj-$(CONFIG_IBMVETH) += ibmveth.o
> obj-$(CONFIG_IBMVNIC) += ibmvnic.o
> obj-$(CONFIG_IBM_EMAC) += emac/
> -obj-$(CONFIG_EHEA) += ehea/
> diff --git a/drivers/net/ethernet/ibm/ehea/Makefile b/drivers/net/ethernet/ibm/ehea/Makefile
> deleted file mode 100644
> index 9e1e5c7aafe2..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/Makefile
> +++ /dev/null
> @@ -1,7 +0,0 @@
> -# SPDX-License-Identifier: GPL-2.0-only
> -#
> -# Makefile for the eHEA ethernet device driver for IBM eServer System p
> -#
> -ehea-y = ehea_main.o ehea_phyp.o ehea_qmr.o ehea_ethtool.o
> -obj-$(CONFIG_EHEA) += ehea.o
> -
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea.h b/drivers/net/ethernet/ibm/ehea/ehea.h
> deleted file mode 100644
> index 208c440a602b..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea.h
> +++ /dev/null
> @@ -1,477 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-or-later */
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea.h
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#ifndef __EHEA_H__
> -#define __EHEA_H__
> -
> -#include <linux/module.h>
> -#include <linux/ethtool.h>
> -#include <linux/vmalloc.h>
> -#include <linux/if_vlan.h>
> -#include <linux/platform_device.h>
> -
> -#include <asm/ibmebus.h>
> -#include <asm/io.h>
> -
> -#define DRV_NAME "ehea"
> -#define DRV_VERSION "EHEA_0107"
> -
> -/* eHEA capability flags */
> -#define DLPAR_PORT_ADD_REM 1
> -#define DLPAR_MEM_ADD 2
> -#define DLPAR_MEM_REM 4
> -#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD | DLPAR_MEM_REM)
> -
> -#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
> - | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
> -
> -#define EHEA_MAX_ENTRIES_RQ1 32767
> -#define EHEA_MAX_ENTRIES_RQ2 16383
> -#define EHEA_MAX_ENTRIES_RQ3 16383
> -#define EHEA_MAX_ENTRIES_SQ 32767
> -#define EHEA_MIN_ENTRIES_QP 127
> -
> -#define EHEA_SMALL_QUEUES
> -
> -#ifdef EHEA_SMALL_QUEUES
> -#define EHEA_MAX_CQE_COUNT 1023
> -#define EHEA_DEF_ENTRIES_SQ 1023
> -#define EHEA_DEF_ENTRIES_RQ1 1023
> -#define EHEA_DEF_ENTRIES_RQ2 1023
> -#define EHEA_DEF_ENTRIES_RQ3 511
> -#else
> -#define EHEA_MAX_CQE_COUNT 4080
> -#define EHEA_DEF_ENTRIES_SQ 4080
> -#define EHEA_DEF_ENTRIES_RQ1 8160
> -#define EHEA_DEF_ENTRIES_RQ2 2040
> -#define EHEA_DEF_ENTRIES_RQ3 2040
> -#endif
> -
> -#define EHEA_MAX_ENTRIES_EQ 20
> -
> -#define EHEA_SG_SQ 2
> -#define EHEA_SG_RQ1 1
> -#define EHEA_SG_RQ2 0
> -#define EHEA_SG_RQ3 0
> -
> -#define EHEA_MAX_PACKET_SIZE 9022 /* for jumbo frames */
> -#define EHEA_RQ2_PKT_SIZE 2048
> -#define EHEA_L_PKT_SIZE 256 /* low latency */
> -
> -/* Send completion signaling */
> -
> -/* Protection Domain Identifier */
> -#define EHEA_PD_ID 0xaabcdeff
> -
> -#define EHEA_RQ2_THRESHOLD 1
> -#define EHEA_RQ3_THRESHOLD 4 /* use RQ3 threshold of 2048 bytes */
> -
> -#define EHEA_SPEED_10G 10000
> -#define EHEA_SPEED_1G 1000
> -#define EHEA_SPEED_100M 100
> -#define EHEA_SPEED_10M 10
> -#define EHEA_SPEED_AUTONEG 0
> -
> -/* Broadcast/Multicast registration types */
> -#define EHEA_BCMC_SCOPE_ALL 0x08
> -#define EHEA_BCMC_SCOPE_SINGLE 0x00
> -#define EHEA_BCMC_MULTICAST 0x04
> -#define EHEA_BCMC_BROADCAST 0x00
> -#define EHEA_BCMC_UNTAGGED 0x02
> -#define EHEA_BCMC_TAGGED 0x00
> -#define EHEA_BCMC_VLANID_ALL 0x01
> -#define EHEA_BCMC_VLANID_SINGLE 0x00
> -
> -#define EHEA_CACHE_LINE 128
> -
> -/* Memory Regions */
> -#define EHEA_MR_ACC_CTRL 0x00800000
> -
> -#define EHEA_BUSMAP_START 0x8000000000000000ULL
> -#define EHEA_INVAL_ADDR 0xFFFFFFFFFFFFFFFFULL
> -#define EHEA_DIR_INDEX_SHIFT 13 /* 8k Entries in 64k block */
> -#define EHEA_TOP_INDEX_SHIFT (EHEA_DIR_INDEX_SHIFT * 2)
> -#define EHEA_MAP_ENTRIES (1 << EHEA_DIR_INDEX_SHIFT)
> -#define EHEA_MAP_SIZE (0x10000) /* currently fixed map size */
> -#define EHEA_INDEX_MASK (EHEA_MAP_ENTRIES - 1)
> -
> -
> -#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
> -
> -/* utility functions */
> -
> -void ehea_dump(void *adr, int len, char *msg);
> -
> -#define EHEA_BMASK(pos, length) (((pos) << 16) + (length))
> -
> -#define EHEA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
> -
> -#define EHEA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
> -
> -#define EHEA_BMASK_MASK(mask) \
> - (0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
> -
> -#define EHEA_BMASK_SET(mask, value) \
> - ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
> -
> -#define EHEA_BMASK_GET(mask, value) \
> - (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
> -
> -/*
> - * Generic ehea page
> - */
> -struct ehea_page {
> - u8 entries[PAGE_SIZE];
> -};
> -
> -/*
> - * Generic queue in linux kernel virtual memory
> - */
> -struct hw_queue {
> - u64 current_q_offset; /* current queue entry */
> - struct ehea_page **queue_pages; /* array of pages belonging to queue */
> - u32 qe_size; /* queue entry size */
> - u32 queue_length; /* queue length allocated in bytes */
> - u32 pagesize;
> - u32 toggle_state; /* toggle flag - per page */
> - u32 reserved; /* 64 bit alignment */
> -};
> -
> -/*
> - * For pSeries this is a 64bit memory address where
> - * I/O memory is mapped into CPU address space
> - */
> -struct h_epa {
> - void __iomem *addr;
> -};
> -
> -struct h_epa_user {
> - u64 addr;
> -};
> -
> -struct h_epas {
> - struct h_epa kernel; /* kernel space accessible resource,
> - set to 0 if unused */
> - struct h_epa_user user; /* user space accessible resource
> - set to 0 if unused */
> -};
> -
> -/*
> - * Memory map data structures
> - */
> -struct ehea_dir_bmap
> -{
> - u64 ent[EHEA_MAP_ENTRIES];
> -};
> -struct ehea_top_bmap
> -{
> - struct ehea_dir_bmap *dir[EHEA_MAP_ENTRIES];
> -};
> -struct ehea_bmap
> -{
> - struct ehea_top_bmap *top[EHEA_MAP_ENTRIES];
> -};
> -
> -struct ehea_qp;
> -struct ehea_cq;
> -struct ehea_eq;
> -struct ehea_port;
> -struct ehea_av;
> -
> -/*
> - * Queue attributes passed to ehea_create_qp()
> - */
> -struct ehea_qp_init_attr {
> - /* input parameter */
> - u32 qp_token; /* queue token */
> - u8 low_lat_rq1;
> - u8 signalingtype; /* cqe generation flag */
> - u8 rq_count; /* num of receive queues */
> - u8 eqe_gen; /* eqe generation flag */
> - u16 max_nr_send_wqes; /* max number of send wqes */
> - u16 max_nr_rwqes_rq1; /* max number of receive wqes */
> - u16 max_nr_rwqes_rq2;
> - u16 max_nr_rwqes_rq3;
> - u8 wqe_size_enc_sq;
> - u8 wqe_size_enc_rq1;
> - u8 wqe_size_enc_rq2;
> - u8 wqe_size_enc_rq3;
> - u8 swqe_imm_data_len; /* immediate data length for swqes */
> - u16 port_nr;
> - u16 rq2_threshold;
> - u16 rq3_threshold;
> - u64 send_cq_handle;
> - u64 recv_cq_handle;
> - u64 aff_eq_handle;
> -
> - /* output parameter */
> - u32 qp_nr;
> - u16 act_nr_send_wqes;
> - u16 act_nr_rwqes_rq1;
> - u16 act_nr_rwqes_rq2;
> - u16 act_nr_rwqes_rq3;
> - u8 act_wqe_size_enc_sq;
> - u8 act_wqe_size_enc_rq1;
> - u8 act_wqe_size_enc_rq2;
> - u8 act_wqe_size_enc_rq3;
> - u32 nr_sq_pages;
> - u32 nr_rq1_pages;
> - u32 nr_rq2_pages;
> - u32 nr_rq3_pages;
> - u32 liobn_sq;
> - u32 liobn_rq1;
> - u32 liobn_rq2;
> - u32 liobn_rq3;
> -};
> -
> -/*
> - * Event Queue attributes, passed as parameter
> - */
> -struct ehea_eq_attr {
> - u32 type;
> - u32 max_nr_of_eqes;
> - u8 eqe_gen; /* generate eqe flag */
> - u64 eq_handle;
> - u32 act_nr_of_eqes;
> - u32 nr_pages;
> - u32 ist1; /* Interrupt service token */
> - u32 ist2;
> - u32 ist3;
> - u32 ist4;
> -};
> -
> -
> -/*
> - * Event Queue
> - */
> -struct ehea_eq {
> - struct ehea_adapter *adapter;
> - struct hw_queue hw_queue;
> - u64 fw_handle;
> - struct h_epas epas;
> - spinlock_t spinlock;
> - struct ehea_eq_attr attr;
> -};
> -
> -/*
> - * HEA Queues
> - */
> -struct ehea_qp {
> - struct ehea_adapter *adapter;
> - u64 fw_handle; /* QP handle for firmware calls */
> - struct hw_queue hw_squeue;
> - struct hw_queue hw_rqueue1;
> - struct hw_queue hw_rqueue2;
> - struct hw_queue hw_rqueue3;
> - struct h_epas epas;
> - struct ehea_qp_init_attr init_attr;
> -};
> -
> -/*
> - * Completion Queue attributes
> - */
> -struct ehea_cq_attr {
> - /* input parameter */
> - u32 max_nr_of_cqes;
> - u32 cq_token;
> - u64 eq_handle;
> -
> - /* output parameter */
> - u32 act_nr_of_cqes;
> - u32 nr_pages;
> -};
> -
> -/*
> - * Completion Queue
> - */
> -struct ehea_cq {
> - struct ehea_adapter *adapter;
> - u64 fw_handle;
> - struct hw_queue hw_queue;
> - struct h_epas epas;
> - struct ehea_cq_attr attr;
> -};
> -
> -/*
> - * Memory Region
> - */
> -struct ehea_mr {
> - struct ehea_adapter *adapter;
> - u64 handle;
> - u64 vaddr;
> - u32 lkey;
> -};
> -
> -/*
> - * Port state information
> - */
> -struct port_stats {
> - int poll_receive_errors;
> - int queue_stopped;
> - int err_tcp_cksum;
> - int err_ip_cksum;
> - int err_frame_crc;
> -};
> -
> -#define EHEA_IRQ_NAME_SIZE 20
> -
> -/*
> - * Queue SKB Array
> - */
> -struct ehea_q_skb_arr {
> - struct sk_buff **arr; /* skb array for queue */
> - int len; /* array length */
> - int index; /* array index */
> - int os_skbs; /* rq2/rq3 only: outstanding skbs */
> -};
> -
> -/*
> - * Port resources
> - */
> -struct ehea_port_res {
> - struct napi_struct napi;
> - struct port_stats p_stats;
> - struct ehea_mr send_mr; /* send memory region */
> - struct ehea_mr recv_mr; /* receive memory region */
> - struct ehea_port *port;
> - char int_recv_name[EHEA_IRQ_NAME_SIZE];
> - char int_send_name[EHEA_IRQ_NAME_SIZE];
> - struct ehea_qp *qp;
> - struct ehea_cq *send_cq;
> - struct ehea_cq *recv_cq;
> - struct ehea_eq *eq;
> - struct ehea_q_skb_arr rq1_skba;
> - struct ehea_q_skb_arr rq2_skba;
> - struct ehea_q_skb_arr rq3_skba;
> - struct ehea_q_skb_arr sq_skba;
> - int sq_skba_size;
> - int swqe_refill_th;
> - atomic_t swqe_avail;
> - int swqe_ll_count;
> - u32 swqe_id_counter;
> - u64 tx_packets;
> - u64 tx_bytes;
> - u64 rx_packets;
> - u64 rx_bytes;
> - int sq_restart_flag;
> -};
> -
> -
> -#define EHEA_MAX_PORTS 16
> -
> -#define EHEA_NUM_PORTRES_FW_HANDLES 6 /* QP handle, SendCQ handle,
> - RecvCQ handle, EQ handle,
> - SendMR handle, RecvMR handle */
> -#define EHEA_NUM_PORT_FW_HANDLES 1 /* EQ handle */
> -#define EHEA_NUM_ADAPTER_FW_HANDLES 2 /* MR handle, NEQ handle */
> -
> -struct ehea_adapter {
> - u64 handle;
> - struct platform_device *ofdev;
> - struct ehea_port *port[EHEA_MAX_PORTS];
> - struct ehea_eq *neq; /* notification event queue */
> - struct tasklet_struct neq_tasklet;
> - struct ehea_mr mr;
> - u32 pd; /* protection domain */
> - u64 max_mc_mac; /* max number of multicast mac addresses */
> - int active_ports;
> - struct list_head list;
> -};
> -
> -
> -struct ehea_mc_list {
> - struct list_head list;
> - u64 macaddr;
> -};
> -
> -/* kdump support */
> -struct ehea_fw_handle_entry {
> - u64 adh; /* Adapter Handle */
> - u64 fwh; /* Firmware Handle */
> -};
> -
> -struct ehea_fw_handle_array {
> - struct ehea_fw_handle_entry *arr;
> - int num_entries;
> - struct mutex lock;
> -};
> -
> -struct ehea_bcmc_reg_entry {
> - u64 adh; /* Adapter Handle */
> - u32 port_id; /* Logical Port Id */
> - u8 reg_type; /* Registration Type */
> - u64 macaddr;
> -};
> -
> -struct ehea_bcmc_reg_array {
> - struct ehea_bcmc_reg_entry *arr;
> - int num_entries;
> - spinlock_t lock;
> -};
> -
> -#define EHEA_PORT_UP 1
> -#define EHEA_PORT_DOWN 0
> -#define EHEA_PHY_LINK_UP 1
> -#define EHEA_PHY_LINK_DOWN 0
> -#define EHEA_MAX_PORT_RES 16
> -struct ehea_port {
> - struct ehea_adapter *adapter; /* adapter that owns this port */
> - struct net_device *netdev;
> - struct rtnl_link_stats64 stats;
> - struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
> - struct platform_device ofdev; /* Open Firmware Device */
> - struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
> - struct ehea_eq *qp_eq;
> - struct work_struct reset_task;
> - struct delayed_work stats_work;
> - struct mutex port_lock;
> - char int_aff_name[EHEA_IRQ_NAME_SIZE];
> - int allmulti; /* Indicates IFF_ALLMULTI state */
> - int promisc; /* Indicates IFF_PROMISC state */
> - int num_mcs;
> - int resets;
> - unsigned long flags;
> - u64 mac_addr;
> - u32 logical_port_id;
> - u32 port_speed;
> - u32 msg_enable;
> - u32 sig_comp_iv;
> - u32 state;
> - u8 phy_link;
> - u8 full_duplex;
> - u8 autoneg;
> - u8 num_def_qps;
> - wait_queue_head_t swqe_avail_wq;
> - wait_queue_head_t restart_wq;
> -};
> -
> -struct port_res_cfg {
> - int max_entries_rcq;
> - int max_entries_scq;
> - int max_entries_sq;
> - int max_entries_rq1;
> - int max_entries_rq2;
> - int max_entries_rq3;
> -};
> -
> -enum ehea_flag_bits {
> - __EHEA_STOP_XFER,
> - __EHEA_DISABLE_PORT_RESET
> -};
> -
> -void ehea_set_ethtool_ops(struct net_device *netdev);
> -int ehea_sense_port_attr(struct ehea_port *port);
> -int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
> -
> -#endif /* __EHEA_H__ */
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
> deleted file mode 100644
> index 1db5b6790a41..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
> +++ /dev/null
> @@ -1,277 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include "ehea.h"
> -#include "ehea_phyp.h"
> -
> -static int ehea_get_link_ksettings(struct net_device *dev,
> - struct ethtool_link_ksettings *cmd)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - u32 supported, advertising;
> - u32 speed;
> - int ret;
> -
> - ret = ehea_sense_port_attr(port);
> -
> - if (ret)
> - return ret;
> -
> - if (netif_carrier_ok(dev)) {
> - switch (port->port_speed) {
> - case EHEA_SPEED_10M:
> - speed = SPEED_10;
> - break;
> - case EHEA_SPEED_100M:
> - speed = SPEED_100;
> - break;
> - case EHEA_SPEED_1G:
> - speed = SPEED_1000;
> - break;
> - case EHEA_SPEED_10G:
> - speed = SPEED_10000;
> - break;
> - default:
> - speed = -1;
> - break; /* BUG */
> - }
> - cmd->base.duplex = port->full_duplex == 1 ?
> - DUPLEX_FULL : DUPLEX_HALF;
> - } else {
> - speed = SPEED_UNKNOWN;
> - cmd->base.duplex = DUPLEX_UNKNOWN;
> - }
> - cmd->base.speed = speed;
> -
> - if (cmd->base.speed == SPEED_10000) {
> - supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
> - advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
> - cmd->base.port = PORT_FIBRE;
> - } else {
> - supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full
> - | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full
> - | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg
> - | SUPPORTED_TP);
> - advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg
> - | ADVERTISED_TP);
> - cmd->base.port = PORT_TP;
> - }
> -
> - cmd->base.autoneg = port->autoneg == 1 ?
> - AUTONEG_ENABLE : AUTONEG_DISABLE;
> -
> - ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
> - supported);
> - ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
> - advertising);
> -
> - return 0;
> -}
> -
> -static int ehea_set_link_ksettings(struct net_device *dev,
> - const struct ethtool_link_ksettings *cmd)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - int ret = 0;
> - u32 sp;
> -
> - if (cmd->base.autoneg == AUTONEG_ENABLE) {
> - sp = EHEA_SPEED_AUTONEG;
> - goto doit;
> - }
> -
> - switch (cmd->base.speed) {
> - case SPEED_10:
> - if (cmd->base.duplex == DUPLEX_FULL)
> - sp = H_SPEED_10M_F;
> - else
> - sp = H_SPEED_10M_H;
> - break;
> -
> - case SPEED_100:
> - if (cmd->base.duplex == DUPLEX_FULL)
> - sp = H_SPEED_100M_F;
> - else
> - sp = H_SPEED_100M_H;
> - break;
> -
> - case SPEED_1000:
> - if (cmd->base.duplex == DUPLEX_FULL)
> - sp = H_SPEED_1G_F;
> - else
> - ret = -EINVAL;
> - break;
> -
> - case SPEED_10000:
> - if (cmd->base.duplex == DUPLEX_FULL)
> - sp = H_SPEED_10G_F;
> - else
> - ret = -EINVAL;
> - break;
> -
> - default:
> - ret = -EINVAL;
> - break;
> - }
> -
> - if (ret)
> - goto out;
> -doit:
> - ret = ehea_set_portspeed(port, sp);
> -
> - if (!ret)
> - netdev_info(dev,
> - "Port speed successfully set: %dMbps %s Duplex\n",
> - port->port_speed,
> - port->full_duplex == 1 ? "Full" : "Half");
> -out:
> - return ret;
> -}
> -
> -static int ehea_nway_reset(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - int ret;
> -
> - ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
> -
> - if (!ret)
> - netdev_info(port->netdev,
> - "Port speed successfully set: %dMbps %s Duplex\n",
> - port->port_speed,
> - port->full_duplex == 1 ? "Full" : "Half");
> - return ret;
> -}
> -
> -static void ehea_get_drvinfo(struct net_device *dev,
> - struct ethtool_drvinfo *info)
> -{
> - strscpy(info->driver, DRV_NAME, sizeof(info->driver));
> - strscpy(info->version, DRV_VERSION, sizeof(info->version));
> -}
> -
> -static u32 ehea_get_msglevel(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - return port->msg_enable;
> -}
> -
> -static void ehea_set_msglevel(struct net_device *dev, u32 value)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - port->msg_enable = value;
> -}
> -
> -static const char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
> - {"sig_comp_iv"},
> - {"swqe_refill_th"},
> - {"port resets"},
> - {"Receive errors"},
> - {"TCP cksum errors"},
> - {"IP cksum errors"},
> - {"Frame cksum errors"},
> - {"num SQ stopped"},
> - {"PR0 free_swqes"},
> - {"PR1 free_swqes"},
> - {"PR2 free_swqes"},
> - {"PR3 free_swqes"},
> - {"PR4 free_swqes"},
> - {"PR5 free_swqes"},
> - {"PR6 free_swqes"},
> - {"PR7 free_swqes"},
> - {"PR8 free_swqes"},
> - {"PR9 free_swqes"},
> - {"PR10 free_swqes"},
> - {"PR11 free_swqes"},
> - {"PR12 free_swqes"},
> - {"PR13 free_swqes"},
> - {"PR14 free_swqes"},
> - {"PR15 free_swqes"},
> -};
> -
> -static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
> -{
> - if (stringset == ETH_SS_STATS) {
> - memcpy(data, &ehea_ethtool_stats_keys,
> - sizeof(ehea_ethtool_stats_keys));
> - }
> -}
> -
> -static int ehea_get_sset_count(struct net_device *dev, int sset)
> -{
> - switch (sset) {
> - case ETH_SS_STATS:
> - return ARRAY_SIZE(ehea_ethtool_stats_keys);
> - default:
> - return -EOPNOTSUPP;
> - }
> -}
> -
> -static void ehea_get_ethtool_stats(struct net_device *dev,
> - struct ethtool_stats *stats, u64 *data)
> -{
> - int i, k, tmp;
> - struct ehea_port *port = netdev_priv(dev);
> -
> - for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)
> - data[i] = 0;
> - i = 0;
> -
> - data[i++] = port->sig_comp_iv;
> - data[i++] = port->port_res[0].swqe_refill_th;
> - data[i++] = port->resets;
> -
> - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
> - tmp += port->port_res[k].p_stats.poll_receive_errors;
> - data[i++] = tmp;
> -
> - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
> - tmp += port->port_res[k].p_stats.err_tcp_cksum;
> - data[i++] = tmp;
> -
> - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
> - tmp += port->port_res[k].p_stats.err_ip_cksum;
> - data[i++] = tmp;
> -
> - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
> - tmp += port->port_res[k].p_stats.err_frame_crc;
> - data[i++] = tmp;
> -
> - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
> - tmp += port->port_res[k].p_stats.queue_stopped;
> - data[i++] = tmp;
> -
> - for (k = 0; k < 16; k++)
> - data[i++] = atomic_read(&port->port_res[k].swqe_avail);
> -}
> -
> -static const struct ethtool_ops ehea_ethtool_ops = {
> - .get_drvinfo = ehea_get_drvinfo,
> - .get_msglevel = ehea_get_msglevel,
> - .set_msglevel = ehea_set_msglevel,
> - .get_link = ethtool_op_get_link,
> - .get_strings = ehea_get_strings,
> - .get_sset_count = ehea_get_sset_count,
> - .get_ethtool_stats = ehea_get_ethtool_stats,
> - .nway_reset = ehea_nway_reset, /* Restart autonegotiation */
> - .get_link_ksettings = ehea_get_link_ksettings,
> - .set_link_ksettings = ehea_set_link_ksettings,
> -};
> -
> -void ehea_set_ethtool_ops(struct net_device *netdev)
> -{
> - netdev->ethtool_ops = &ehea_ethtool_ops;
> -}
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_hw.h b/drivers/net/ethernet/ibm/ehea/ehea_hw.h
> deleted file mode 100644
> index 590933a45d65..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_hw.h
> +++ /dev/null
> @@ -1,253 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-or-later */
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_hw.h
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#ifndef __EHEA_HW_H__
> -#define __EHEA_HW_H__
> -
> -#define QPX_SQA_VALUE EHEA_BMASK_IBM(48, 63)
> -#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48, 63)
> -#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48, 63)
> -#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48, 63)
> -
> -#define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
> -
> -struct ehea_qptemm {
> - u64 qpx_hcr;
> - u64 qpx_c;
> - u64 qpx_herr;
> - u64 qpx_aer;
> - u64 qpx_sqa;
> - u64 qpx_sqc;
> - u64 qpx_rq1a;
> - u64 qpx_rq1c;
> - u64 qpx_st;
> - u64 qpx_aerr;
> - u64 qpx_tenure;
> - u64 qpx_reserved1[(0x098 - 0x058) / 8];
> - u64 qpx_portp;
> - u64 qpx_reserved2[(0x100 - 0x0A0) / 8];
> - u64 qpx_t;
> - u64 qpx_sqhp;
> - u64 qpx_sqptp;
> - u64 qpx_reserved3[(0x140 - 0x118) / 8];
> - u64 qpx_sqwsize;
> - u64 qpx_reserved4[(0x170 - 0x148) / 8];
> - u64 qpx_sqsize;
> - u64 qpx_reserved5[(0x1B0 - 0x178) / 8];
> - u64 qpx_sigt;
> - u64 qpx_wqecnt;
> - u64 qpx_rq1hp;
> - u64 qpx_rq1ptp;
> - u64 qpx_rq1size;
> - u64 qpx_reserved6[(0x220 - 0x1D8) / 8];
> - u64 qpx_rq1wsize;
> - u64 qpx_reserved7[(0x240 - 0x228) / 8];
> - u64 qpx_pd;
> - u64 qpx_scqn;
> - u64 qpx_rcqn;
> - u64 qpx_aeqn;
> - u64 reserved49;
> - u64 qpx_ram;
> - u64 qpx_reserved8[(0x300 - 0x270) / 8];
> - u64 qpx_rq2a;
> - u64 qpx_rq2c;
> - u64 qpx_rq2hp;
> - u64 qpx_rq2ptp;
> - u64 qpx_rq2size;
> - u64 qpx_rq2wsize;
> - u64 qpx_rq2th;
> - u64 qpx_rq3a;
> - u64 qpx_rq3c;
> - u64 qpx_rq3hp;
> - u64 qpx_rq3ptp;
> - u64 qpx_rq3size;
> - u64 qpx_rq3wsize;
> - u64 qpx_rq3th;
> - u64 qpx_lpn;
> - u64 qpx_reserved9[(0x400 - 0x378) / 8];
> - u64 reserved_ext[(0x500 - 0x400) / 8];
> - u64 reserved2[(0x1000 - 0x500) / 8];
> -};
> -
> -#define MRx_HCR_LPARID_VALID EHEA_BMASK_IBM(0, 0)
> -
> -#define MRMWMM_OFFSET(x) offsetof(struct ehea_mrmwmm, x)
> -
> -struct ehea_mrmwmm {
> - u64 mrx_hcr;
> - u64 mrx_c;
> - u64 mrx_herr;
> - u64 mrx_aer;
> - u64 mrx_pp;
> - u64 reserved1;
> - u64 reserved2;
> - u64 reserved3;
> - u64 reserved4[(0x200 - 0x40) / 8];
> - u64 mrx_ctl[64];
> -};
> -
> -#define QPEDMM_OFFSET(x) offsetof(struct ehea_qpedmm, x)
> -
> -struct ehea_qpedmm {
> -
> - u64 reserved0[(0x400) / 8];
> - u64 qpedx_phh;
> - u64 qpedx_ppsgp;
> - u64 qpedx_ppsgu;
> - u64 qpedx_ppdgp;
> - u64 qpedx_ppdgu;
> - u64 qpedx_aph;
> - u64 qpedx_apsgp;
> - u64 qpedx_apsgu;
> - u64 qpedx_apdgp;
> - u64 qpedx_apdgu;
> - u64 qpedx_apav;
> - u64 qpedx_apsav;
> - u64 qpedx_hcr;
> - u64 reserved1[4];
> - u64 qpedx_rrl0;
> - u64 qpedx_rrrkey0;
> - u64 qpedx_rrva0;
> - u64 reserved2;
> - u64 qpedx_rrl1;
> - u64 qpedx_rrrkey1;
> - u64 qpedx_rrva1;
> - u64 reserved3;
> - u64 qpedx_rrl2;
> - u64 qpedx_rrrkey2;
> - u64 qpedx_rrva2;
> - u64 reserved4;
> - u64 qpedx_rrl3;
> - u64 qpedx_rrrkey3;
> - u64 qpedx_rrva3;
> -};
> -
> -#define CQX_FECADDER EHEA_BMASK_IBM(32, 63)
> -#define CQX_FEC_CQE_CNT EHEA_BMASK_IBM(32, 63)
> -#define CQX_N1_GENERATE_COMP_EVENT EHEA_BMASK_IBM(0, 0)
> -#define CQX_EP_EVENT_PENDING EHEA_BMASK_IBM(0, 0)
> -
> -#define CQTEMM_OFFSET(x) offsetof(struct ehea_cqtemm, x)
> -
> -struct ehea_cqtemm {
> - u64 cqx_hcr;
> - u64 cqx_c;
> - u64 cqx_herr;
> - u64 cqx_aer;
> - u64 cqx_ptp;
> - u64 cqx_tp;
> - u64 cqx_fec;
> - u64 cqx_feca;
> - u64 cqx_ep;
> - u64 cqx_eq;
> - u64 reserved1;
> - u64 cqx_n0;
> - u64 cqx_n1;
> - u64 reserved2[(0x1000 - 0x60) / 8];
> -};
> -
> -#define EQTEMM_OFFSET(x) offsetof(struct ehea_eqtemm, x)
> -
> -struct ehea_eqtemm {
> - u64 eqx_hcr;
> - u64 eqx_c;
> - u64 eqx_herr;
> - u64 eqx_aer;
> - u64 eqx_ptp;
> - u64 eqx_tp;
> - u64 eqx_ssba;
> - u64 eqx_psba;
> - u64 eqx_cec;
> - u64 eqx_meql;
> - u64 eqx_xisbi;
> - u64 eqx_xisc;
> - u64 eqx_it;
> -};
> -
> -/*
> - * These access functions will be changed when the dissuccsion about
> - * the new access methods for POWER has settled.
> - */
> -
> -static inline u64 epa_load(struct h_epa epa, u32 offset)
> -{
> - return __raw_readq((void __iomem *)(epa.addr + offset));
> -}
> -
> -static inline void epa_store(struct h_epa epa, u32 offset, u64 value)
> -{
> - __raw_writeq(value, (void __iomem *)(epa.addr + offset));
> - epa_load(epa, offset); /* synchronize explicitly to eHEA */
> -}
> -
> -static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
> -{
> - __raw_writeq(value, (void __iomem *)(epa.addr + offset));
> -}
> -
> -#define epa_store_cq(epa, offset, value)\
> - epa_store(epa, CQTEMM_OFFSET(offset), value)
> -#define epa_load_cq(epa, offset)\
> - epa_load(epa, CQTEMM_OFFSET(offset))
> -
> -static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
> -{
> - struct h_epa epa = qp->epas.kernel;
> - epa_store_acc(epa, QPTEMM_OFFSET(qpx_sqa),
> - EHEA_BMASK_SET(QPX_SQA_VALUE, nr_wqes));
> -}
> -
> -static inline void ehea_update_rq3a(struct ehea_qp *qp, u16 nr_wqes)
> -{
> - struct h_epa epa = qp->epas.kernel;
> - epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq3a),
> - EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
> -}
> -
> -static inline void ehea_update_rq2a(struct ehea_qp *qp, u16 nr_wqes)
> -{
> - struct h_epa epa = qp->epas.kernel;
> - epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq2a),
> - EHEA_BMASK_SET(QPX_RQ2A_VALUE, nr_wqes));
> -}
> -
> -static inline void ehea_update_rq1a(struct ehea_qp *qp, u16 nr_wqes)
> -{
> - struct h_epa epa = qp->epas.kernel;
> - epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq1a),
> - EHEA_BMASK_SET(QPX_RQ3A_VALUE, nr_wqes));
> -}
> -
> -static inline void ehea_update_feca(struct ehea_cq *cq, u32 nr_cqes)
> -{
> - struct h_epa epa = cq->epas.kernel;
> - epa_store_acc(epa, CQTEMM_OFFSET(cqx_feca),
> - EHEA_BMASK_SET(CQX_FECADDER, nr_cqes));
> -}
> -
> -static inline void ehea_reset_cq_n1(struct ehea_cq *cq)
> -{
> - struct h_epa epa = cq->epas.kernel;
> - epa_store_cq(epa, cqx_n1,
> - EHEA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, 1));
> -}
> -
> -static inline void ehea_reset_cq_ep(struct ehea_cq *my_cq)
> -{
> - struct h_epa epa = my_cq->epas.kernel;
> - epa_store_acc(epa, CQTEMM_OFFSET(cqx_ep),
> - EHEA_BMASK_SET(CQX_EP_EVENT_PENDING, 0));
> -}
> -
> -#endif /* __EHEA_HW_H__ */
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
> deleted file mode 100644
> index bfc8699a05b9..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
> +++ /dev/null
> @@ -1,3581 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_main.c
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/device.h>
> -#include <linux/in.h>
> -#include <linux/ip.h>
> -#include <linux/tcp.h>
> -#include <linux/udp.h>
> -#include <linux/if.h>
> -#include <linux/list.h>
> -#include <linux/slab.h>
> -#include <linux/if_ether.h>
> -#include <linux/notifier.h>
> -#include <linux/reboot.h>
> -#include <linux/memory.h>
> -#include <asm/kexec.h>
> -#include <linux/mutex.h>
> -#include <linux/prefetch.h>
> -#include <linux/of.h>
> -#include <linux/of_device.h>
> -#include <linux/platform_device.h>
> -
> -#include <net/ip.h>
> -
> -#include "ehea.h"
> -#include "ehea_qmr.h"
> -#include "ehea_phyp.h"
> -
> -
> -MODULE_LICENSE("GPL");
> -MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
> -MODULE_DESCRIPTION("IBM eServer HEA Driver");
> -MODULE_VERSION(DRV_VERSION);
> -
> -
> -static int msg_level = -1;
> -static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
> -static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
> -static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
> -static int sq_entries = EHEA_DEF_ENTRIES_SQ;
> -static int use_mcs = 1;
> -static int prop_carrier_state;
> -
> -module_param(msg_level, int, 0);
> -module_param(rq1_entries, int, 0);
> -module_param(rq2_entries, int, 0);
> -module_param(rq3_entries, int, 0);
> -module_param(sq_entries, int, 0);
> -module_param(prop_carrier_state, int, 0);
> -module_param(use_mcs, int, 0);
> -
> -MODULE_PARM_DESC(msg_level, "msg_level");
> -MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
> - "port to stack. 1:yes, 0:no. Default = 0 ");
> -MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
> - "[2^x - 1], x = [7..14]. Default = "
> - __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
> -MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
> - "[2^x - 1], x = [7..14]. Default = "
> - __MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
> -MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
> - "[2^x - 1], x = [7..14]. Default = "
> - __MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
> -MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
> - "[2^x - 1], x = [7..14]. Default = "
> - __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
> -MODULE_PARM_DESC(use_mcs, " Multiple receive queues, 1: enable, 0: disable, "
> - "Default = 1");
> -
> -static int port_name_cnt;
> -static LIST_HEAD(adapter_list);
> -static unsigned long ehea_driver_flags;
> -static DEFINE_MUTEX(dlpar_mem_lock);
> -static struct ehea_fw_handle_array ehea_fw_handles;
> -static struct ehea_bcmc_reg_array ehea_bcmc_regs;
> -
> -
> -static int ehea_probe_adapter(struct platform_device *dev);
> -
> -static void ehea_remove(struct platform_device *dev);
> -
> -static const struct of_device_id ehea_module_device_table[] = {
> - {
> - .name = "lhea",
> - .compatible = "IBM,lhea",
> - },
> - {
> - .type = "network",
> - .compatible = "IBM,lhea-ethernet",
> - },
> - {},
> -};
> -MODULE_DEVICE_TABLE(of, ehea_module_device_table);
> -
> -static const struct of_device_id ehea_device_table[] = {
> - {
> - .name = "lhea",
> - .compatible = "IBM,lhea",
> - },
> - {},
> -};
> -MODULE_DEVICE_TABLE(of, ehea_device_table);
> -
> -static struct platform_driver ehea_driver = {
> - .driver = {
> - .name = "ehea",
> - .owner = THIS_MODULE,
> - .of_match_table = ehea_device_table,
> - },
> - .probe = ehea_probe_adapter,
> - .remove = ehea_remove,
> -};
> -
> -void ehea_dump(void *adr, int len, char *msg)
> -{
> - int x;
> - unsigned char *deb = adr;
> - for (x = 0; x < len; x += 16) {
> - pr_info("%s adr=%p ofs=%04x %016llx %016llx\n",
> - msg, deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
> - deb += 16;
> - }
> -}
> -
> -static void ehea_schedule_port_reset(struct ehea_port *port)
> -{
> - if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
> - schedule_work(&port->reset_task);
> -}
> -
> -static void ehea_update_firmware_handles(void)
> -{
> - struct ehea_fw_handle_entry *arr = NULL;
> - struct ehea_adapter *adapter;
> - int num_adapters = 0;
> - int num_ports = 0;
> - int num_portres = 0;
> - int i = 0;
> - int num_fw_handles, k, l;
> -
> - /* Determine number of handles */
> - mutex_lock(&ehea_fw_handles.lock);
> -
> - list_for_each_entry(adapter, &adapter_list, list) {
> - num_adapters++;
> -
> - for (k = 0; k < EHEA_MAX_PORTS; k++) {
> - struct ehea_port *port = adapter->port[k];
> -
> - if (!port || (port->state != EHEA_PORT_UP))
> - continue;
> -
> - num_ports++;
> - num_portres += port->num_def_qps;
> - }
> - }
> -
> - num_fw_handles = num_adapters * EHEA_NUM_ADAPTER_FW_HANDLES +
> - num_ports * EHEA_NUM_PORT_FW_HANDLES +
> - num_portres * EHEA_NUM_PORTRES_FW_HANDLES;
> -
> - if (num_fw_handles) {
> - arr = kzalloc_objs(*arr, num_fw_handles);
> - if (!arr)
> - goto out; /* Keep the existing array */
> - } else
> - goto out_update;
> -
> - list_for_each_entry(adapter, &adapter_list, list) {
> - if (num_adapters == 0)
> - break;
> -
> - for (k = 0; k < EHEA_MAX_PORTS; k++) {
> - struct ehea_port *port = adapter->port[k];
> -
> - if (!port || (port->state != EHEA_PORT_UP) ||
> - (num_ports == 0))
> - continue;
> -
> - for (l = 0; l < port->num_def_qps; l++) {
> - struct ehea_port_res *pr = &port->port_res[l];
> -
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = pr->qp->fw_handle;
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = pr->send_cq->fw_handle;
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = pr->recv_cq->fw_handle;
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = pr->eq->fw_handle;
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = pr->send_mr.handle;
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = pr->recv_mr.handle;
> - }
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = port->qp_eq->fw_handle;
> - num_ports--;
> - }
> -
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = adapter->neq->fw_handle;
> -
> - if (adapter->mr.handle) {
> - arr[i].adh = adapter->handle;
> - arr[i++].fwh = adapter->mr.handle;
> - }
> - num_adapters--;
> - }
> -
> -out_update:
> - kfree(ehea_fw_handles.arr);
> - ehea_fw_handles.arr = arr;
> - ehea_fw_handles.num_entries = i;
> -out:
> - mutex_unlock(&ehea_fw_handles.lock);
> -}
> -
> -static void ehea_update_bcmc_registrations(void)
> -{
> - unsigned long flags;
> - struct ehea_bcmc_reg_entry *arr = NULL;
> - struct ehea_adapter *adapter;
> - struct ehea_mc_list *mc_entry;
> - int num_registrations = 0;
> - int i = 0;
> - int k;
> -
> - spin_lock_irqsave(&ehea_bcmc_regs.lock, flags);
> -
> - /* Determine number of registrations */
> - list_for_each_entry(adapter, &adapter_list, list)
> - for (k = 0; k < EHEA_MAX_PORTS; k++) {
> - struct ehea_port *port = adapter->port[k];
> -
> - if (!port || (port->state != EHEA_PORT_UP))
> - continue;
> -
> - num_registrations += 2; /* Broadcast registrations */
> -
> - list_for_each_entry(mc_entry, &port->mc_list->list,list)
> - num_registrations += 2;
> - }
> -
> - if (num_registrations) {
> - arr = kzalloc_objs(*arr, num_registrations, GFP_ATOMIC);
> - if (!arr)
> - goto out; /* Keep the existing array */
> - } else
> - goto out_update;
> -
> - list_for_each_entry(adapter, &adapter_list, list) {
> - for (k = 0; k < EHEA_MAX_PORTS; k++) {
> - struct ehea_port *port = adapter->port[k];
> -
> - if (!port || (port->state != EHEA_PORT_UP))
> - continue;
> -
> - if (num_registrations == 0)
> - goto out_update;
> -
> - arr[i].adh = adapter->handle;
> - arr[i].port_id = port->logical_port_id;
> - arr[i].reg_type = EHEA_BCMC_BROADCAST |
> - EHEA_BCMC_UNTAGGED;
> - arr[i++].macaddr = port->mac_addr;
> -
> - arr[i].adh = adapter->handle;
> - arr[i].port_id = port->logical_port_id;
> - arr[i].reg_type = EHEA_BCMC_BROADCAST |
> - EHEA_BCMC_VLANID_ALL;
> - arr[i++].macaddr = port->mac_addr;
> - num_registrations -= 2;
> -
> - list_for_each_entry(mc_entry,
> - &port->mc_list->list, list) {
> - if (num_registrations == 0)
> - goto out_update;
> -
> - arr[i].adh = adapter->handle;
> - arr[i].port_id = port->logical_port_id;
> - arr[i].reg_type = EHEA_BCMC_MULTICAST |
> - EHEA_BCMC_UNTAGGED;
> - if (mc_entry->macaddr == 0)
> - arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL;
> - arr[i++].macaddr = mc_entry->macaddr;
> -
> - arr[i].adh = adapter->handle;
> - arr[i].port_id = port->logical_port_id;
> - arr[i].reg_type = EHEA_BCMC_MULTICAST |
> - EHEA_BCMC_VLANID_ALL;
> - if (mc_entry->macaddr == 0)
> - arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL;
> - arr[i++].macaddr = mc_entry->macaddr;
> - num_registrations -= 2;
> - }
> - }
> - }
> -
> -out_update:
> - kfree(ehea_bcmc_regs.arr);
> - ehea_bcmc_regs.arr = arr;
> - ehea_bcmc_regs.num_entries = i;
> -out:
> - spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
> -}
> -
> -static void ehea_get_stats64(struct net_device *dev,
> - struct rtnl_link_stats64 *stats)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - u64 rx_packets = 0, tx_packets = 0, rx_bytes = 0, tx_bytes = 0;
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - rx_packets += port->port_res[i].rx_packets;
> - rx_bytes += port->port_res[i].rx_bytes;
> - }
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - tx_packets += port->port_res[i].tx_packets;
> - tx_bytes += port->port_res[i].tx_bytes;
> - }
> -
> - stats->tx_packets = tx_packets;
> - stats->rx_bytes = rx_bytes;
> - stats->tx_bytes = tx_bytes;
> - stats->rx_packets = rx_packets;
> -
> - stats->multicast = port->stats.multicast;
> - stats->rx_errors = port->stats.rx_errors;
> -}
> -
> -static void ehea_update_stats(struct work_struct *work)
> -{
> - struct ehea_port *port =
> - container_of(work, struct ehea_port, stats_work.work);
> - struct net_device *dev = port->netdev;
> - struct rtnl_link_stats64 *stats = &port->stats;
> - struct hcp_ehea_port_cb2 *cb2;
> - u64 hret;
> -
> - cb2 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb2) {
> - netdev_err(dev, "No mem for cb2. Some interface statistics were not updated\n");
> - goto resched;
> - }
> -
> - hret = ehea_h_query_ehea_port(port->adapter->handle,
> - port->logical_port_id,
> - H_PORT_CB2, H_PORT_CB2_ALL, cb2);
> - if (hret != H_SUCCESS) {
> - netdev_err(dev, "query_ehea_port failed\n");
> - goto out_herr;
> - }
> -
> - if (netif_msg_hw(port))
> - ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
> -
> - stats->multicast = cb2->rxmcp;
> - stats->rx_errors = cb2->rxuerr;
> -
> -out_herr:
> - free_page((unsigned long)cb2);
> -resched:
> - schedule_delayed_work(&port->stats_work,
> - round_jiffies_relative(msecs_to_jiffies(1000)));
> -}
> -
> -static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
> -{
> - struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
> - struct net_device *dev = pr->port->netdev;
> - int max_index_mask = pr->rq1_skba.len - 1;
> - int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes;
> - int adder = 0;
> - int i;
> -
> - pr->rq1_skba.os_skbs = 0;
> -
> - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
> - if (nr_of_wqes > 0)
> - pr->rq1_skba.index = index;
> - pr->rq1_skba.os_skbs = fill_wqes;
> - return;
> - }
> -
> - for (i = 0; i < fill_wqes; i++) {
> - if (!skb_arr_rq1[index]) {
> - skb_arr_rq1[index] = netdev_alloc_skb(dev,
> - EHEA_L_PKT_SIZE);
> - if (!skb_arr_rq1[index]) {
> - pr->rq1_skba.os_skbs = fill_wqes - i;
> - break;
> - }
> - }
> - index--;
> - index &= max_index_mask;
> - adder++;
> - }
> -
> - if (adder == 0)
> - return;
> -
> - /* Ring doorbell */
> - ehea_update_rq1a(pr->qp, adder);
> -}
> -
> -static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
> -{
> - struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
> - struct net_device *dev = pr->port->netdev;
> - int i;
> -
> - if (nr_rq1a > pr->rq1_skba.len) {
> - netdev_err(dev, "NR_RQ1A bigger than skb array len\n");
> - return;
> - }
> -
> - for (i = 0; i < nr_rq1a; i++) {
> - skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
> - if (!skb_arr_rq1[i])
> - break;
> - }
> - /* Ring doorbell */
> - ehea_update_rq1a(pr->qp, i - 1);
> -}
> -
> -static int ehea_refill_rq_def(struct ehea_port_res *pr,
> - struct ehea_q_skb_arr *q_skba, int rq_nr,
> - int num_wqes, int wqe_type, int packet_size)
> -{
> - struct net_device *dev = pr->port->netdev;
> - struct ehea_qp *qp = pr->qp;
> - struct sk_buff **skb_arr = q_skba->arr;
> - struct ehea_rwqe *rwqe;
> - int i, index, max_index_mask, fill_wqes;
> - int adder = 0;
> - int ret = 0;
> -
> - fill_wqes = q_skba->os_skbs + num_wqes;
> - q_skba->os_skbs = 0;
> -
> - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
> - q_skba->os_skbs = fill_wqes;
> - return ret;
> - }
> -
> - index = q_skba->index;
> - max_index_mask = q_skba->len - 1;
> - for (i = 0; i < fill_wqes; i++) {
> - u64 tmp_addr;
> - struct sk_buff *skb;
> -
> - skb = netdev_alloc_skb_ip_align(dev, packet_size);
> - if (!skb) {
> - q_skba->os_skbs = fill_wqes - i;
> - if (q_skba->os_skbs == q_skba->len - 2) {
> - netdev_info(pr->port->netdev,
> - "rq%i ran dry - no mem for skb\n",
> - rq_nr);
> - ret = -ENOMEM;
> - }
> - break;
> - }
> -
> - skb_arr[index] = skb;
> - tmp_addr = ehea_map_vaddr(skb->data);
> - if (tmp_addr == -1) {
> - dev_consume_skb_any(skb);
> - q_skba->os_skbs = fill_wqes - i;
> - ret = 0;
> - break;
> - }
> -
> - rwqe = ehea_get_next_rwqe(qp, rq_nr);
> - rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
> - | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
> - rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
> - rwqe->sg_list[0].vaddr = tmp_addr;
> - rwqe->sg_list[0].len = packet_size;
> - rwqe->data_segments = 1;
> -
> - index++;
> - index &= max_index_mask;
> - adder++;
> - }
> -
> - q_skba->index = index;
> - if (adder == 0)
> - goto out;
> -
> - /* Ring doorbell */
> - iosync();
> - if (rq_nr == 2)
> - ehea_update_rq2a(pr->qp, adder);
> - else
> - ehea_update_rq3a(pr->qp, adder);
> -out:
> - return ret;
> -}
> -
> -
> -static int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes)
> -{
> - return ehea_refill_rq_def(pr, &pr->rq2_skba, 2,
> - nr_of_wqes, EHEA_RWQE2_TYPE,
> - EHEA_RQ2_PKT_SIZE);
> -}
> -
> -
> -static int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes)
> -{
> - return ehea_refill_rq_def(pr, &pr->rq3_skba, 3,
> - nr_of_wqes, EHEA_RWQE3_TYPE,
> - EHEA_MAX_PACKET_SIZE);
> -}
> -
> -static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
> -{
> - *rq_num = (cqe->type & EHEA_CQE_TYPE_RQ) >> 5;
> - if ((cqe->status & EHEA_CQE_STAT_ERR_MASK) == 0)
> - return 0;
> - if (((cqe->status & EHEA_CQE_STAT_ERR_TCP) != 0) &&
> - (cqe->header_length == 0))
> - return 0;
> - return -EINVAL;
> -}
> -
> -static inline void ehea_fill_skb(struct net_device *dev,
> - struct sk_buff *skb, struct ehea_cqe *cqe,
> - struct ehea_port_res *pr)
> -{
> - int length = cqe->num_bytes_transfered - 4; /*remove CRC */
> -
> - skb_put(skb, length);
> - skb->protocol = eth_type_trans(skb, dev);
> -
> - /* The packet was not an IPV4 packet so a complemented checksum was
> - calculated. The value is found in the Internet Checksum field. */
> - if (cqe->status & EHEA_CQE_BLIND_CKSUM) {
> - skb->ip_summed = CHECKSUM_COMPLETE;
> - skb->csum = csum_unfold(~cqe->inet_checksum_value);
> - } else
> - skb->ip_summed = CHECKSUM_UNNECESSARY;
> -
> - skb_record_rx_queue(skb, pr - &pr->port->port_res[0]);
> -}
> -
> -static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
> - int arr_len,
> - struct ehea_cqe *cqe)
> -{
> - int skb_index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
> - struct sk_buff *skb;
> - void *pref;
> - int x;
> -
> - x = skb_index + 1;
> - x &= (arr_len - 1);
> -
> - pref = skb_array[x];
> - if (pref) {
> - prefetchw(pref);
> - prefetchw(pref + EHEA_CACHE_LINE);
> -
> - pref = (skb_array[x]->data);
> - prefetch(pref);
> - prefetch(pref + EHEA_CACHE_LINE);
> - prefetch(pref + EHEA_CACHE_LINE * 2);
> - prefetch(pref + EHEA_CACHE_LINE * 3);
> - }
> -
> - skb = skb_array[skb_index];
> - skb_array[skb_index] = NULL;
> - return skb;
> -}
> -
> -static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
> - int arr_len, int wqe_index)
> -{
> - struct sk_buff *skb;
> - void *pref;
> - int x;
> -
> - x = wqe_index + 1;
> - x &= (arr_len - 1);
> -
> - pref = skb_array[x];
> - if (pref) {
> - prefetchw(pref);
> - prefetchw(pref + EHEA_CACHE_LINE);
> -
> - pref = (skb_array[x]->data);
> - prefetchw(pref);
> - prefetchw(pref + EHEA_CACHE_LINE);
> - }
> -
> - skb = skb_array[wqe_index];
> - skb_array[wqe_index] = NULL;
> - return skb;
> -}
> -
> -static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
> - struct ehea_cqe *cqe, int *processed_rq2,
> - int *processed_rq3)
> -{
> - struct sk_buff *skb;
> -
> - if (cqe->status & EHEA_CQE_STAT_ERR_TCP)
> - pr->p_stats.err_tcp_cksum++;
> - if (cqe->status & EHEA_CQE_STAT_ERR_IP)
> - pr->p_stats.err_ip_cksum++;
> - if (cqe->status & EHEA_CQE_STAT_ERR_CRC)
> - pr->p_stats.err_frame_crc++;
> -
> - if (rq == 2) {
> - *processed_rq2 += 1;
> - skb = get_skb_by_index(pr->rq2_skba.arr, pr->rq2_skba.len, cqe);
> - dev_kfree_skb(skb);
> - } else if (rq == 3) {
> - *processed_rq3 += 1;
> - skb = get_skb_by_index(pr->rq3_skba.arr, pr->rq3_skba.len, cqe);
> - dev_kfree_skb(skb);
> - }
> -
> - if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
> - if (netif_msg_rx_err(pr->port)) {
> - pr_err("Critical receive error for QP %d. Resetting port.\n",
> - pr->qp->init_attr.qp_nr);
> - ehea_dump(cqe, sizeof(*cqe), "CQE");
> - }
> - ehea_schedule_port_reset(pr->port);
> - return 1;
> - }
> -
> - return 0;
> -}
> -
> -static int ehea_proc_rwqes(struct net_device *dev,
> - struct ehea_port_res *pr,
> - int budget)
> -{
> - struct ehea_port *port = pr->port;
> - struct ehea_qp *qp = pr->qp;
> - struct ehea_cqe *cqe;
> - struct sk_buff *skb;
> - struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
> - struct sk_buff **skb_arr_rq2 = pr->rq2_skba.arr;
> - struct sk_buff **skb_arr_rq3 = pr->rq3_skba.arr;
> - int skb_arr_rq1_len = pr->rq1_skba.len;
> - int skb_arr_rq2_len = pr->rq2_skba.len;
> - int skb_arr_rq3_len = pr->rq3_skba.len;
> - int processed, processed_rq1, processed_rq2, processed_rq3;
> - u64 processed_bytes = 0;
> - int wqe_index, last_wqe_index, rq, port_reset;
> -
> - processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
> - last_wqe_index = 0;
> -
> - cqe = ehea_poll_rq1(qp, &wqe_index);
> - while ((processed < budget) && cqe) {
> - ehea_inc_rq1(qp);
> - processed_rq1++;
> - processed++;
> - if (netif_msg_rx_status(port))
> - ehea_dump(cqe, sizeof(*cqe), "CQE");
> -
> - last_wqe_index = wqe_index;
> - rmb();
> - if (!ehea_check_cqe(cqe, &rq)) {
> - if (rq == 1) {
> - /* LL RQ1 */
> - skb = get_skb_by_index_ll(skb_arr_rq1,
> - skb_arr_rq1_len,
> - wqe_index);
> - if (unlikely(!skb)) {
> - netif_info(port, rx_err, dev,
> - "LL rq1: skb=NULL\n");
> -
> - skb = netdev_alloc_skb(dev,
> - EHEA_L_PKT_SIZE);
> - if (!skb)
> - break;
> - }
> - skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
> - cqe->num_bytes_transfered - 4);
> - ehea_fill_skb(dev, skb, cqe, pr);
> - } else if (rq == 2) {
> - /* RQ2 */
> - skb = get_skb_by_index(skb_arr_rq2,
> - skb_arr_rq2_len, cqe);
> - if (unlikely(!skb)) {
> - netif_err(port, rx_err, dev,
> - "rq2: skb=NULL\n");
> - break;
> - }
> - ehea_fill_skb(dev, skb, cqe, pr);
> - processed_rq2++;
> - } else {
> - /* RQ3 */
> - skb = get_skb_by_index(skb_arr_rq3,
> - skb_arr_rq3_len, cqe);
> - if (unlikely(!skb)) {
> - netif_err(port, rx_err, dev,
> - "rq3: skb=NULL\n");
> - break;
> - }
> - ehea_fill_skb(dev, skb, cqe, pr);
> - processed_rq3++;
> - }
> -
> - processed_bytes += skb->len;
> -
> - if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
> - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
> - cqe->vlan_tag);
> -
> - napi_gro_receive(&pr->napi, skb);
> - } else {
> - pr->p_stats.poll_receive_errors++;
> - port_reset = ehea_treat_poll_error(pr, rq, cqe,
> - &processed_rq2,
> - &processed_rq3);
> - if (port_reset)
> - break;
> - }
> - cqe = ehea_poll_rq1(qp, &wqe_index);
> - }
> -
> - pr->rx_packets += processed;
> - pr->rx_bytes += processed_bytes;
> -
> - ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
> - ehea_refill_rq2(pr, processed_rq2);
> - ehea_refill_rq3(pr, processed_rq3);
> -
> - return processed;
> -}
> -
> -#define SWQE_RESTART_CHECK 0xdeadbeaff00d0000ull
> -
> -static void reset_sq_restart_flag(struct ehea_port *port)
> -{
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - struct ehea_port_res *pr = &port->port_res[i];
> - pr->sq_restart_flag = 0;
> - }
> - wake_up(&port->restart_wq);
> -}
> -
> -static void check_sqs(struct ehea_port *port)
> -{
> - struct ehea_swqe *swqe;
> - int swqe_index;
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - struct ehea_port_res *pr = &port->port_res[i];
> - int ret;
> - swqe = ehea_get_swqe(pr->qp, &swqe_index);
> - memset(swqe, 0, SWQE_HEADER_SIZE);
> - atomic_dec(&pr->swqe_avail);
> -
> - swqe->tx_control |= EHEA_SWQE_PURGE;
> - swqe->wr_id = SWQE_RESTART_CHECK;
> - swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
> - swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT;
> - swqe->immediate_data_length = 80;
> -
> - ehea_post_swqe(pr->qp, swqe);
> -
> - ret = wait_event_timeout(port->restart_wq,
> - pr->sq_restart_flag == 0,
> - msecs_to_jiffies(100));
> -
> - if (!ret) {
> - pr_err("HW/SW queues out of sync\n");
> - ehea_schedule_port_reset(pr->port);
> - return;
> - }
> - }
> -}
> -
> -
> -static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
> -{
> - struct sk_buff *skb;
> - struct ehea_cq *send_cq = pr->send_cq;
> - struct ehea_cqe *cqe;
> - int quota = my_quota;
> - int cqe_counter = 0;
> - int swqe_av = 0;
> - int index;
> - struct netdev_queue *txq = netdev_get_tx_queue(pr->port->netdev,
> - pr - &pr->port->port_res[0]);
> -
> - cqe = ehea_poll_cq(send_cq);
> - while (cqe && (quota > 0)) {
> - ehea_inc_cq(send_cq);
> -
> - cqe_counter++;
> - rmb();
> -
> - if (cqe->wr_id == SWQE_RESTART_CHECK) {
> - pr->sq_restart_flag = 1;
> - swqe_av++;
> - break;
> - }
> -
> - if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
> - pr_err("Bad send completion status=0x%04X\n",
> - cqe->status);
> -
> - if (netif_msg_tx_err(pr->port))
> - ehea_dump(cqe, sizeof(*cqe), "Send CQE");
> -
> - if (cqe->status & EHEA_CQE_STAT_RESET_MASK) {
> - pr_err("Resetting port\n");
> - ehea_schedule_port_reset(pr->port);
> - break;
> - }
> - }
> -
> - if (netif_msg_tx_done(pr->port))
> - ehea_dump(cqe, sizeof(*cqe), "CQE");
> -
> - if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
> - == EHEA_SWQE2_TYPE)) {
> -
> - index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
> - skb = pr->sq_skba.arr[index];
> - dev_consume_skb_any(skb);
> - pr->sq_skba.arr[index] = NULL;
> - }
> -
> - swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
> - quota--;
> -
> - cqe = ehea_poll_cq(send_cq);
> - }
> -
> - ehea_update_feca(send_cq, cqe_counter);
> - atomic_add(swqe_av, &pr->swqe_avail);
> -
> - if (unlikely(netif_tx_queue_stopped(txq) &&
> - (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))) {
> - __netif_tx_lock(txq, smp_processor_id());
> - if (netif_tx_queue_stopped(txq) &&
> - (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))
> - netif_tx_wake_queue(txq);
> - __netif_tx_unlock(txq);
> - }
> -
> - wake_up(&pr->port->swqe_avail_wq);
> -
> - return cqe;
> -}
> -
> -#define EHEA_POLL_MAX_CQES 65535
> -
> -static int ehea_poll(struct napi_struct *napi, int budget)
> -{
> - struct ehea_port_res *pr = container_of(napi, struct ehea_port_res,
> - napi);
> - struct net_device *dev = pr->port->netdev;
> - struct ehea_cqe *cqe;
> - struct ehea_cqe *cqe_skb = NULL;
> - int wqe_index;
> - int rx = 0;
> -
> - cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
> - rx += ehea_proc_rwqes(dev, pr, budget - rx);
> -
> - while (rx != budget) {
> - napi_complete(napi);
> - ehea_reset_cq_ep(pr->recv_cq);
> - ehea_reset_cq_ep(pr->send_cq);
> - ehea_reset_cq_n1(pr->recv_cq);
> - ehea_reset_cq_n1(pr->send_cq);
> - rmb();
> - cqe = ehea_poll_rq1(pr->qp, &wqe_index);
> - cqe_skb = ehea_poll_cq(pr->send_cq);
> -
> - if (!cqe && !cqe_skb)
> - return rx;
> -
> - if (!napi_schedule(napi))
> - return rx;
> -
> - cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
> - rx += ehea_proc_rwqes(dev, pr, budget - rx);
> - }
> -
> - return rx;
> -}
> -
> -static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
> -{
> - struct ehea_port_res *pr = param;
> -
> - napi_schedule(&pr->napi);
> -
> - return IRQ_HANDLED;
> -}
> -
> -static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
> -{
> - struct ehea_port *port = param;
> - struct ehea_eqe *eqe;
> - struct ehea_qp *qp;
> - u32 qp_token;
> - u64 resource_type, aer, aerr;
> - int reset_port = 0;
> -
> - eqe = ehea_poll_eq(port->qp_eq);
> -
> - while (eqe) {
> - qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
> - pr_err("QP aff_err: entry=0x%llx, token=0x%x\n",
> - eqe->entry, qp_token);
> -
> - qp = port->port_res[qp_token].qp;
> -
> - resource_type = ehea_error_data(port->adapter, qp->fw_handle,
> - &aer, &aerr);
> -
> - if (resource_type == EHEA_AER_RESTYPE_QP) {
> - if ((aer & EHEA_AER_RESET_MASK) ||
> - (aerr & EHEA_AERR_RESET_MASK))
> - reset_port = 1;
> - } else
> - reset_port = 1; /* Reset in case of CQ or EQ error */
> -
> - eqe = ehea_poll_eq(port->qp_eq);
> - }
> -
> - if (reset_port) {
> - pr_err("Resetting port\n");
> - ehea_schedule_port_reset(port);
> - }
> -
> - return IRQ_HANDLED;
> -}
> -
> -static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
> - int logical_port)
> -{
> - int i;
> -
> - for (i = 0; i < EHEA_MAX_PORTS; i++)
> - if (adapter->port[i])
> - if (adapter->port[i]->logical_port_id == logical_port)
> - return adapter->port[i];
> - return NULL;
> -}
> -
> -int ehea_sense_port_attr(struct ehea_port *port)
> -{
> - int ret;
> - u64 hret;
> - struct hcp_ehea_port_cb0 *cb0;
> -
> - /* may be called via ehea_neq_tasklet() */
> - cb0 = (void *)get_zeroed_page(GFP_ATOMIC);
> - if (!cb0) {
> - pr_err("no mem for cb0\n");
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_port(port->adapter->handle,
> - port->logical_port_id, H_PORT_CB0,
> - EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF),
> - cb0);
> - if (hret != H_SUCCESS) {
> - ret = -EIO;
> - goto out_free;
> - }
> -
> - /* MAC address */
> - port->mac_addr = cb0->port_mac_addr << 16;
> -
> - if (!is_valid_ether_addr((u8 *)&port->mac_addr)) {
> - ret = -EADDRNOTAVAIL;
> - goto out_free;
> - }
> -
> - /* Port speed */
> - switch (cb0->port_speed) {
> - case H_SPEED_10M_H:
> - port->port_speed = EHEA_SPEED_10M;
> - port->full_duplex = 0;
> - break;
> - case H_SPEED_10M_F:
> - port->port_speed = EHEA_SPEED_10M;
> - port->full_duplex = 1;
> - break;
> - case H_SPEED_100M_H:
> - port->port_speed = EHEA_SPEED_100M;
> - port->full_duplex = 0;
> - break;
> - case H_SPEED_100M_F:
> - port->port_speed = EHEA_SPEED_100M;
> - port->full_duplex = 1;
> - break;
> - case H_SPEED_1G_F:
> - port->port_speed = EHEA_SPEED_1G;
> - port->full_duplex = 1;
> - break;
> - case H_SPEED_10G_F:
> - port->port_speed = EHEA_SPEED_10G;
> - port->full_duplex = 1;
> - break;
> - default:
> - port->port_speed = 0;
> - port->full_duplex = 0;
> - break;
> - }
> -
> - port->autoneg = 1;
> - port->num_mcs = cb0->num_default_qps;
> -
> - /* Number of default QPs */
> - if (use_mcs)
> - port->num_def_qps = cb0->num_default_qps;
> - else
> - port->num_def_qps = 1;
> -
> - if (!port->num_def_qps) {
> - ret = -EINVAL;
> - goto out_free;
> - }
> -
> - ret = 0;
> -out_free:
> - if (ret || netif_msg_probe(port))
> - ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr");
> - free_page((unsigned long)cb0);
> -out:
> - return ret;
> -}
> -
> -int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
> -{
> - struct hcp_ehea_port_cb4 *cb4;
> - u64 hret;
> - int ret = 0;
> -
> - cb4 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb4) {
> - pr_err("no mem for cb4\n");
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - cb4->port_speed = port_speed;
> -
> - netif_carrier_off(port->netdev);
> -
> - hret = ehea_h_modify_ehea_port(port->adapter->handle,
> - port->logical_port_id,
> - H_PORT_CB4, H_PORT_CB4_SPEED, cb4);
> - if (hret == H_SUCCESS) {
> - port->autoneg = port_speed == EHEA_SPEED_AUTONEG ? 1 : 0;
> -
> - hret = ehea_h_query_ehea_port(port->adapter->handle,
> - port->logical_port_id,
> - H_PORT_CB4, H_PORT_CB4_SPEED,
> - cb4);
> - if (hret == H_SUCCESS) {
> - switch (cb4->port_speed) {
> - case H_SPEED_10M_H:
> - port->port_speed = EHEA_SPEED_10M;
> - port->full_duplex = 0;
> - break;
> - case H_SPEED_10M_F:
> - port->port_speed = EHEA_SPEED_10M;
> - port->full_duplex = 1;
> - break;
> - case H_SPEED_100M_H:
> - port->port_speed = EHEA_SPEED_100M;
> - port->full_duplex = 0;
> - break;
> - case H_SPEED_100M_F:
> - port->port_speed = EHEA_SPEED_100M;
> - port->full_duplex = 1;
> - break;
> - case H_SPEED_1G_F:
> - port->port_speed = EHEA_SPEED_1G;
> - port->full_duplex = 1;
> - break;
> - case H_SPEED_10G_F:
> - port->port_speed = EHEA_SPEED_10G;
> - port->full_duplex = 1;
> - break;
> - default:
> - port->port_speed = 0;
> - port->full_duplex = 0;
> - break;
> - }
> - } else {
> - pr_err("Failed sensing port speed\n");
> - ret = -EIO;
> - }
> - } else {
> - if (hret == H_AUTHORITY) {
> - pr_info("Hypervisor denied setting port speed\n");
> - ret = -EPERM;
> - } else {
> - ret = -EIO;
> - pr_err("Failed setting port speed\n");
> - }
> - }
> - if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP))
> - netif_carrier_on(port->netdev);
> -
> - free_page((unsigned long)cb4);
> -out:
> - return ret;
> -}
> -
> -static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
> -{
> - int ret;
> - u8 ec;
> - u8 portnum;
> - struct ehea_port *port;
> - struct net_device *dev;
> -
> - ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
> - portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
> - port = ehea_get_port(adapter, portnum);
> - if (!port) {
> - netdev_err(NULL, "unknown portnum %x\n", portnum);
> - return;
> - }
> - dev = port->netdev;
> -
> - switch (ec) {
> - case EHEA_EC_PORTSTATE_CHG: /* port state change */
> -
> - if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
> - if (!netif_carrier_ok(dev)) {
> - ret = ehea_sense_port_attr(port);
> - if (ret) {
> - netdev_err(dev, "failed resensing port attributes\n");
> - break;
> - }
> -
> - netif_info(port, link, dev,
> - "Logical port up: %dMbps %s Duplex\n",
> - port->port_speed,
> - port->full_duplex == 1 ?
> - "Full" : "Half");
> -
> - netif_carrier_on(dev);
> - netif_wake_queue(dev);
> - }
> - } else
> - if (netif_carrier_ok(dev)) {
> - netif_info(port, link, dev,
> - "Logical port down\n");
> - netif_carrier_off(dev);
> - netif_tx_disable(dev);
> - }
> -
> - if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
> - port->phy_link = EHEA_PHY_LINK_UP;
> - netif_info(port, link, dev,
> - "Physical port up\n");
> - if (prop_carrier_state)
> - netif_carrier_on(dev);
> - } else {
> - port->phy_link = EHEA_PHY_LINK_DOWN;
> - netif_info(port, link, dev,
> - "Physical port down\n");
> - if (prop_carrier_state)
> - netif_carrier_off(dev);
> - }
> -
> - if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
> - netdev_info(dev,
> - "External switch port is primary port\n");
> - else
> - netdev_info(dev,
> - "External switch port is backup port\n");
> -
> - break;
> - case EHEA_EC_ADAPTER_MALFUNC:
> - netdev_err(dev, "Adapter malfunction\n");
> - break;
> - case EHEA_EC_PORT_MALFUNC:
> - netdev_info(dev, "Port malfunction\n");
> - netif_carrier_off(dev);
> - netif_tx_disable(dev);
> - break;
> - default:
> - netdev_err(dev, "unknown event code %x, eqe=0x%llX\n", ec, eqe);
> - break;
> - }
> -}
> -
> -static void ehea_neq_tasklet(struct tasklet_struct *t)
> -{
> - struct ehea_adapter *adapter = from_tasklet(adapter, t, neq_tasklet);
> - struct ehea_eqe *eqe;
> - u64 event_mask;
> -
> - eqe = ehea_poll_eq(adapter->neq);
> - pr_debug("eqe=%p\n", eqe);
> -
> - while (eqe) {
> - pr_debug("*eqe=%lx\n", (unsigned long) eqe->entry);
> - ehea_parse_eqe(adapter, eqe->entry);
> - eqe = ehea_poll_eq(adapter->neq);
> - pr_debug("next eqe=%p\n", eqe);
> - }
> -
> - event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1)
> - | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1)
> - | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1);
> -
> - ehea_h_reset_events(adapter->handle,
> - adapter->neq->fw_handle, event_mask);
> -}
> -
> -static irqreturn_t ehea_interrupt_neq(int irq, void *param)
> -{
> - struct ehea_adapter *adapter = param;
> - tasklet_hi_schedule(&adapter->neq_tasklet);
> - return IRQ_HANDLED;
> -}
> -
> -
> -static int ehea_fill_port_res(struct ehea_port_res *pr)
> -{
> - int ret;
> - struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
> -
> - ehea_init_fill_rq1(pr, pr->rq1_skba.len);
> -
> - ret = ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1);
> -
> - ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3 - 1);
> -
> - return ret;
> -}
> -
> -static int ehea_reg_interrupts(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_port_res *pr;
> - int i, ret;
> -
> -
> - snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
> - dev->name);
> -
> - ret = ibmebus_request_irq(port->qp_eq->attr.ist1,
> - ehea_qp_aff_irq_handler,
> - 0, port->int_aff_name, port);
> - if (ret) {
> - netdev_err(dev, "failed registering irq for qp_aff_irq_handler:ist=%X\n",
> - port->qp_eq->attr.ist1);
> - goto out_free_qpeq;
> - }
> -
> - netif_info(port, ifup, dev,
> - "irq_handle 0x%X for function qp_aff_irq_handler registered\n",
> - port->qp_eq->attr.ist1);
> -
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - pr = &port->port_res[i];
> - snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
> - "%s-queue%d", dev->name, i);
> - ret = ibmebus_request_irq(pr->eq->attr.ist1,
> - ehea_recv_irq_handler,
> - 0, pr->int_send_name, pr);
> - if (ret) {
> - netdev_err(dev, "failed registering irq for ehea_queue port_res_nr:%d, ist=%X\n",
> - i, pr->eq->attr.ist1);
> - goto out_free_req;
> - }
> - netif_info(port, ifup, dev,
> - "irq_handle 0x%X for function ehea_queue_int %d registered\n",
> - pr->eq->attr.ist1, i);
> - }
> -out:
> - return ret;
> -
> -
> -out_free_req:
> - while (--i >= 0) {
> - u32 ist = port->port_res[i].eq->attr.ist1;
> - ibmebus_free_irq(ist, &port->port_res[i]);
> - }
> -
> -out_free_qpeq:
> - ibmebus_free_irq(port->qp_eq->attr.ist1, port);
> - i = port->num_def_qps;
> -
> - goto out;
> -
> -}
> -
> -static void ehea_free_interrupts(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_port_res *pr;
> - int i;
> -
> - /* send */
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - pr = &port->port_res[i];
> - ibmebus_free_irq(pr->eq->attr.ist1, pr);
> - netif_info(port, intr, dev,
> - "free send irq for res %d with handle 0x%X\n",
> - i, pr->eq->attr.ist1);
> - }
> -
> - /* associated events */
> - ibmebus_free_irq(port->qp_eq->attr.ist1, port);
> - netif_info(port, intr, dev,
> - "associated event interrupt for handle 0x%X freed\n",
> - port->qp_eq->attr.ist1);
> -}
> -
> -static int ehea_configure_port(struct ehea_port *port)
> -{
> - int ret, i;
> - u64 hret, mask;
> - struct hcp_ehea_port_cb0 *cb0;
> -
> - ret = -ENOMEM;
> - cb0 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb0)
> - goto out;
> -
> - cb0->port_rc = EHEA_BMASK_SET(PXLY_RC_VALID, 1)
> - | EHEA_BMASK_SET(PXLY_RC_IP_CHKSUM, 1)
> - | EHEA_BMASK_SET(PXLY_RC_TCP_UDP_CHKSUM, 1)
> - | EHEA_BMASK_SET(PXLY_RC_VLAN_XTRACT, 1)
> - | EHEA_BMASK_SET(PXLY_RC_VLAN_TAG_FILTER,
> - PXLY_RC_VLAN_FILTER)
> - | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
> -
> - for (i = 0; i < port->num_mcs; i++)
> - if (use_mcs)
> - cb0->default_qpn_arr[i] =
> - port->port_res[i].qp->init_attr.qp_nr;
> - else
> - cb0->default_qpn_arr[i] =
> - port->port_res[0].qp->init_attr.qp_nr;
> -
> - if (netif_msg_ifup(port))
> - ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
> -
> - mask = EHEA_BMASK_SET(H_PORT_CB0_PRC, 1)
> - | EHEA_BMASK_SET(H_PORT_CB0_DEFQPNARRAY, 1);
> -
> - hret = ehea_h_modify_ehea_port(port->adapter->handle,
> - port->logical_port_id,
> - H_PORT_CB0, mask, cb0);
> - ret = -EIO;
> - if (hret != H_SUCCESS)
> - goto out_free;
> -
> - ret = 0;
> -
> -out_free:
> - free_page((unsigned long)cb0);
> -out:
> - return ret;
> -}
> -
> -static int ehea_gen_smrs(struct ehea_port_res *pr)
> -{
> - int ret;
> - struct ehea_adapter *adapter = pr->port->adapter;
> -
> - ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr);
> - if (ret)
> - goto out;
> -
> - ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr);
> - if (ret)
> - goto out_free;
> -
> - return 0;
> -
> -out_free:
> - ehea_rem_mr(&pr->send_mr);
> -out:
> - pr_err("Generating SMRS failed\n");
> - return -EIO;
> -}
> -
> -static int ehea_rem_smrs(struct ehea_port_res *pr)
> -{
> - if ((ehea_rem_mr(&pr->send_mr)) ||
> - (ehea_rem_mr(&pr->recv_mr)))
> - return -EIO;
> - else
> - return 0;
> -}
> -
> -static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
> -{
> - int arr_size = sizeof(void *) * max_q_entries;
> -
> - q_skba->arr = vzalloc(arr_size);
> - if (!q_skba->arr)
> - return -ENOMEM;
> -
> - q_skba->len = max_q_entries;
> - q_skba->index = 0;
> - q_skba->os_skbs = 0;
> -
> - return 0;
> -}
> -
> -static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
> - struct port_res_cfg *pr_cfg, int queue_token)
> -{
> - struct ehea_adapter *adapter = port->adapter;
> - enum ehea_eq_type eq_type = EHEA_EQ;
> - struct ehea_qp_init_attr *init_attr = NULL;
> - int ret = -EIO;
> - u64 tx_bytes, rx_bytes, tx_packets, rx_packets;
> -
> - tx_bytes = pr->tx_bytes;
> - tx_packets = pr->tx_packets;
> - rx_bytes = pr->rx_bytes;
> - rx_packets = pr->rx_packets;
> -
> - memset(pr, 0, sizeof(struct ehea_port_res));
> -
> - pr->tx_bytes = tx_bytes;
> - pr->tx_packets = tx_packets;
> - pr->rx_bytes = rx_bytes;
> - pr->rx_packets = rx_packets;
> -
> - pr->port = port;
> -
> - pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
> - if (!pr->eq) {
> - pr_err("create_eq failed (eq)\n");
> - goto out_free;
> - }
> -
> - pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
> - pr->eq->fw_handle,
> - port->logical_port_id);
> - if (!pr->recv_cq) {
> - pr_err("create_cq failed (cq_recv)\n");
> - goto out_free;
> - }
> -
> - pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
> - pr->eq->fw_handle,
> - port->logical_port_id);
> - if (!pr->send_cq) {
> - pr_err("create_cq failed (cq_send)\n");
> - goto out_free;
> - }
> -
> - if (netif_msg_ifup(port))
> - pr_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d\n",
> - pr->send_cq->attr.act_nr_of_cqes,
> - pr->recv_cq->attr.act_nr_of_cqes);
> -
> - init_attr = kzalloc_obj(*init_attr);
> - if (!init_attr) {
> - ret = -ENOMEM;
> - pr_err("no mem for ehea_qp_init_attr\n");
> - goto out_free;
> - }
> -
> - init_attr->low_lat_rq1 = 1;
> - init_attr->signalingtype = 1; /* generate CQE if specified in WQE */
> - init_attr->rq_count = 3;
> - init_attr->qp_token = queue_token;
> - init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq;
> - init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1;
> - init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2;
> - init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3;
> - init_attr->wqe_size_enc_sq = EHEA_SG_SQ;
> - init_attr->wqe_size_enc_rq1 = EHEA_SG_RQ1;
> - init_attr->wqe_size_enc_rq2 = EHEA_SG_RQ2;
> - init_attr->wqe_size_enc_rq3 = EHEA_SG_RQ3;
> - init_attr->rq2_threshold = EHEA_RQ2_THRESHOLD;
> - init_attr->rq3_threshold = EHEA_RQ3_THRESHOLD;
> - init_attr->port_nr = port->logical_port_id;
> - init_attr->send_cq_handle = pr->send_cq->fw_handle;
> - init_attr->recv_cq_handle = pr->recv_cq->fw_handle;
> - init_attr->aff_eq_handle = port->qp_eq->fw_handle;
> -
> - pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr);
> - if (!pr->qp) {
> - pr_err("create_qp failed\n");
> - ret = -EIO;
> - goto out_free;
> - }
> -
> - if (netif_msg_ifup(port))
> - pr_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d\n",
> - init_attr->qp_nr,
> - init_attr->act_nr_send_wqes,
> - init_attr->act_nr_rwqes_rq1,
> - init_attr->act_nr_rwqes_rq2,
> - init_attr->act_nr_rwqes_rq3);
> -
> - pr->sq_skba_size = init_attr->act_nr_send_wqes + 1;
> -
> - ret = ehea_init_q_skba(&pr->sq_skba, pr->sq_skba_size);
> - ret |= ehea_init_q_skba(&pr->rq1_skba, init_attr->act_nr_rwqes_rq1 + 1);
> - ret |= ehea_init_q_skba(&pr->rq2_skba, init_attr->act_nr_rwqes_rq2 + 1);
> - ret |= ehea_init_q_skba(&pr->rq3_skba, init_attr->act_nr_rwqes_rq3 + 1);
> - if (ret)
> - goto out_free;
> -
> - pr->swqe_refill_th = init_attr->act_nr_send_wqes / 10;
> - if (ehea_gen_smrs(pr) != 0) {
> - ret = -EIO;
> - goto out_free;
> - }
> -
> - atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
> -
> - kfree(init_attr);
> -
> - netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll);
> -
> - ret = 0;
> - goto out;
> -
> -out_free:
> - kfree(init_attr);
> - vfree(pr->sq_skba.arr);
> - vfree(pr->rq1_skba.arr);
> - vfree(pr->rq2_skba.arr);
> - vfree(pr->rq3_skba.arr);
> - ehea_destroy_qp(pr->qp);
> - ehea_destroy_cq(pr->send_cq);
> - ehea_destroy_cq(pr->recv_cq);
> - ehea_destroy_eq(pr->eq);
> -out:
> - return ret;
> -}
> -
> -static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
> -{
> - int ret, i;
> -
> - if (pr->qp)
> - netif_napi_del(&pr->napi);
> -
> - ret = ehea_destroy_qp(pr->qp);
> -
> - if (!ret) {
> - ehea_destroy_cq(pr->send_cq);
> - ehea_destroy_cq(pr->recv_cq);
> - ehea_destroy_eq(pr->eq);
> -
> - for (i = 0; i < pr->rq1_skba.len; i++)
> - dev_kfree_skb(pr->rq1_skba.arr[i]);
> -
> - for (i = 0; i < pr->rq2_skba.len; i++)
> - dev_kfree_skb(pr->rq2_skba.arr[i]);
> -
> - for (i = 0; i < pr->rq3_skba.len; i++)
> - dev_kfree_skb(pr->rq3_skba.arr[i]);
> -
> - for (i = 0; i < pr->sq_skba.len; i++)
> - dev_kfree_skb(pr->sq_skba.arr[i]);
> -
> - vfree(pr->rq1_skba.arr);
> - vfree(pr->rq2_skba.arr);
> - vfree(pr->rq3_skba.arr);
> - vfree(pr->sq_skba.arr);
> - ret = ehea_rem_smrs(pr);
> - }
> - return ret;
> -}
> -
> -static void write_swqe2_immediate(struct sk_buff *skb, struct ehea_swqe *swqe,
> - u32 lkey)
> -{
> - int skb_data_size = skb_headlen(skb);
> - u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
> - struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
> - unsigned int immediate_len = SWQE2_MAX_IMM;
> -
> - swqe->descriptors = 0;
> -
> - if (skb_is_gso(skb)) {
> - swqe->tx_control |= EHEA_SWQE_TSO;
> - swqe->mss = skb_shinfo(skb)->gso_size;
> - /*
> - * For TSO packets we only copy the headers into the
> - * immediate area.
> - */
> - immediate_len = skb_tcp_all_headers(skb);
> - }
> -
> - if (skb_is_gso(skb) || skb_data_size >= SWQE2_MAX_IMM) {
> - skb_copy_from_linear_data(skb, imm_data, immediate_len);
> - swqe->immediate_data_length = immediate_len;
> -
> - if (skb_data_size > immediate_len) {
> - sg1entry->l_key = lkey;
> - sg1entry->len = skb_data_size - immediate_len;
> - sg1entry->vaddr =
> - ehea_map_vaddr(skb->data + immediate_len);
> - swqe->descriptors++;
> - }
> - } else {
> - skb_copy_from_linear_data(skb, imm_data, skb_data_size);
> - swqe->immediate_data_length = skb_data_size;
> - }
> -}
> -
> -static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
> - struct ehea_swqe *swqe, u32 lkey)
> -{
> - struct ehea_vsgentry *sg_list, *sg1entry, *sgentry;
> - skb_frag_t *frag;
> - int nfrags, sg1entry_contains_frag_data, i;
> -
> - nfrags = skb_shinfo(skb)->nr_frags;
> - sg1entry = &swqe->u.immdata_desc.sg_entry;
> - sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list;
> - sg1entry_contains_frag_data = 0;
> -
> - write_swqe2_immediate(skb, swqe, lkey);
> -
> - /* write descriptors */
> - if (nfrags > 0) {
> - if (swqe->descriptors == 0) {
> - /* sg1entry not yet used */
> - frag = &skb_shinfo(skb)->frags[0];
> -
> - /* copy sg1entry data */
> - sg1entry->l_key = lkey;
> - sg1entry->len = skb_frag_size(frag);
> - sg1entry->vaddr =
> - ehea_map_vaddr(skb_frag_address(frag));
> - swqe->descriptors++;
> - sg1entry_contains_frag_data = 1;
> - }
> -
> - for (i = sg1entry_contains_frag_data; i < nfrags; i++) {
> -
> - frag = &skb_shinfo(skb)->frags[i];
> - sgentry = &sg_list[i - sg1entry_contains_frag_data];
> -
> - sgentry->l_key = lkey;
> - sgentry->len = skb_frag_size(frag);
> - sgentry->vaddr = ehea_map_vaddr(skb_frag_address(frag));
> - swqe->descriptors++;
> - }
> - }
> -}
> -
> -static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
> -{
> - int ret = 0;
> - u64 hret;
> - u8 reg_type;
> -
> - /* De/Register untagged packets */
> - reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_UNTAGGED;
> - hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
> - port->logical_port_id,
> - reg_type, port->mac_addr, 0, hcallid);
> - if (hret != H_SUCCESS) {
> - pr_err("%sregistering bc address failed (tagged)\n",
> - hcallid == H_REG_BCMC ? "" : "de");
> - ret = -EIO;
> - goto out_herr;
> - }
> -
> - /* De/Register VLAN packets */
> - reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL;
> - hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
> - port->logical_port_id,
> - reg_type, port->mac_addr, 0, hcallid);
> - if (hret != H_SUCCESS) {
> - pr_err("%sregistering bc address failed (vlan)\n",
> - hcallid == H_REG_BCMC ? "" : "de");
> - ret = -EIO;
> - }
> -out_herr:
> - return ret;
> -}
> -
> -static int ehea_set_mac_addr(struct net_device *dev, void *sa)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct sockaddr *mac_addr = sa;
> - struct hcp_ehea_port_cb0 *cb0;
> - int ret;
> - u64 hret;
> -
> - if (!is_valid_ether_addr(mac_addr->sa_data)) {
> - ret = -EADDRNOTAVAIL;
> - goto out;
> - }
> -
> - cb0 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb0) {
> - pr_err("no mem for cb0\n");
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - memcpy(&(cb0->port_mac_addr), &(mac_addr->sa_data[0]), ETH_ALEN);
> -
> - cb0->port_mac_addr = cb0->port_mac_addr >> 16;
> -
> - hret = ehea_h_modify_ehea_port(port->adapter->handle,
> - port->logical_port_id, H_PORT_CB0,
> - EHEA_BMASK_SET(H_PORT_CB0_MAC, 1), cb0);
> - if (hret != H_SUCCESS) {
> - ret = -EIO;
> - goto out_free;
> - }
> -
> - eth_hw_addr_set(dev, mac_addr->sa_data);
> -
> - /* Deregister old MAC in pHYP */
> - if (port->state == EHEA_PORT_UP) {
> - ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
> - if (ret)
> - goto out_upregs;
> - }
> -
> - port->mac_addr = cb0->port_mac_addr << 16;
> -
> - /* Register new MAC in pHYP */
> - if (port->state == EHEA_PORT_UP) {
> - ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
> - if (ret)
> - goto out_upregs;
> - }
> -
> - ret = 0;
> -
> -out_upregs:
> - ehea_update_bcmc_registrations();
> -out_free:
> - free_page((unsigned long)cb0);
> -out:
> - return ret;
> -}
> -
> -static void ehea_promiscuous_error(u64 hret, int enable)
> -{
> - if (hret == H_AUTHORITY)
> - pr_info("Hypervisor denied %sabling promiscuous mode\n",
> - enable == 1 ? "en" : "dis");
> - else
> - pr_err("failed %sabling promiscuous mode\n",
> - enable == 1 ? "en" : "dis");
> -}
> -
> -static void ehea_promiscuous(struct net_device *dev, int enable)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct hcp_ehea_port_cb7 *cb7;
> - u64 hret;
> -
> - if (enable == port->promisc)
> - return;
> -
> - cb7 = (void *)get_zeroed_page(GFP_ATOMIC);
> - if (!cb7) {
> - pr_err("no mem for cb7\n");
> - goto out;
> - }
> -
> - /* Modify Pxs_DUCQPN in CB7 */
> - cb7->def_uc_qpn = enable == 1 ? port->port_res[0].qp->fw_handle : 0;
> -
> - hret = ehea_h_modify_ehea_port(port->adapter->handle,
> - port->logical_port_id,
> - H_PORT_CB7, H_PORT_CB7_DUCQPN, cb7);
> - if (hret) {
> - ehea_promiscuous_error(hret, enable);
> - goto out;
> - }
> -
> - port->promisc = enable;
> -out:
> - free_page((unsigned long)cb7);
> -}
> -
> -static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
> - u32 hcallid)
> -{
> - u64 hret;
> - u8 reg_type;
> -
> - reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_UNTAGGED;
> - if (mc_mac_addr == 0)
> - reg_type |= EHEA_BCMC_SCOPE_ALL;
> -
> - hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
> - port->logical_port_id,
> - reg_type, mc_mac_addr, 0, hcallid);
> - if (hret)
> - goto out;
> -
> - reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_VLANID_ALL;
> - if (mc_mac_addr == 0)
> - reg_type |= EHEA_BCMC_SCOPE_ALL;
> -
> - hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
> - port->logical_port_id,
> - reg_type, mc_mac_addr, 0, hcallid);
> -out:
> - return hret;
> -}
> -
> -static int ehea_drop_multicast_list(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_mc_list *mc_entry = port->mc_list;
> - struct list_head *pos;
> - struct list_head *temp;
> - int ret = 0;
> - u64 hret;
> -
> - list_for_each_safe(pos, temp, &(port->mc_list->list)) {
> - mc_entry = list_entry(pos, struct ehea_mc_list, list);
> -
> - hret = ehea_multicast_reg_helper(port, mc_entry->macaddr,
> - H_DEREG_BCMC);
> - if (hret) {
> - pr_err("failed deregistering mcast MAC\n");
> - ret = -EIO;
> - }
> -
> - list_del(pos);
> - kfree(mc_entry);
> - }
> - return ret;
> -}
> -
> -static void ehea_allmulti(struct net_device *dev, int enable)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - u64 hret;
> -
> - if (!port->allmulti) {
> - if (enable) {
> - /* Enable ALLMULTI */
> - ehea_drop_multicast_list(dev);
> - hret = ehea_multicast_reg_helper(port, 0, H_REG_BCMC);
> - if (!hret)
> - port->allmulti = 1;
> - else
> - netdev_err(dev,
> - "failed enabling IFF_ALLMULTI\n");
> - }
> - } else {
> - if (!enable) {
> - /* Disable ALLMULTI */
> - hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
> - if (!hret)
> - port->allmulti = 0;
> - else
> - netdev_err(dev,
> - "failed disabling IFF_ALLMULTI\n");
> - }
> - }
> -}
> -
> -static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
> -{
> - struct ehea_mc_list *ehea_mcl_entry;
> - u64 hret;
> -
> - ehea_mcl_entry = kzalloc_obj(*ehea_mcl_entry, GFP_ATOMIC);
> - if (!ehea_mcl_entry)
> - return;
> -
> - INIT_LIST_HEAD(&ehea_mcl_entry->list);
> -
> - memcpy(&ehea_mcl_entry->macaddr, mc_mac_addr, ETH_ALEN);
> -
> - hret = ehea_multicast_reg_helper(port, ehea_mcl_entry->macaddr,
> - H_REG_BCMC);
> - if (!hret)
> - list_add(&ehea_mcl_entry->list, &port->mc_list->list);
> - else {
> - pr_err("failed registering mcast MAC\n");
> - kfree(ehea_mcl_entry);
> - }
> -}
> -
> -static void ehea_set_multicast_list(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct netdev_hw_addr *ha;
> - int ret;
> -
> - ehea_promiscuous(dev, !!(dev->flags & IFF_PROMISC));
> -
> - if (dev->flags & IFF_ALLMULTI) {
> - ehea_allmulti(dev, 1);
> - goto out;
> - }
> - ehea_allmulti(dev, 0);
> -
> - if (!netdev_mc_empty(dev)) {
> - ret = ehea_drop_multicast_list(dev);
> - if (ret) {
> - /* Dropping the current multicast list failed.
> - * Enabling ALL_MULTI is the best we can do.
> - */
> - ehea_allmulti(dev, 1);
> - }
> -
> - if (netdev_mc_count(dev) > port->adapter->max_mc_mac) {
> - pr_info("Mcast registration limit reached (0x%llx). Use ALLMULTI!\n",
> - port->adapter->max_mc_mac);
> - goto out;
> - }
> -
> - netdev_for_each_mc_addr(ha, dev)
> - ehea_add_multicast_entry(port, ha->addr);
> -
> - }
> -out:
> - ehea_update_bcmc_registrations();
> -}
> -
> -static void xmit_common(struct sk_buff *skb, struct ehea_swqe *swqe)
> -{
> - swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT | EHEA_SWQE_CRC;
> -
> - if (vlan_get_protocol(skb) != htons(ETH_P_IP))
> - return;
> -
> - if (skb->ip_summed == CHECKSUM_PARTIAL)
> - swqe->tx_control |= EHEA_SWQE_IP_CHECKSUM;
> -
> - swqe->ip_start = skb_network_offset(skb);
> - swqe->ip_end = swqe->ip_start + ip_hdrlen(skb) - 1;
> -
> - switch (ip_hdr(skb)->protocol) {
> - case IPPROTO_UDP:
> - if (skb->ip_summed == CHECKSUM_PARTIAL)
> - swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM;
> -
> - swqe->tcp_offset = swqe->ip_end + 1 +
> - offsetof(struct udphdr, check);
> - break;
> -
> - case IPPROTO_TCP:
> - if (skb->ip_summed == CHECKSUM_PARTIAL)
> - swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM;
> -
> - swqe->tcp_offset = swqe->ip_end + 1 +
> - offsetof(struct tcphdr, check);
> - break;
> - }
> -}
> -
> -static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
> - struct ehea_swqe *swqe, u32 lkey)
> -{
> - swqe->tx_control |= EHEA_SWQE_DESCRIPTORS_PRESENT;
> -
> - xmit_common(skb, swqe);
> -
> - write_swqe2_data(skb, dev, swqe, lkey);
> -}
> -
> -static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
> - struct ehea_swqe *swqe)
> -{
> - u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
> -
> - xmit_common(skb, swqe);
> -
> - if (!skb->data_len)
> - skb_copy_from_linear_data(skb, imm_data, skb->len);
> - else
> - skb_copy_bits(skb, 0, imm_data, skb->len);
> -
> - swqe->immediate_data_length = skb->len;
> - dev_consume_skb_any(skb);
> -}
> -
> -static netdev_tx_t ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_swqe *swqe;
> - u32 lkey;
> - int swqe_index;
> - struct ehea_port_res *pr;
> - struct netdev_queue *txq;
> -
> - pr = &port->port_res[skb_get_queue_mapping(skb)];
> - txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
> -
> - swqe = ehea_get_swqe(pr->qp, &swqe_index);
> - memset(swqe, 0, SWQE_HEADER_SIZE);
> - atomic_dec(&pr->swqe_avail);
> -
> - if (skb_vlan_tag_present(skb)) {
> - swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
> - swqe->vlan_tag = skb_vlan_tag_get(skb);
> - }
> -
> - pr->tx_packets++;
> - pr->tx_bytes += skb->len;
> -
> - if (skb->len <= SWQE3_MAX_IMM) {
> - u32 sig_iv = port->sig_comp_iv;
> - u32 swqe_num = pr->swqe_id_counter;
> - ehea_xmit3(skb, dev, swqe);
> - swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE3_TYPE)
> - | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, swqe_num);
> - if (pr->swqe_ll_count >= (sig_iv - 1)) {
> - swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
> - sig_iv);
> - swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
> - pr->swqe_ll_count = 0;
> - } else
> - pr->swqe_ll_count += 1;
> - } else {
> - swqe->wr_id =
> - EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
> - | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
> - | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1)
> - | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index);
> - pr->sq_skba.arr[pr->sq_skba.index] = skb;
> -
> - pr->sq_skba.index++;
> - pr->sq_skba.index &= (pr->sq_skba.len - 1);
> -
> - lkey = pr->send_mr.lkey;
> - ehea_xmit2(skb, dev, swqe, lkey);
> - swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
> - }
> - pr->swqe_id_counter += 1;
> -
> - netif_info(port, tx_queued, dev,
> - "post swqe on QP %d\n", pr->qp->init_attr.qp_nr);
> - if (netif_msg_tx_queued(port))
> - ehea_dump(swqe, 512, "swqe");
> -
> - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
> - netif_tx_stop_queue(txq);
> - swqe->tx_control |= EHEA_SWQE_PURGE;
> - }
> -
> - ehea_post_swqe(pr->qp, swqe);
> -
> - if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
> - pr->p_stats.queue_stopped++;
> - netif_tx_stop_queue(txq);
> - }
> -
> - return NETDEV_TX_OK;
> -}
> -
> -static int ehea_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_adapter *adapter = port->adapter;
> - struct hcp_ehea_port_cb1 *cb1;
> - int index;
> - u64 hret;
> - int err = 0;
> -
> - cb1 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb1) {
> - pr_err("no mem for cb1\n");
> - err = -ENOMEM;
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
> - H_PORT_CB1, H_PORT_CB1_ALL, cb1);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_port failed\n");
> - err = -EINVAL;
> - goto out;
> - }
> -
> - index = (vid / 64);
> - cb1->vlan_filter[index] |= ((u64)(0x8000000000000000 >> (vid & 0x3F)));
> -
> - hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
> - H_PORT_CB1, H_PORT_CB1_ALL, cb1);
> - if (hret != H_SUCCESS) {
> - pr_err("modify_ehea_port failed\n");
> - err = -EINVAL;
> - }
> -out:
> - free_page((unsigned long)cb1);
> - return err;
> -}
> -
> -static int ehea_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_adapter *adapter = port->adapter;
> - struct hcp_ehea_port_cb1 *cb1;
> - int index;
> - u64 hret;
> - int err = 0;
> -
> - cb1 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb1) {
> - pr_err("no mem for cb1\n");
> - err = -ENOMEM;
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
> - H_PORT_CB1, H_PORT_CB1_ALL, cb1);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_port failed\n");
> - err = -EINVAL;
> - goto out;
> - }
> -
> - index = (vid / 64);
> - cb1->vlan_filter[index] &= ~((u64)(0x8000000000000000 >> (vid & 0x3F)));
> -
> - hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
> - H_PORT_CB1, H_PORT_CB1_ALL, cb1);
> - if (hret != H_SUCCESS) {
> - pr_err("modify_ehea_port failed\n");
> - err = -EINVAL;
> - }
> -out:
> - free_page((unsigned long)cb1);
> - return err;
> -}
> -
> -static int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
> -{
> - int ret = -EIO;
> - u64 hret;
> - u16 dummy16 = 0;
> - u64 dummy64 = 0;
> - struct hcp_modify_qp_cb0 *cb0;
> -
> - cb0 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb0) {
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_qp failed (1)\n");
> - goto out;
> - }
> -
> - cb0->qp_ctl_reg = H_QP_CR_STATE_INITIALIZED;
> - hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
> - &dummy64, &dummy64, &dummy16, &dummy16);
> - if (hret != H_SUCCESS) {
> - pr_err("modify_ehea_qp failed (1)\n");
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_qp failed (2)\n");
> - goto out;
> - }
> -
> - cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_INITIALIZED;
> - hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
> - &dummy64, &dummy64, &dummy16, &dummy16);
> - if (hret != H_SUCCESS) {
> - pr_err("modify_ehea_qp failed (2)\n");
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_qp failed (3)\n");
> - goto out;
> - }
> -
> - cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RDY2SND;
> - hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
> - &dummy64, &dummy64, &dummy16, &dummy16);
> - if (hret != H_SUCCESS) {
> - pr_err("modify_ehea_qp failed (3)\n");
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_qp failed (4)\n");
> - goto out;
> - }
> -
> - ret = 0;
> -out:
> - free_page((unsigned long)cb0);
> - return ret;
> -}
> -
> -static int ehea_port_res_setup(struct ehea_port *port, int def_qps)
> -{
> - int ret, i;
> - struct port_res_cfg pr_cfg, pr_cfg_small_rx;
> - enum ehea_eq_type eq_type = EHEA_EQ;
> -
> - port->qp_eq = ehea_create_eq(port->adapter, eq_type,
> - EHEA_MAX_ENTRIES_EQ, 1);
> - if (!port->qp_eq) {
> - ret = -EINVAL;
> - pr_err("ehea_create_eq failed (qp_eq)\n");
> - goto out_kill_eq;
> - }
> -
> - pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
> - pr_cfg.max_entries_scq = sq_entries * 2;
> - pr_cfg.max_entries_sq = sq_entries;
> - pr_cfg.max_entries_rq1 = rq1_entries;
> - pr_cfg.max_entries_rq2 = rq2_entries;
> - pr_cfg.max_entries_rq3 = rq3_entries;
> -
> - pr_cfg_small_rx.max_entries_rcq = 1;
> - pr_cfg_small_rx.max_entries_scq = sq_entries;
> - pr_cfg_small_rx.max_entries_sq = sq_entries;
> - pr_cfg_small_rx.max_entries_rq1 = 1;
> - pr_cfg_small_rx.max_entries_rq2 = 1;
> - pr_cfg_small_rx.max_entries_rq3 = 1;
> -
> - for (i = 0; i < def_qps; i++) {
> - ret = ehea_init_port_res(port, &port->port_res[i], &pr_cfg, i);
> - if (ret)
> - goto out_clean_pr;
> - }
> - for (i = def_qps; i < def_qps; i++) {
> - ret = ehea_init_port_res(port, &port->port_res[i],
> - &pr_cfg_small_rx, i);
> - if (ret)
> - goto out_clean_pr;
> - }
> -
> - return 0;
> -
> -out_clean_pr:
> - while (--i >= 0)
> - ehea_clean_portres(port, &port->port_res[i]);
> -
> -out_kill_eq:
> - ehea_destroy_eq(port->qp_eq);
> - return ret;
> -}
> -
> -static int ehea_clean_all_portres(struct ehea_port *port)
> -{
> - int ret = 0;
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++)
> - ret |= ehea_clean_portres(port, &port->port_res[i]);
> -
> - ret |= ehea_destroy_eq(port->qp_eq);
> -
> - return ret;
> -}
> -
> -static void ehea_remove_adapter_mr(struct ehea_adapter *adapter)
> -{
> - if (adapter->active_ports)
> - return;
> -
> - ehea_rem_mr(&adapter->mr);
> -}
> -
> -static int ehea_add_adapter_mr(struct ehea_adapter *adapter)
> -{
> - if (adapter->active_ports)
> - return 0;
> -
> - return ehea_reg_kernel_mr(adapter, &adapter->mr);
> -}
> -
> -static int ehea_up(struct net_device *dev)
> -{
> - int ret, i;
> - struct ehea_port *port = netdev_priv(dev);
> -
> - if (port->state == EHEA_PORT_UP)
> - return 0;
> -
> - ret = ehea_port_res_setup(port, port->num_def_qps);
> - if (ret) {
> - netdev_err(dev, "port_res_failed\n");
> - goto out;
> - }
> -
> - /* Set default QP for this port */
> - ret = ehea_configure_port(port);
> - if (ret) {
> - netdev_err(dev, "ehea_configure_port failed. ret:%d\n", ret);
> - goto out_clean_pr;
> - }
> -
> - ret = ehea_reg_interrupts(dev);
> - if (ret) {
> - netdev_err(dev, "reg_interrupts failed. ret:%d\n", ret);
> - goto out_clean_pr;
> - }
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
> - if (ret) {
> - netdev_err(dev, "activate_qp failed\n");
> - goto out_free_irqs;
> - }
> - }
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - ret = ehea_fill_port_res(&port->port_res[i]);
> - if (ret) {
> - netdev_err(dev, "out_free_irqs\n");
> - goto out_free_irqs;
> - }
> - }
> -
> - ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
> - if (ret) {
> - ret = -EIO;
> - goto out_free_irqs;
> - }
> -
> - port->state = EHEA_PORT_UP;
> -
> - ret = 0;
> - goto out;
> -
> -out_free_irqs:
> - ehea_free_interrupts(dev);
> -
> -out_clean_pr:
> - ehea_clean_all_portres(port);
> -out:
> - if (ret)
> - netdev_info(dev, "Failed starting. ret=%i\n", ret);
> -
> - ehea_update_bcmc_registrations();
> - ehea_update_firmware_handles();
> -
> - return ret;
> -}
> -
> -static void port_napi_disable(struct ehea_port *port)
> -{
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++)
> - napi_disable(&port->port_res[i].napi);
> -}
> -
> -static void port_napi_enable(struct ehea_port *port)
> -{
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++)
> - napi_enable(&port->port_res[i].napi);
> -}
> -
> -static int ehea_open(struct net_device *dev)
> -{
> - int ret;
> - struct ehea_port *port = netdev_priv(dev);
> -
> - mutex_lock(&port->port_lock);
> -
> - netif_info(port, ifup, dev, "enabling port\n");
> -
> - netif_carrier_off(dev);
> -
> - ret = ehea_up(dev);
> - if (!ret) {
> - port_napi_enable(port);
> - netif_tx_start_all_queues(dev);
> - }
> -
> - mutex_unlock(&port->port_lock);
> - schedule_delayed_work(&port->stats_work,
> - round_jiffies_relative(msecs_to_jiffies(1000)));
> -
> - return ret;
> -}
> -
> -static int ehea_down(struct net_device *dev)
> -{
> - int ret;
> - struct ehea_port *port = netdev_priv(dev);
> -
> - if (port->state == EHEA_PORT_DOWN)
> - return 0;
> -
> - ehea_drop_multicast_list(dev);
> - ehea_allmulti(dev, 0);
> - ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
> -
> - ehea_free_interrupts(dev);
> -
> - port->state = EHEA_PORT_DOWN;
> -
> - ehea_update_bcmc_registrations();
> -
> - ret = ehea_clean_all_portres(port);
> - if (ret)
> - netdev_info(dev, "Failed freeing resources. ret=%i\n", ret);
> -
> - ehea_update_firmware_handles();
> -
> - return ret;
> -}
> -
> -static int ehea_stop(struct net_device *dev)
> -{
> - int ret;
> - struct ehea_port *port = netdev_priv(dev);
> -
> - netif_info(port, ifdown, dev, "disabling port\n");
> -
> - set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
> - cancel_work_sync(&port->reset_task);
> - cancel_delayed_work_sync(&port->stats_work);
> - mutex_lock(&port->port_lock);
> - netif_tx_stop_all_queues(dev);
> - port_napi_disable(port);
> - ret = ehea_down(dev);
> - mutex_unlock(&port->port_lock);
> - clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
> - return ret;
> -}
> -
> -static void ehea_purge_sq(struct ehea_qp *orig_qp)
> -{
> - struct ehea_qp qp = *orig_qp;
> - struct ehea_qp_init_attr *init_attr = &qp.init_attr;
> - struct ehea_swqe *swqe;
> - int wqe_index;
> - int i;
> -
> - for (i = 0; i < init_attr->act_nr_send_wqes; i++) {
> - swqe = ehea_get_swqe(&qp, &wqe_index);
> - swqe->tx_control |= EHEA_SWQE_PURGE;
> - }
> -}
> -
> -static void ehea_flush_sq(struct ehea_port *port)
> -{
> - int i;
> -
> - for (i = 0; i < port->num_def_qps; i++) {
> - struct ehea_port_res *pr = &port->port_res[i];
> - int swqe_max = pr->sq_skba_size - 2 - pr->swqe_ll_count;
> - int ret;
> -
> - ret = wait_event_timeout(port->swqe_avail_wq,
> - atomic_read(&pr->swqe_avail) >= swqe_max,
> - msecs_to_jiffies(100));
> -
> - if (!ret) {
> - pr_err("WARNING: sq not flushed completely\n");
> - break;
> - }
> - }
> -}
> -
> -static int ehea_stop_qps(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_adapter *adapter = port->adapter;
> - struct hcp_modify_qp_cb0 *cb0;
> - int ret = -EIO;
> - int dret;
> - int i;
> - u64 hret;
> - u64 dummy64 = 0;
> - u16 dummy16 = 0;
> -
> - cb0 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb0) {
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - for (i = 0; i < (port->num_def_qps); i++) {
> - struct ehea_port_res *pr = &port->port_res[i];
> - struct ehea_qp *qp = pr->qp;
> -
> - /* Purge send queue */
> - ehea_purge_sq(qp);
> -
> - /* Disable queue pair */
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
> - cb0);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_qp failed (1)\n");
> - goto out;
> - }
> -
> - cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
> - cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED;
> -
> - hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
> - 1), cb0, &dummy64,
> - &dummy64, &dummy16, &dummy16);
> - if (hret != H_SUCCESS) {
> - pr_err("modify_ehea_qp failed (1)\n");
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
> - cb0);
> - if (hret != H_SUCCESS) {
> - pr_err("query_ehea_qp failed (2)\n");
> - goto out;
> - }
> -
> - /* deregister shared memory regions */
> - dret = ehea_rem_smrs(pr);
> - if (dret) {
> - pr_err("unreg shared memory region failed\n");
> - goto out;
> - }
> - }
> -
> - ret = 0;
> -out:
> - free_page((unsigned long)cb0);
> -
> - return ret;
> -}
> -
> -static void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
> -{
> - struct ehea_qp qp = *orig_qp;
> - struct ehea_qp_init_attr *init_attr = &qp.init_attr;
> - struct ehea_rwqe *rwqe;
> - struct sk_buff **skba_rq2 = pr->rq2_skba.arr;
> - struct sk_buff **skba_rq3 = pr->rq3_skba.arr;
> - struct sk_buff *skb;
> - u32 lkey = pr->recv_mr.lkey;
> -
> -
> - int i;
> - int index;
> -
> - for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) {
> - rwqe = ehea_get_next_rwqe(&qp, 2);
> - rwqe->sg_list[0].l_key = lkey;
> - index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
> - skb = skba_rq2[index];
> - if (skb)
> - rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
> - }
> -
> - for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) {
> - rwqe = ehea_get_next_rwqe(&qp, 3);
> - rwqe->sg_list[0].l_key = lkey;
> - index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
> - skb = skba_rq3[index];
> - if (skb)
> - rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
> - }
> -}
> -
> -static int ehea_restart_qps(struct net_device *dev)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> - struct ehea_adapter *adapter = port->adapter;
> - int ret = 0;
> - int i;
> -
> - struct hcp_modify_qp_cb0 *cb0;
> - u64 hret;
> - u64 dummy64 = 0;
> - u16 dummy16 = 0;
> -
> - cb0 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb0)
> - return -ENOMEM;
> -
> - for (i = 0; i < (port->num_def_qps); i++) {
> - struct ehea_port_res *pr = &port->port_res[i];
> - struct ehea_qp *qp = pr->qp;
> -
> - ret = ehea_gen_smrs(pr);
> - if (ret) {
> - netdev_err(dev, "creation of shared memory regions failed\n");
> - goto out;
> - }
> -
> - ehea_update_rqs(qp, pr);
> -
> - /* Enable queue pair */
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
> - cb0);
> - if (hret != H_SUCCESS) {
> - netdev_err(dev, "query_ehea_qp failed (1)\n");
> - ret = -EFAULT;
> - goto out;
> - }
> -
> - cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
> - cb0->qp_ctl_reg |= H_QP_CR_ENABLED;
> -
> - hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
> - 1), cb0, &dummy64,
> - &dummy64, &dummy16, &dummy16);
> - if (hret != H_SUCCESS) {
> - netdev_err(dev, "modify_ehea_qp failed (1)\n");
> - ret = -EFAULT;
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
> - EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
> - cb0);
> - if (hret != H_SUCCESS) {
> - netdev_err(dev, "query_ehea_qp failed (2)\n");
> - ret = -EFAULT;
> - goto out;
> - }
> -
> - /* refill entire queue */
> - ehea_refill_rq1(pr, pr->rq1_skba.index, 0);
> - ehea_refill_rq2(pr, 0);
> - ehea_refill_rq3(pr, 0);
> - }
> -out:
> - free_page((unsigned long)cb0);
> -
> - return ret;
> -}
> -
> -static void ehea_reset_port(struct work_struct *work)
> -{
> - int ret;
> - struct ehea_port *port =
> - container_of(work, struct ehea_port, reset_task);
> - struct net_device *dev = port->netdev;
> -
> - mutex_lock(&dlpar_mem_lock);
> - port->resets++;
> - mutex_lock(&port->port_lock);
> - netif_tx_disable(dev);
> -
> - port_napi_disable(port);
> -
> - ehea_down(dev);
> -
> - ret = ehea_up(dev);
> - if (ret)
> - goto out;
> -
> - ehea_set_multicast_list(dev);
> -
> - netif_info(port, timer, dev, "reset successful\n");
> -
> - port_napi_enable(port);
> -
> - netif_tx_wake_all_queues(dev);
> -out:
> - mutex_unlock(&port->port_lock);
> - mutex_unlock(&dlpar_mem_lock);
> -}
> -
> -static void ehea_rereg_mrs(void)
> -{
> - int ret, i;
> - struct ehea_adapter *adapter;
> -
> - pr_info("LPAR memory changed - re-initializing driver\n");
> -
> - list_for_each_entry(adapter, &adapter_list, list)
> - if (adapter->active_ports) {
> - /* Shutdown all ports */
> - for (i = 0; i < EHEA_MAX_PORTS; i++) {
> - struct ehea_port *port = adapter->port[i];
> - struct net_device *dev;
> -
> - if (!port)
> - continue;
> -
> - dev = port->netdev;
> -
> - if (dev->flags & IFF_UP) {
> - mutex_lock(&port->port_lock);
> - netif_tx_disable(dev);
> - ehea_flush_sq(port);
> - ret = ehea_stop_qps(dev);
> - if (ret) {
> - mutex_unlock(&port->port_lock);
> - goto out;
> - }
> - port_napi_disable(port);
> - mutex_unlock(&port->port_lock);
> - }
> - reset_sq_restart_flag(port);
> - }
> -
> - /* Unregister old memory region */
> - ret = ehea_rem_mr(&adapter->mr);
> - if (ret) {
> - pr_err("unregister MR failed - driver inoperable!\n");
> - goto out;
> - }
> - }
> -
> - clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
> -
> - list_for_each_entry(adapter, &adapter_list, list)
> - if (adapter->active_ports) {
> - /* Register new memory region */
> - ret = ehea_reg_kernel_mr(adapter, &adapter->mr);
> - if (ret) {
> - pr_err("register MR failed - driver inoperable!\n");
> - goto out;
> - }
> -
> - /* Restart all ports */
> - for (i = 0; i < EHEA_MAX_PORTS; i++) {
> - struct ehea_port *port = adapter->port[i];
> -
> - if (port) {
> - struct net_device *dev = port->netdev;
> -
> - if (dev->flags & IFF_UP) {
> - mutex_lock(&port->port_lock);
> - ret = ehea_restart_qps(dev);
> - if (!ret) {
> - check_sqs(port);
> - port_napi_enable(port);
> - netif_tx_wake_all_queues(dev);
> - } else {
> - netdev_err(dev, "Unable to restart QPS\n");
> - }
> - mutex_unlock(&port->port_lock);
> - }
> - }
> - }
> - }
> - pr_info("re-initializing driver complete\n");
> -out:
> - return;
> -}
> -
> -static void ehea_tx_watchdog(struct net_device *dev, unsigned int txqueue)
> -{
> - struct ehea_port *port = netdev_priv(dev);
> -
> - if (netif_carrier_ok(dev) &&
> - !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
> - ehea_schedule_port_reset(port);
> -}
> -
> -static int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
> -{
> - struct hcp_query_ehea *cb;
> - u64 hret;
> - int ret;
> -
> - cb = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb) {
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - hret = ehea_h_query_ehea(adapter->handle, cb);
> -
> - if (hret != H_SUCCESS) {
> - ret = -EIO;
> - goto out_herr;
> - }
> -
> - adapter->max_mc_mac = cb->max_mc_mac - 1;
> - ret = 0;
> -
> -out_herr:
> - free_page((unsigned long)cb);
> -out:
> - return ret;
> -}
> -
> -static int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
> -{
> - struct hcp_ehea_port_cb4 *cb4;
> - u64 hret;
> - int ret = 0;
> -
> - *jumbo = 0;
> -
> - /* (Try to) enable *jumbo frames */
> - cb4 = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!cb4) {
> - pr_err("no mem for cb4\n");
> - ret = -ENOMEM;
> - goto out;
> - } else {
> - hret = ehea_h_query_ehea_port(port->adapter->handle,
> - port->logical_port_id,
> - H_PORT_CB4,
> - H_PORT_CB4_JUMBO, cb4);
> - if (hret == H_SUCCESS) {
> - if (cb4->jumbo_frame)
> - *jumbo = 1;
> - else {
> - cb4->jumbo_frame = 1;
> - hret = ehea_h_modify_ehea_port(port->adapter->
> - handle,
> - port->
> - logical_port_id,
> - H_PORT_CB4,
> - H_PORT_CB4_JUMBO,
> - cb4);
> - if (hret == H_SUCCESS)
> - *jumbo = 1;
> - }
> - } else
> - ret = -EINVAL;
> -
> - free_page((unsigned long)cb4);
> - }
> -out:
> - return ret;
> -}
> -
> -static ssize_t log_port_id_show(struct device *dev,
> - struct device_attribute *attr, char *buf)
> -{
> - struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
> - return sprintf(buf, "%d", port->logical_port_id);
> -}
> -
> -static DEVICE_ATTR_RO(log_port_id);
> -
> -static void logical_port_release(struct device *dev)
> -{
> - struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
> - of_node_put(port->ofdev.dev.of_node);
> -}
> -
> -static struct device *ehea_register_port(struct ehea_port *port,
> - struct device_node *dn)
> -{
> - int ret;
> -
> - port->ofdev.dev.of_node = of_node_get(dn);
> - port->ofdev.dev.parent = &port->adapter->ofdev->dev;
> - port->ofdev.dev.bus = &ibmebus_bus_type;
> -
> - dev_set_name(&port->ofdev.dev, "port%d", port_name_cnt++);
> - port->ofdev.dev.release = logical_port_release;
> -
> - ret = of_device_register(&port->ofdev);
> - if (ret) {
> - pr_err("failed to register device. ret=%d\n", ret);
> - put_device(&port->ofdev.dev);
> - goto out;
> - }
> -
> - ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
> - if (ret) {
> - pr_err("failed to register attributes, ret=%d\n", ret);
> - goto out_unreg_of_dev;
> - }
> -
> - return &port->ofdev.dev;
> -
> -out_unreg_of_dev:
> - of_device_unregister(&port->ofdev);
> -out:
> - return NULL;
> -}
> -
> -static void ehea_unregister_port(struct ehea_port *port)
> -{
> - device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
> - of_device_unregister(&port->ofdev);
> -}
> -
> -static const struct net_device_ops ehea_netdev_ops = {
> - .ndo_open = ehea_open,
> - .ndo_stop = ehea_stop,
> - .ndo_start_xmit = ehea_start_xmit,
> - .ndo_get_stats64 = ehea_get_stats64,
> - .ndo_set_mac_address = ehea_set_mac_addr,
> - .ndo_validate_addr = eth_validate_addr,
> - .ndo_set_rx_mode = ehea_set_multicast_list,
> - .ndo_vlan_rx_add_vid = ehea_vlan_rx_add_vid,
> - .ndo_vlan_rx_kill_vid = ehea_vlan_rx_kill_vid,
> - .ndo_tx_timeout = ehea_tx_watchdog,
> -};
> -
> -static struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
> - u32 logical_port_id,
> - struct device_node *dn)
> -{
> - int ret;
> - struct net_device *dev;
> - struct ehea_port *port;
> - struct device *port_dev;
> - int jumbo;
> -
> - /* allocate memory for the port structures */
> - dev = alloc_etherdev_mq(sizeof(struct ehea_port), EHEA_MAX_PORT_RES);
> -
> - if (!dev) {
> - ret = -ENOMEM;
> - goto out_err;
> - }
> -
> - port = netdev_priv(dev);
> -
> - mutex_init(&port->port_lock);
> - port->state = EHEA_PORT_DOWN;
> - port->sig_comp_iv = sq_entries / 10;
> -
> - port->adapter = adapter;
> - port->netdev = dev;
> - port->logical_port_id = logical_port_id;
> -
> - port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
> -
> - port->mc_list = kzalloc_obj(struct ehea_mc_list);
> - if (!port->mc_list) {
> - ret = -ENOMEM;
> - goto out_free_ethdev;
> - }
> -
> - INIT_LIST_HEAD(&port->mc_list->list);
> -
> - ret = ehea_sense_port_attr(port);
> - if (ret)
> - goto out_free_mc_list;
> -
> - netif_set_real_num_rx_queues(dev, port->num_def_qps);
> - netif_set_real_num_tx_queues(dev, port->num_def_qps);
> -
> - port_dev = ehea_register_port(port, dn);
> - if (!port_dev)
> - goto out_free_mc_list;
> -
> - SET_NETDEV_DEV(dev, port_dev);
> -
> - /* initialize net_device structure */
> - eth_hw_addr_set(dev, (u8 *)&port->mac_addr);
> -
> - dev->netdev_ops = &ehea_netdev_ops;
> - ehea_set_ethtool_ops(dev);
> -
> - dev->hw_features = NETIF_F_SG | NETIF_F_TSO |
> - NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_CTAG_TX;
> - dev->features = NETIF_F_SG | NETIF_F_TSO |
> - NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
> - NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
> - NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXCSUM;
> - dev->vlan_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HIGHDMA |
> - NETIF_F_IP_CSUM;
> - dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
> -
> - /* MTU range: 68 - 9022 */
> - dev->min_mtu = ETH_MIN_MTU;
> - dev->max_mtu = EHEA_MAX_PACKET_SIZE;
> -
> - INIT_WORK(&port->reset_task, ehea_reset_port);
> - INIT_DELAYED_WORK(&port->stats_work, ehea_update_stats);
> -
> - init_waitqueue_head(&port->swqe_avail_wq);
> - init_waitqueue_head(&port->restart_wq);
> -
> - ret = register_netdev(dev);
> - if (ret) {
> - pr_err("register_netdev failed. ret=%d\n", ret);
> - goto out_unreg_port;
> - }
> -
> - ret = ehea_get_jumboframe_status(port, &jumbo);
> - if (ret)
> - netdev_err(dev, "failed determining jumbo frame status\n");
> -
> - netdev_info(dev, "Jumbo frames are %sabled\n",
> - jumbo == 1 ? "en" : "dis");
> -
> - adapter->active_ports++;
> -
> - return port;
> -
> -out_unreg_port:
> - ehea_unregister_port(port);
> -
> -out_free_mc_list:
> - kfree(port->mc_list);
> -
> -out_free_ethdev:
> - free_netdev(dev);
> -
> -out_err:
> - pr_err("setting up logical port with id=%d failed, ret=%d\n",
> - logical_port_id, ret);
> - return NULL;
> -}
> -
> -static void ehea_shutdown_single_port(struct ehea_port *port)
> -{
> - struct ehea_adapter *adapter = port->adapter;
> -
> - cancel_work_sync(&port->reset_task);
> - cancel_delayed_work_sync(&port->stats_work);
> - unregister_netdev(port->netdev);
> - ehea_unregister_port(port);
> - kfree(port->mc_list);
> - free_netdev(port->netdev);
> - adapter->active_ports--;
> -}
> -
> -static int ehea_setup_ports(struct ehea_adapter *adapter)
> -{
> - struct device_node *lhea_dn;
> - struct device_node *eth_dn;
> -
> - const u32 *dn_log_port_id;
> - int i = 0;
> -
> - lhea_dn = adapter->ofdev->dev.of_node;
> - for_each_child_of_node(lhea_dn, eth_dn) {
> - dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
> - NULL);
> - if (!dn_log_port_id) {
> - pr_err("bad device node: eth_dn name=%pOF\n", eth_dn);
> - continue;
> - }
> -
> - if (ehea_add_adapter_mr(adapter)) {
> - pr_err("creating MR failed\n");
> - of_node_put(eth_dn);
> - return -EIO;
> - }
> -
> - adapter->port[i] = ehea_setup_single_port(adapter,
> - *dn_log_port_id,
> - eth_dn);
> - if (adapter->port[i])
> - netdev_info(adapter->port[i]->netdev,
> - "logical port id #%d\n", *dn_log_port_id);
> - else
> - ehea_remove_adapter_mr(adapter);
> -
> - i++;
> - }
> - return 0;
> -}
> -
> -static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
> - u32 logical_port_id)
> -{
> - struct device_node *lhea_dn;
> - struct device_node *eth_dn;
> - const u32 *dn_log_port_id;
> -
> - lhea_dn = adapter->ofdev->dev.of_node;
> - for_each_child_of_node(lhea_dn, eth_dn) {
> - dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
> - NULL);
> - if (dn_log_port_id)
> - if (*dn_log_port_id == logical_port_id)
> - return eth_dn;
> - }
> -
> - return NULL;
> -}
> -
> -static ssize_t probe_port_store(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf, size_t count)
> -{
> - struct ehea_adapter *adapter = dev_get_drvdata(dev);
> - struct ehea_port *port;
> - struct device_node *eth_dn = NULL;
> - int i;
> -
> - u32 logical_port_id;
> -
> - sscanf(buf, "%d", &logical_port_id);
> -
> - port = ehea_get_port(adapter, logical_port_id);
> -
> - if (port) {
> - netdev_info(port->netdev, "adding port with logical port id=%d failed: port already configured\n",
> - logical_port_id);
> - return -EINVAL;
> - }
> -
> - eth_dn = ehea_get_eth_dn(adapter, logical_port_id);
> -
> - if (!eth_dn) {
> - pr_info("no logical port with id %d found\n", logical_port_id);
> - return -EINVAL;
> - }
> -
> - if (ehea_add_adapter_mr(adapter)) {
> - pr_err("creating MR failed\n");
> - of_node_put(eth_dn);
> - return -EIO;
> - }
> -
> - port = ehea_setup_single_port(adapter, logical_port_id, eth_dn);
> -
> - of_node_put(eth_dn);
> -
> - if (port) {
> - for (i = 0; i < EHEA_MAX_PORTS; i++)
> - if (!adapter->port[i]) {
> - adapter->port[i] = port;
> - break;
> - }
> -
> - netdev_info(port->netdev, "added: (logical port id=%d)\n",
> - logical_port_id);
> - } else {
> - ehea_remove_adapter_mr(adapter);
> - return -EIO;
> - }
> -
> - return (ssize_t) count;
> -}
> -
> -static ssize_t remove_port_store(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf, size_t count)
> -{
> - struct ehea_adapter *adapter = dev_get_drvdata(dev);
> - struct ehea_port *port;
> - int i;
> - u32 logical_port_id;
> -
> - sscanf(buf, "%d", &logical_port_id);
> -
> - port = ehea_get_port(adapter, logical_port_id);
> -
> - if (port) {
> - netdev_info(port->netdev, "removed: (logical port id=%d)\n",
> - logical_port_id);
> -
> - ehea_shutdown_single_port(port);
> -
> - for (i = 0; i < EHEA_MAX_PORTS; i++)
> - if (adapter->port[i] == port) {
> - adapter->port[i] = NULL;
> - break;
> - }
> - } else {
> - pr_err("removing port with logical port id=%d failed. port not configured.\n",
> - logical_port_id);
> - return -EINVAL;
> - }
> -
> - ehea_remove_adapter_mr(adapter);
> -
> - return (ssize_t) count;
> -}
> -
> -static DEVICE_ATTR_WO(probe_port);
> -static DEVICE_ATTR_WO(remove_port);
> -
> -static int ehea_create_device_sysfs(struct platform_device *dev)
> -{
> - int ret = device_create_file(&dev->dev, &dev_attr_probe_port);
> - if (ret)
> - goto out;
> -
> - ret = device_create_file(&dev->dev, &dev_attr_remove_port);
> - if (ret)
> - device_remove_file(&dev->dev, &dev_attr_probe_port);
> -out:
> - return ret;
> -}
> -
> -static void ehea_remove_device_sysfs(struct platform_device *dev)
> -{
> - device_remove_file(&dev->dev, &dev_attr_probe_port);
> - device_remove_file(&dev->dev, &dev_attr_remove_port);
> -}
> -
> -static int ehea_reboot_notifier(struct notifier_block *nb,
> - unsigned long action, void *unused)
> -{
> - if (action == SYS_RESTART) {
> - pr_info("Reboot: freeing all eHEA resources\n");
> - ibmebus_unregister_driver(&ehea_driver);
> - }
> - return NOTIFY_DONE;
> -}
> -
> -static struct notifier_block ehea_reboot_nb = {
> - .notifier_call = ehea_reboot_notifier,
> -};
> -
> -static int ehea_mem_notifier(struct notifier_block *nb,
> - unsigned long action, void *data)
> -{
> - int ret = NOTIFY_BAD;
> - struct memory_notify *arg = data;
> -
> - mutex_lock(&dlpar_mem_lock);
> -
> - switch (action) {
> - case MEM_CANCEL_OFFLINE:
> - pr_info("memory offlining canceled");
> - fallthrough; /* re-add canceled memory block */
> -
> - case MEM_ONLINE:
> - pr_info("memory is going online");
> - set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
> - if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
> - goto out_unlock;
> - ehea_rereg_mrs();
> - break;
> -
> - case MEM_GOING_OFFLINE:
> - pr_info("memory is going offline");
> - set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
> - if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
> - goto out_unlock;
> - ehea_rereg_mrs();
> - break;
> -
> - default:
> - break;
> - }
> -
> - ehea_update_firmware_handles();
> - ret = NOTIFY_OK;
> -
> -out_unlock:
> - mutex_unlock(&dlpar_mem_lock);
> - return ret;
> -}
> -
> -static struct notifier_block ehea_mem_nb = {
> - .notifier_call = ehea_mem_notifier,
> -};
> -
> -static void ehea_crash_handler(void)
> -{
> - int i;
> -
> - if (ehea_fw_handles.arr)
> - for (i = 0; i < ehea_fw_handles.num_entries; i++)
> - ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
> - ehea_fw_handles.arr[i].fwh,
> - FORCE_FREE);
> -
> - if (ehea_bcmc_regs.arr)
> - for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
> - ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
> - ehea_bcmc_regs.arr[i].port_id,
> - ehea_bcmc_regs.arr[i].reg_type,
> - ehea_bcmc_regs.arr[i].macaddr,
> - 0, H_DEREG_BCMC);
> -}
> -
> -static atomic_t ehea_memory_hooks_registered;
> -
> -/* Register memory hooks on probe of first adapter */
> -static int ehea_register_memory_hooks(void)
> -{
> - int ret = 0;
> -
> - if (atomic_inc_return(&ehea_memory_hooks_registered) > 1)
> - return 0;
> -
> - ret = ehea_create_busmap();
> - if (ret) {
> - pr_info("ehea_create_busmap failed\n");
> - goto out;
> - }
> -
> - ret = register_reboot_notifier(&ehea_reboot_nb);
> - if (ret) {
> - pr_info("register_reboot_notifier failed\n");
> - goto out;
> - }
> -
> - ret = register_memory_notifier(&ehea_mem_nb);
> - if (ret) {
> - pr_info("register_memory_notifier failed\n");
> - goto out2;
> - }
> -
> - ret = crash_shutdown_register(ehea_crash_handler);
> - if (ret) {
> - pr_info("crash_shutdown_register failed\n");
> - goto out3;
> - }
> -
> - return 0;
> -
> -out3:
> - unregister_memory_notifier(&ehea_mem_nb);
> -out2:
> - unregister_reboot_notifier(&ehea_reboot_nb);
> -out:
> - atomic_dec(&ehea_memory_hooks_registered);
> - return ret;
> -}
> -
> -static void ehea_unregister_memory_hooks(void)
> -{
> - /* Only remove the hooks if we've registered them */
> - if (atomic_read(&ehea_memory_hooks_registered) == 0)
> - return;
> -
> - unregister_reboot_notifier(&ehea_reboot_nb);
> - if (crash_shutdown_unregister(ehea_crash_handler))
> - pr_info("failed unregistering crash handler\n");
> - unregister_memory_notifier(&ehea_mem_nb);
> -}
> -
> -static int ehea_probe_adapter(struct platform_device *dev)
> -{
> - struct ehea_adapter *adapter;
> - const u64 *adapter_handle;
> - int ret;
> - int i;
> -
> - ret = ehea_register_memory_hooks();
> - if (ret)
> - return ret;
> -
> - if (!dev || !dev->dev.of_node) {
> - pr_err("Invalid ibmebus device probed\n");
> - return -EINVAL;
> - }
> -
> - adapter = devm_kzalloc(&dev->dev, sizeof(*adapter), GFP_KERNEL);
> - if (!adapter) {
> - ret = -ENOMEM;
> - dev_err(&dev->dev, "no mem for ehea_adapter\n");
> - goto out;
> - }
> -
> - list_add(&adapter->list, &adapter_list);
> -
> - adapter->ofdev = dev;
> -
> - adapter_handle = of_get_property(dev->dev.of_node, "ibm,hea-handle",
> - NULL);
> - if (adapter_handle)
> - adapter->handle = *adapter_handle;
> -
> - if (!adapter->handle) {
> - dev_err(&dev->dev, "failed getting handle for adapter"
> - " '%pOF'\n", dev->dev.of_node);
> - ret = -ENODEV;
> - goto out_free_ad;
> - }
> -
> - adapter->pd = EHEA_PD_ID;
> -
> - platform_set_drvdata(dev, adapter);
> -
> -
> - /* initialize adapter and ports */
> - /* get adapter properties */
> - ret = ehea_sense_adapter_attr(adapter);
> - if (ret) {
> - dev_err(&dev->dev, "sense_adapter_attr failed: %d\n", ret);
> - goto out_free_ad;
> - }
> -
> - adapter->neq = ehea_create_eq(adapter,
> - EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
> - if (!adapter->neq) {
> - ret = -EIO;
> - dev_err(&dev->dev, "NEQ creation failed\n");
> - goto out_free_ad;
> - }
> -
> - tasklet_setup(&adapter->neq_tasklet, ehea_neq_tasklet);
> -
> - ret = ehea_create_device_sysfs(dev);
> - if (ret)
> - goto out_kill_eq;
> -
> - ret = ehea_setup_ports(adapter);
> - if (ret) {
> - dev_err(&dev->dev, "setup_ports failed\n");
> - goto out_rem_dev_sysfs;
> - }
> -
> - ret = ibmebus_request_irq(adapter->neq->attr.ist1,
> - ehea_interrupt_neq, 0,
> - "ehea_neq", adapter);
> - if (ret) {
> - dev_err(&dev->dev, "requesting NEQ IRQ failed\n");
> - goto out_shutdown_ports;
> - }
> -
> - /* Handle any events that might be pending. */
> - tasklet_hi_schedule(&adapter->neq_tasklet);
> -
> - ret = 0;
> - goto out;
> -
> -out_shutdown_ports:
> - for (i = 0; i < EHEA_MAX_PORTS; i++)
> - if (adapter->port[i]) {
> - ehea_shutdown_single_port(adapter->port[i]);
> - adapter->port[i] = NULL;
> - }
> -
> -out_rem_dev_sysfs:
> - ehea_remove_device_sysfs(dev);
> -
> -out_kill_eq:
> - ehea_destroy_eq(adapter->neq);
> -
> -out_free_ad:
> - list_del(&adapter->list);
> -
> -out:
> - ehea_update_firmware_handles();
> -
> - return ret;
> -}
> -
> -static void ehea_remove(struct platform_device *dev)
> -{
> - struct ehea_adapter *adapter = platform_get_drvdata(dev);
> - int i;
> -
> - for (i = 0; i < EHEA_MAX_PORTS; i++)
> - if (adapter->port[i]) {
> - ehea_shutdown_single_port(adapter->port[i]);
> - adapter->port[i] = NULL;
> - }
> -
> - ehea_remove_device_sysfs(dev);
> -
> - ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
> - tasklet_kill(&adapter->neq_tasklet);
> -
> - ehea_destroy_eq(adapter->neq);
> - ehea_remove_adapter_mr(adapter);
> - list_del(&adapter->list);
> -
> - ehea_update_firmware_handles();
> -}
> -
> -static int check_module_parm(void)
> -{
> - int ret = 0;
> -
> - if ((rq1_entries < EHEA_MIN_ENTRIES_QP) ||
> - (rq1_entries > EHEA_MAX_ENTRIES_RQ1)) {
> - pr_info("Bad parameter: rq1_entries\n");
> - ret = -EINVAL;
> - }
> - if ((rq2_entries < EHEA_MIN_ENTRIES_QP) ||
> - (rq2_entries > EHEA_MAX_ENTRIES_RQ2)) {
> - pr_info("Bad parameter: rq2_entries\n");
> - ret = -EINVAL;
> - }
> - if ((rq3_entries < EHEA_MIN_ENTRIES_QP) ||
> - (rq3_entries > EHEA_MAX_ENTRIES_RQ3)) {
> - pr_info("Bad parameter: rq3_entries\n");
> - ret = -EINVAL;
> - }
> - if ((sq_entries < EHEA_MIN_ENTRIES_QP) ||
> - (sq_entries > EHEA_MAX_ENTRIES_SQ)) {
> - pr_info("Bad parameter: sq_entries\n");
> - ret = -EINVAL;
> - }
> -
> - return ret;
> -}
> -
> -static ssize_t capabilities_show(struct device_driver *drv, char *buf)
> -{
> - return sprintf(buf, "%d", EHEA_CAPABILITIES);
> -}
> -
> -static DRIVER_ATTR_RO(capabilities);
> -
> -static int __init ehea_module_init(void)
> -{
> - int ret;
> -
> - pr_info("IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION);
> -
> - memset(&ehea_fw_handles, 0, sizeof(ehea_fw_handles));
> - memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
> -
> - mutex_init(&ehea_fw_handles.lock);
> - spin_lock_init(&ehea_bcmc_regs.lock);
> -
> - ret = check_module_parm();
> - if (ret)
> - goto out;
> -
> - ret = ibmebus_register_driver(&ehea_driver);
> - if (ret) {
> - pr_err("failed registering eHEA device driver on ebus\n");
> - goto out;
> - }
> -
> - ret = driver_create_file(&ehea_driver.driver,
> - &driver_attr_capabilities);
> - if (ret) {
> - pr_err("failed to register capabilities attribute, ret=%d\n",
> - ret);
> - goto out2;
> - }
> -
> - return ret;
> -
> -out2:
> - ibmebus_unregister_driver(&ehea_driver);
> -out:
> - return ret;
> -}
> -
> -static void __exit ehea_module_exit(void)
> -{
> - driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
> - ibmebus_unregister_driver(&ehea_driver);
> - ehea_unregister_memory_hooks();
> - kfree(ehea_fw_handles.arr);
> - kfree(ehea_bcmc_regs.arr);
> - ehea_destroy_busmap();
> -}
> -
> -module_init(ehea_module_init);
> -module_exit(ehea_module_exit);
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.c b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
> deleted file mode 100644
> index e63716e139f5..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
> +++ /dev/null
> @@ -1,612 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include "ehea_phyp.h"
> -
> -
> -static inline u16 get_order_of_qentries(u16 queue_entries)
> -{
> - u8 ld = 1; /* logarithmus dualis */
> - while (((1U << ld) - 1) < queue_entries)
> - ld++;
> - return ld - 1;
> -}
> -
> -/* Defines for H_CALL H_ALLOC_RESOURCE */
> -#define H_ALL_RES_TYPE_QP 1
> -#define H_ALL_RES_TYPE_CQ 2
> -#define H_ALL_RES_TYPE_EQ 3
> -#define H_ALL_RES_TYPE_MR 5
> -#define H_ALL_RES_TYPE_MW 6
> -
> -static long ehea_plpar_hcall_norets(unsigned long opcode,
> - unsigned long arg1,
> - unsigned long arg2,
> - unsigned long arg3,
> - unsigned long arg4,
> - unsigned long arg5,
> - unsigned long arg6,
> - unsigned long arg7)
> -{
> - long ret;
> - int i, sleep_msecs;
> -
> - for (i = 0; i < 5; i++) {
> - ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
> - arg5, arg6, arg7);
> -
> - if (H_IS_LONG_BUSY(ret)) {
> - sleep_msecs = get_longbusy_msecs(ret);
> - msleep_interruptible(sleep_msecs);
> - continue;
> - }
> -
> - if (ret < H_SUCCESS)
> - pr_err("opcode=%lx ret=%lx"
> - " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
> - " arg5=%lx arg6=%lx arg7=%lx\n",
> - opcode, ret,
> - arg1, arg2, arg3, arg4, arg5, arg6, arg7);
> -
> - return ret;
> - }
> -
> - return H_BUSY;
> -}
> -
> -static long ehea_plpar_hcall9(unsigned long opcode,
> - unsigned long *outs, /* array of 9 outputs */
> - unsigned long arg1,
> - unsigned long arg2,
> - unsigned long arg3,
> - unsigned long arg4,
> - unsigned long arg5,
> - unsigned long arg6,
> - unsigned long arg7,
> - unsigned long arg8,
> - unsigned long arg9)
> -{
> - long ret;
> - int i, sleep_msecs;
> - u8 cb_cat;
> -
> - for (i = 0; i < 5; i++) {
> - ret = plpar_hcall9(opcode, outs,
> - arg1, arg2, arg3, arg4, arg5,
> - arg6, arg7, arg8, arg9);
> -
> - if (H_IS_LONG_BUSY(ret)) {
> - sleep_msecs = get_longbusy_msecs(ret);
> - msleep_interruptible(sleep_msecs);
> - continue;
> - }
> -
> - cb_cat = EHEA_BMASK_GET(H_MEHEAPORT_CAT, arg2);
> -
> - if ((ret < H_SUCCESS) && !(((ret == H_AUTHORITY)
> - && (opcode == H_MODIFY_HEA_PORT))
> - && (((cb_cat == H_PORT_CB4) && ((arg3 == H_PORT_CB4_JUMBO)
> - || (arg3 == H_PORT_CB4_SPEED))) || ((cb_cat == H_PORT_CB7)
> - && (arg3 == H_PORT_CB7_DUCQPN)))))
> - pr_err("opcode=%lx ret=%lx"
> - " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
> - " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
> - " arg9=%lx"
> - " out1=%lx out2=%lx out3=%lx out4=%lx"
> - " out5=%lx out6=%lx out7=%lx out8=%lx"
> - " out9=%lx\n",
> - opcode, ret,
> - arg1, arg2, arg3, arg4, arg5,
> - arg6, arg7, arg8, arg9,
> - outs[0], outs[1], outs[2], outs[3], outs[4],
> - outs[5], outs[6], outs[7], outs[8]);
> - return ret;
> - }
> -
> - return H_BUSY;
> -}
> -
> -u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
> - const u64 qp_handle, const u64 sel_mask, void *cb_addr)
> -{
> - return ehea_plpar_hcall_norets(H_QUERY_HEA_QP,
> - adapter_handle, /* R4 */
> - qp_category, /* R5 */
> - qp_handle, /* R6 */
> - sel_mask, /* R7 */
> - __pa(cb_addr), /* R8 */
> - 0, 0);
> -}
> -
> -/* input param R5 */
> -#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
> -#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
> -#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
> -#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
> -#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
> -#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
> -#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
> -#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
> -#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
> -#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
> -
> -/* input param R9 */
> -#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
> -#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32, 63)
> -
> -/* input param R10 */
> -#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
> -#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
> -#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
> -#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
> -/* Max Send Scatter Gather Elements */
> -#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
> -#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
> -/* Max Receive SG Elements RQ1 */
> -#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
> -#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
> -
> -/* input param R11 */
> -#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
> -/* max swqe immediate data length */
> -#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
> -
> -/* input param R12 */
> -#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
> -/* Threshold RQ2 */
> -#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
> -/* Threshold RQ3 */
> -
> -/* output param R6 */
> -#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
> -#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
> -#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
> -#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
> -
> -/* output param, R7 */
> -#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
> -#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
> -#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
> -#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
> -#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
> -
> -/* output param R8,R9 */
> -#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
> -#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
> -#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
> -#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
> -
> -/* output param R11,R12 */
> -#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
> -#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
> -#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
> -#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
> -
> -u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
> - struct ehea_qp_init_attr *init_attr, const u32 pd,
> - u64 *qp_handle, struct h_epas *h_epas)
> -{
> - u64 hret;
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - u64 allocate_controls =
> - EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_QPP, 0)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_RQR, 6) /* rq1 & rq2 & rq3 */
> - | EHEA_BMASK_SET(H_ALL_RES_QP_EQEG, 0) /* EQE gen. disabled */
> - | EHEA_BMASK_SET(H_ALL_RES_QP_LL_QP, init_attr->low_lat_rq1)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_DMA128, 0)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_HSM, 0)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_SIGT, init_attr->signalingtype)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_RES_TYP, H_ALL_RES_TYPE_QP);
> -
> - u64 r9_reg = EHEA_BMASK_SET(H_ALL_RES_QP_PD, pd)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_TOKEN, init_attr->qp_token);
> -
> - u64 max_r10_reg =
> - EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SWQE,
> - get_order_of_qentries(init_attr->max_nr_send_wqes))
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1WQE,
> - get_order_of_qentries(init_attr->max_nr_rwqes_rq1))
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2WQE,
> - get_order_of_qentries(init_attr->max_nr_rwqes_rq2))
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3WQE,
> - get_order_of_qentries(init_attr->max_nr_rwqes_rq3))
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SSGE, init_attr->wqe_size_enc_sq)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1SGE,
> - init_attr->wqe_size_enc_rq1)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2SGE,
> - init_attr->wqe_size_enc_rq2)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3SGE,
> - init_attr->wqe_size_enc_rq3);
> -
> - u64 r11_in =
> - EHEA_BMASK_SET(H_ALL_RES_QP_SWQE_IDL, init_attr->swqe_imm_data_len)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_PORT_NUM, init_attr->port_nr);
> - u64 threshold =
> - EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
> - | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
> -
> - hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
> - outs,
> - adapter_handle, /* R4 */
> - allocate_controls, /* R5 */
> - init_attr->send_cq_handle, /* R6 */
> - init_attr->recv_cq_handle, /* R7 */
> - init_attr->aff_eq_handle, /* R8 */
> - r9_reg, /* R9 */
> - max_r10_reg, /* R10 */
> - r11_in, /* R11 */
> - threshold); /* R12 */
> -
> - *qp_handle = outs[0];
> - init_attr->qp_nr = (u32)outs[1];
> -
> - init_attr->act_nr_send_wqes =
> - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, outs[2]);
> - init_attr->act_nr_rwqes_rq1 =
> - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, outs[2]);
> - init_attr->act_nr_rwqes_rq2 =
> - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, outs[2]);
> - init_attr->act_nr_rwqes_rq3 =
> - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, outs[2]);
> -
> - init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
> - init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
> - init_attr->act_wqe_size_enc_rq2 = init_attr->wqe_size_enc_rq2;
> - init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
> -
> - init_attr->nr_sq_pages =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, outs[4]);
> - init_attr->nr_rq1_pages =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, outs[4]);
> - init_attr->nr_rq2_pages =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, outs[5]);
> - init_attr->nr_rq3_pages =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, outs[5]);
> -
> - init_attr->liobn_sq =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, outs[7]);
> - init_attr->liobn_rq1 =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, outs[7]);
> - init_attr->liobn_rq2 =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, outs[8]);
> - init_attr->liobn_rq3 =
> - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, outs[8]);
> -
> - if (!hret)
> - hcp_epas_ctor(h_epas, outs[6], outs[6]);
> -
> - return hret;
> -}
> -
> -u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
> - struct ehea_cq_attr *cq_attr,
> - u64 *cq_handle, struct h_epas *epas)
> -{
> - u64 hret;
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
> - outs,
> - adapter_handle, /* R4 */
> - H_ALL_RES_TYPE_CQ, /* R5 */
> - cq_attr->eq_handle, /* R6 */
> - cq_attr->cq_token, /* R7 */
> - cq_attr->max_nr_of_cqes, /* R8 */
> - 0, 0, 0, 0); /* R9-R12 */
> -
> - *cq_handle = outs[0];
> - cq_attr->act_nr_of_cqes = outs[3];
> - cq_attr->nr_pages = outs[4];
> -
> - if (!hret)
> - hcp_epas_ctor(epas, outs[5], outs[6]);
> -
> - return hret;
> -}
> -
> -/* Defines for H_CALL H_ALLOC_RESOURCE */
> -#define H_ALL_RES_TYPE_QP 1
> -#define H_ALL_RES_TYPE_CQ 2
> -#define H_ALL_RES_TYPE_EQ 3
> -#define H_ALL_RES_TYPE_MR 5
> -#define H_ALL_RES_TYPE_MW 6
> -
> -/* input param R5 */
> -#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
> -#define H_ALL_RES_EQ_NON_NEQ_ISN EHEA_BMASK_IBM(6, 7)
> -#define H_ALL_RES_EQ_INH_EQE_GEN EHEA_BMASK_IBM(16, 16)
> -#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
> -/* input param R6 */
> -#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
> -
> -/* output param R6 */
> -#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
> -
> -/* output param R7 */
> -#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
> -
> -/* output param R8 */
> -#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
> -
> -/* output param R9 */
> -#define H_ALL_RES_EQ_ACT_EQ_IST_C EHEA_BMASK_IBM(30, 31)
> -#define H_ALL_RES_EQ_ACT_EQ_IST_1 EHEA_BMASK_IBM(40, 63)
> -
> -/* output param R10 */
> -#define H_ALL_RES_EQ_ACT_EQ_IST_2 EHEA_BMASK_IBM(40, 63)
> -
> -/* output param R11 */
> -#define H_ALL_RES_EQ_ACT_EQ_IST_3 EHEA_BMASK_IBM(40, 63)
> -
> -/* output param R12 */
> -#define H_ALL_RES_EQ_ACT_EQ_IST_4 EHEA_BMASK_IBM(40, 63)
> -
> -u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
> - struct ehea_eq_attr *eq_attr, u64 *eq_handle)
> -{
> - u64 hret, allocate_controls;
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - /* resource type */
> - allocate_controls =
> - EHEA_BMASK_SET(H_ALL_RES_EQ_RES_TYPE, H_ALL_RES_TYPE_EQ)
> - | EHEA_BMASK_SET(H_ALL_RES_EQ_NEQ, eq_attr->type ? 1 : 0)
> - | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
> - | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
> -
> - hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
> - outs,
> - adapter_handle, /* R4 */
> - allocate_controls, /* R5 */
> - eq_attr->max_nr_of_eqes, /* R6 */
> - 0, 0, 0, 0, 0, 0); /* R7-R10 */
> -
> - *eq_handle = outs[0];
> - eq_attr->act_nr_of_eqes = outs[3];
> - eq_attr->nr_pages = outs[4];
> - eq_attr->ist1 = outs[5];
> - eq_attr->ist2 = outs[6];
> - eq_attr->ist3 = outs[7];
> - eq_attr->ist4 = outs[8];
> -
> - return hret;
> -}
> -
> -u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat,
> - const u64 qp_handle, const u64 sel_mask,
> - void *cb_addr, u64 *inv_attr_id, u64 *proc_mask,
> - u16 *out_swr, u16 *out_rwr)
> -{
> - u64 hret;
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP,
> - outs,
> - adapter_handle, /* R4 */
> - (u64) cat, /* R5 */
> - qp_handle, /* R6 */
> - sel_mask, /* R7 */
> - __pa(cb_addr), /* R8 */
> - 0, 0, 0, 0); /* R9-R12 */
> -
> - *inv_attr_id = outs[0];
> - *out_swr = outs[3];
> - *out_rwr = outs[4];
> - *proc_mask = outs[5];
> -
> - return hret;
> -}
> -
> -u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize,
> - const u8 queue_type, const u64 resource_handle,
> - const u64 log_pageaddr, u64 count)
> -{
> - u64 reg_control;
> -
> - reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
> - | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
> -
> - return ehea_plpar_hcall_norets(H_REGISTER_HEA_RPAGES,
> - adapter_handle, /* R4 */
> - reg_control, /* R5 */
> - resource_handle, /* R6 */
> - log_pageaddr, /* R7 */
> - count, /* R8 */
> - 0, 0); /* R9-R10 */
> -}
> -
> -u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
> - const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
> - struct ehea_mr *mr)
> -{
> - u64 hret;
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - hret = ehea_plpar_hcall9(H_REGISTER_SMR,
> - outs,
> - adapter_handle , /* R4 */
> - orig_mr_handle, /* R5 */
> - vaddr_in, /* R6 */
> - (((u64)access_ctrl) << 32ULL), /* R7 */
> - pd, /* R8 */
> - 0, 0, 0, 0); /* R9-R12 */
> -
> - mr->handle = outs[0];
> - mr->lkey = (u32)outs[2];
> -
> - return hret;
> -}
> -
> -u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
> -{
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA,
> - outs,
> - adapter_handle, /* R4 */
> - H_DISABLE_GET_EHEA_WQE_P, /* R5 */
> - qp_handle, /* R6 */
> - 0, 0, 0, 0, 0, 0); /* R7-R12 */
> -}
> -
> -u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
> - u64 force_bit)
> -{
> - return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
> - adapter_handle, /* R4 */
> - res_handle, /* R5 */
> - force_bit,
> - 0, 0, 0, 0); /* R7-R10 */
> -}
> -
> -u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
> - const u64 length, const u32 access_ctrl,
> - const u32 pd, u64 *mr_handle, u32 *lkey)
> -{
> - u64 hret;
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> -
> - hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
> - outs,
> - adapter_handle, /* R4 */
> - 5, /* R5 */
> - vaddr, /* R6 */
> - length, /* R7 */
> - (((u64) access_ctrl) << 32ULL), /* R8 */
> - pd, /* R9 */
> - 0, 0, 0); /* R10-R12 */
> -
> - *mr_handle = outs[0];
> - *lkey = (u32)outs[2];
> - return hret;
> -}
> -
> -u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
> - const u8 pagesize, const u8 queue_type,
> - const u64 log_pageaddr, const u64 count)
> -{
> - if ((count > 1) && (log_pageaddr & ~PAGE_MASK)) {
> - pr_err("not on pageboundary\n");
> - return H_PARAMETER;
> - }
> -
> - return ehea_h_register_rpage(adapter_handle, pagesize,
> - queue_type, mr_handle,
> - log_pageaddr, count);
> -}
> -
> -u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr)
> -{
> - u64 hret, cb_logaddr;
> -
> - cb_logaddr = __pa(cb_addr);
> -
> - hret = ehea_plpar_hcall_norets(H_QUERY_HEA,
> - adapter_handle, /* R4 */
> - cb_logaddr, /* R5 */
> - 0, 0, 0, 0, 0); /* R6-R10 */
> -#ifdef DEBUG
> - ehea_dump(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
> -#endif
> - return hret;
> -}
> -
> -u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
> - const u8 cb_cat, const u64 select_mask,
> - void *cb_addr)
> -{
> - u64 port_info;
> - u64 cb_logaddr = __pa(cb_addr);
> - u64 arr_index = 0;
> -
> - port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
> - | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
> -
> - return ehea_plpar_hcall_norets(H_QUERY_HEA_PORT,
> - adapter_handle, /* R4 */
> - port_info, /* R5 */
> - select_mask, /* R6 */
> - arr_index, /* R7 */
> - cb_logaddr, /* R8 */
> - 0, 0); /* R9-R10 */
> -}
> -
> -u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
> - const u8 cb_cat, const u64 select_mask,
> - void *cb_addr)
> -{
> - unsigned long outs[PLPAR_HCALL9_BUFSIZE];
> - u64 port_info;
> - u64 arr_index = 0;
> - u64 cb_logaddr = __pa(cb_addr);
> -
> - port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
> - | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
> -#ifdef DEBUG
> - ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL");
> -#endif
> - return ehea_plpar_hcall9(H_MODIFY_HEA_PORT,
> - outs,
> - adapter_handle, /* R4 */
> - port_info, /* R5 */
> - select_mask, /* R6 */
> - arr_index, /* R7 */
> - cb_logaddr, /* R8 */
> - 0, 0, 0, 0); /* R9-R12 */
> -}
> -
> -u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
> - const u8 reg_type, const u64 mc_mac_addr,
> - const u16 vlan_id, const u32 hcall_id)
> -{
> - u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id;
> - u64 mac_addr = mc_mac_addr >> 16;
> -
> - r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
> - r6_reg_type = EHEA_BMASK_SET(H_REGBCMC_REGTYPE, reg_type);
> - r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
> - r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
> -
> - return ehea_plpar_hcall_norets(hcall_id,
> - adapter_handle, /* R4 */
> - r5_port_num, /* R5 */
> - r6_reg_type, /* R6 */
> - r7_mc_mac_addr, /* R7 */
> - r8_vlan_id, /* R8 */
> - 0, 0); /* R9-R12 */
> -}
> -
> -u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
> - const u64 event_mask)
> -{
> - return ehea_plpar_hcall_norets(H_RESET_EVENTS,
> - adapter_handle, /* R4 */
> - neq_handle, /* R5 */
> - event_mask, /* R6 */
> - 0, 0, 0, 0); /* R7-R12 */
> -}
> -
> -u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
> - void *rblock)
> -{
> - return ehea_plpar_hcall_norets(H_ERROR_DATA,
> - adapter_handle, /* R4 */
> - ressource_handle, /* R5 */
> - __pa(rblock), /* R6 */
> - 0, 0, 0, 0); /* R7-R12 */
> -}
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
> deleted file mode 100644
> index e8b56c103410..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
> +++ /dev/null
> @@ -1,433 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-or-later */
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#ifndef __EHEA_PHYP_H__
> -#define __EHEA_PHYP_H__
> -
> -#include <linux/delay.h>
> -#include <asm/hvcall.h>
> -#include "ehea.h"
> -#include "ehea_hw.h"
> -
> -/* Some abbreviations used here:
> - *
> - * hcp_* - structures, variables and functions releated to Hypervisor Calls
> - */
> -
> -/* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */
> -#define EHEA_MAX_RPAGE 512
> -
> -/* Notification Event Queue (NEQ) Entry bit masks */
> -#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
> -#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)
> -#define NEQE_PORT_UP EHEA_BMASK_IBM(16, 16)
> -#define NEQE_EXTSWITCH_PORT_UP EHEA_BMASK_IBM(17, 17)
> -#define NEQE_EXTSWITCH_PRIMARY EHEA_BMASK_IBM(18, 18)
> -#define NEQE_PLID EHEA_BMASK_IBM(16, 47)
> -
> -/* Notification Event Codes */
> -#define EHEA_EC_PORTSTATE_CHG 0x30
> -#define EHEA_EC_ADAPTER_MALFUNC 0x32
> -#define EHEA_EC_PORT_MALFUNC 0x33
> -
> -/* Notification Event Log Register (NELR) bit masks */
> -#define NELR_PORT_MALFUNC EHEA_BMASK_IBM(61, 61)
> -#define NELR_ADAPTER_MALFUNC EHEA_BMASK_IBM(62, 62)
> -#define NELR_PORTSTATE_CHG EHEA_BMASK_IBM(63, 63)
> -
> -static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel,
> - u64 paddr_user)
> -{
> - /* To support 64k pages we must round to 64k page boundary */
> - epas->kernel.addr = ioremap((paddr_kernel & PAGE_MASK), PAGE_SIZE) +
> - (paddr_kernel & ~PAGE_MASK);
> - epas->user.addr = paddr_user;
> -}
> -
> -static inline void hcp_epas_dtor(struct h_epas *epas)
> -{
> - if (epas->kernel.addr)
> - iounmap((void __iomem *)((u64)epas->kernel.addr & PAGE_MASK));
> -
> - epas->user.addr = 0;
> - epas->kernel.addr = 0;
> -}
> -
> -struct hcp_modify_qp_cb0 {
> - u64 qp_ctl_reg; /* 00 */
> - u32 max_swqe; /* 02 */
> - u32 max_rwqe; /* 03 */
> - u32 port_nb; /* 04 */
> - u32 reserved0; /* 05 */
> - u64 qp_aer; /* 06 */
> - u64 qp_tenure; /* 08 */
> -};
> -
> -/* Hcall Query/Modify Queue Pair Control Block 0 Selection Mask Bits */
> -#define H_QPCB0_ALL EHEA_BMASK_IBM(0, 5)
> -#define H_QPCB0_QP_CTL_REG EHEA_BMASK_IBM(0, 0)
> -#define H_QPCB0_MAX_SWQE EHEA_BMASK_IBM(1, 1)
> -#define H_QPCB0_MAX_RWQE EHEA_BMASK_IBM(2, 2)
> -#define H_QPCB0_PORT_NB EHEA_BMASK_IBM(3, 3)
> -#define H_QPCB0_QP_AER EHEA_BMASK_IBM(4, 4)
> -#define H_QPCB0_QP_TENURE EHEA_BMASK_IBM(5, 5)
> -
> -/* Queue Pair Control Register Status Bits */
> -#define H_QP_CR_ENABLED 0x8000000000000000ULL /* QP enabled */
> - /* QP States: */
> -#define H_QP_CR_STATE_RESET 0x0000010000000000ULL /* Reset */
> -#define H_QP_CR_STATE_INITIALIZED 0x0000020000000000ULL /* Initialized */
> -#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */
> -#define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */
> -#define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */
> -#define H_QP_CR_RES_STATE 0x0000007F00000000ULL /* Resultant state */
> -
> -struct hcp_modify_qp_cb1 {
> - u32 qpn; /* 00 */
> - u32 qp_asyn_ev_eq_nb; /* 01 */
> - u64 sq_cq_handle; /* 02 */
> - u64 rq_cq_handle; /* 04 */
> - /* sgel = scatter gather element */
> - u32 sgel_nb_sq; /* 06 */
> - u32 sgel_nb_rq1; /* 07 */
> - u32 sgel_nb_rq2; /* 08 */
> - u32 sgel_nb_rq3; /* 09 */
> -};
> -
> -/* Hcall Query/Modify Queue Pair Control Block 1 Selection Mask Bits */
> -#define H_QPCB1_ALL EHEA_BMASK_IBM(0, 7)
> -#define H_QPCB1_QPN EHEA_BMASK_IBM(0, 0)
> -#define H_QPCB1_ASYN_EV_EQ_NB EHEA_BMASK_IBM(1, 1)
> -#define H_QPCB1_SQ_CQ_HANDLE EHEA_BMASK_IBM(2, 2)
> -#define H_QPCB1_RQ_CQ_HANDLE EHEA_BMASK_IBM(3, 3)
> -#define H_QPCB1_SGEL_NB_SQ EHEA_BMASK_IBM(4, 4)
> -#define H_QPCB1_SGEL_NB_RQ1 EHEA_BMASK_IBM(5, 5)
> -#define H_QPCB1_SGEL_NB_RQ2 EHEA_BMASK_IBM(6, 6)
> -#define H_QPCB1_SGEL_NB_RQ3 EHEA_BMASK_IBM(7, 7)
> -
> -struct hcp_query_ehea {
> - u32 cur_num_qps; /* 00 */
> - u32 cur_num_cqs; /* 01 */
> - u32 cur_num_eqs; /* 02 */
> - u32 cur_num_mrs; /* 03 */
> - u32 auth_level; /* 04 */
> - u32 max_num_qps; /* 05 */
> - u32 max_num_cqs; /* 06 */
> - u32 max_num_eqs; /* 07 */
> - u32 max_num_mrs; /* 08 */
> - u32 reserved0; /* 09 */
> - u32 int_clock_freq; /* 10 */
> - u32 max_num_pds; /* 11 */
> - u32 max_num_addr_handles; /* 12 */
> - u32 max_num_cqes; /* 13 */
> - u32 max_num_wqes; /* 14 */
> - u32 max_num_sgel_rq1wqe; /* 15 */
> - u32 max_num_sgel_rq2wqe; /* 16 */
> - u32 max_num_sgel_rq3wqe; /* 17 */
> - u32 mr_page_size; /* 18 */
> - u32 reserved1; /* 19 */
> - u64 max_mr_size; /* 20 */
> - u64 reserved2; /* 22 */
> - u32 num_ports; /* 24 */
> - u32 reserved3; /* 25 */
> - u32 reserved4; /* 26 */
> - u32 reserved5; /* 27 */
> - u64 max_mc_mac; /* 28 */
> - u64 ehea_cap; /* 30 */
> - u32 max_isn_per_eq; /* 32 */
> - u32 max_num_neq; /* 33 */
> - u64 max_num_vlan_ids; /* 34 */
> - u32 max_num_port_group; /* 36 */
> - u32 max_num_phys_port; /* 37 */
> -
> -};
> -
> -/* Hcall Query/Modify Port Control Block defines */
> -#define H_PORT_CB0 0
> -#define H_PORT_CB1 1
> -#define H_PORT_CB2 2
> -#define H_PORT_CB3 3
> -#define H_PORT_CB4 4
> -#define H_PORT_CB5 5
> -#define H_PORT_CB6 6
> -#define H_PORT_CB7 7
> -
> -struct hcp_ehea_port_cb0 {
> - u64 port_mac_addr;
> - u64 port_rc;
> - u64 reserved0;
> - u32 port_op_state;
> - u32 port_speed;
> - u32 ext_swport_op_state;
> - u32 neg_tpf_prpf;
> - u32 num_default_qps;
> - u32 reserved1;
> - u64 default_qpn_arr[16];
> -};
> -
> -/* Hcall Query/Modify Port Control Block 0 Selection Mask Bits */
> -#define H_PORT_CB0_ALL EHEA_BMASK_IBM(0, 7) /* Set all bits */
> -#define H_PORT_CB0_MAC EHEA_BMASK_IBM(0, 0) /* MAC address */
> -#define H_PORT_CB0_PRC EHEA_BMASK_IBM(1, 1) /* Port Recv Control */
> -#define H_PORT_CB0_DEFQPNARRAY EHEA_BMASK_IBM(7, 7) /* Default QPN Array */
> -
> -/* Hcall Query Port: Returned port speed values */
> -#define H_SPEED_10M_H 1 /* 10 Mbps, Half Duplex */
> -#define H_SPEED_10M_F 2 /* 10 Mbps, Full Duplex */
> -#define H_SPEED_100M_H 3 /* 100 Mbps, Half Duplex */
> -#define H_SPEED_100M_F 4 /* 100 Mbps, Full Duplex */
> -#define H_SPEED_1G_F 6 /* 1 Gbps, Full Duplex */
> -#define H_SPEED_10G_F 8 /* 10 Gbps, Full Duplex */
> -
> -/* Port Receive Control Status Bits */
> -#define PXLY_RC_VALID EHEA_BMASK_IBM(49, 49)
> -#define PXLY_RC_VLAN_XTRACT EHEA_BMASK_IBM(50, 50)
> -#define PXLY_RC_TCP_6_TUPLE EHEA_BMASK_IBM(51, 51)
> -#define PXLY_RC_UDP_6_TUPLE EHEA_BMASK_IBM(52, 52)
> -#define PXLY_RC_TCP_3_TUPLE EHEA_BMASK_IBM(53, 53)
> -#define PXLY_RC_TCP_2_TUPLE EHEA_BMASK_IBM(54, 54)
> -#define PXLY_RC_LLC_SNAP EHEA_BMASK_IBM(55, 55)
> -#define PXLY_RC_JUMBO_FRAME EHEA_BMASK_IBM(56, 56)
> -#define PXLY_RC_FRAG_IP_PKT EHEA_BMASK_IBM(57, 57)
> -#define PXLY_RC_TCP_UDP_CHKSUM EHEA_BMASK_IBM(58, 58)
> -#define PXLY_RC_IP_CHKSUM EHEA_BMASK_IBM(59, 59)
> -#define PXLY_RC_MAC_FILTER EHEA_BMASK_IBM(60, 60)
> -#define PXLY_RC_UNTAG_FILTER EHEA_BMASK_IBM(61, 61)
> -#define PXLY_RC_VLAN_TAG_FILTER EHEA_BMASK_IBM(62, 63)
> -
> -#define PXLY_RC_VLAN_FILTER 2
> -#define PXLY_RC_VLAN_PERM 0
> -
> -
> -#define H_PORT_CB1_ALL 0x8000000000000000ULL
> -
> -struct hcp_ehea_port_cb1 {
> - u64 vlan_filter[64];
> -};
> -
> -#define H_PORT_CB2_ALL 0xFFE0000000000000ULL
> -
> -struct hcp_ehea_port_cb2 {
> - u64 rxo;
> - u64 rxucp;
> - u64 rxufd;
> - u64 rxuerr;
> - u64 rxftl;
> - u64 rxmcp;
> - u64 rxbcp;
> - u64 txo;
> - u64 txucp;
> - u64 txmcp;
> - u64 txbcp;
> -};
> -
> -struct hcp_ehea_port_cb3 {
> - u64 vlan_bc_filter[64];
> - u64 vlan_mc_filter[64];
> - u64 vlan_un_filter[64];
> - u64 port_mac_hash_array[64];
> -};
> -
> -#define H_PORT_CB4_ALL 0xF000000000000000ULL
> -#define H_PORT_CB4_JUMBO 0x1000000000000000ULL
> -#define H_PORT_CB4_SPEED 0x8000000000000000ULL
> -
> -struct hcp_ehea_port_cb4 {
> - u32 port_speed;
> - u32 pause_frame;
> - u32 ens_port_op_state;
> - u32 jumbo_frame;
> - u32 ens_port_wrap;
> -};
> -
> -/* Hcall Query/Modify Port Control Block 5 Selection Mask Bits */
> -#define H_PORT_CB5_RCU 0x0001000000000000ULL
> -#define PXS_RCU EHEA_BMASK_IBM(61, 63)
> -
> -struct hcp_ehea_port_cb5 {
> - u64 prc; /* 00 */
> - u64 uaa; /* 01 */
> - u64 macvc; /* 02 */
> - u64 xpcsc; /* 03 */
> - u64 xpcsp; /* 04 */
> - u64 pcsid; /* 05 */
> - u64 xpcsst; /* 06 */
> - u64 pthlb; /* 07 */
> - u64 pthrb; /* 08 */
> - u64 pqu; /* 09 */
> - u64 pqd; /* 10 */
> - u64 prt; /* 11 */
> - u64 wsth; /* 12 */
> - u64 rcb; /* 13 */
> - u64 rcm; /* 14 */
> - u64 rcu; /* 15 */
> - u64 macc; /* 16 */
> - u64 pc; /* 17 */
> - u64 pst; /* 18 */
> - u64 ducqpn; /* 19 */
> - u64 mcqpn; /* 20 */
> - u64 mma; /* 21 */
> - u64 pmc0h; /* 22 */
> - u64 pmc0l; /* 23 */
> - u64 lbc; /* 24 */
> -};
> -
> -#define H_PORT_CB6_ALL 0xFFFFFE7FFFFF8000ULL
> -
> -struct hcp_ehea_port_cb6 {
> - u64 rxo; /* 00 */
> - u64 rx64; /* 01 */
> - u64 rx65; /* 02 */
> - u64 rx128; /* 03 */
> - u64 rx256; /* 04 */
> - u64 rx512; /* 05 */
> - u64 rx1024; /* 06 */
> - u64 rxbfcs; /* 07 */
> - u64 rxime; /* 08 */
> - u64 rxrle; /* 09 */
> - u64 rxorle; /* 10 */
> - u64 rxftl; /* 11 */
> - u64 rxjab; /* 12 */
> - u64 rxse; /* 13 */
> - u64 rxce; /* 14 */
> - u64 rxrf; /* 15 */
> - u64 rxfrag; /* 16 */
> - u64 rxuoc; /* 17 */
> - u64 rxcpf; /* 18 */
> - u64 rxsb; /* 19 */
> - u64 rxfd; /* 20 */
> - u64 rxoerr; /* 21 */
> - u64 rxaln; /* 22 */
> - u64 ducqpn; /* 23 */
> - u64 reserved0; /* 24 */
> - u64 rxmcp; /* 25 */
> - u64 rxbcp; /* 26 */
> - u64 txmcp; /* 27 */
> - u64 txbcp; /* 28 */
> - u64 txo; /* 29 */
> - u64 tx64; /* 30 */
> - u64 tx65; /* 31 */
> - u64 tx128; /* 32 */
> - u64 tx256; /* 33 */
> - u64 tx512; /* 34 */
> - u64 tx1024; /* 35 */
> - u64 txbfcs; /* 36 */
> - u64 txcpf; /* 37 */
> - u64 txlf; /* 38 */
> - u64 txrf; /* 39 */
> - u64 txime; /* 40 */
> - u64 txsc; /* 41 */
> - u64 txmc; /* 42 */
> - u64 txsqe; /* 43 */
> - u64 txdef; /* 44 */
> - u64 txlcol; /* 45 */
> - u64 txexcol; /* 46 */
> - u64 txcse; /* 47 */
> - u64 txbor; /* 48 */
> -};
> -
> -#define H_PORT_CB7_DUCQPN 0x8000000000000000ULL
> -
> -struct hcp_ehea_port_cb7 {
> - u64 def_uc_qpn;
> -};
> -
> -u64 ehea_h_query_ehea_qp(const u64 adapter_handle,
> - const u8 qp_category,
> - const u64 qp_handle, const u64 sel_mask,
> - void *cb_addr);
> -
> -u64 ehea_h_modify_ehea_qp(const u64 adapter_handle,
> - const u8 cat,
> - const u64 qp_handle,
> - const u64 sel_mask,
> - void *cb_addr,
> - u64 *inv_attr_id,
> - u64 *proc_mask, u16 *out_swr, u16 *out_rwr);
> -
> -u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
> - struct ehea_eq_attr *eq_attr, u64 *eq_handle);
> -
> -u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
> - struct ehea_cq_attr *cq_attr,
> - u64 *cq_handle, struct h_epas *epas);
> -
> -u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
> - struct ehea_qp_init_attr *init_attr,
> - const u32 pd,
> - u64 *qp_handle, struct h_epas *h_epas);
> -
> -#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48, 55)
> -#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62, 63)
> -
> -u64 ehea_h_register_rpage(const u64 adapter_handle,
> - const u8 pagesize,
> - const u8 queue_type,
> - const u64 resource_handle,
> - const u64 log_pageaddr, u64 count);
> -
> -#define H_DISABLE_GET_EHEA_WQE_P 1
> -#define H_DISABLE_GET_SQ_WQE_P 2
> -#define H_DISABLE_GET_RQC 3
> -
> -u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle);
> -
> -#define FORCE_FREE 1
> -#define NORMAL_FREE 0
> -
> -u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
> - u64 force_bit);
> -
> -u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
> - const u64 length, const u32 access_ctrl,
> - const u32 pd, u64 *mr_handle, u32 *lkey);
> -
> -u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
> - const u8 pagesize, const u8 queue_type,
> - const u64 log_pageaddr, const u64 count);
> -
> -u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
> - const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
> - struct ehea_mr *mr);
> -
> -u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr);
> -
> -/* output param R5 */
> -#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40, 47)
> -#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48, 63)
> -
> -u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
> - const u8 cb_cat, const u64 select_mask,
> - void *cb_addr);
> -
> -u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
> - const u8 cb_cat, const u64 select_mask,
> - void *cb_addr);
> -
> -#define H_REGBCMC_PN EHEA_BMASK_IBM(48, 63)
> -#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(60, 63)
> -#define H_REGBCMC_MACADDR EHEA_BMASK_IBM(16, 63)
> -#define H_REGBCMC_VLANID EHEA_BMASK_IBM(52, 63)
> -
> -u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
> - const u8 reg_type, const u64 mc_mac_addr,
> - const u16 vlan_id, const u32 hcall_id);
> -
> -u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
> - const u64 event_mask);
> -
> -u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
> - void *rblock);
> -
> -#endif /* __EHEA_PHYP_H__ */
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
> deleted file mode 100644
> index 60629a0032b2..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
> +++ /dev/null
> @@ -1,999 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/mm.h>
> -#include <linux/slab.h>
> -#include "ehea.h"
> -#include "ehea_phyp.h"
> -#include "ehea_qmr.h"
> -
> -static struct ehea_bmap *ehea_bmap;
> -
> -static void *hw_qpageit_get_inc(struct hw_queue *queue)
> -{
> - void *retvalue = hw_qeit_get(queue);
> -
> - queue->current_q_offset += queue->pagesize;
> - if (queue->current_q_offset > queue->queue_length) {
> - queue->current_q_offset -= queue->pagesize;
> - retvalue = NULL;
> - } else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) {
> - pr_err("not on pageboundary\n");
> - retvalue = NULL;
> - }
> - return retvalue;
> -}
> -
> -static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
> - const u32 pagesize, const u32 qe_size)
> -{
> - int pages_per_kpage = PAGE_SIZE / pagesize;
> - int i, k;
> -
> - if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) {
> - pr_err("pagesize conflict! kernel pagesize=%d, ehea pagesize=%d\n",
> - (int)PAGE_SIZE, (int)pagesize);
> - return -EINVAL;
> - }
> -
> - queue->queue_length = nr_of_pages * pagesize;
> - queue->queue_pages = kmalloc_array(nr_of_pages, sizeof(void *),
> - GFP_KERNEL);
> - if (!queue->queue_pages)
> - return -ENOMEM;
> -
> - /*
> - * allocate pages for queue:
> - * outer loop allocates whole kernel pages (page aligned) and
> - * inner loop divides a kernel page into smaller hea queue pages
> - */
> - i = 0;
> - while (i < nr_of_pages) {
> - u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
> - if (!kpage)
> - goto out_nomem;
> - for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
> - (queue->queue_pages)[i] = (struct ehea_page *)kpage;
> - kpage += pagesize;
> - i++;
> - }
> - }
> -
> - queue->current_q_offset = 0;
> - queue->qe_size = qe_size;
> - queue->pagesize = pagesize;
> - queue->toggle_state = 1;
> -
> - return 0;
> -out_nomem:
> - for (i = 0; i < nr_of_pages; i += pages_per_kpage) {
> - if (!(queue->queue_pages)[i])
> - break;
> - free_page((unsigned long)(queue->queue_pages)[i]);
> - }
> - return -ENOMEM;
> -}
> -
> -static void hw_queue_dtor(struct hw_queue *queue)
> -{
> - int pages_per_kpage;
> - int i, nr_pages;
> -
> - if (!queue || !queue->queue_pages)
> - return;
> -
> - pages_per_kpage = PAGE_SIZE / queue->pagesize;
> -
> - nr_pages = queue->queue_length / queue->pagesize;
> -
> - for (i = 0; i < nr_pages; i += pages_per_kpage)
> - free_page((unsigned long)(queue->queue_pages)[i]);
> -
> - kfree(queue->queue_pages);
> -}
> -
> -struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
> - int nr_of_cqe, u64 eq_handle, u32 cq_token)
> -{
> - struct ehea_cq *cq;
> - u64 hret, rpage;
> - u32 counter;
> - int ret;
> - void *vpage;
> -
> - cq = kzalloc_obj(*cq);
> - if (!cq)
> - goto out_nomem;
> -
> - cq->attr.max_nr_of_cqes = nr_of_cqe;
> - cq->attr.cq_token = cq_token;
> - cq->attr.eq_handle = eq_handle;
> -
> - cq->adapter = adapter;
> -
> - hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr,
> - &cq->fw_handle, &cq->epas);
> - if (hret != H_SUCCESS) {
> - pr_err("alloc_resource_cq failed\n");
> - goto out_freemem;
> - }
> -
> - ret = hw_queue_ctor(&cq->hw_queue, cq->attr.nr_pages,
> - EHEA_PAGESIZE, sizeof(struct ehea_cqe));
> - if (ret)
> - goto out_freeres;
> -
> - for (counter = 0; counter < cq->attr.nr_pages; counter++) {
> - vpage = hw_qpageit_get_inc(&cq->hw_queue);
> - if (!vpage) {
> - pr_err("hw_qpageit_get_inc failed\n");
> - goto out_kill_hwq;
> - }
> -
> - rpage = __pa(vpage);
> - hret = ehea_h_register_rpage(adapter->handle,
> - 0, EHEA_CQ_REGISTER_ORIG,
> - cq->fw_handle, rpage, 1);
> - if (hret < H_SUCCESS) {
> - pr_err("register_rpage_cq failed ehea_cq=%p hret=%llx counter=%i act_pages=%i\n",
> - cq, hret, counter, cq->attr.nr_pages);
> - goto out_kill_hwq;
> - }
> -
> - if (counter == (cq->attr.nr_pages - 1)) {
> - vpage = hw_qpageit_get_inc(&cq->hw_queue);
> -
> - if ((hret != H_SUCCESS) || (vpage)) {
> - pr_err("registration of pages not complete hret=%llx\n",
> - hret);
> - goto out_kill_hwq;
> - }
> - } else {
> - if (hret != H_PAGE_REGISTERED) {
> - pr_err("CQ: registration of page failed hret=%llx\n",
> - hret);
> - goto out_kill_hwq;
> - }
> - }
> - }
> -
> - hw_qeit_reset(&cq->hw_queue);
> - ehea_reset_cq_ep(cq);
> - ehea_reset_cq_n1(cq);
> -
> - return cq;
> -
> -out_kill_hwq:
> - hw_queue_dtor(&cq->hw_queue);
> -
> -out_freeres:
> - ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE);
> -
> -out_freemem:
> - kfree(cq);
> -
> -out_nomem:
> - return NULL;
> -}
> -
> -static u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
> -{
> - u64 hret;
> - u64 adapter_handle = cq->adapter->handle;
> -
> - /* deregister all previous registered pages */
> - hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
> - if (hret != H_SUCCESS)
> - return hret;
> -
> - hw_queue_dtor(&cq->hw_queue);
> - kfree(cq);
> -
> - return hret;
> -}
> -
> -int ehea_destroy_cq(struct ehea_cq *cq)
> -{
> - u64 hret, aer, aerr;
> - if (!cq)
> - return 0;
> -
> - hcp_epas_dtor(&cq->epas);
> - hret = ehea_destroy_cq_res(cq, NORMAL_FREE);
> - if (hret == H_R_STATE) {
> - ehea_error_data(cq->adapter, cq->fw_handle, &aer, &aerr);
> - hret = ehea_destroy_cq_res(cq, FORCE_FREE);
> - }
> -
> - if (hret != H_SUCCESS) {
> - pr_err("destroy CQ failed\n");
> - return -EIO;
> - }
> -
> - return 0;
> -}
> -
> -struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
> - const enum ehea_eq_type type,
> - const u32 max_nr_of_eqes, const u8 eqe_gen)
> -{
> - int ret, i;
> - u64 hret, rpage;
> - void *vpage;
> - struct ehea_eq *eq;
> -
> - eq = kzalloc_obj(*eq);
> - if (!eq)
> - return NULL;
> -
> - eq->adapter = adapter;
> - eq->attr.type = type;
> - eq->attr.max_nr_of_eqes = max_nr_of_eqes;
> - eq->attr.eqe_gen = eqe_gen;
> - spin_lock_init(&eq->spinlock);
> -
> - hret = ehea_h_alloc_resource_eq(adapter->handle,
> - &eq->attr, &eq->fw_handle);
> - if (hret != H_SUCCESS) {
> - pr_err("alloc_resource_eq failed\n");
> - goto out_freemem;
> - }
> -
> - ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages,
> - EHEA_PAGESIZE, sizeof(struct ehea_eqe));
> - if (ret) {
> - pr_err("can't allocate eq pages\n");
> - goto out_freeres;
> - }
> -
> - for (i = 0; i < eq->attr.nr_pages; i++) {
> - vpage = hw_qpageit_get_inc(&eq->hw_queue);
> - if (!vpage) {
> - pr_err("hw_qpageit_get_inc failed\n");
> - hret = H_RESOURCE;
> - goto out_kill_hwq;
> - }
> -
> - rpage = __pa(vpage);
> -
> - hret = ehea_h_register_rpage(adapter->handle, 0,
> - EHEA_EQ_REGISTER_ORIG,
> - eq->fw_handle, rpage, 1);
> -
> - if (i == (eq->attr.nr_pages - 1)) {
> - /* last page */
> - vpage = hw_qpageit_get_inc(&eq->hw_queue);
> - if ((hret != H_SUCCESS) || (vpage))
> - goto out_kill_hwq;
> -
> - } else {
> - if (hret != H_PAGE_REGISTERED)
> - goto out_kill_hwq;
> -
> - }
> - }
> -
> - hw_qeit_reset(&eq->hw_queue);
> - return eq;
> -
> -out_kill_hwq:
> - hw_queue_dtor(&eq->hw_queue);
> -
> -out_freeres:
> - ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE);
> -
> -out_freemem:
> - kfree(eq);
> - return NULL;
> -}
> -
> -struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
> -{
> - struct ehea_eqe *eqe;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&eq->spinlock, flags);
> - eqe = hw_eqit_eq_get_inc_valid(&eq->hw_queue);
> - spin_unlock_irqrestore(&eq->spinlock, flags);
> -
> - return eqe;
> -}
> -
> -static u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
> -{
> - u64 hret;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&eq->spinlock, flags);
> -
> - hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force);
> - spin_unlock_irqrestore(&eq->spinlock, flags);
> -
> - if (hret != H_SUCCESS)
> - return hret;
> -
> - hw_queue_dtor(&eq->hw_queue);
> - kfree(eq);
> -
> - return hret;
> -}
> -
> -int ehea_destroy_eq(struct ehea_eq *eq)
> -{
> - u64 hret, aer, aerr;
> - if (!eq)
> - return 0;
> -
> - hcp_epas_dtor(&eq->epas);
> -
> - hret = ehea_destroy_eq_res(eq, NORMAL_FREE);
> - if (hret == H_R_STATE) {
> - ehea_error_data(eq->adapter, eq->fw_handle, &aer, &aerr);
> - hret = ehea_destroy_eq_res(eq, FORCE_FREE);
> - }
> -
> - if (hret != H_SUCCESS) {
> - pr_err("destroy EQ failed\n");
> - return -EIO;
> - }
> -
> - return 0;
> -}
> -
> -/* allocates memory for a queue and registers pages in phyp */
> -static int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
> - int nr_pages, int wqe_size, int act_nr_sges,
> - struct ehea_adapter *adapter, int h_call_q_selector)
> -{
> - u64 hret, rpage;
> - int ret, cnt;
> - void *vpage;
> -
> - ret = hw_queue_ctor(hw_queue, nr_pages, EHEA_PAGESIZE, wqe_size);
> - if (ret)
> - return ret;
> -
> - for (cnt = 0; cnt < nr_pages; cnt++) {
> - vpage = hw_qpageit_get_inc(hw_queue);
> - if (!vpage) {
> - pr_err("hw_qpageit_get_inc failed\n");
> - goto out_kill_hwq;
> - }
> - rpage = __pa(vpage);
> - hret = ehea_h_register_rpage(adapter->handle,
> - 0, h_call_q_selector,
> - qp->fw_handle, rpage, 1);
> - if (hret < H_SUCCESS) {
> - pr_err("register_rpage_qp failed\n");
> - goto out_kill_hwq;
> - }
> - }
> - hw_qeit_reset(hw_queue);
> - return 0;
> -
> -out_kill_hwq:
> - hw_queue_dtor(hw_queue);
> - return -EIO;
> -}
> -
> -static inline u32 map_wqe_size(u8 wqe_enc_size)
> -{
> - return 128 << wqe_enc_size;
> -}
> -
> -struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
> - u32 pd, struct ehea_qp_init_attr *init_attr)
> -{
> - int ret;
> - u64 hret;
> - struct ehea_qp *qp;
> - u32 wqe_size_in_bytes_sq, wqe_size_in_bytes_rq1;
> - u32 wqe_size_in_bytes_rq2, wqe_size_in_bytes_rq3;
> -
> -
> - qp = kzalloc_obj(*qp);
> - if (!qp)
> - return NULL;
> -
> - qp->adapter = adapter;
> -
> - hret = ehea_h_alloc_resource_qp(adapter->handle, init_attr, pd,
> - &qp->fw_handle, &qp->epas);
> - if (hret != H_SUCCESS) {
> - pr_err("ehea_h_alloc_resource_qp failed\n");
> - goto out_freemem;
> - }
> -
> - wqe_size_in_bytes_sq = map_wqe_size(init_attr->act_wqe_size_enc_sq);
> - wqe_size_in_bytes_rq1 = map_wqe_size(init_attr->act_wqe_size_enc_rq1);
> - wqe_size_in_bytes_rq2 = map_wqe_size(init_attr->act_wqe_size_enc_rq2);
> - wqe_size_in_bytes_rq3 = map_wqe_size(init_attr->act_wqe_size_enc_rq3);
> -
> - ret = ehea_qp_alloc_register(qp, &qp->hw_squeue, init_attr->nr_sq_pages,
> - wqe_size_in_bytes_sq,
> - init_attr->act_wqe_size_enc_sq, adapter,
> - 0);
> - if (ret) {
> - pr_err("can't register for sq ret=%x\n", ret);
> - goto out_freeres;
> - }
> -
> - ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue1,
> - init_attr->nr_rq1_pages,
> - wqe_size_in_bytes_rq1,
> - init_attr->act_wqe_size_enc_rq1,
> - adapter, 1);
> - if (ret) {
> - pr_err("can't register for rq1 ret=%x\n", ret);
> - goto out_kill_hwsq;
> - }
> -
> - if (init_attr->rq_count > 1) {
> - ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue2,
> - init_attr->nr_rq2_pages,
> - wqe_size_in_bytes_rq2,
> - init_attr->act_wqe_size_enc_rq2,
> - adapter, 2);
> - if (ret) {
> - pr_err("can't register for rq2 ret=%x\n", ret);
> - goto out_kill_hwr1q;
> - }
> - }
> -
> - if (init_attr->rq_count > 2) {
> - ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue3,
> - init_attr->nr_rq3_pages,
> - wqe_size_in_bytes_rq3,
> - init_attr->act_wqe_size_enc_rq3,
> - adapter, 3);
> - if (ret) {
> - pr_err("can't register for rq3 ret=%x\n", ret);
> - goto out_kill_hwr2q;
> - }
> - }
> -
> - qp->init_attr = *init_attr;
> -
> - return qp;
> -
> -out_kill_hwr2q:
> - hw_queue_dtor(&qp->hw_rqueue2);
> -
> -out_kill_hwr1q:
> - hw_queue_dtor(&qp->hw_rqueue1);
> -
> -out_kill_hwsq:
> - hw_queue_dtor(&qp->hw_squeue);
> -
> -out_freeres:
> - ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
> - ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE);
> -
> -out_freemem:
> - kfree(qp);
> - return NULL;
> -}
> -
> -static u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
> -{
> - u64 hret;
> - struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
> -
> -
> - ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
> - hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
> - if (hret != H_SUCCESS)
> - return hret;
> -
> - hw_queue_dtor(&qp->hw_squeue);
> - hw_queue_dtor(&qp->hw_rqueue1);
> -
> - if (qp_attr->rq_count > 1)
> - hw_queue_dtor(&qp->hw_rqueue2);
> - if (qp_attr->rq_count > 2)
> - hw_queue_dtor(&qp->hw_rqueue3);
> - kfree(qp);
> -
> - return hret;
> -}
> -
> -int ehea_destroy_qp(struct ehea_qp *qp)
> -{
> - u64 hret, aer, aerr;
> - if (!qp)
> - return 0;
> -
> - hcp_epas_dtor(&qp->epas);
> -
> - hret = ehea_destroy_qp_res(qp, NORMAL_FREE);
> - if (hret == H_R_STATE) {
> - ehea_error_data(qp->adapter, qp->fw_handle, &aer, &aerr);
> - hret = ehea_destroy_qp_res(qp, FORCE_FREE);
> - }
> -
> - if (hret != H_SUCCESS) {
> - pr_err("destroy QP failed\n");
> - return -EIO;
> - }
> -
> - return 0;
> -}
> -
> -static inline int ehea_calc_index(unsigned long i, unsigned long s)
> -{
> - return (i >> s) & EHEA_INDEX_MASK;
> -}
> -
> -static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap,
> - int dir)
> -{
> - if (!ehea_top_bmap->dir[dir]) {
> - ehea_top_bmap->dir[dir] =
> - kzalloc_obj(struct ehea_dir_bmap);
> - if (!ehea_top_bmap->dir[dir])
> - return -ENOMEM;
> - }
> - return 0;
> -}
> -
> -static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir)
> -{
> - if (!ehea_bmap->top[top]) {
> - ehea_bmap->top[top] =
> - kzalloc_obj(struct ehea_top_bmap);
> - if (!ehea_bmap->top[top])
> - return -ENOMEM;
> - }
> - return ehea_init_top_bmap(ehea_bmap->top[top], dir);
> -}
> -
> -static DEFINE_MUTEX(ehea_busmap_mutex);
> -static unsigned long ehea_mr_len;
> -
> -#define EHEA_BUSMAP_ADD_SECT 1
> -#define EHEA_BUSMAP_REM_SECT 0
> -
> -static void ehea_rebuild_busmap(void)
> -{
> - u64 vaddr = EHEA_BUSMAP_START;
> - int top, dir, idx;
> -
> - for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
> - struct ehea_top_bmap *ehea_top;
> - int valid_dir_entries = 0;
> -
> - if (!ehea_bmap->top[top])
> - continue;
> - ehea_top = ehea_bmap->top[top];
> - for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
> - struct ehea_dir_bmap *ehea_dir;
> - int valid_entries = 0;
> -
> - if (!ehea_top->dir[dir])
> - continue;
> - valid_dir_entries++;
> - ehea_dir = ehea_top->dir[dir];
> - for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
> - if (!ehea_dir->ent[idx])
> - continue;
> - valid_entries++;
> - ehea_dir->ent[idx] = vaddr;
> - vaddr += EHEA_SECTSIZE;
> - }
> - if (!valid_entries) {
> - ehea_top->dir[dir] = NULL;
> - kfree(ehea_dir);
> - }
> - }
> - if (!valid_dir_entries) {
> - ehea_bmap->top[top] = NULL;
> - kfree(ehea_top);
> - }
> - }
> -}
> -
> -static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add)
> -{
> - unsigned long i, start_section, end_section;
> -
> - if (!nr_pages)
> - return 0;
> -
> - if (!ehea_bmap) {
> - ehea_bmap = kzalloc_obj(struct ehea_bmap);
> - if (!ehea_bmap)
> - return -ENOMEM;
> - }
> -
> - start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE;
> - end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE);
> - /* Mark entries as valid or invalid only; address is assigned later */
> - for (i = start_section; i < end_section; i++) {
> - u64 flag;
> - int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
> - int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
> - int idx = i & EHEA_INDEX_MASK;
> -
> - if (add) {
> - int ret = ehea_init_bmap(ehea_bmap, top, dir);
> - if (ret)
> - return ret;
> - flag = 1; /* valid */
> - ehea_mr_len += EHEA_SECTSIZE;
> - } else {
> - if (!ehea_bmap->top[top])
> - continue;
> - if (!ehea_bmap->top[top]->dir[dir])
> - continue;
> - flag = 0; /* invalid */
> - ehea_mr_len -= EHEA_SECTSIZE;
> - }
> -
> - ehea_bmap->top[top]->dir[dir]->ent[idx] = flag;
> - }
> - ehea_rebuild_busmap(); /* Assign contiguous addresses for mr */
> - return 0;
> -}
> -
> -int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages)
> -{
> - int ret;
> -
> - mutex_lock(&ehea_busmap_mutex);
> - ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT);
> - mutex_unlock(&ehea_busmap_mutex);
> - return ret;
> -}
> -
> -int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages)
> -{
> - int ret;
> -
> - mutex_lock(&ehea_busmap_mutex);
> - ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_REM_SECT);
> - mutex_unlock(&ehea_busmap_mutex);
> - return ret;
> -}
> -
> -static int ehea_is_hugepage(unsigned long pfn)
> -{
> - if (pfn & EHEA_HUGEPAGE_PFN_MASK)
> - return 0;
> -
> - if (page_shift(pfn_to_page(pfn)) != EHEA_HUGEPAGESHIFT)
> - return 0;
> -
> - return 1;
> -}
> -
> -static int ehea_create_busmap_callback(unsigned long initial_pfn,
> - unsigned long total_nr_pages, void *arg)
> -{
> - int ret;
> - unsigned long pfn, start_pfn, end_pfn, nr_pages;
> -
> - if ((total_nr_pages * PAGE_SIZE) < EHEA_HUGEPAGE_SIZE)
> - return ehea_update_busmap(initial_pfn, total_nr_pages,
> - EHEA_BUSMAP_ADD_SECT);
> -
> - /* Given chunk is >= 16GB -> check for hugepages */
> - start_pfn = initial_pfn;
> - end_pfn = initial_pfn + total_nr_pages;
> - pfn = start_pfn;
> -
> - while (pfn < end_pfn) {
> - if (ehea_is_hugepage(pfn)) {
> - /* Add mem found in front of the hugepage */
> - nr_pages = pfn - start_pfn;
> - ret = ehea_update_busmap(start_pfn, nr_pages,
> - EHEA_BUSMAP_ADD_SECT);
> - if (ret)
> - return ret;
> -
> - /* Skip the hugepage */
> - pfn += (EHEA_HUGEPAGE_SIZE / PAGE_SIZE);
> - start_pfn = pfn;
> - } else
> - pfn += (EHEA_SECTSIZE / PAGE_SIZE);
> - }
> -
> - /* Add mem found behind the hugepage(s) */
> - nr_pages = pfn - start_pfn;
> - return ehea_update_busmap(start_pfn, nr_pages, EHEA_BUSMAP_ADD_SECT);
> -}
> -
> -int ehea_create_busmap(void)
> -{
> - int ret;
> -
> - mutex_lock(&ehea_busmap_mutex);
> - ehea_mr_len = 0;
> - ret = walk_system_ram_range(0, 1ULL << MAX_PHYSMEM_BITS, NULL,
> - ehea_create_busmap_callback);
> - mutex_unlock(&ehea_busmap_mutex);
> - return ret;
> -}
> -
> -void ehea_destroy_busmap(void)
> -{
> - int top, dir;
> - mutex_lock(&ehea_busmap_mutex);
> - if (!ehea_bmap)
> - goto out_destroy;
> -
> - for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
> - if (!ehea_bmap->top[top])
> - continue;
> -
> - for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
> - if (!ehea_bmap->top[top]->dir[dir])
> - continue;
> -
> - kfree(ehea_bmap->top[top]->dir[dir]);
> - }
> -
> - kfree(ehea_bmap->top[top]);
> - }
> -
> - kfree(ehea_bmap);
> - ehea_bmap = NULL;
> -out_destroy:
> - mutex_unlock(&ehea_busmap_mutex);
> -}
> -
> -u64 ehea_map_vaddr(void *caddr)
> -{
> - int top, dir, idx;
> - unsigned long index, offset;
> -
> - if (!ehea_bmap)
> - return EHEA_INVAL_ADDR;
> -
> - index = __pa(caddr) >> SECTION_SIZE_BITS;
> - top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK;
> - if (!ehea_bmap->top[top])
> - return EHEA_INVAL_ADDR;
> -
> - dir = (index >> EHEA_DIR_INDEX_SHIFT) & EHEA_INDEX_MASK;
> - if (!ehea_bmap->top[top]->dir[dir])
> - return EHEA_INVAL_ADDR;
> -
> - idx = index & EHEA_INDEX_MASK;
> - if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
> - return EHEA_INVAL_ADDR;
> -
> - offset = (unsigned long)caddr & (EHEA_SECTSIZE - 1);
> - return ehea_bmap->top[top]->dir[dir]->ent[idx] | offset;
> -}
> -
> -static inline void *ehea_calc_sectbase(int top, int dir, int idx)
> -{
> - unsigned long ret = idx;
> - ret |= dir << EHEA_DIR_INDEX_SHIFT;
> - ret |= top << EHEA_TOP_INDEX_SHIFT;
> - return __va(ret << SECTION_SIZE_BITS);
> -}
> -
> -static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
> - struct ehea_adapter *adapter,
> - struct ehea_mr *mr)
> -{
> - void *pg;
> - u64 j, m, hret;
> - unsigned long k = 0;
> - u64 pt_abs = __pa(pt);
> -
> - void *sectbase = ehea_calc_sectbase(top, dir, idx);
> -
> - for (j = 0; j < (EHEA_PAGES_PER_SECTION / EHEA_MAX_RPAGE); j++) {
> -
> - for (m = 0; m < EHEA_MAX_RPAGE; m++) {
> - pg = sectbase + ((k++) * EHEA_PAGESIZE);
> - pt[m] = __pa(pg);
> - }
> - hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0,
> - 0, pt_abs, EHEA_MAX_RPAGE);
> -
> - if ((hret != H_SUCCESS) &&
> - (hret != H_PAGE_REGISTERED)) {
> - ehea_h_free_resource(adapter->handle, mr->handle,
> - FORCE_FREE);
> - pr_err("register_rpage_mr failed\n");
> - return hret;
> - }
> - }
> - return hret;
> -}
> -
> -static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt,
> - struct ehea_adapter *adapter,
> - struct ehea_mr *mr)
> -{
> - u64 hret = H_SUCCESS;
> - int idx;
> -
> - for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
> - if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
> - continue;
> -
> - hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
> - if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
> - return hret;
> - }
> - return hret;
> -}
> -
> -static u64 ehea_reg_mr_dir_sections(int top, u64 *pt,
> - struct ehea_adapter *adapter,
> - struct ehea_mr *mr)
> -{
> - u64 hret = H_SUCCESS;
> - int dir;
> -
> - for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
> - if (!ehea_bmap->top[top]->dir[dir])
> - continue;
> -
> - hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
> - if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
> - return hret;
> - }
> - return hret;
> -}
> -
> -int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
> -{
> - int ret;
> - u64 *pt;
> - u64 hret;
> - u32 acc_ctrl = EHEA_MR_ACC_CTRL;
> -
> - unsigned long top;
> -
> - pt = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!pt) {
> - pr_err("no mem\n");
> - ret = -ENOMEM;
> - goto out;
> - }
> -
> - hret = ehea_h_alloc_resource_mr(adapter->handle, EHEA_BUSMAP_START,
> - ehea_mr_len, acc_ctrl, adapter->pd,
> - &mr->handle, &mr->lkey);
> -
> - if (hret != H_SUCCESS) {
> - pr_err("alloc_resource_mr failed\n");
> - ret = -EIO;
> - goto out;
> - }
> -
> - if (!ehea_bmap) {
> - ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
> - pr_err("no busmap available\n");
> - ret = -EIO;
> - goto out;
> - }
> -
> - for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
> - if (!ehea_bmap->top[top])
> - continue;
> -
> - hret = ehea_reg_mr_dir_sections(top, pt, adapter, mr);
> - if((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
> - break;
> - }
> -
> - if (hret != H_SUCCESS) {
> - ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
> - pr_err("registering mr failed\n");
> - ret = -EIO;
> - goto out;
> - }
> -
> - mr->vaddr = EHEA_BUSMAP_START;
> - mr->adapter = adapter;
> - ret = 0;
> -out:
> - free_page((unsigned long)pt);
> - return ret;
> -}
> -
> -int ehea_rem_mr(struct ehea_mr *mr)
> -{
> - u64 hret;
> -
> - if (!mr || !mr->adapter)
> - return -EINVAL;
> -
> - hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
> - FORCE_FREE);
> - if (hret != H_SUCCESS) {
> - pr_err("destroy MR failed\n");
> - return -EIO;
> - }
> -
> - return 0;
> -}
> -
> -int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
> - struct ehea_mr *shared_mr)
> -{
> - u64 hret;
> -
> - hret = ehea_h_register_smr(adapter->handle, old_mr->handle,
> - old_mr->vaddr, EHEA_MR_ACC_CTRL,
> - adapter->pd, shared_mr);
> - if (hret != H_SUCCESS)
> - return -EIO;
> -
> - shared_mr->adapter = adapter;
> -
> - return 0;
> -}
> -
> -static void print_error_data(u64 *data)
> -{
> - int length;
> - u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
> - u64 resource = data[1];
> -
> - length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]);
> -
> - if (length > EHEA_PAGESIZE)
> - length = EHEA_PAGESIZE;
> -
> - if (type == EHEA_AER_RESTYPE_QP)
> - pr_err("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, port=%llX\n",
> - resource, data[6], data[12], data[22]);
> - else if (type == EHEA_AER_RESTYPE_CQ)
> - pr_err("CQ (resource=%llX) state: AER=0x%llX\n",
> - resource, data[6]);
> - else if (type == EHEA_AER_RESTYPE_EQ)
> - pr_err("EQ (resource=%llX) state: AER=0x%llX\n",
> - resource, data[6]);
> -
> - ehea_dump(data, length, "error data");
> -}
> -
> -u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
> - u64 *aer, u64 *aerr)
> -{
> - unsigned long ret;
> - u64 *rblock;
> - u64 type = 0;
> -
> - rblock = (void *)get_zeroed_page(GFP_KERNEL);
> - if (!rblock) {
> - pr_err("Cannot allocate rblock memory\n");
> - goto out;
> - }
> -
> - ret = ehea_h_error_data(adapter->handle, res_handle, rblock);
> -
> - if (ret == H_SUCCESS) {
> - type = EHEA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
> - *aer = rblock[6];
> - *aerr = rblock[12];
> - print_error_data(rblock);
> - } else if (ret == H_R_STATE) {
> - pr_err("No error data available: %llX\n", res_handle);
> - } else
> - pr_err("Error data could not be fetched: %llX\n", res_handle);
> -
> - free_page((unsigned long)rblock);
> -out:
> - return type;
> -}
> diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.h b/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
> deleted file mode 100644
> index 7c7cccd820f7..000000000000
> --- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
> +++ /dev/null
> @@ -1,390 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-or-later */
> -/*
> - * linux/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
> - *
> - * eHEA ethernet device driver for IBM eServer System p
> - *
> - * (C) Copyright IBM Corp. 2006
> - *
> - * Authors:
> - * Christoph Raisch <raisch@de.ibm.com>
> - * Jan-Bernd Themann <themann@de.ibm.com>
> - * Thomas Klein <tklein@de.ibm.com>
> - */
> -
> -#ifndef __EHEA_QMR_H__
> -#define __EHEA_QMR_H__
> -
> -#include <linux/prefetch.h>
> -#include "ehea.h"
> -#include "ehea_hw.h"
> -
> -/*
> - * page size of ehea hardware queues
> - */
> -
> -#define EHEA_PAGESHIFT 12
> -#define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT)
> -#define EHEA_SECTSIZE (1UL << 24)
> -#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT)
> -#define EHEA_HUGEPAGESHIFT 34
> -#define EHEA_HUGEPAGE_SIZE (1UL << EHEA_HUGEPAGESHIFT)
> -#define EHEA_HUGEPAGE_PFN_MASK ((EHEA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT)
> -
> -#if ((1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE)
> -#error eHEA module cannot work if kernel sectionsize < ehea sectionsize
> -#endif
> -
> -/* Some abbreviations used here:
> - *
> - * WQE - Work Queue Entry
> - * SWQE - Send Work Queue Entry
> - * RWQE - Receive Work Queue Entry
> - * CQE - Completion Queue Entry
> - * EQE - Event Queue Entry
> - * MR - Memory Region
> - */
> -
> -/* Use of WR_ID field for EHEA */
> -#define EHEA_WR_ID_COUNT EHEA_BMASK_IBM(0, 19)
> -#define EHEA_WR_ID_TYPE EHEA_BMASK_IBM(20, 23)
> -#define EHEA_SWQE2_TYPE 0x1
> -#define EHEA_SWQE3_TYPE 0x2
> -#define EHEA_RWQE2_TYPE 0x3
> -#define EHEA_RWQE3_TYPE 0x4
> -#define EHEA_WR_ID_INDEX EHEA_BMASK_IBM(24, 47)
> -#define EHEA_WR_ID_REFILL EHEA_BMASK_IBM(48, 63)
> -
> -struct ehea_vsgentry {
> - u64 vaddr;
> - u32 l_key;
> - u32 len;
> -};
> -
> -/* maximum number of sg entries allowed in a WQE */
> -#define EHEA_MAX_WQE_SG_ENTRIES 252
> -#define SWQE2_MAX_IMM (0xD0 - 0x30)
> -#define SWQE3_MAX_IMM 224
> -
> -/* tx control flags for swqe */
> -#define EHEA_SWQE_CRC 0x8000
> -#define EHEA_SWQE_IP_CHECKSUM 0x4000
> -#define EHEA_SWQE_TCP_CHECKSUM 0x2000
> -#define EHEA_SWQE_TSO 0x1000
> -#define EHEA_SWQE_SIGNALLED_COMPLETION 0x0800
> -#define EHEA_SWQE_VLAN_INSERT 0x0400
> -#define EHEA_SWQE_IMM_DATA_PRESENT 0x0200
> -#define EHEA_SWQE_DESCRIPTORS_PRESENT 0x0100
> -#define EHEA_SWQE_WRAP_CTL_REC 0x0080
> -#define EHEA_SWQE_WRAP_CTL_FORCE 0x0040
> -#define EHEA_SWQE_BIND 0x0020
> -#define EHEA_SWQE_PURGE 0x0010
> -
> -/* sizeof(struct ehea_swqe) less the union */
> -#define SWQE_HEADER_SIZE 32
> -
> -struct ehea_swqe {
> - u64 wr_id;
> - u16 tx_control;
> - u16 vlan_tag;
> - u8 reserved1;
> - u8 ip_start;
> - u8 ip_end;
> - u8 immediate_data_length;
> - u8 tcp_offset;
> - u8 reserved2;
> - u16 reserved2b;
> - u8 wrap_tag;
> - u8 descriptors; /* number of valid descriptors in WQE */
> - u16 reserved3;
> - u16 reserved4;
> - u16 mss;
> - u32 reserved5;
> - union {
> - /* Send WQE Format 1 */
> - struct {
> - struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
> - } no_immediate_data;
> -
> - /* Send WQE Format 2 */
> - struct {
> - struct ehea_vsgentry sg_entry;
> - /* 0x30 */
> - u8 immediate_data[SWQE2_MAX_IMM];
> - /* 0xd0 */
> - struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
> - } immdata_desc __packed;
> -
> - /* Send WQE Format 3 */
> - struct {
> - u8 immediate_data[SWQE3_MAX_IMM];
> - } immdata_nodesc;
> - } u;
> -};
> -
> -struct ehea_rwqe {
> - u64 wr_id; /* work request ID */
> - u8 reserved1[5];
> - u8 data_segments;
> - u16 reserved2;
> - u64 reserved3;
> - u64 reserved4;
> - struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
> -};
> -
> -#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
> -
> -#define EHEA_CQE_TYPE_RQ 0x60
> -#define EHEA_CQE_STAT_ERR_MASK 0x700F
> -#define EHEA_CQE_STAT_FAT_ERR_MASK 0xF
> -#define EHEA_CQE_BLIND_CKSUM 0x8000
> -#define EHEA_CQE_STAT_ERR_TCP 0x4000
> -#define EHEA_CQE_STAT_ERR_IP 0x2000
> -#define EHEA_CQE_STAT_ERR_CRC 0x1000
> -
> -/* Defines which bad send cqe stati lead to a port reset */
> -#define EHEA_CQE_STAT_RESET_MASK 0x0002
> -
> -struct ehea_cqe {
> - u64 wr_id; /* work request ID from WQE */
> - u8 type;
> - u8 valid;
> - u16 status;
> - u16 reserved1;
> - u16 num_bytes_transfered;
> - u16 vlan_tag;
> - u16 inet_checksum_value;
> - u8 reserved2;
> - u8 header_length;
> - u16 reserved3;
> - u16 page_offset;
> - u16 wqe_count;
> - u32 qp_token;
> - u32 timestamp;
> - u32 reserved4;
> - u64 reserved5[3];
> -};
> -
> -#define EHEA_EQE_VALID EHEA_BMASK_IBM(0, 0)
> -#define EHEA_EQE_IS_CQE EHEA_BMASK_IBM(1, 1)
> -#define EHEA_EQE_IDENTIFIER EHEA_BMASK_IBM(2, 7)
> -#define EHEA_EQE_QP_CQ_NUMBER EHEA_BMASK_IBM(8, 31)
> -#define EHEA_EQE_QP_TOKEN EHEA_BMASK_IBM(32, 63)
> -#define EHEA_EQE_CQ_TOKEN EHEA_BMASK_IBM(32, 63)
> -#define EHEA_EQE_KEY EHEA_BMASK_IBM(32, 63)
> -#define EHEA_EQE_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
> -#define EHEA_EQE_EQ_NUMBER EHEA_BMASK_IBM(48, 63)
> -#define EHEA_EQE_SM_ID EHEA_BMASK_IBM(48, 63)
> -#define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55)
> -#define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
> -
> -#define EHEA_AER_RESTYPE_QP 0x8
> -#define EHEA_AER_RESTYPE_CQ 0x4
> -#define EHEA_AER_RESTYPE_EQ 0x3
> -
> -/* Defines which affiliated errors lead to a port reset */
> -#define EHEA_AER_RESET_MASK 0xFFFFFFFFFEFFFFFFULL
> -#define EHEA_AERR_RESET_MASK 0xFFFFFFFFFFFFFFFFULL
> -
> -struct ehea_eqe {
> - u64 entry;
> -};
> -
> -#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52, 63)
> -#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0, 7)
> -
> -static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
> -{
> - struct ehea_page *current_page;
> -
> - if (q_offset >= queue->queue_length)
> - q_offset -= queue->queue_length;
> - current_page = (queue->queue_pages)[q_offset >> EHEA_PAGESHIFT];
> - return ¤t_page->entries[q_offset & (EHEA_PAGESIZE - 1)];
> -}
> -
> -static inline void *hw_qeit_get(struct hw_queue *queue)
> -{
> - return hw_qeit_calc(queue, queue->current_q_offset);
> -}
> -
> -static inline void hw_qeit_inc(struct hw_queue *queue)
> -{
> - queue->current_q_offset += queue->qe_size;
> - if (queue->current_q_offset >= queue->queue_length) {
> - queue->current_q_offset = 0;
> - /* toggle the valid flag */
> - queue->toggle_state = (~queue->toggle_state) & 1;
> - }
> -}
> -
> -static inline void *hw_qeit_get_inc(struct hw_queue *queue)
> -{
> - void *retvalue = hw_qeit_get(queue);
> - hw_qeit_inc(queue);
> - return retvalue;
> -}
> -
> -static inline void *hw_qeit_get_inc_valid(struct hw_queue *queue)
> -{
> - struct ehea_cqe *retvalue = hw_qeit_get(queue);
> - u8 valid = retvalue->valid;
> - void *pref;
> -
> - if ((valid >> 7) == (queue->toggle_state & 1)) {
> - /* this is a good one */
> - hw_qeit_inc(queue);
> - pref = hw_qeit_calc(queue, queue->current_q_offset);
> - prefetch(pref);
> - prefetch(pref + 128);
> - } else
> - retvalue = NULL;
> - return retvalue;
> -}
> -
> -static inline void *hw_qeit_get_valid(struct hw_queue *queue)
> -{
> - struct ehea_cqe *retvalue = hw_qeit_get(queue);
> - void *pref;
> - u8 valid;
> -
> - pref = hw_qeit_calc(queue, queue->current_q_offset);
> - prefetch(pref);
> - prefetch(pref + 128);
> - prefetch(pref + 256);
> - valid = retvalue->valid;
> - if (!((valid >> 7) == (queue->toggle_state & 1)))
> - retvalue = NULL;
> - return retvalue;
> -}
> -
> -static inline void *hw_qeit_reset(struct hw_queue *queue)
> -{
> - queue->current_q_offset = 0;
> - return hw_qeit_get(queue);
> -}
> -
> -static inline void *hw_qeit_eq_get_inc(struct hw_queue *queue)
> -{
> - u64 last_entry_in_q = queue->queue_length - queue->qe_size;
> - void *retvalue;
> -
> - retvalue = hw_qeit_get(queue);
> - queue->current_q_offset += queue->qe_size;
> - if (queue->current_q_offset > last_entry_in_q) {
> - queue->current_q_offset = 0;
> - queue->toggle_state = (~queue->toggle_state) & 1;
> - }
> - return retvalue;
> -}
> -
> -static inline void *hw_eqit_eq_get_inc_valid(struct hw_queue *queue)
> -{
> - void *retvalue = hw_qeit_get(queue);
> - u32 qe = *(u8 *)retvalue;
> - if ((qe >> 7) == (queue->toggle_state & 1))
> - hw_qeit_eq_get_inc(queue);
> - else
> - retvalue = NULL;
> - return retvalue;
> -}
> -
> -static inline struct ehea_rwqe *ehea_get_next_rwqe(struct ehea_qp *qp,
> - int rq_nr)
> -{
> - struct hw_queue *queue;
> -
> - if (rq_nr == 1)
> - queue = &qp->hw_rqueue1;
> - else if (rq_nr == 2)
> - queue = &qp->hw_rqueue2;
> - else
> - queue = &qp->hw_rqueue3;
> -
> - return hw_qeit_get_inc(queue);
> -}
> -
> -static inline struct ehea_swqe *ehea_get_swqe(struct ehea_qp *my_qp,
> - int *wqe_index)
> -{
> - struct hw_queue *queue = &my_qp->hw_squeue;
> - struct ehea_swqe *wqe_p;
> -
> - *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_SQ);
> - wqe_p = hw_qeit_get_inc(&my_qp->hw_squeue);
> -
> - return wqe_p;
> -}
> -
> -static inline void ehea_post_swqe(struct ehea_qp *my_qp, struct ehea_swqe *swqe)
> -{
> - iosync();
> - ehea_update_sqa(my_qp, 1);
> -}
> -
> -static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
> -{
> - struct hw_queue *queue = &qp->hw_rqueue1;
> -
> - *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_RQ1);
> - return hw_qeit_get_valid(queue);
> -}
> -
> -static inline void ehea_inc_cq(struct ehea_cq *cq)
> -{
> - hw_qeit_inc(&cq->hw_queue);
> -}
> -
> -static inline void ehea_inc_rq1(struct ehea_qp *qp)
> -{
> - hw_qeit_inc(&qp->hw_rqueue1);
> -}
> -
> -static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
> -{
> - return hw_qeit_get_valid(&my_cq->hw_queue);
> -}
> -
> -#define EHEA_CQ_REGISTER_ORIG 0
> -#define EHEA_EQ_REGISTER_ORIG 0
> -
> -enum ehea_eq_type {
> - EHEA_EQ = 0, /* event queue */
> - EHEA_NEQ /* notification event queue */
> -};
> -
> -struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
> - enum ehea_eq_type type,
> - const u32 length, const u8 eqe_gen);
> -
> -int ehea_destroy_eq(struct ehea_eq *eq);
> -
> -struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq);
> -
> -struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
> - u64 eq_handle, u32 cq_token);
> -
> -int ehea_destroy_cq(struct ehea_cq *cq);
> -
> -struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter, u32 pd,
> - struct ehea_qp_init_attr *init_attr);
> -
> -int ehea_destroy_qp(struct ehea_qp *qp);
> -
> -int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr);
> -
> -int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
> - struct ehea_mr *shared_mr);
> -
> -int ehea_rem_mr(struct ehea_mr *mr);
> -
> -u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
> - u64 *aer, u64 *aerr);
> -
> -int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages);
> -int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages);
> -int ehea_create_busmap(void);
> -void ehea_destroy_busmap(void);
> -u64 ehea_map_vaddr(void *caddr);
> -
> -#endif /* __EHEA_QMR_H__ */
> --
> 2.47.3
>
^ permalink raw reply
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
From: Jiri Slaby @ 2026-06-30 5:42 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
skhan, federico.vaga, carlos.bilbao, avadhut.naik, alexs,
si.yanteng, dzm91, 2023002089, tsbogend, dsahern, jani.nikula,
mchehab+huawei, gregkh, tytso, herbert, ebiggers, johannes.berg,
geert, pablo, tglx, mashiro.chen, mingo, dqfext, jreuter, sdf,
pkshih, enelsonmoore, mkl, toke, kees, crossd, jlayton,
wangliang74, aha310510, takamitz, kuniyu, linux-doc, linux-mips
In-Reply-To: <20260629152930.4c2131ed@kernel.org>
On 30. 06. 26, 0:29, Jakub Kicinski wrote:
> On Mon, 29 Jun 2026 07:24:51 +0200 Jiri Slaby wrote:
>> And net-tools are broken by the uapi/linux/rose.h removal:
>> rose.c:39:10: fatal error: linux/rose.h: No such file or directory
>> at:
>> https://github.com/ecki/net-tools/blob/2ab3c5efdb5c220bc9a649fded56c361136bff1a/lib/rose.c#L39
>
> Looks like the code for rose is already well separated from the rest.
> Should we just ask net-tools to delete it? Or do you feel strongly
> about restoring the now-defunct header?
No strong opinion from me. net-tools are easy to fix.
The builds of LLVMs (versions 15 to 21 at least) are broken nonetheless.
They are easy to fix as well -- by backporting the fix from main or 22.
(15--21 are likely unmaintained upstream already, but still
used/required widely).
$ osc whatdependson openSUSE:Factory llvm19 standard x86_64
llvm19 :
MozillaThunderbird
firefox-esr
ghc
gtkd
ldc
lfortran
python-PyMuPDF
redumper
tilix
zig0.14
$ osc whatdependson openSUSE:Factory llvm21 standard x86_64
llvm21 :
OpenImageDenoise
chromium
embree
ispc
leechcraft
python-PyMuPDF
python314
python314:base
python314:doc
python315
python315:base
python315:doc
rpcs3
rust-keylime
zig0.16
thanks,
--
js
suse labs
^ permalink raw reply
* Re: [PATCH net] net/smc: fix UAF in smc_cdc_rx_handler() by pinning the socket
From: Sidraya Jayagond @ 2026-06-30 5:39 UTC (permalink / raw)
To: Xiang Mei, D . Wythe, Dust Li, Wenjia Zhang, Mahanta Jambigi,
Tony Lu, Wen Gu, netdev
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Hans Wippel, linux-rdma, linux-s390, Weiming Shi
In-Reply-To: <20260627014948.3049512-1-xmei5@asu.edu>
On 27/06/26 7:19 am, Xiang Mei wrote:
> smc_cdc_rx_handler() looks up the connection by token under the link
> group's conns_lock, drops the lock, and then dereferences conn and the
> smc_sock derived from it, ending in sock_hold(&smc->sk) inside
> smc_cdc_msg_recv(). No reference is held across the lock release.
>
> The only reference pinning the socket while the connection is
> discoverable in the link group is taken in smc_lgr_register_conn()
> (sock_hold) and dropped in __smc_lgr_unregister_conn() (sock_put), both
> under conns_lock. Once the handler drops conns_lock, a concurrent
> close() -> smc_release() -> smc_conn_free() -> smc_lgr_unregister_conn()
> can drop that reference and free the smc_sock, so the handler's later
> sock_hold() runs on freed memory:
>
> WARNING: lib/refcount.c:25 at refcount_warn_saturate
> Workqueue: rxe_wq do_work
> refcount_warn_saturate (lib/refcount.c:25)
> smc_cdc_msg_recv (net/smc/smc_cdc.c:430)
> smc_cdc_rx_handler (net/smc/smc_cdc.c:502)
> smc_wr_rx_tasklet_fn (net/smc/smc_wr.c:445)
> tasklet_action_common (kernel/softirq.c:938)
> handle_softirqs (kernel/softirq.c:622)
> Kernel panic - not syncing: panic_on_warn set
>
> Only SMC-R is affected. The SMC-D receive tasklet is stopped by
> tasklet_kill(&conn->rx_tsklet) in smc_conn_free() before the connection
> is unregistered, so it cannot run concurrently with the free.
>
> Take the socket reference while still holding conns_lock, so the
> registration reference can no longer be the last one, and drop it once
> the handler is done.
>
> Fixes: d7b0e37c1ac1 ("net/smc: restructure CDC message reception")
> Reported-by: Weiming Shi <bestswngs@gmail.com>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Xiang Mei <xmei5@asu.edu>
> ---
> net/smc/smc_cdc.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c
> index 619b3bab3824..b809139d7e87 100644
> --- a/net/smc/smc_cdc.c
> +++ b/net/smc/smc_cdc.c
> @@ -483,21 +483,27 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf)
> lgr = smc_get_lgr(link);
> read_lock_bh(&lgr->conns_lock);
> conn = smc_lgr_find_conn(ntohl(cdc->token), lgr);
> + if (conn && !conn->out_of_sync)
> + sock_hold(&container_of(conn, struct smc_sock, conn)->sk);
> + else
> + conn = NULL;
> read_unlock_bh(&lgr->conns_lock);
> - if (!conn || conn->out_of_sync)
> + if (!conn)
> return;
> smc = container_of(conn, struct smc_sock, conn);
>
Fix looks correct.
A few nits on the implementation:
container_of() is called twice for the same conn. The conn = NULL
sentinel and the second post unlock check can also be dropped. Flip the
condition, early return inside the lock, compute smc once:
if (!conn || conn->out_of_sync) {
read_unlock_bh(&lgr->conns_lock);
return;
}
smc = container_of(conn, struct smc_sock, conn);
sock_hold(&smc->sk);
read_unlock_bh(&lgr->conns_lock);
Also please initialize smc = NULL at declaration, it's not a bug now
since the early return guards it, just to make it refactor safe.
> if (cdc->prod_flags.failover_validation) {
> smc_cdc_msg_validate(smc, cdc, link);
> - return;
> + goto out;
> }
> if (smc_cdc_before(ntohs(cdc->seqno),
> conn->local_rx_ctrl.seqno))
> /* received seqno is old */
> - return;
> + goto out;
>
> smc_cdc_msg_recv(smc, cdc);
> +out:
> + sock_put(&smc->sk);
> }
>
> static struct smc_wr_rx_handler smc_cdc_rx_handlers[] = {
^ permalink raw reply
* Re: [PATCH net v2 0/2] Fix to possible skb leak due to race condtion in tx path
From: Parthiban.Veerasooran @ 2026-06-30 5:38 UTC (permalink / raw)
To: Selvamani.Rajagopal
Cc: netdev, linux-kernel, andrew, andrew+netdev, pier.beruto, davem,
edumazet, kuba, pabeni
In-Reply-To: <20260626-fix-race-condition-and-crash-v2-0-b6c5c10e604f@onsemi.com>
Hi Selvamani,
On 26/06/26 9:05 pm, Selvamani Rajagopal via B4 Relay wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> Now the traffic is handled in threaded IRQ, and the
> disable_traffic flag is checked before handling the
> data, new race condition is exposed, in which
> buffer may leak, if threaded IRQ interrupts the
> trasmit path midway.
>
> With this change, disable_traffic and waiting_tx_skb
> pointer are protected by spin lock/unlock pair.
>
> This is highlighted in Sashiko review
> https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260611-level-trigger-v5-0-4533a9e85ce2%40onsemi.com
>
> Also on buffer overrun condition, probably due to loss of
> SPI data chunks, receive path doesn't see the expected
> data chunk with end_valid bit set. As a result, driver
> keeps adding data chunks to the skb before running out
> of space and kernel panic is seen.
>
> With this change, before adding data to the skb, if there
> is no space, skb is freed and driver starts looking for
> new frame by looking for a data chunk with start_valid
> bit set.
>
> [ 705.405490] skbuff: skb_over_panic: text:ffffffd2eb72a264 len:1600 put:64 head:ffffff804e5cdc40 data:ffffff804e5cdc80 tail:0x680 end:0x640 dev:eth1
> [ 705.405569] ------------[ cut here ]------------
> [ 705.405575] kernel BUG at net/core/skbuff.c:214!
> [ 705.405589] Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
>
> [ 6703.427690] Call trace:
> [ 705.925157] skb_panic+0x58/0x68 (P)
> [ 705.928726] skb_put+0x74/0x80
> [ 705.931772] oa_tc6_update_rx_skb+0x44/0x98 [oa_tc6_mod]
> [ 705.937084] oa_tc6_macphy_threaded_irq+0x3f4/0x900 [oa_tc6_mod]
> [ 705.943084] irq_thread_fn+0x34/0xb8
> [ 705.946654] irq_thread+0x1a0/0x300
> [ 705.950134] kthread+0x138/0x150
> [ 705.953356] ret_from_fork+0x10/0x20
>
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
> ---
> Changes in v2:
> - Improvment to how error -EAGAIN is handled. Took care of
> couple of use cases where start_bit and end_bit may be missing or
> repeated due to lost data chunks.
> - Protected handling of waiting_tx_skb pointer with spin lock
> - Link to v1: https://lore.kernel.org/r/20260621-fix-race-condition-and-crash-v1-0-87e290d9357f@onsemi.com
I performed a one-hour quick test using two instances of the LAN8651
MAC-PHY Click (Test Case 2), and it ran without any crashes. Thank you
for the fixes.
Best regards,
Parthiban V
>
> ---
> Selvamani Rajagopal (2):
> net: ethernet: oa_tc6: Protect skb pointer used by two different kernel instances
> net: ethernet: oa_tc6: Improvement in buffer overflow handling
>
> drivers/net/ethernet/oa_tc6.c | 91 ++++++++++++++++++++++++++++++-------------
> 1 file changed, 64 insertions(+), 27 deletions(-)
> ---
> base-commit: 805185b7c7a1069e407b6f7b3bc98e44d415f484
> change-id: 20260621-fix-race-condition-and-crash-94d055a665c4
>
> Best regards,
> --
> Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
>
>
^ permalink raw reply
* Re: [PATCH v3 3/3] drm/xe/xe_ras: Add error-event support for CRI
From: Raag Jadav @ 2026-06-30 5:20 UTC (permalink / raw)
To: Riana Tauro
Cc: intel-xe, dri-devel, netdev, aravind.iddamsetty, anshuman.gupta,
rodrigo.vivi, joonas.lahtinen, kuba, simona.vetter, airlied,
pratik.bari, joshua.santosh.ranjan, ashwin.kumar.kulkarni,
shubham.kumar, ravi.kishore.koppuravuri, maarten.lankhorst,
mallesh.koujalagi, soham.purkait
In-Reply-To: <20260622101716.3313496-8-riana.tauro@intel.com>
On Mon, Jun 22, 2026 at 03:47:20PM +0530, Riana Tauro wrote:
> Add error-event support for Correctable errors in CRI.
> error-event is reported to userspace for all errors that crossed
> threshold on receiving an interrupt for correctable errors.
...
> +static void ras_send_error_event(struct xe_device *xe, u8 severity, u8 component)
> +{
> + u8 drm_severity, drm_component;
> + u32 value;
> + int ret;
> +
> + drm_severity = xe_to_drm_ras_severity(severity);
> + if (drm_severity == DRM_XE_RAS_ERR_SEV_MAX)
> + return;
> +
> + drm_component = xe_to_drm_ras_component(component);
> + if (drm_component == DRM_XE_RAS_ERR_COMP_MAX)
> + return;
> +
> + ret = xe_ras_get_counter(xe, severity, component, &value);
> + if (ret)
> + return;
> +
> + xe_drm_ras_event(xe, drm_component, drm_severity, value, GFP_KERNEL);
> +}
> +
> void xe_ras_counter_threshold_crossed(struct xe_device *xe,
> struct xe_sysctrl_event_response *response)
> {
> @@ -152,6 +203,8 @@ void xe_ras_counter_threshold_crossed(struct xe_device *xe,
> severity = errors[id].common.severity;
> component = errors[id].common.component;
>
> + ras_send_error_event(xe, severity, component);
We already have error-value as part of the event, so this looks like
a lot of redundant duplicate events if threshold is set high enough.
I'm wondering if we use a local variable as a bitmap for components
(which we set here) and only send event for_each_set_bit() after the
loop?
Raag
> xe_warn(xe, "[RAS]: %s %s detected\n",
> comp_to_str(component), sev_to_str(severity));
> }
> --
> 2.47.1
>
^ permalink raw reply
* Re: [PATCH nf] netfilter: ip6t_ah: validate AH header length
From: Florian Westphal @ 2026-06-30 5:16 UTC (permalink / raw)
To: Zhixing Chen
Cc: Pablo Neira Ayuso, Phil Sutter, netfilter-devel, coreteam, netdev
In-Reply-To: <20260618125848.93550-1-running910@gmail.com>
Zhixing Chen <running910@gmail.com> wrote:
> ip6t_ah checks that the fixed AH header is present, then uses hdrlen to
> derive the advertised AH header length for matching.
>
> Return false if the skb does not contain the advertised AH header length.
> This avoids matching AH headers whose advertised length is not present in
> the skb.
>
> Signed-off-by: Zhixing Chen <running910@gmail.com>
> ---
>
> I noticed ip6t_hbh and ip6t_rt already do this advertised-length check
> for their IPv6 extension headers, so this keeps ip6t_ah in line with
> those matches.
Could you make a v2 that addresses
https://sashiko.dev/#/patchset/20260618125848.93550-1-running910%40gmail.com
?
We should not return false in matches for malformed packets without
also setting ->hotdrop = true.
^ permalink raw reply
* [PATCH net 9/9] netfilter: nftables: restrict checkum update offset
From: Florian Westphal @ 2026-06-30 4:52 UTC (permalink / raw)
To: netdev
Cc: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski,
netfilter-devel, pablo
In-Reply-To: <20260630045243.2657-1-fw@strlen.de>
After previous patch, writes to network header are restricted.
However, there is another way to manipulate the l3 header: The
checksum update function.
Restrict this for network header writes, only the ipv4 header is
allowed. This needs run-time checks because BRIDGE, INET, NETDEV
families can carry l3 headers other than IP.
checksum updates to the udp/tcp (l4) headers are not restricted.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/netfilter/nft_payload.c | 100 ++++++++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 9c974df59b42..391539a1ceaa 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -1000,6 +1000,83 @@ static bool nft_ll_write_ok(const struct nft_pktinfo *pkt, int offset)
return offset <= skb_network_offset(pkt->skb);
}
+static bool nft_payload_validate_inet_csum_offset(const struct nft_ctx *ctx,
+ const struct nft_payload_set *priv)
+{
+ switch (priv->base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ if (ctx->family == NFPROTO_IPV4) {
+ if (offsetof(struct iphdr, check) == priv->csum_offset)
+ return true;
+
+ return false;
+ }
+ return true; /* run time validation required */
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ if (priv->csum_flags) /* makes no sense, asks for "re-update" of L4 checksum */
+ return false;
+
+ /* no further check here; offset can't be negative so bogus
+ * offsets can corrupt L4 or payload but not l3 headers.
+ * We already allow arbitrary l4/inner payload writes.
+ */
+ return true;
+ case NFT_PAYLOAD_INNER_HEADER:
+ return true;
+ case NFT_PAYLOAD_TUN_HEADER:
+ break;
+ }
+
+ return false;
+}
+
+/* do not allow arbitrary network header mangling via bogus csum_off.
+ * We only support ipv4. Only NFPROTO_IPV4 can be checked from control
+ * plane.
+ */
+static bool nft_payload_csum_nh_write_ok(const struct nft_payload_set *priv,
+ const struct nft_pktinfo *pkt)
+{
+ switch (pkt->state->pf) {
+ case NFPROTO_IPV4:
+ /* Warning: NFPROTO_INET was not checked; we can't return true here. */
+ return priv->csum_offset == offsetof(struct iphdr, check);
+ case NFPROTO_IPV6:
+ return false;
+ case NFPROTO_BRIDGE:
+ return pkt->ethertype == htons(ETH_P_IP) &&
+ priv->csum_offset == offsetof(struct iphdr, check);
+ case NFPROTO_NETDEV:
+ return pkt->skb->protocol == htons(ETH_P_IP) &&
+ priv->csum_offset == offsetof(struct iphdr, check);
+ }
+
+ return false;
+}
+
+static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv)
+{
+ switch (priv->base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ return nft_payload_csum_nh_write_ok(priv, pkt);
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ case NFT_PAYLOAD_INNER_HEADER:
+ /* neither offsets are validated, offsets cannot be
+ * negative so real l3 headers cannot be mangled.
+ */
+ return true;
+ case NFT_PAYLOAD_TUN_HEADER:
+ break;
+ }
+
+ return false;
+}
+
static void nft_payload_set_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
@@ -1064,6 +1141,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
tsum = csum_partial(src, priv->len, 0);
if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
+ nft_payload_csum_write_ok(pkt, priv) &&
nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
goto err;
@@ -1130,7 +1208,26 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
switch (csum_type) {
case NFT_PAYLOAD_CSUM_NONE:
+ if (priv->csum_offset) /* nonsensical */
+ return -EINVAL;
+
+ if (priv->csum_flags == 0)
+ break;
+
+ /* Userspace requests L4 checksum update, e.g.:
+ * - IPv6 stateless NAT (no l3 csum)
+ * - transport header mangling
+ * - inner data mangling
+ */
+ if (priv->base == NFT_PAYLOAD_NETWORK_HEADER ||
+ priv->base == NFT_PAYLOAD_TRANSPORT_HEADER ||
+ priv->base == NFT_PAYLOAD_INNER_HEADER)
+ break;
+
+ return -EINVAL;
case NFT_PAYLOAD_CSUM_INET:
+ if (!nft_payload_validate_inet_csum_offset(ctx, priv))
+ return -EINVAL;
break;
case NFT_PAYLOAD_CSUM_SCTP:
if (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER)
@@ -1138,6 +1235,9 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
if (priv->csum_offset != offsetof(struct sctphdr, checksum))
return -EINVAL;
+
+ if (priv->csum_flags)
+ return -EINVAL;
break;
default:
return -EOPNOTSUPP;
--
2.53.0
^ permalink raw reply related
* [PATCH net 8/9] netfilter: nftables: restrict linklayer and network header writes
From: Florian Westphal @ 2026-06-30 4:52 UTC (permalink / raw)
To: netdev
Cc: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski,
netfilter-devel, pablo
In-Reply-To: <20260630045243.2657-1-fw@strlen.de>
Don't permit arbitrary writes to linklayer and network header data.
Several spots in network stack trust header validation performed in
ipv4/ipv6 before PRE_ROUTING hook.
For linklayer, allow writes for netdev ingress. For other hooks, only
allow link layer writes that do not spill into network header.
For network header, check the offset/length combinations:
- changing dscp requires store at offset 0 for checsum fixups, so
make sure ip version + length field isn't altered.
- ip6 dscp starts directly after the version field, so make sure it
remains 6.
Several of these checks could already be done at rule insertion time.
Risk is that this might cause ruleset load failures for existing
rulesets. With this change such writes are silently skipped and packet
passes unchanged.
Transport and inner header bases are not checked / restricted.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/netfilter/nft_payload.c | 170 ++++++++++++++++++++++++++++++++++++
1 file changed, 170 insertions(+)
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 345eff140d56..9c974df59b42 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -834,6 +834,172 @@ nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len,
return true;
}
+/* Ingress is very early, before l3 protocol handlers.
+ * There should be no in-tree code that trusts l3/l4 headers
+ * between ingress and NF_INET_PRE_ROUTING hooks.
+ */
+static bool nft_in_ingress(const struct nf_hook_state *s)
+{
+ return s->pf == NFPROTO_NETDEV && s->hook == NF_NETDEV_INGRESS;
+}
+
+static bool nft_nh_write_ok_ip4(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+ unsigned int offset = priv->offset + skb_network_offset(pkt->skb);
+ const u8 *new_octets = (const u8 *)src;
+ u8 old_octet;
+
+ switch (priv->offset) {
+ case 0: /* csum fixups does expand dscp/tos store to 2 bytes.
+ * make sure ihl/version remain unchanged.
+ */
+ if (skb_copy_bits(pkt->skb, offset, &old_octet, sizeof(old_octet)))
+ return false;
+
+ return priv->len == 2 &&
+ *new_octets == old_octet;
+ case offsetof(struct iphdr, tos):
+ return priv->len == 1;
+ case offsetof(struct iphdr, id):
+ return priv->len == 2;
+ case offsetof(struct iphdr, ttl):
+ if (priv->len == 1)
+ return true;
+
+ if (priv->len != 2)
+ return false;
+
+ /* same, csum fixup does expand ttl store to two bytes.
+ * check protocol is not altered.
+ */
+ if (skb_copy_bits(pkt->skb, offset + 1, &old_octet, sizeof(old_octet)))
+ return false;
+
+ return new_octets[1] == old_octet;
+ case offsetof(struct iphdr, check):
+ return priv->len <= 2 + 4 + 4;
+ case offsetof(struct iphdr, saddr):
+ return priv->len <= 4 + 4;
+ case offsetof(struct iphdr, daddr):
+ return priv->len <= 4;
+ }
+
+ return false;
+}
+
+static bool nft_nh_write_ok_ip6(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+ const struct ipv6hdr *ih = (const void *)src;
+
+ switch (priv->offset) {
+ case 0: /* store to dscp must not alter ip6 version */
+ return priv->len <= 4 && ih->version == 6;
+ case 2:
+ return priv->len <= 2;
+ case offsetof(struct ipv6hdr, hop_limit):
+ return priv->len == 1;
+ case offsetof(struct ipv6hdr, saddr):
+ return priv->len <= 16 + 16;
+ case offsetof(struct ipv6hdr, daddr):
+ return priv->len <= 16;
+ }
+
+ return false;
+}
+
+static bool nft_nh_write_ok_arp(const struct nft_payload_set *priv)
+{
+ /* Variable size for standard ethernet arp */
+ const unsigned int eth_ip = 2 * (ETH_ALEN + 4);
+ unsigned int offset = priv->offset;
+
+ switch (offset) {
+ case offsetof(struct arphdr, ar_op):
+ return priv->len == 2;
+ default:
+ break;
+ }
+
+ /* permit writes post fixed arp header size. offset + len are
+ * checked vs skb size via skb_ensure_writable.
+ */
+ return offset >= sizeof(struct arphdr) && priv->len <= eth_ip;
+}
+
+static bool nft_nh_write_ok_netdev(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+#ifdef CONFIG_NF_TABLES_NETDEV
+ switch (pkt->skb->protocol) {
+ case htons(ETH_P_ARP):
+ return nft_nh_write_ok_arp(priv);
+ case htons(ETH_P_IP):
+ return nft_nh_write_ok_ip4(pkt, priv, src);
+ case htons(ETH_P_IPV6):
+ return nft_nh_write_ok_ip6(pkt, priv, src);
+ }
+#endif
+ /* default to false for now, relax later in case we have
+ * use-cases that need inner header manipulation for
+ * encapsulated traffic like vlan or PPPoE.
+ */
+ return false;
+}
+
+static bool nft_nh_write_ok_bridge(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
+ switch (pkt->ethertype) {
+ case htons(ETH_P_ARP):
+ return nft_nh_write_ok_arp(priv);
+ case htons(ETH_P_IP):
+ return nft_nh_write_ok_ip4(pkt, priv, src);
+ case htons(ETH_P_IPV6):
+ return nft_nh_write_ok_ip6(pkt, priv, src);
+ }
+#endif
+ /* see nft_nh_write_ok_netdev: default to false */
+ return false;
+}
+
+static bool nft_nh_write_ok(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+ switch (pkt->state->pf) {
+ case NFPROTO_ARP:
+ return nft_nh_write_ok_arp(priv);
+ case NFPROTO_BRIDGE:
+ return nft_nh_write_ok_bridge(pkt, priv, src);
+ case NFPROTO_IPV4:
+ return nft_nh_write_ok_ip4(pkt, priv, src);
+ case NFPROTO_IPV6:
+ return nft_nh_write_ok_ip6(pkt, priv, src);
+ case NFPROTO_NETDEV:
+ if (pkt->state->hook == NF_NETDEV_INGRESS)
+ return true;
+ return nft_nh_write_ok_netdev(pkt, priv, src);
+ }
+
+ return false;
+}
+
+/* check linklayer modifications don't spill into network header. */
+static bool nft_ll_write_ok(const struct nft_pktinfo *pkt, int offset)
+{
+ if (nft_in_ingress(pkt->state))
+ return true;
+
+ return offset <= skb_network_offset(pkt->skb);
+}
+
static void nft_payload_set_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
@@ -861,8 +1027,12 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
}
offset = skb_mac_header(skb) - skb->data - vlan_hlen;
+ if (!nft_ll_write_ok(pkt, priv->len + priv->offset + offset))
+ goto err;
break;
case NFT_PAYLOAD_NETWORK_HEADER:
+ if (!nft_nh_write_ok(pkt, priv, src))
+ goto err;
offset = skb_network_offset(skb);
break;
case NFT_PAYLOAD_TRANSPORT_HEADER:
--
2.53.0
^ permalink raw reply related
* [PATCH net 7/9] netfilter: nfnetlink_queue: restrict writes to network header
From: Florian Westphal @ 2026-06-30 4:52 UTC (permalink / raw)
To: netdev
Cc: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski,
netfilter-devel, pablo
In-Reply-To: <20260630045243.2657-1-fw@strlen.de>
nfnetlink_queue doesn't allow selective replacements of some part of the
payload, only complete replacement.
If the new data is shorter, skb is trimmed, otherwise expanded.
Add minimal validation of the new ip/ipv6 header. Check total len
matches skb length. Disallow ip option modifications.
IPv6 extension headers are also disabled.
IP options and exthdrs could be allowed later after validation pass or
ip option recompile.
Transport header is not checked.
Bridge modifications are rejected. Given userspace doesn't even receive
L2 headers, use is limited and I don't think there are any users of
bridge nfnetlink_queue, let alone users that modifiy payload.
Arp isn't supported at all.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/netfilter/nfnetlink_queue.c | 170 ++++++++++++++++++++++++++++++++
1 file changed, 170 insertions(+)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 80ca077b81bd..35d4c6c628ff 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1184,6 +1184,173 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
return err;
}
+static bool nfqnl_validate_ipopts(const struct iphdr *iph_new,
+ const struct nf_queue_entry *e)
+{
+ const struct iphdr *iph_orig = ip_hdr(e->skb);
+ unsigned int ihl = iph_new->ihl * 4;
+
+ if (iph_new->ihl != iph_orig->ihl)
+ return false;
+ if (ihl == sizeof(*iph_orig))
+ return true;
+
+ return memcmp(iph_new + 1, ip_hdr(e->skb) + 1, ihl - sizeof(*iph_orig)) == 0;
+}
+
+static bool nfqnl_validate_ip4(const struct iphdr *iph, unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ unsigned int ihl;
+
+ if (data_len < sizeof(*iph))
+ return false;
+
+ ihl = iph->ihl * 4u;
+ if (ihl < sizeof(*iph) || data_len < ihl)
+ return false;
+
+ if (iph->version != 4 ||
+ ((iph->frag_off ^ ip_hdr(e->skb)->frag_off) & ~htons(IP_DF)) != 0)
+ return false;
+
+ /* BIG TCP won't work; netlink attr len is u16 */
+ if (ntohs(iph->tot_len) != data_len)
+ return false;
+
+ /* support for ipopts mangling would require
+ * recompile + skb transport header update.
+ */
+ return nfqnl_validate_ipopts(iph, e);
+}
+
+static bool nfqnl_validate_one_exthdr(const u8 *data,
+ unsigned int data_len,
+ const struct nf_queue_entry *e,
+ int start, int hdrlen)
+{
+ u16 octets;
+
+ if (data_len < hdrlen || hdrlen < 2)
+ return false;
+
+ while (hdrlen > 0) {
+ if (data_len < sizeof(octets))
+ return false;
+ data_len -= sizeof(octets);
+
+ if (skb_copy_bits(e->skb, start, &octets, sizeof(octets)))
+ return false;
+
+ if (hdrlen < sizeof(octets))
+ return false;
+
+ hdrlen -= sizeof(octets);
+ if (memcmp(data, &octets, sizeof(octets)))
+ return false;
+
+ start += sizeof(octets);
+ data += sizeof(octets);
+ }
+
+ return true;
+}
+
+static bool nfqnl_validate_exthdr(const struct ipv6hdr *ip6_new,
+ unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ const struct ipv6hdr *ip6_orig = ipv6_hdr(e->skb);
+ int exthdr_cnt = 0, start = sizeof(*ip6_orig);
+ const u8 *data = (const u8 *)ip6_new;
+ u8 orig_nexthdr = ip6_orig->nexthdr;
+ u8 new_nexthdr = ip6_new->nexthdr;
+
+ if (new_nexthdr != orig_nexthdr)
+ return false;
+
+ data += sizeof(*ip6_new);
+ data_len -= sizeof(*ip6_new);
+
+ while (ipv6_ext_hdr(orig_nexthdr)) {
+ const struct ipv6_opt_hdr *hp;
+ struct ipv6_opt_hdr _hdr;
+ int hdrlen;
+
+ if (orig_nexthdr == NEXTHDR_NONE)
+ return true;
+
+ if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT))
+ return false;
+
+ hp = skb_header_pointer(e->skb, start, sizeof(_hdr), &_hdr);
+ if (!hp)
+ return false;
+
+ switch (orig_nexthdr) {
+ case NEXTHDR_FRAGMENT:
+ hdrlen = sizeof(struct frag_hdr);
+ break;
+ case NEXTHDR_AUTH:
+ hdrlen = ipv6_authlen(hp);
+ break;
+ default:
+ hdrlen = ipv6_optlen(hp);
+ break;
+ }
+
+ if (!nfqnl_validate_one_exthdr(data, data_len, e,
+ start, hdrlen))
+ return false;
+
+ orig_nexthdr = hp->nexthdr;
+ hp = (const void *)data;
+ new_nexthdr = hp->nexthdr;
+
+ if (new_nexthdr != orig_nexthdr)
+ return false;
+
+ data_len -= hdrlen;
+ start += hdrlen;
+ data += hdrlen;
+ }
+
+ return true;
+}
+
+static bool nfqnl_validate_ip6(const struct ipv6hdr *ip6, unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ if (data_len < sizeof(*ip6))
+ return false;
+
+ /* BIG TCP/jumbograms won't work; netlink attr len is u16 */
+ if (ntohs(ip6->payload_len) != data_len - sizeof(*ip6))
+ return false;
+
+ if (ip6->version != 6)
+ return false;
+
+ return nfqnl_validate_exthdr(ip6, data_len, e);
+}
+
+static bool nfqnl_validate_write(const void *data, unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ switch (e->state.pf) {
+ case NFPROTO_IPV4:
+ return nfqnl_validate_ip4(data, data_len, e);
+ case NFPROTO_IPV6:
+ return nfqnl_validate_ip6(data, data_len, e) &&
+ !(IP6CB(e->skb)->flags & IP6SKB_JUMBOGRAM);
+ case NFPROTO_BRIDGE:
+ /* No write support. Bridge is dubious: userspace doesn't even see L2 header */
+ return false;
+ }
+
+ return false;
+}
+
static int
nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff)
{
@@ -1192,6 +1359,9 @@ nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int di
if (e->state.net->user_ns != &init_user_ns)
return -EPERM;
+ if (!nfqnl_validate_write(data, data_len, e))
+ return -EINVAL;
+
if (diff < 0) {
unsigned int min_len = skb_transport_offset(e->skb);
--
2.53.0
^ permalink raw reply related
* [PATCH net 6/9] netfilter: nft_fib: reject fib expression on the netdev egress hook
From: Florian Westphal @ 2026-06-30 4:52 UTC (permalink / raw)
To: netdev
Cc: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski,
netfilter-devel, pablo
In-Reply-To: <20260630045243.2657-1-fw@strlen.de>
From: Theodor Arsenij Larionov-Trichkine <theodorlarionov@gmail.com>
A fib expression in a netdev egress base chain dereferences nft_in(pkt),
NULL on the transmit path, causing a NULL pointer dereference at eval.
nft_fib_validate() masks the hook with NF_INET_* values, but netdev hook
numbers are a separate enum that aliases them (NF_NETDEV_EGRESS ==
NF_INET_LOCAL_IN), so an egress chain passes validation and then faults.
Add nft_fib_netdev_validate() that limits each result/flag to the netdev
hook where the device it reads exists: the input-device cases (OIF,
OIFNAME, ADDRTYPE with F_IIF) to ingress, the output-device case (ADDRTYPE
with F_OIF) to egress, ADDRTYPE with no device flag to both. Also restrict
nft_fib_validate() to NFPROTO_IPV4/IPV6/INET so its NF_INET_* masks are
not applied to another family's hooks.
Fixes: 42df6e1d221d ("netfilter: Introduce egress hook")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/netfilter-devel/ajxsjcDOnwllMfoR@strlen.de/
Signed-off-by: Theodor Arsenij Larionov-Trichkine <theodorlarionov@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/netfilter/nft_fib.c | 9 +++++++++
net/netfilter/nft_fib_netdev.c | 29 ++++++++++++++++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c
index e048f05694cd..89555380f1c5 100644
--- a/net/netfilter/nft_fib.c
+++ b/net/netfilter/nft_fib.c
@@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr)
const struct nft_fib *priv = nft_expr_priv(expr);
unsigned int hooks;
+ switch (ctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_INET:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
case NFT_FIB_RESULT_OIFNAME:
diff --git a/net/netfilter/nft_fib_netdev.c b/net/netfilter/nft_fib_netdev.c
index 3f3478abd845..5774a7544027 100644
--- a/net/netfilter/nft_fib_netdev.c
+++ b/net/netfilter/nft_fib_netdev.c
@@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr,
regs->verdict.code = NFT_BREAK;
}
+static int nft_fib_netdev_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr)
+{
+ const struct nft_fib *priv = nft_expr_priv(expr);
+ unsigned int hooks;
+
+ switch (priv->result) {
+ case NFT_FIB_RESULT_OIF:
+ case NFT_FIB_RESULT_OIFNAME:
+ hooks = (1 << NF_NETDEV_INGRESS);
+ break;
+ case NFT_FIB_RESULT_ADDRTYPE:
+ if (priv->flags & NFTA_FIB_F_IIF)
+ hooks = (1 << NF_NETDEV_INGRESS);
+ else if (priv->flags & NFTA_FIB_F_OIF)
+ hooks = (1 << NF_NETDEV_EGRESS);
+ else
+ hooks = (1 << NF_NETDEV_INGRESS) |
+ (1 << NF_NETDEV_EGRESS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return nft_chain_validate_hooks(ctx->chain, hooks);
+}
+
static struct nft_expr_type nft_fib_netdev_type;
static const struct nft_expr_ops nft_fib_netdev_ops = {
.type = &nft_fib_netdev_type,
@@ -57,7 +84,7 @@ static const struct nft_expr_ops nft_fib_netdev_ops = {
.eval = nft_fib_netdev_eval,
.init = nft_fib_init,
.dump = nft_fib_dump,
- .validate = nft_fib_validate,
+ .validate = nft_fib_netdev_validate,
};
static struct nft_expr_type nft_fib_netdev_type __read_mostly = {
--
2.53.0
^ permalink raw reply related
* [PATCH net 5/9] netfilter: nfnetlink_cthelper: cap to maximum number of expectation per master
From: Florian Westphal @ 2026-06-30 4:52 UTC (permalink / raw)
To: netdev
Cc: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski,
netfilter-devel, pablo
In-Reply-To: <20260630045243.2657-1-fw@strlen.de>
From: Pablo Neira Ayuso <pablo@netfilter.org>
If userspace helper policy updates sets maximum number of expectation to
zero, cap it to NF_CT_EXPECT_MAX_CNT (255) on updates too.
Fixes: 397c8300972f ("netfilter: nf_conntrack_helper: cap maximum number of expectation at helper registration")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/netfilter/nfnetlink_cthelper.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index f1460b683d7a..2cbcca9110db 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -163,6 +163,8 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
expect_policy->max_expected =
ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
+ if (!expect_policy->max_expected)
+ expect_policy->max_expected = NF_CT_EXPECT_MAX_CNT;
if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
return -EINVAL;
--
2.53.0
^ permalink raw reply related
* [PATCH net 4/9] netfilter: nf_conntrack_sip: validate skb_dst() before accessing it
From: Florian Westphal @ 2026-06-30 4:52 UTC (permalink / raw)
To: netdev
Cc: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski,
netfilter-devel, pablo
In-Reply-To: <20260630045243.2657-1-fw@strlen.de>
From: Pablo Neira Ayuso <pablo@netfilter.org>
tc ingress and openvswitch do not guarantee routing information to be
available. These subsystems use the conntrack helper infrastructure, and
the SIP helper relies on the skb_dst() to be present if
sip_external_media is set to 1 (which is disabled by default as a module
parameter).
This effectively disables the sip_external_media toggle for these
subsystems without resulting in a crash.
Fixes: cae3a2627520 ("openvswitch: Allow attaching helpers to ct action")
Fixes: b57dc7c13ea9 ("net/sched: Introduce action ct")
Cc: stable@vger.kernel.org
Reported-by: Ren Wei <n05ec@lzu.edu.cn>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/netfilter/nf_conntrack_sip.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 5ec3a4a4bbd7..f3f90a866338 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -956,7 +956,6 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
return NF_ACCEPT;
saddr = &ct->tuplehash[!dir].tuple.src.u3;
} else if (sip_external_media) {
- struct net_device *dev = skb_dst(skb)->dev;
struct dst_entry *dst = NULL;
struct flowi fl;
@@ -978,7 +977,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
* through the same interface as the signalling peer.
*/
if (dst) {
- bool external_media = (dst->dev == dev);
+ const struct dst_entry *this_dst = skb_dst(skb);
+ bool external_media = false;
+
+ if (this_dst && dst->dev == this_dst->dev)
+ external_media = true;
dst_release(dst);
if (external_media)
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox