Linux wireless drivers development
 help / color / mirror / Atom feed
From: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
To: <linux-wireless@vger.kernel.org>, <johannes@sipsolutions.net>
Cc: <arend.vanspriel@broadcom.com>,
	<wlan-kernel-dev-list@infineon.com>,
	<gokulkumar.sivakumar@infineon.com>
Subject: [PATCH wireless-next v3 10/25] wifi: inffmac: add dev_evt.c/h
Date: Wed, 2 Sep 2026 16:50:41 +0000	[thread overview]
Message-ID: <20260902165057.456447-11-gokulkumar.sivakumar@infineon.com> (raw)
In-Reply-To: <20260902165057.456447-1-gokulkumar.sivakumar@infineon.com>

Driver implementation for registering and handling various types of
asynchronous events generated by the CP or the WLAN firmware in the
Device.

Signed-off-by: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
---
 .../net/wireless/infineon/inffmac/dev_evt.c   | 847 ++++++++++++++++++
 .../net/wireless/infineon/inffmac/dev_evt.h   | 447 +++++++++
 2 files changed, 1294 insertions(+)
 create mode 100644 drivers/net/wireless/infineon/inffmac/dev_evt.c
 create mode 100644 drivers/net/wireless/infineon/inffmac/dev_evt.h

diff --git a/drivers/net/wireless/infineon/inffmac/dev_evt.c b/drivers/net/wireless/infineon/inffmac/dev_evt.c
new file mode 100644
index 000000000000..6d63ad4afab1
--- /dev/null
+++ b/drivers/net/wireless/infineon/inffmac/dev_evt.c
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Copyright (c) 2025-2026, Infineon Technologies AG, or an affiliate of Infineon Technologies AG.
+ * All rights reserved.
+ */
+#include <linux/netdevice.h>
+
+#include "main.h"
+#include "chan.h"
+#include "utils.h"
+#include "cfg80211.h"
+#include "debug.h"
+#include "dev_evt.h"
+#include "dev_cmd.h"
+#include "interface.h"
+#include "bus_proto.h"
+#include "net.h"
+
+/**
+ * struct inff_fwevt_queue_item - event item on event queue.
+ *
+ * @q: list element for queuing.
+ * @code: event code.
+ * @ifidx: interface index related to this event.
+ * @ifaddr: ethernet address for interface.
+ * @emsg: common parameters of the firmware event message.
+ * @datalen: length of the data array
+ * @data: event specific data part of the firmware event.
+ */
+struct inff_fwevt_queue_item {
+	struct list_head q;
+	enum inff_fwevt_code code;
+	u8 ifidx;
+	u8 ifaddr[ETH_ALEN];
+	struct inff_event_msg_be emsg;
+	u32 datalen;
+	u8 data[] __counted_by(datalen);
+};
+
+/*
+ * struct inff_fwevt_code_name - code, name mapping entry.
+ */
+struct inff_fwevt_code_name {
+	enum inff_fwevt_code code;
+	const char *name;
+};
+
+#ifdef DEBUG
+/* array for mapping code to event name */
+static struct inff_fwevt_code_name
+fwevt_names[] = {
+	{INFF_E_SET_SSID, "SET_SSID"},
+	{INFF_E_JOIN, "JOIN"},
+	{INFF_E_START, "START"},
+	{INFF_E_AUTH, "AUTH"},
+	{INFF_E_AUTH_IND, "AUTH_IND"},
+	{INFF_E_DEAUTH, "DEAUTH"},
+	{INFF_E_DEAUTH_IND, "DEAUTH_IND"},
+	{INFF_E_ASSOC, "ASSOC"},
+	{INFF_E_ASSOC_IND, "ASSOC_IND"},
+	{INFF_E_REASSOC, "REASSOC"},
+	{INFF_E_REASSOC_IND, "REASSOC_IND"},
+	{INFF_E_DISASSOC, "DISASSOC"},
+	{INFF_E_DISASSOC_IND, "DISASSOC_IND"},
+	{INFF_E_QUIET_START, "QUIET_START"},
+	{INFF_E_QUIET_END, "QUIET_END"},
+	{INFF_E_BEACON_RX, "BEACON_RX"},
+	{INFF_E_LINK, "LINK"},
+	{INFF_E_MIC_ERROR, "MIC_ERROR"},
+	{INFF_E_NDIS_LINK, "NDIS_LINK"},
+	{INFF_E_ROAM, "ROAM"},
+	{INFF_E_TXFAIL, "TXFAIL"},
+	{INFF_E_PMKID_CACHE, "PMKID_CACHE"},
+	{INFF_E_RETROGRADE_TSF, "RETROGRADE_TSF"},
+	{INFF_E_PRUNE, "PRUNE"},
+	{INFF_E_AUTOAUTH, "AUTOAUTH"},
+	{INFF_E_EAPOL_MSG, "EAPOL_MSG"},
+	{INFF_E_SCAN_COMPLETE, "SCAN_COMPLETE"},
+	{INFF_E_ADDTS_IND, "ADDTS_IND"},
+	{INFF_E_DELTS_IND, "DELTS_IND"},
+	{INFF_E_BCNSENT_IND, "BCNSENT_IND"},
+	{INFF_E_BCNRX_MSG, "BCNRX_MSG"},
+	{INFF_E_BCNLOST_MSG, "BCNLOST_MSG"},
+	{INFF_E_ROAM_PREP, "ROAM_PREP"},
+	{INFF_E_RESET_COMPLETE, "RESET_COMPLETE"},
+	{INFF_E_JOIN_START, "JOIN_START"},
+	{INFF_E_ROAM_START, "ROAM_START"},
+	{INFF_E_ASSOC_START, "ASSOC_START"},
+	{INFF_E_IBSS_ASSOC, "IBSS_ASSOC"},
+	{INFF_E_RADIO, "RADIO"},
+	{INFF_E_PSM_WATCHDOG, "PSM_WATCHDOG"},
+	{INFF_E_PROBREQ_MSG, "PROBREQ_MSG"},
+	{INFF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"},
+	{INFF_E_PSK_SUP, "PSK_SUP"},
+	{INFF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"},
+	{INFF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"},
+	{INFF_E_ICV_ERROR, "ICV_ERROR"},
+	{INFF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"},
+	{INFF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"},
+	{INFF_E_TRACE, "TRACE"},
+	{INFF_E_IF, "IF"},
+	{INFF_E_RSSI, "RSSI"},
+	{INFF_E_EXTLOG_MSG, "EXTLOG_MSG"},
+	{INFF_E_ACTION_FRAME, "ACTION_FRAME"},
+	{INFF_E_ACTION_FRAME_TX_COMPLETE, "ACTION_FRAME_TX_COMPLETE"},
+	{INFF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND"},
+	{INFF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND"},
+	{INFF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED"},
+	{INFF_E_AP_STARTED, "AP_STARTED"},
+	{INFF_E_DFS_AP_STOP, "DFS_AP_STOP"},
+	{INFF_E_DFS_AP_RESUME, "DFS_AP_RESUME"},
+	{INFF_E_ESCAN_RESULT, "ESCAN_RESULT"},
+	{INFF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRAME_OFF_CHAN_COMPLETE"},
+	{INFF_E_PROBERESP_MSG, "PROBERESP_MSG"},
+	{INFF_E_PROBEREQ_MSG, "PROBEREQ_MSG"},
+	{INFF_E_DCS_REQUEST, "DCS_REQUEST"},
+	{INFF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"},
+	{INFF_E_ACTION_FRAME_RX_COMPLETE, "ACTION_FRAME_RX_COMPLETE"},
+	{INFF_E_SA_COMPLETE_IND, "SA_COMPLETE_IND"},
+	{INFF_E_ASSOC_REQ_IE, "ASSOC_REQ_IE"},
+	{INFF_E_ASSOC_RESP_IE, "ASSOC_RESP_IE"},
+	{INFF_E_BCMC_CREDIT_SUPPORT, "BCMC_CREDIT_SUPPORT"},
+	{INFF_E_EXT_AUTH_REQ, "EXT_AUTH_REQ"},
+	{INFF_E_EXT_AUTH_FRAME_RX, "EXT_AUTH_FRAME_RX"},
+	{INFF_E_MGMT_FRAME_TXSTATUS, "MGMT_FRAME_TXSTATUS"},
+	{INFF_E_MGMT_FRAME_OFF_CHAN_COMPLETE, "MGMT_FRAME_OFF_CHAN_COMPLETE"},
+	{INFF_E_EXT_ASSOC_FRAME_RX, "EXT_ASSOC_FRAME_RX"},
+};
+
+/**
+ * inff_fwevt_name() - returns name for given event code.
+ *
+ * @code: code to lookup.
+ */
+const char *
+inff_fwevt_name(enum inff_fwevt_code code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fwevt_names); i++) {
+		if (fwevt_names[i].code == code)
+			return fwevt_names[i].name;
+	}
+	return "unknown";
+}
+#else
+const char *
+inff_fwevt_name(enum inff_fwevt_code code)
+{
+	return "nodebug";
+}
+#endif
+
+/**
+ * inff_fwevt_queue_event() - create and queue event.
+ *
+ * @fwevt: firmware event handling info.
+ * @event: event queue entry.
+ */
+static void
+inff_fwevt_queue_event(struct inff_fwevt_info *fwevt,
+		       struct inff_fwevt_queue_item *event)
+{
+	ulong flags;
+
+	spin_lock_irqsave(&fwevt->evt_q_lock, flags);
+	list_add_tail(&event->q, &fwevt->event_q);
+	spin_unlock_irqrestore(&fwevt->evt_q_lock, flags);
+	schedule_work(&fwevt->event_work);
+}
+
+/**
+ * inff_fwevt_dequeue_event() - get event from the queue.
+ *
+ * @fwevt: firmware event handling info.
+ */
+static struct inff_fwevt_queue_item *
+inff_fwevt_dequeue_event(struct inff_fwevt_info *fwevt)
+{
+	struct inff_fwevt_queue_item *event = NULL;
+	ulong flags;
+
+	spin_lock_irqsave(&fwevt->evt_q_lock, flags);
+	if (!list_empty(&fwevt->event_q)) {
+		event = list_first_entry(&fwevt->event_q,
+					 struct inff_fwevt_queue_item, q);
+		list_del(&event->q);
+	}
+	spin_unlock_irqrestore(&fwevt->evt_q_lock, flags);
+
+	return event;
+}
+
+/**
+ * inff_fwevt_event_worker() - firmware event worker.
+ *
+ * @work: worker object.
+ */
+static void
+inff_fwevt_event_worker(struct work_struct *work)
+{
+	struct inff_pub *drvr;
+	struct inff_if *ifp;
+	struct inff_fwevt_info *fwevt;
+	struct inff_fwevt_queue_item *event;
+	struct inff_event_msg_be *emsg_be;
+	struct inff_event_msg emsg;
+
+	fwevt = container_of(work, struct inff_fwevt_info, event_work);
+	drvr = container_of(fwevt, struct inff_pub, fwevt);
+
+	while ((event = inff_fwevt_dequeue_event(fwevt))) {
+		inff_dbg(DEVEVT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
+			 inff_fwevt_name(event->code), event->code,
+			 event->emsg.ifidx, event->emsg.bsscfgidx,
+			 event->emsg.addr);
+		if (event->emsg.bsscfgidx >= INFF_MAX_IFS) {
+			iphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx);
+			goto event_free;
+		}
+
+		/* convert event message */
+		emsg_be = &event->emsg;
+		emsg.version = be16_to_cpu(emsg_be->version);
+		emsg.flags = be16_to_cpu(emsg_be->flags);
+		emsg.event_code = event->code;
+		emsg.status = be32_to_cpu(emsg_be->status);
+		emsg.reason = be32_to_cpu(emsg_be->reason);
+		emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
+		emsg.datalen = be32_to_cpu(emsg_be->datalen);
+		memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
+		memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
+		emsg.ifidx = emsg_be->ifidx;
+		emsg.bsscfgidx = emsg_be->bsscfgidx;
+
+		inff_dbg(DEVEVT, "  version %u flags %u status %u reason %u\n",
+			 emsg.version, emsg.flags, emsg.status, emsg.reason);
+		inff_dbg_hex_dump(INFF_MSGLVL_ON(DEVEVT), event->data,
+				  min_t(u32, emsg.datalen, 64),
+				  "event payload, len=%d\n", emsg.datalen);
+
+		ifp = drvr->iflist[emsg.bsscfgidx];
+		if (!ifp)
+			ifp = inff_get_ifp(drvr, 0);
+
+		/* Call the registered event handler */
+		if (fwevt->evt_handler[event->code]) {
+			if (fwevt->evt_handler[event->code](ifp, &emsg, event->data))
+				iphy_err(drvr, "event handler failed (%d)\n",
+					 event->code);
+		} else {
+			iphy_err(drvr, "unhandled event %d ignored\n", event->code);
+		}
+event_free:
+		kfree(event);
+	}
+}
+
+/**
+ * inff_fwevt_attach() - initialize firmware event handling.
+ *
+ * @drvr: driver information object.
+ */
+void
+inff_fwevt_attach(struct inff_pub *drvr)
+{
+	struct inff_fwevt_info *fwevt = &drvr->fwevt;
+
+	INIT_WORK(&fwevt->event_work, inff_fwevt_event_worker);
+	spin_lock_init(&fwevt->evt_q_lock);
+	INIT_LIST_HEAD(&fwevt->event_q);
+}
+
+/**
+ * inff_fwevt_detach() - cleanup firmware event handling.
+ *
+ * @drvr: driver information object.
+ */
+void
+inff_fwevt_detach(struct inff_pub *drvr)
+{
+	struct inff_fwevt_info *fwevt = &drvr->fwevt;
+
+	/* cancel the worker if initialized */
+	if (fwevt->event_work.func) {
+		cancel_work_sync(&fwevt->event_work);
+		WARN_ON(!list_empty(&fwevt->event_q));
+		memset(fwevt->evt_handler, 0, sizeof(fwevt->evt_handler));
+	}
+}
+
+/**
+ * inff_fwevt_register() - register handler for given event code.
+ *
+ * @drvr: driver information object.
+ * @code: event code.
+ * @handler: handler for the given event code.
+ */
+int
+inff_fwevt_register(struct inff_pub *drvr, enum inff_fwevt_code code,
+		    inff_fwevt_handler_t handler)
+{
+	if (drvr->fwevt.evt_handler[code]) {
+		iphy_err(drvr, "event code %d already registered\n", code);
+		return -ENOSPC;
+	}
+	drvr->fwevt.evt_handler[code] = handler;
+	inff_dbg(TRACE, "event handler registered for %s\n",
+		 inff_fwevt_name(code));
+	return 0;
+}
+
+/**
+ * inff_fwevt_unregister() - remove handler for given code.
+ *
+ * @drvr: driver information object.
+ * @code: event code.
+ */
+void
+inff_fwevt_unregister(struct inff_pub *drvr,
+		      enum inff_fwevt_code code)
+{
+	inff_dbg(TRACE, "event handler cleared for %s\n",
+		 inff_fwevt_name(code));
+	drvr->fwevt.evt_handler[code] = NULL;
+}
+
+/**
+ * inff_fwevt_activate_events() - enables firmware events registered.
+ *
+ * @ifp: primary interface object.
+ */
+int
+inff_fwevt_activate_events(struct inff_if *ifp)
+{
+	struct inff_pub *drvr = ifp->drvr;
+	int i, err;
+	struct eventmsgs_ext *eventmask_msg;
+	u32 msglen;
+
+	msglen = EVENTMSGS_EXT_STRUCT_SIZE + INFF_EVENTING_MASK_LEN;
+	eventmask_msg = kzalloc(msglen, GFP_KERNEL);
+	if (!eventmask_msg)
+		return -ENOMEM;
+
+	for (i = 0; i < INFF_E_LAST; i++) {
+		if (ifp->drvr->fwevt.evt_handler[i]) {
+			inff_dbg(DEVEVT, "enable event %s\n",
+				 inff_fwevt_name(i));
+			setbit(eventmask_msg->mask, i);
+		}
+	}
+
+	/* want to handle IF event as well */
+	inff_dbg(DEVEVT, "enable event IF\n");
+	setbit(eventmask_msg->mask, INFF_E_IF);
+
+	eventmask_msg->ver = EVENTMSGS_VER;
+	eventmask_msg->command = EVENTMSGS_SET_MASK;
+	eventmask_msg->len = INFF_EVENTING_MASK_LEN;
+
+	err = inff_fwcmd_iovar_data_set(ifp, "event_msgs_ext", eventmask_msg,
+					msglen);
+	if (!err)
+		goto end;
+
+	err = inff_fwcmd_iovar_data_set(ifp, "event_msgs", eventmask_msg->mask,
+					INFF_EVENTING_MASK_LEN);
+	if (err)
+		iphy_err(drvr, "Set event_msgs error (%d)\n", err);
+
+end:
+	kfree(eventmask_msg);
+	return err;
+}
+
+/**
+ * inff_fwevt_process_event() - process skb as firmware event.
+ *
+ * @drvr: driver information object.
+ * @event_packet: event packet to process.
+ * @packet_len: length of the packet
+ * @gfp: memory allocation flags.
+ *
+ * If the packet buffer contains a firmware event message it will
+ * dispatch the event to a registered handler (using worker).
+ */
+void
+inff_fwevt_process_event(struct inff_pub *drvr,
+			 struct inff_event *event_packet,
+			 u32 packet_len, gfp_t gfp)
+{
+	enum inff_fwevt_code code;
+	struct inff_fwevt_info *fwevt = &drvr->fwevt;
+	struct inff_fwevt_queue_item *event;
+	void *data;
+	u32 datalen;
+
+	/* get event info */
+	code = get_unaligned_be32(&event_packet->msg.event_type);
+	datalen = get_unaligned_be32(&event_packet->msg.datalen);
+	data = &event_packet[1];
+
+	if (code >= INFF_E_LAST)
+		return;
+
+	if (code != INFF_E_IF && !fwevt->evt_handler[code])
+		return;
+
+	if (datalen > INFF_DCMD_MAXLEN ||
+	    datalen + sizeof(*event_packet) > packet_len)
+		return;
+
+	event = kzalloc_flex(*event, data, datalen, gfp);
+	if (!event)
+		return;
+
+	event->datalen = datalen;
+	event->code = code;
+	event->ifidx = event_packet->msg.ifidx;
+
+	/* use memcpy to get aligned event message */
+	memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
+	memcpy(event->data, data, datalen);
+	memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
+
+	inff_fwevt_queue_event(fwevt, event);
+}
+
+void
+inff_fwevt_process_skb(struct inff_pub *drvr, struct sk_buff *skb, u16 stype,
+		       gfp_t gfp)
+{
+	struct inff_event *event_packet;
+	u16 subtype, usr_stype;
+
+	/* only process events when protocol matches */
+	if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
+		return;
+
+	if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
+		return;
+
+	event_packet = (struct inff_event *)skb_mac_header(skb);
+
+	/* check subtype if needed */
+	if (unlikely(stype)) {
+		subtype = get_unaligned_be16(&event_packet->hdr.subtype);
+		if (subtype != stype)
+			return;
+	}
+
+	if (memcmp(INF_OUI, &event_packet->hdr.oui[0],
+		   sizeof(event_packet->hdr.oui)))
+		return;
+
+	/* final match on usr_subtype */
+	usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
+	if (usr_stype != INFILCP_INF_SUBTYPE_EVENT)
+		return;
+
+	inff_fwevt_process_event(drvr, event_packet, skb->len + ETH_HLEN, gfp);
+}
+
+static s32
+inff_notify_vif_event(struct inff_if *ifp, const struct inff_event_msg *e, void *data)
+{
+	struct inff_pub *drvr = ifp->drvr;
+	struct inff_cfg80211_info *cfg = drvr->config;
+	struct inff_if_event *ifevent = (struct inff_if_event *)data;
+	struct inff_cfg80211_vif_event *event = &cfg->vif_event;
+	struct inff_cfg80211_vif *vif;
+	enum nl80211_iftype iftype = NL80211_IFTYPE_UNSPECIFIED;
+	int err = 0;
+
+	inff_dbg(DEVEVT, "%s (%d) action: %u ifidx: %u bsscfgidx: %u flags: %u role: %u\n",
+		 inff_fwevt_name(e->event_code), e->event_code,
+		 ifevent->action, ifevent->ifidx, ifevent->bsscfgidx,
+		 ifevent->flags, ifevent->role);
+
+	if (ifevent->ifidx >= INFF_MAX_IFS) {
+		iphy_err(drvr, "Invalid interface index: %u\n", ifevent->ifidx);
+		return -EINVAL;
+	}
+
+	spin_lock(&event->vif_event_lock);
+	event->action = ifevent->action;
+	vif = event->vif;
+
+	switch (ifevent->action) {
+	case INFF_E_IF_ADD:
+		inff_dbg(DEVEVT, "adding %s (%pM) interface\n", e->ifname,
+			 e->addr);
+
+		switch (ifevent->role) {
+		case INFF_E_IF_ROLE_STA:
+			iftype = NL80211_IFTYPE_STATION;
+			break;
+		case INFF_E_IF_ROLE_AP:
+			iftype = NL80211_IFTYPE_AP;
+			break;
+		default:
+			iphy_err(drvr, "Invalid interface role: %d\n", ifevent->role);
+			spin_unlock(&event->vif_event_lock);
+			return -EINVAL;
+		}
+
+		if (ifevent->bsscfgidx >= INFF_MAX_IFS) {
+			iphy_err(drvr, "invalid bsscfg index: %u\n",
+				 ifevent->bsscfgidx);
+			spin_unlock(&event->vif_event_lock);
+			return -EINVAL;
+		}
+
+		ifp = drvr->iflist[ifevent->bsscfgidx];
+		if (ifp) {
+			if (ifevent->bsscfgidx == 0) {
+				inff_dbg(INFO,
+					 "ignore IF ADD event for existing primary interface %s\n",
+					 ifp->ndev->name);
+				spin_unlock(&event->vif_event_lock);
+				return 0;
+			}
+
+			/*
+			 * Remove the corresponding existing interface, to add it again,
+			 * incase if its INFF_E_IF_DEL event was missed earlier.
+			 */
+			iphy_err(drvr,
+				 "netdev:%s already exists, removing to add it again\n",
+				 ifp->ndev->name);
+			inff_net_del_if(drvr, ifp, false);
+		}
+
+		ifp = inff_net_add_if(drvr, ifevent->bsscfgidx, ifevent->ifidx,
+				      e->ifname, e->addr, iftype);
+		if (IS_ERR_OR_NULL(ifp)) {
+			iphy_err(drvr, "interface (role: %d) addition error (%ld)\n",
+				 ifevent->role, PTR_ERR(ifp));
+			spin_unlock(&event->vif_event_lock);
+			return PTR_ERR(ifp);
+		}
+
+		if (!vif) {
+			spin_unlock(&event->vif_event_lock);
+			/* Interface Add event may not be upon user request */
+			vif = inff_alloc_vif(cfg, iftype);
+			if (IS_ERR(vif)) {
+				inff_net_del_if(drvr, ifp, false);
+				return PTR_ERR(vif);
+			}
+		}
+
+		ifp->vif = vif;
+		vif->ifp = ifp;
+
+		if (ifp->ndev) {
+			vif->wdev.netdev = ifp->ndev;
+			ifp->ndev->ieee80211_ptr = &vif->wdev;
+			SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+		}
+
+		inff_proto_add_if(drvr, ifp);
+
+		spin_unlock(&event->vif_event_lock);
+		if (inff_vif_event_armed(cfg)) {
+			wake_up(&event->vif_wq);
+			break;
+		}
+
+		if (ifp->ndev) {
+			/* Interface Add event may not be upon user request */
+			err = inff_net_attach(ifp, false);
+			if (err) {
+				inff_err("netdevice register failed with err:%d\n",
+					 err);
+				inff_net_del_if(drvr, ifp, false);
+			}
+		}
+
+		break;
+	case INFF_E_IF_DEL:
+		inff_dbg(DEVEVT, "deleting %s (%pM) interface\n", e->ifname,
+			 e->addr);
+
+		spin_unlock(&event->vif_event_lock);
+		if (inff_vif_event_armed(cfg)) {
+			wake_up(&event->vif_wq);
+			break;
+		}
+
+		/* Interface Delete event may not be upon user request */
+		if (!ifp || ifp->bsscfgidx != ifevent->bsscfgidx)
+			break;
+
+		inff_net_del_if(drvr, ifp, false);
+
+		break;
+	case INFF_E_IF_CHANGE:
+		inff_dbg(DEVEVT, "changing %s (%pM) interface\n", e->ifname,
+			 e->addr);
+
+		inff_proto_reset_if(drvr, ifp);
+
+		spin_unlock(&event->vif_event_lock);
+		if (inff_vif_event_armed(cfg))
+			wake_up(&event->vif_wq);
+
+		break;
+	default:
+		err = -EINVAL;
+		spin_unlock(&event->vif_event_lock);
+		break;
+	}
+
+	return err;
+}
+
+void inff_fwevt_register_handlers(struct inff_cfg80211_info *cfg)
+{
+	inff_fwevt_register(cfg->pub, INFF_E_IF,
+			    inff_notify_vif_event);
+}
+
+/*
+ * inff_cpevt_dequeue_event() - get event from the queue.
+ *
+ * @evi: event handling info.
+ * @event_q: event queue.
+ */
+static struct inff_cpevt_queue_item *
+inff_cpevt_dequeue_event(struct inff_cpevt_info *evi, struct list_head *event_q)
+{
+	struct inff_cpevt_queue_item *event = NULL;
+	ulong flags;
+
+	spin_lock_irqsave(&evi->lock, flags);
+	if (!list_empty(event_q)) {
+		event = list_first_entry(event_q,
+					 struct inff_cpevt_queue_item, list);
+		list_del(&event->list);
+	}
+	spin_unlock_irqrestore(&evi->lock, flags);
+
+	return event;
+}
+
+/*
+ * inff_cpevt_queue_event() - queue event.
+ * @evi: event handling info.
+ * @event: event item.
+ * @event_q: event queue.
+ */
+static void
+inff_cpevt_queue_event(struct inff_cpevt_info *evi,
+		       struct inff_cpevt_queue_item *event,
+		       struct list_head *event_q)
+{
+	ulong flags;
+
+	spin_lock_irqsave(&evi->lock, flags);
+	list_add_tail(&event->list, event_q);
+	spin_unlock_irqrestore(&evi->lock, flags);
+}
+
+static int
+inff_cpevt_alloc_buf(struct inff_cpevt_info *evi)
+{
+	struct inff_cpevt_queue_item *event_item;
+	u8 i;
+
+	INIT_LIST_HEAD(&evi->idle_q);
+	INIT_LIST_HEAD(&evi->wait_q);
+	INIT_LIST_HEAD(&evi->event_q);
+	INIT_LIST_HEAD(&evi->monitor_q);
+	spin_lock_init(&evi->lock);
+
+	for (i = 0; i < EVENT_MAX_RX_BUF; i++) {
+		event_item = kzalloc_obj(*event_item);
+		if (!event_item)
+			return -ENODATA;
+
+		INIT_LIST_HEAD(&event_item->list);
+		memset(&event_item->event, 0, sizeof(event_item->event));
+
+		spin_lock(&evi->lock);
+		list_add_tail(&event_item->list, &evi->idle_q);
+		spin_unlock(&evi->lock);
+	}
+
+	return 0;
+}
+
+static void
+inff_cpevt_free_buf(struct list_head *q, const char name[])
+{
+	struct inff_cpevt_queue_item *event_item;
+	struct inff_cpevt_queue_item *next = NULL;
+	u32 count = 0;
+
+	list_for_each_entry_safe(event_item, next, q, list) {
+		list_del(&event_item->list);
+		kfree(event_item);
+		count++;
+	}
+	inff_dbg(INFO, "%s Q: free pkt count %d\n", name, count);
+}
+
+static int
+inff_notify_cpevt_scan(struct inff_pub *drvr, struct inff_cpevt *event)
+{
+	struct inff_cpevt_scan *scan_ev = NULL;
+
+	if (event->version != INFF_CP_SCAN_EVENT_VER) {
+		inff_err("version (%d) != %d\n", event->version, INFF_CP_SCAN_EVENT_VER);
+		return -ENODATA;
+	}
+
+	if (event->len != sizeof(*scan_ev)) {
+		inff_err("len %d != scan_event %ld\n", event->len, sizeof(*scan_ev));
+		return -ENODATA;
+	}
+
+	scan_ev = (struct inff_cpevt_scan *)event->data;
+	return inff_cp_scan_event_handler(drvr, scan_ev);
+}
+
+static int
+inff_cpevt_handler(struct inff_pub *drvr, struct inff_cpevt *e)
+{
+	int ret = 0;
+
+	switch (e->type) {
+	case INFF_CP_E_SCAN:
+		ret = inff_notify_cpevt_scan(drvr, e);
+		break;
+	default:
+		inff_err("unsupported event: %d\n", e->type);
+		/* driver bypass this event, keep forward to user */
+		break;
+	}
+
+	if (ret)
+		inff_err("handle event code (%d) failed\n", e->type);
+	return ret;
+}
+
+/*
+ * inff_cpevt_worker() - event worker.
+ *
+ * @work: worker object.
+ */
+static void
+inff_cpevt_worker(struct work_struct *work)
+{
+	struct inff_pub *drvr;
+	struct inff_cpevt_info *evi;
+	struct inff_cpevt_queue_item *event_item = NULL;
+
+	evi = container_of(work, struct inff_cpevt_info, event_work);
+	drvr = container_of(evi, struct inff_pub, evi);
+
+	while ((event_item = inff_cpevt_dequeue_event(evi, &evi->wait_q))) {
+		inff_cpevt_handler(drvr, &event_item->event);
+		inff_cpevt_queue_event(evi, event_item, &evi->idle_q);
+	}
+}
+
+/*
+ * inff_cpevt_attach() - initialize event handling.
+ * @drvr: driver information object.
+ */
+int
+inff_cpevt_attach(struct inff_pub *drvr)
+{
+	struct inff_cpevt_info *evi = &drvr->evi;
+
+	if (inff_cpevt_alloc_buf(evi)) {
+		inff_err("Failed to alloc event buffer\n");
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&evi->event_work, inff_cpevt_worker);
+
+	return 0;
+}
+
+/*
+ * inff_cpevt_detach() - cleanup event handling.
+ * @drvr: driver information object.
+ */
+void
+inff_cpevt_detach(struct inff_pub *drvr)
+{
+	struct inff_cpevt_info *evi = &drvr->evi;
+
+	/* cancel the worker if initialized */
+	if (evi->event_work.func)
+		cancel_work_sync(&evi->event_work);
+
+	spin_lock(&evi->lock);
+
+	inff_cpevt_free_buf(&evi->idle_q, "idle");
+	inff_cpevt_free_buf(&evi->wait_q, "wait");
+	inff_cpevt_free_buf(&evi->event_q, "event");
+	inff_cpevt_free_buf(&evi->monitor_q, "monitor");
+
+	spin_unlock(&evi->lock);
+}
+
+/*
+ * inff_cpevt_process_skb() - process skb as event.
+ * @drvr: driver information object.
+ * @pkt: event packet to process.
+ * @inirq: in irq.
+ * Dispatch the event packet to worker.
+ */
+void
+inff_cpevt_process_skb(struct inff_pub *drvr, struct sk_buff *pkt)
+{
+	struct inff_cpevt_info *evi = &drvr->evi;
+	struct inff_cpevt_queue_item *event_item;
+
+	if (pkt->len > sizeof(struct inff_cpevt)) {
+		inff_err("event len (%d) > %ld\n", pkt->len, sizeof(struct inff_cpevt));
+		return;
+	}
+
+	event_item = inff_cpevt_dequeue_event(evi, &evi->idle_q);
+	if (!event_item) {
+		inff_err("no buffer in idle q\n");
+		return;
+	}
+
+	memset(&event_item->event, 0, sizeof(event_item->event));
+	memcpy(&event_item->event, pkt->data, pkt->len);
+
+	inff_dbg_hex_dump(INFF_MSGLVL_ON(DEVEVT), pkt->data,
+			  min_t(u32, pkt->len, 64),
+			  "event payload, len=%d\n", pkt->len);
+
+	inff_cpevt_queue_event(evi, event_item, &evi->wait_q);
+
+	schedule_work(&evi->event_work);
+}
diff --git a/drivers/net/wireless/infineon/inffmac/dev_evt.h b/drivers/net/wireless/infineon/inffmac/dev_evt.h
new file mode 100644
index 000000000000..cc9d4384b1b8
--- /dev/null
+++ b/drivers/net/wireless/infineon/inffmac/dev_evt.h
@@ -0,0 +1,447 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Copyright (c) 2025-2026, Infineon Technologies AG, or an affiliate of Infineon Technologies AG.
+ * All rights reserved.
+ */
+
+#ifndef INFF_DEV_EVT_H
+#define INFF_DEV_EVT_H
+
+#include <linux/unaligned.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+
+#define INF_OUI		"\x00\x03\x19"
+
+/* formward declarations */
+struct inff_pub;
+struct inff_if;
+struct inff_cfg80211_info;
+
+/* list of firmware events */
+/* firmware event codes sent by the dongle */
+enum inff_fwevt_code {
+	INFF_E_SET_SSID = 0,
+	INFF_E_JOIN = 1,
+	INFF_E_START = 2,
+	INFF_E_AUTH = 3,
+	INFF_E_AUTH_IND = 4,
+	INFF_E_DEAUTH = 5,
+	INFF_E_DEAUTH_IND = 6,
+	INFF_E_ASSOC = 7,
+	INFF_E_ASSOC_IND = 8,
+	INFF_E_REASSOC = 9,
+	INFF_E_REASSOC_IND = 10,
+	INFF_E_DISASSOC = 11,
+	INFF_E_DISASSOC_IND = 12,
+	INFF_E_QUIET_START = 13,
+	INFF_E_QUIET_END = 14,
+	INFF_E_BEACON_RX = 15,
+	INFF_E_LINK = 16,
+	INFF_E_MIC_ERROR = 17,
+	INFF_E_NDIS_LINK = 18,
+	INFF_E_ROAM = 19,
+	INFF_E_TXFAIL = 20,
+	INFF_E_PMKID_CACHE = 21,
+	INFF_E_RETROGRADE_TSF = 22,
+	INFF_E_PRUNE = 23,
+	INFF_E_AUTOAUTH = 24,
+	INFF_E_EAPOL_MSG = 25,
+	INFF_E_SCAN_COMPLETE = 26,
+	INFF_E_ADDTS_IND = 27,
+	INFF_E_DELTS_IND = 28,
+	INFF_E_BCNSENT_IND = 29,
+	INFF_E_BCNRX_MSG = 30,
+	INFF_E_BCNLOST_MSG = 31,
+	INFF_E_ROAM_PREP = 32,
+	INFF_E_RESET_COMPLETE = 35,
+	INFF_E_JOIN_START = 36,
+	INFF_E_ROAM_START = 37,
+	INFF_E_ASSOC_START = 38,
+	INFF_E_IBSS_ASSOC = 39,
+	INFF_E_RADIO = 40,
+	INFF_E_PSM_WATCHDOG = 41,
+	INFF_E_PROBREQ_MSG = 44,
+	INFF_E_SCAN_CONFIRM_IND = 45,
+	INFF_E_PSK_SUP = 46,
+	INFF_E_COUNTRY_CODE_CHANGED = 47,
+	INFF_E_EXCEEDED_MEDIUM_TIME = 48,
+	INFF_E_ICV_ERROR = 49,
+	INFF_E_UNICAST_DECODE_ERROR = 50,
+	INFF_E_MULTICAST_DECODE_ERROR = 51,
+	INFF_E_TRACE = 52,
+	INFF_E_IF = 54,
+	INFF_E_RSSI = 56,
+	INFF_E_EXTLOG_MSG = 58,
+	INFF_E_ACTION_FRAME = 59,
+	INFF_E_ACTION_FRAME_TX_COMPLETE = 60,
+	INFF_E_PRE_ASSOC_IND = 61,
+	INFF_E_PRE_REASSOC_IND = 62,
+	INFF_E_CHANNEL_ADOPTED = 63,
+	INFF_E_AP_STARTED = 64,
+	INFF_E_DFS_AP_STOP = 65,
+	INFF_E_DFS_AP_RESUME = 66,
+	INFF_E_ESCAN_RESULT = 69,
+	INFF_E_ACTION_FRAME_OFF_CHAN_COMPLETE = 70,
+	INFF_E_PROBERESP_MSG = 71,
+	INFF_E_PROBEREQ_MSG = 72,
+	INFF_E_DCS_REQUEST = 73,
+	INFF_E_FIFO_CREDIT_MAP = 74,
+	INFF_E_ACTION_FRAME_RX_COMPLETE = 75,
+	INFF_E_SA_COMPLETE_IND = 80,
+	INFF_E_ASSOC_REQ_IE = 87,
+	INFF_E_ASSOC_RESP_IE = 88,
+	INFF_E_BCMC_CREDIT_SUPPORT = 127,
+	INFF_E_EXT_AUTH_REQ = 187,
+	INFF_E_EXT_AUTH_FRAME_RX = 188,
+	INFF_E_MGMT_FRAME_TXSTATUS = 189,
+	INFF_E_MGMT_FRAME_OFF_CHAN_COMPLETE = 190,
+	INFF_E_EXT_ASSOC_FRAME_RX = 196,
+	/* this determines event mask length which must match
+	 * minimum length check in device firmware so it is
+	 * hard-coded here.
+	 */
+	INFF_E_LAST = 203
+};
+
+/* list of CP events */
+/* CP event codes sent by the dongle */
+enum inff_cpevt_code {
+	INFF_CP_E_NW = 0,
+	INFF_CP_E_SCAN = 1
+};
+
+#define INFF_EVENTING_MASK_LEN		DIV_ROUND_UP(INFF_E_LAST, 8)
+
+/* flags field values in struct inff_event_msg */
+#define INFF_EVENT_MSG_LINK		0x01
+#define INFF_EVENT_MSG_FLUSHTXQ	0x02
+#define INFF_EVENT_MSG_GROUP		0x04
+
+/* status field values in struct inff_event_msg */
+#define INFF_E_STATUS_SUCCESS			0
+#define INFF_E_STATUS_FAIL			1
+#define INFF_E_STATUS_TIMEOUT			2
+#define INFF_E_STATUS_NO_NETWORKS		3
+#define INFF_E_STATUS_ABORT			4
+#define INFF_E_STATUS_NO_ACK			5
+#define INFF_E_STATUS_UNSOLICITED		6
+#define INFF_E_STATUS_ATTEMPT			7
+#define INFF_E_STATUS_PARTIAL			8
+#define INFF_E_STATUS_NEWSCAN			9
+#define INFF_E_STATUS_NEWASSOC			10
+#define INFF_E_STATUS_11HQUIET			11
+#define INFF_E_STATUS_SUPPRESS			12
+#define INFF_E_STATUS_NOCHANS			13
+#define INFF_E_STATUS_CS_ABORT			15
+#define INFF_E_STATUS_ERROR			16
+
+/* status field values for PSK_SUP event */
+#define INFF_E_STATUS_FWSUP_WAIT_M1		4
+#define INFF_E_STATUS_FWSUP_PREP_M2		5
+#define INFF_E_STATUS_FWSUP_COMPLETED		6
+#define INFF_E_STATUS_FWSUP_TIMEOUT		7
+#define INFF_E_STATUS_FWSUP_WAIT_M3		8
+#define INFF_E_STATUS_FWSUP_PREP_M4		9
+#define INFF_E_STATUS_FWSUP_WAIT_G1		10
+#define INFF_E_STATUS_FWSUP_PREP_G2		11
+
+/* reason field values in struct inff_event_msg */
+/* roam reason codes */
+#define INFF_ROAM_E_REASON_INITIAL_ASSOC     0     /* initial assoc */
+#define INFF_ROAM_E_REASON_LOW_RSSI          1     /* roamed due to low RSSI */
+#define INFF_ROAM_E_REASON_DEAUTH            2     /* roamed due to DEAUTH indication */
+#define INFF_ROAM_E_REASON_DISASSOC          3     /* roamed due to DISASSOC indication */
+#define INFF_ROAM_E_REASON_BCNS_LOST         4     /* roamed due to lost beacons */
+#define INFF_ROAM_E_REASON_FAST_ROAM_FAILED  5     /* roamed due to fast roam failure */
+#define INFF_ROAM_E_REASON_DIRECTED_ROAM     6     /* roamed due to request by AP */
+#define INFF_ROAM_E_REASON_TSPEC_REJECTED    7     /* roamed due to TSPEC rejection */
+#define INFF_ROAM_E_REASON_BETTER_AP         8     /* roamed due to finding better AP */
+#define INFF_ROAM_E_REASON_MINTXRATE         9     /* roamed because at mintxrate for too long */
+#define INFF_ROAM_E_REASON_TXFAIL            10    /* We can hear AP, but AP can't hear us */
+#define INFF_ROAM_E_REASON_BSSTRANS_REQ      11    /* roamed due to BSS Transition request by AP */
+#define INFF_ROAM_E_REASON_LOW_RSSI_CU       12    /* roamed due to low RSSI and Channel Usage */
+#define INFF_ROAM_E_REASON_RADAR_DETECTED    13    /* roamed due to radar detection by STA */
+#define INFF_ROAM_E_REASON_CSA               14    /* roamed due to CSA from AP */
+#define INFF_ROAM_E_REASON_ESTM_LOW          15    /* roamed due to ESTM low tput */
+#define INFF_ROAM_E_REASON_LAST              16
+
+#define INFF_E_REASON_LINK_BSSCFG_DIS		4
+#define INFF_E_REASON_FAST_ROAM_FAILED		5
+#define INFF_E_REASON_DIRECTED_ROAM		6
+#define INFF_E_REASON_TSPEC_REJECTED		7
+#define INFF_E_REASON_BETTER_AP		8
+
+/* reason field values for PSK_SUP event */
+#define INFF_E_REASON_FWSUP_OTHER		0
+#define INFF_E_REASON_FWSUP_DECRYPT_KEY_DATA	1
+#define INFF_E_REASON_FWSUP_BAD_UCAST_WEP128	2
+#define INFF_E_REASON_FWSUP_BAD_UCAST_WEP40	3
+#define INFF_E_REASON_FWSUP_UNSUP_KEY_LEN	4
+#define INFF_E_REASON_FWSUP_PW_KEY_CIPHER	5
+#define INFF_E_REASON_FWSUP_MSG3_TOO_MANY_IE	6
+#define INFF_E_REASON_FWSUP_MSG3_IE_MISMATCH	7
+#define INFF_E_REASON_FWSUP_NO_INSTALL_FLAG	8
+#define INFF_E_REASON_FWSUP_MSG3_NO_GTK	9
+#define INFF_E_REASON_FWSUP_GRP_KEY_CIPHER	10
+#define INFF_E_REASON_FWSUP_GRP_MSG1_NO_GTK	11
+#define INFF_E_REASON_FWSUP_GTK_DECRYPT_FAIL	12
+#define INFF_E_REASON_FWSUP_SEND_FAIL		13
+#define INFF_E_REASON_FWSUP_DEAUTH		14
+#define INFF_E_REASON_FWSUP_WPA_PSK_TMO	15
+#define INFF_E_REASON_FWSUP_WPA_PSK_M1_TMO	16
+#define INFF_E_REASON_FWSUP_WPA_PSK_M3_TMO	17
+
+/* action field values for inff_ifevent */
+#define INFF_E_IF_ADD				1
+#define INFF_E_IF_DEL				2
+#define INFF_E_IF_CHANGE			3
+
+/* flag field values for inff_ifevent */
+#define INFF_E_IF_FLAG_NOIF			1
+
+/* role field values for inff_ifevent */
+#define INFF_E_IF_ROLE_STA			0
+#define INFF_E_IF_ROLE_AP			1
+
+/**
+ * definitions for event packet validation.
+ */
+#define INFILCP_INF_SUBTYPE_EVENT		1
+#define INFILCP_SUBTYPE_VENDOR_LONG		32769
+
+/**
+ * struct inff_ethhdr - Infineon specific ether header.
+ *
+ * @subtype: subtype for this packet.
+ * @length: length of appended data.
+ * @version: version indication.
+ * @oui: OUI of this packet.
+ * @usr_subtype: subtype for this OUI.
+ */
+struct inff_ethhdr {
+	__be16 subtype;
+	__be16 length;
+	u8 version;
+	u8 oui[3];
+	__be16 usr_subtype;
+} __packed;
+
+struct inff_event_msg_be {
+	__be16 version;
+	__be16 flags;
+	__be32 event_type;
+	__be32 status;
+	__be32 reason;
+	__be32 auth_type;
+	__be32 datalen;
+	u8 addr[ETH_ALEN];
+	char ifname[IFNAMSIZ];
+	u8 ifidx;
+	u8 bsscfgidx;
+} __packed;
+
+/**
+ * struct inff_event - contents of Infineon event packet.
+ *
+ * @eth: standard ether header.
+ * @hdr: Infineon specific ether header.
+ * @msg: common part of the actual event message.
+ */
+struct inff_event {
+	struct ethhdr eth;
+	struct inff_ethhdr hdr;
+	struct inff_event_msg_be msg;
+} __packed;
+
+#define EVENT_MAX_DATA_LEN 1024
+#define EVENT_MAX_RX_BUF 10
+
+struct inff_cpevt {
+	u16 type;
+	u16 len;
+	u8 version;
+	u8 data[EVENT_MAX_DATA_LEN];
+};
+
+/**
+ * struct inff_event_msg - firmware event message.
+ *
+ * @version: version information.
+ * @flags: event flags.
+ * @event_code: firmware event code.
+ * @status: status information.
+ * @reason: reason code.
+ * @auth_type: authentication type.
+ * @datalen: length of event data buffer.
+ * @addr: ether address.
+ * @ifname: interface name.
+ * @ifidx: interface index.
+ * @bsscfgidx: bsscfg index.
+ */
+struct inff_event_msg {
+	u16 version;
+	u16 flags;
+	u32 event_code;
+	u32 status;
+	u32 reason;
+	s32 auth_type;
+	u32 datalen;
+	u8 addr[ETH_ALEN];
+	char ifname[IFNAMSIZ];
+	u8 ifidx;
+	u8 bsscfgidx;
+};
+
+struct inff_if_event {
+	u8 ifidx;
+	u8 action;
+	u8 flags;
+	u8 bsscfgidx;
+	u8 role;
+};
+
+enum event_msgs_ext_command {
+	EVENTMSGS_NONE		=	0,
+	EVENTMSGS_SET_BIT	=	1,
+	EVENTMSGS_RESET_BIT	=	2,
+	EVENTMSGS_SET_MASK	=	3
+};
+
+#define EVENTMSGS_VER 1
+#define EVENTMSGS_EXT_STRUCT_SIZE	offsetof(struct eventmsgs_ext, mask[0])
+
+/* len-	for SET it would be mask size from the application to the firmware */
+/*		for GET it would be actual firmware mask size */
+/* maxgetsize -	is only used for GET. indicate max mask size that the */
+/*				application can read from the firmware */
+struct eventmsgs_ext {
+	u8	ver;
+	u8	command;
+	u8	len;
+	u8	maxgetsize;
+	u8	mask[];
+};
+
+struct inff_fwevt_roam_reason_name {
+	u32 reason;
+	char *reason_name;
+};
+
+typedef int (*inff_fwevt_handler_t)(struct inff_if *ifp,
+				    const struct inff_event_msg *evtmsg,
+				    void *data);
+
+/**
+ * struct inff_fwevt_info - firmware event handling information.
+ *
+ * @event_work: event worker.
+ * @evt_q_lock: lock for event queue protection.
+ * @event_q: event queue.
+ * @evt_handler: registered event handlers.
+ */
+struct inff_fwevt_info {
+	struct work_struct event_work;
+	spinlock_t evt_q_lock;	/* lock for event queue protection */
+	struct list_head event_q;
+
+	int (*evt_handler[INFF_E_LAST])(struct inff_if *ifp,
+					const struct inff_event_msg *evtmsg,
+					void *data);
+};
+
+/*
+ * struct inff_cpevt_queue_item - event item on event queue.
+ *
+ * @list: list element for queuing.
+ * @event: event specific data part of the event.
+ */
+struct inff_cpevt_queue_item {
+	struct list_head list;
+	struct inff_cpevt event;
+};
+
+/*
+ * struct inff_cpevt_info - event handling information.
+ *
+ * @event_work: event worker.
+ * @event_q_lock: lock for event queue protection.
+ * @event_q: event queue.
+ */
+struct inff_cpevt_info {
+	struct work_struct event_work;
+	/* lock for event queue protection */
+	spinlock_t lock;
+	struct list_head idle_q;
+	struct list_head wait_q;
+	struct list_head event_q;
+	struct list_head monitor_q;
+};
+
+#define INFF_CP_NW_EVENT_VER 2
+
+/*
+ * struct inff_cpevt_nw - contents of CP network event.
+ */
+struct inff_cpevt_nw {
+	u8 type;
+	u8 if_idx;
+	union {
+		u8 mac[ETH_ALEN];
+		u32 ipv4;		/* IPv4 address in network byte order */
+		u32 reason;
+		u32 pad[2];
+	} u;
+	u32 ipv6[4];
+} __packed;
+
+/* Scan Event */
+#define INFF_CP_SCAN_EVENT_VER		2
+#define INFF_CP_SCAN_IE_LEN_MAX		896
+
+/*
+ * struct inff_cpevt_scan - contents of CP scan event.
+ */
+struct inff_cpevt_scan {
+	u8     ssid_length;	/* SSID length */
+	char   ssid[IEEE80211_MAX_SSID_LEN + 1]; /* SSID of the access point */
+	u32    security_type;	/* WiFi security type */
+	u8     macaddr[ETH_ALEN];	/* MAC Address of the access point */
+	s16    signal_strength;	/* signal strength */
+	u8     channel;	/* channel number */
+	u8     band;	/* WiFi band of access point */
+	bool   scan_complete;	/* WiFi scan complete/incomplete */
+	u16    beacon_period;	/* Interval between two consecutive beacon frames. Unit: Kusec */
+	u16    capability;	/* Capability information */
+	u32    ie_len;	/* Length of the IE. */
+
+	/* Pointer to the received Beacon/Probe Response IE (Information Element). */
+	u8     ie[INFF_CP_SCAN_IE_LEN_MAX];
+} __packed;
+
+const char *inff_fwevt_name(enum inff_fwevt_code code);
+
+void inff_fwevt_attach(struct inff_pub *drvr);
+void inff_fwevt_detach(struct inff_pub *drvr);
+int inff_fwevt_register(struct inff_pub *drvr, enum inff_fwevt_code code,
+			int (*handler)(struct inff_if *ifp,
+				       const struct inff_event_msg *evtmsg,
+				       void *data));
+void inff_fwevt_unregister(struct inff_pub *drvr,
+			   enum inff_fwevt_code code);
+int inff_fwevt_activate_events(struct inff_if *ifp);
+void inff_fwevt_process_event(struct inff_pub *drvr,
+			      struct inff_event *event_packet,
+			      u32 packet_len, gfp_t gfp);
+void inff_fwevt_process_skb(struct inff_pub *drvr, struct sk_buff *skb, u16 stype,
+			    gfp_t gfp);
+void inff_fwevt_register_handlers(struct inff_cfg80211_info *cfg);
+
+int inff_cpevt_attach(struct inff_pub *drvr);
+void inff_cpevt_detach(struct inff_pub *drvr);
+void inff_cpevt_process_skb(struct inff_pub *drvr, struct sk_buff *pkt);
+
+#endif /* INFF_DEV_EVT_H */
-- 
2.43.0


  parent reply	other threads:[~2026-09-02 16:53 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-02 16:50 [PATCH wireless-next v3 00/25] wifi: inffmac: introducing a driver for Infineon's new generation chipsets Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 01/25] wifi: inffmac: add a new driver directory for infineon WLAN vendor Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 02/25] wifi: inffmac: add firmware.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 03/25] wifi: inffmac: add dfu.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 04/25] wifi: inffmac: add trxhdr.h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 05/25] wifi: inffmac: add chip.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 06/25] wifi: inffmac: add chip_{cyw5591x/acw74xx}.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 07/25] wifi: inffmac: add icdc.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 08/25] wifi: inffmac: add main.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 09/25] wifi: inffmac: add dev_cmd.c/h Gokul Sivakumar
2026-09-02 16:50 ` Gokul Sivakumar [this message]
2026-09-02 16:50 ` [PATCH wireless-next v3 11/25] wifi: inffmac: add net.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 12/25] wifi: inffmac: add cfg80211.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 13/25] wifi: inffmac: add interface.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 14/25] wifi: inffmac: add he.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 15/25] wifi: inffmac: add feature.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 16/25] wifi: inffmac: add bus_proto.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 17/25] wifi: inffmac: add sdio.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 18/25] wifi: inffmac: add fwsignal.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 19/25] wifi: inffmac: add bcdc.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 20/25] wifi: inffmac: add ie.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 21/25] wifi: inffmac: add scan.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 22/25] wifi: inffmac: add chan.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 23/25] wifi: inffmac: add debug.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 24/25] wifi: inffmac: add utils.c/h Gokul Sivakumar
2026-09-02 16:50 ` [PATCH wireless-next v3 25/25] wifi: inffmac: add Kconfig, Makefile Gokul Sivakumar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260902165057.456447-11-gokulkumar.sivakumar@infineon.com \
    --to=gokulkumar.sivakumar@infineon.com \
    --cc=arend.vanspriel@broadcom.com \
    --cc=johannes@sipsolutions.net \
    --cc=linux-wireless@vger.kernel.org \
    --cc=wlan-kernel-dev-list@infineon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox