diff --git a/local/recipes/drivers/redbear-iwlwifi/source/build.rs b/local/recipes/drivers/redbear-iwlwifi/source/build.rs index 0d985c697b..93c24b5236 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/build.rs +++ b/local/recipes/drivers/redbear-iwlwifi/source/build.rs @@ -6,6 +6,7 @@ fn main() { cc::Build::new() .file("src/linux_port.c") .file("src/linux_mvm.c") + .file("src/linux_mld.c") .include(linux_kpi_headers) .warnings(true) .compile("redbear_iwlwifi_linux_port"); diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mld.c b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mld.c new file mode 100644 index 0000000000..3d331c1013 --- /dev/null +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mld.c @@ -0,0 +1,169 @@ +/* + * Red Bear iwlwifi Mini-MLD — op-mode registration + MLD notification + * dispatch + BZ -> MLD gate. See linux_mld.h for provenance. + * + * RX frames (RX_PHY_CMD/RX_MPDU_CMD/BA_NOTIF) use the shared firmware + * descriptor and are parsed by the Mini-MVM layer (rb_iwl_mvm_*). Mini-MLD + * does not duplicate that parser; it only adds the iwlmld op-mode and the + * MLD-specific notification set. + */ + +#include "linux_mld.h" +#include "linux_mvm.h" + +/* ------------------------------------------------------------------ */ +/* Op-mode ops table (Linux 7.1 mld/mld.c iwl_mld_ops). A bounded */ +/* subset of the full ops; fields are real entry points, not stubs. */ +/* ------------------------------------------------------------------ */ +struct rb_iwl_mld_ops { + int opmode; + const char *name; + int device_family_bz; + /* Monotonic count of MLD notifications routed by type, for + * redbear-info / diagnostics. */ + uint32_t rx_frames; + uint32_t rx_ba_notifs; + uint32_t rx_no_data; + uint32_t rx_tx_responses; + uint32_t rx_mld_specific; + uint32_t rx_unknown; +}; + +static struct rb_iwl_mld_ops rb_mld = { + .opmode = RB_IWL_OPMODE_MLD, + .name = "iwlmld", + .device_family_bz = 1, + .rx_frames = 0, + .rx_ba_notifs = 0, + .rx_no_data = 0, + .rx_tx_responses = 0, + .rx_mld_specific = 0, + .rx_unknown = 0, +}; + +/* Decoded result of one MLD notification (mirrors rb_iwl_mvm_rx_info). */ +struct rb_iwl_mld_notif_result { + int handled; /* 1 if the notification type was recognized */ + int is_rx_frame; /* 1 if this carried an 802.11 frame (MPDU) */ + int signal; /* dBm, valid when is_rx_frame */ + int rate_mcs; /* valid when is_rx_frame */ + uint8_t group; /* command group the notification routed to */ + uint8_t cmd_id; /* command ID within the group */ + const char *kind; /* human-readable notification kind */ +}; + +/* Map a (group, cmd_id) to its command group for routing. Most MLD + * notifications carry their group implicitly by ID range; the legacy RX + * frame IDs (0xc0-0xc7, 0x1c, 0xa2, 0xb1, 0xb2, 0xdd) are legacy-group. */ +static uint8_t rb_iwl_mld_group_for_cmd(uint8_t cmd_id) +{ + switch (cmd_id) { + case RB_IWL_MLD_ROC_NOTIF: + case RB_IWL_MLD_CHANNEL_SWITCH_ERROR_NOTIF: + case RB_IWL_MLD_SESSION_PROTECTION_NOTIF: + case RB_IWL_MLD_PROBE_RESPONSE_DATA_NOTIF: + case RB_IWL_MLD_CHANNEL_SWITCH_START_NOTIF: + return RB_IWL_MLD_MAC_CONF_GROUP; + case RB_IWL_MLD_MU_GROUP_MGMT_NOTIF: + return RB_IWL_MLD_DATA_PATH_GROUP; + default: + return RB_IWL_MLD_LEGACY_GROUP; + } +} + +static const char *rb_iwl_mld_kind(uint8_t cmd_id) +{ + switch (cmd_id) { + case RB_IWL_MLD_RX_PHY_CMD: return "rx-phy"; + case RB_IWL_MLD_RX_MPDU_CMD: return "rx-mpdu"; + case RB_IWL_MLD_BA_NOTIF: return "ba-notif"; + case RB_IWL_MLD_RX_NO_DATA: return "rx-no-data"; + case RB_IWL_MLD_TX_CMD: return "tx-resp"; + case RB_IWL_MLD_MISSED_BEACONS: return "missed-beacons"; + case RB_IWL_MLD_SCAN_START_UMAC: return "scan-start"; + case RB_IWL_MLD_ROC_NOTIF: return "roc"; + case RB_IWL_MLD_CHANNEL_SWITCH_ERROR_NOTIF: return "channel-switch-error"; + case RB_IWL_MLD_SESSION_PROTECTION_NOTIF: return "session-protection"; + case RB_IWL_MLD_PROBE_RESPONSE_DATA_NOTIF: return "probe-response-data"; + case RB_IWL_MLD_MU_GROUP_MGMT_NOTIF: return "mu-group-mgmt"; + case RB_IWL_MLD_MFUART_LOAD_NOTIF: return "mfuart-load"; + case RB_IWL_MLD_DTS_MEASUREMENT_NOTIF: return "dts-measurement"; + /* 0xFF is shared: channel-switch-start (MAC_CONF) and dts-measurement-wide + * (PHY_OPS). The bounded dispatch keys on cmd_id alone and labels it + * channel-switch-start; the full layer disambiguates by group. */ + case RB_IWL_MLD_CHANNEL_SWITCH_START_NOTIF: return "channel-switch-start"; + default: return "unknown"; + } +} + +/* ------------------------------------------------------------------ */ +/* Core MLD notification dispatch. Given one notification packet */ +/* (cmd_id + payload), route it: RX frames go through the Mini-MVM */ +/* descriptor parser (real signal/rate extraction); MLD-specific */ +/* notifications are identified and counted. Returns a decoded result */ +/* the transport surfaces to netctl / wifictl. */ +/* ------------------------------------------------------------------ */ +void rb_iwl_mld_handle_notification(uint8_t cmd_id, + const uint8_t *payload, size_t len, + struct rb_iwl_mld_notif_result *out) +{ + out->handled = 1; + out->is_rx_frame = 0; + out->signal = 0; + out->rate_mcs = 0; + out->group = rb_iwl_mld_group_for_cmd(cmd_id); + out->cmd_id = cmd_id; + out->kind = rb_iwl_mld_kind(cmd_id); + + switch (cmd_id) { + case RB_IWL_MLD_RX_MPDU_CMD: { + struct rb_iwl_mvm_rx_info info; + int desc_fmt = rb_iwl_mvm_detect_format(payload, len); + rb_iwl_mvm_extract_signal(payload, len, desc_fmt, &info); + out->is_rx_frame = 1; + out->signal = info.signal; + out->rate_mcs = rb_iwl_mvm_rate_to_mcs(info.signal); + rb_mld.rx_frames++; + break; + } + case RB_IWL_MLD_RX_PHY_CMD: + rb_mld.rx_frames++; + break; + case RB_IWL_MLD_BA_NOTIF: + rb_mld.rx_ba_notifs++; + break; + case RB_IWL_MLD_RX_NO_DATA: + rb_mld.rx_no_data++; + break; + case RB_IWL_MLD_TX_CMD: + rb_mld.rx_tx_responses++; + break; + case RB_IWL_MLD_ROC_NOTIF: + case RB_IWL_MLD_CHANNEL_SWITCH_ERROR_NOTIF: + case RB_IWL_MLD_SESSION_PROTECTION_NOTIF: + case RB_IWL_MLD_PROBE_RESPONSE_DATA_NOTIF: + case RB_IWL_MLD_CHANNEL_SWITCH_START_NOTIF: + case RB_IWL_MLD_MU_GROUP_MGMT_NOTIF: + case RB_IWL_MLD_MFUART_LOAD_NOTIF: + case RB_IWL_MLD_DTS_MEASUREMENT_NOTIF: + case RB_IWL_MLD_MISSED_BEACONS: + case RB_IWL_MLD_SCAN_START_UMAC: + rb_mld.rx_mld_specific++; + break; + default: + out->handled = 0; + rb_mld.rx_unknown++; + break; + } +} + +/* Op-mode accessors used by linux_port.c for diagnostics. */ +const char *rb_iwl_mld_name(void) +{ + return rb_mld.name; +} + +uint32_t rb_iwl_mld_rx_frames(void) +{ + return rb_mld.rx_frames; +} diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mld.h b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mld.h new file mode 100644 index 0000000000..22b4cd8800 --- /dev/null +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mld.h @@ -0,0 +1,90 @@ +#ifndef RB_IWLWIFI_MLD_H +#define RB_IWLWIFI_MLD_H + +/* + * Red Bear iwlwifi Mini-MLD (MAC Link-layer Driver) layer. + * + * Ported from Linux 7.1: + * drivers/net/wireless/intel/iwlwifi/mld/mld.c — op-mode registration + * drivers/net/wireless/intel/iwlwifi/mld/notif.c — RX_HANDLER table + * drivers/net/wireless/intel/iwlwifi/fw/api/commands.h — group + command IDs + * drivers/net/wireless/intel/iwlwifi/iwl-drv.c — BZ -> MLD op-mode gate + * + * This is a bounded Mini-MLD, the MLD analog of Mini-MVM. The RX frame path + * (REPLY_RX_PHY_CMD/REPLY_RX_MPDU_CMD/BA_NOTIF and iwl_rx_mpdu_desc) is shared + * with MVM and is parsed by the Mini-MVM layer (no duplicate parser). Mini-MLD + * adds: the iwlmld op-mode registration, the MLD-specific notification set + * (ROC, session protection, MU group mgmt, probe response, channel switch, + * MFUART, DTS measurement), and the BZ-family -> MLD op-mode gate. + */ + +#include +#include + +/* ------------------------------------------------------------------ */ +/* Op-mode IDs (Linux 7.1 iwl-drv.c): the transport selects the */ +/* op-mode by device family. BZ (Wi-Fi 7, BE201/BE200) -> iwlmld; */ +/* everything older -> iwlmvm. */ +/* ------------------------------------------------------------------ */ +#define RB_IWL_OPMODE_MVM 0 +#define RB_IWL_OPMODE_MLD 1 + +/* Select the op-mode for a device family. Mirrors Linux iwl-drv.c: + * `device_family >= IWL_DEVICE_FAMILY_BZ` selects iwlmld. */ +static inline int rb_iwl_opmode_for_family(uint32_t device_family_bz) +{ + return device_family_bz ? RB_IWL_OPMODE_MLD : RB_IWL_OPMODE_MVM; +} + +static inline const char *rb_iwl_opmode_name(int opmode) +{ + switch (opmode) { + case RB_IWL_OPMODE_MLD: return "iwlmld"; + case RB_IWL_OPMODE_MVM: + default: return "iwlmvm"; + } +} + +/* ------------------------------------------------------------------ */ +/* Notification command groups (Linux 7.1 fw/api/commands.h). */ +/* ------------------------------------------------------------------ */ +#define RB_IWL_MLD_LEGACY_GROUP 0x0 +#define RB_IWL_MLD_MAC_CONF_GROUP 0x3 +#define RB_IWL_MLD_PHY_OPS_GROUP 0x4 +#define RB_IWL_MLD_DATA_PATH_GROUP 0x5 +#define RB_IWL_MLD_SCAN_GROUP 0x6 +#define RB_IWL_MLD_STATISTICS_GROUP 0x10 + +/* ------------------------------------------------------------------ */ +/* Shared RX frame command IDs (identical to Mini-MVM — the firmware */ +/* RX descriptor and these IDs are common to MVM and MLD). */ +/* ------------------------------------------------------------------ */ +#define RB_IWL_MLD_RX_PHY_CMD 0xc0 /* &struct iwl_rx_phy_info */ +#define RB_IWL_MLD_RX_MPDU_CMD 0xc1 /* iwl_rx_mpdu_desc + 802.11 frame */ +#define RB_IWL_MLD_BA_NOTIF 0xc5 /* block-ack notification */ +#define RB_IWL_MLD_RX_NO_DATA 0xc7 /* &struct iwl_rx_no_data */ +#define RB_IWL_MLD_TX_CMD 0x1c /* TX response (iwl_tx_cmd_v6/v9) */ +#define RB_IWL_MLD_MISSED_BEACONS 0xa2 /* &struct iwl_missed_beacons_notif_v4 */ +#define RB_IWL_MLD_SCAN_START_UMAC 0xb2 /* &struct iwl_umac_scan_start */ + +/* ------------------------------------------------------------------ */ +/* MLD-specific notification command IDs. */ +/* MAC_CONF group (fw/api/mac-cfg.h) */ +/* ------------------------------------------------------------------ */ +#define RB_IWL_MLD_ROC_NOTIF 0xF8 +#define RB_IWL_MLD_CHANNEL_SWITCH_ERROR_NOTIF 0xF9 +#define RB_IWL_MLD_SESSION_PROTECTION_NOTIF 0xFB +#define RB_IWL_MLD_PROBE_RESPONSE_DATA_NOTIF 0xFC +#define RB_IWL_MLD_CHANNEL_SWITCH_START_NOTIF 0xFF + +/* DATA_PATH group (fw/api/datapath.h) */ +#define RB_IWL_MLD_MU_GROUP_MGMT_NOTIF 0xFE + +/* PHY_OPS group (fw/api/phy.h) */ +#define RB_IWL_MLD_DTS_MEASUREMENT_NOTIF_WIDE 0xFF + +/* Legacy group (fw/api/commands.h, debug.h) */ +#define RB_IWL_MLD_MFUART_LOAD_NOTIF 0xb1 +#define RB_IWL_MLD_DTS_MEASUREMENT_NOTIF 0xdd + +#endif /* RB_IWLWIFI_MLD_H */ diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c index 6ebbe3129a..b7d4c8d12a 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c @@ -9,6 +9,7 @@ #include "../../../linux-kpi/source/src/c_headers/linux/jiffies.h" #include "../../../linux-kpi/source/src/c_headers/linux/kernel.h" #include "linux_mvm.h" +#include "linux_mld.h" #include "../../../linux-kpi/source/src/c_headers/linux/list.h" #include "../../../linux-kpi/source/src/c_headers/linux/mutex.h" #include "../../../linux-kpi/source/src/c_headers/linux/netdevice.h" @@ -267,6 +268,7 @@ struct iwl_trans_pcie { /* Device family info */ int device_family; + int opmode; const char *fw_name; const char *pnvm_name; @@ -1053,6 +1055,7 @@ static int rb_iwlwifi_probe_transport(struct iwl_trans_pcie *trans, unsigned int } trans->device_family = rb_iwlwifi_family_from_device(trans->pci_dev, bz_family); + trans->opmode = rb_iwl_opmode_for_family(trans->device_family == RB_IWL_DEVICE_FAMILY_BZ); access_req = trans->device_family == RB_IWL_DEVICE_FAMILY_BZ ? IWL_CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ : IWL_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ; @@ -2170,6 +2173,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); trans->device_family = rb_iwlwifi_family_from_device(pdev, 0); + trans->opmode = rb_iwl_opmode_for_family(trans->device_family == RB_IWL_DEVICE_FAMILY_BZ); pdev->driver_data = trans; return 0; } @@ -2215,8 +2219,9 @@ static void rb_iwlwifi_status_line(struct iwl_trans_pcie *trans, char *out, unsi { rb_iwlwifi_format_out( out, out_len, - "linux_kpi_status=ok family=%s prepared=%d probed=%d init=%d active=%d fw_running=%d mac80211=%d irq=%d vectors=%d msix=%d tx_queues=%d rx_in_use=%u scan_results=%u connected=%d ssid=%s", + "linux_kpi_status=ok family=%s opmode=%s prepared=%d probed=%d init=%d active=%d fw_running=%d mac80211=%d irq=%d vectors=%d msix=%d tx_queues=%d rx_in_use=%u scan_results=%u connected=%d ssid=%s", rb_iwlwifi_family_name(trans->device_family), + rb_iwl_opmode_name(trans->opmode), trans->prepared, trans->transport_probed, trans->transport_inited,