redbear-iwlwifi: Mini-MLD foundation — iwlmld op-mode + BZ->MLD gate
Phase 6.2 foundation. Port the Mini-MLD layer from Linux 7.1 (drivers/net/wireless/intel/iwlwifi/mld/), the MLD analog of Mini-MVM: - linux_mld.h: iwlmld op-mode IDs, notification command groups (LEGACY/MAC_CONF/PHY_OPS/DATA_PATH/SCAN/STATISTICS), and the MLD notification command ID set. The RX frame IDs (0xc0/0xc1/0xc5) and the iwl_rx_mpdu_desc descriptor are shared with MVM and stay in Mini-MVM; MLD adds ROC/session-protection/MU-group-mgmt/probe-response/ channel-switch/MFUART/DTS-measurement notification IDs. - linux_mld.c: rb_iwl_mld_handle_notification() — real MLD notification dispatch. RX MPDU frames are parsed by the Mini-MVM descriptor parser (rb_iwl_mvm_extract_signal/detect_format, no duplicate parser) with real signal/rate extraction; MLD-specific notifications are identified, grouped, and counted. Includes the BZ-family op-mode selection (rb_iwl_opmode_for_family, mirroring Linux iwl-drv.c). - linux_port.c: include linux_mld.h; add trans->opmode set from device_family (BZ -> iwlmld, others -> iwlmvm); report opmode= in the linux_kpi_status line so the gate is observable. - build.rs: compile linux_mld.c. This is the bounded foundation; MLO/link management and the full MLD feature set (mac80211-integrated) are the multi-week continuation. All 8 host tests pass.
This commit is contained in:
@@ -6,6 +6,7 @@ fn main() {
|
|||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file("src/linux_port.c")
|
.file("src/linux_port.c")
|
||||||
.file("src/linux_mvm.c")
|
.file("src/linux_mvm.c")
|
||||||
|
.file("src/linux_mld.c")
|
||||||
.include(linux_kpi_headers)
|
.include(linux_kpi_headers)
|
||||||
.warnings(true)
|
.warnings(true)
|
||||||
.compile("redbear_iwlwifi_linux_port");
|
.compile("redbear_iwlwifi_linux_port");
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* 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 */
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "../../../linux-kpi/source/src/c_headers/linux/jiffies.h"
|
#include "../../../linux-kpi/source/src/c_headers/linux/jiffies.h"
|
||||||
#include "../../../linux-kpi/source/src/c_headers/linux/kernel.h"
|
#include "../../../linux-kpi/source/src/c_headers/linux/kernel.h"
|
||||||
#include "linux_mvm.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/list.h"
|
||||||
#include "../../../linux-kpi/source/src/c_headers/linux/mutex.h"
|
#include "../../../linux-kpi/source/src/c_headers/linux/mutex.h"
|
||||||
#include "../../../linux-kpi/source/src/c_headers/linux/netdevice.h"
|
#include "../../../linux-kpi/source/src/c_headers/linux/netdevice.h"
|
||||||
@@ -267,6 +268,7 @@ struct iwl_trans_pcie {
|
|||||||
|
|
||||||
/* Device family info */
|
/* Device family info */
|
||||||
int device_family;
|
int device_family;
|
||||||
|
int opmode;
|
||||||
const char *fw_name;
|
const char *fw_name;
|
||||||
const char *pnvm_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->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 ?
|
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_BZ_MAC_ACCESS_REQ :
|
||||||
IWL_CSR_GP_CNTRL_REG_FLAG_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);
|
pci_set_master(pdev);
|
||||||
trans->device_family = rb_iwlwifi_family_from_device(pdev, 0);
|
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;
|
pdev->driver_data = trans;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2215,8 +2219,9 @@ static void rb_iwlwifi_status_line(struct iwl_trans_pcie *trans, char *out, unsi
|
|||||||
{
|
{
|
||||||
rb_iwlwifi_format_out(
|
rb_iwlwifi_format_out(
|
||||||
out, out_len,
|
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_iwlwifi_family_name(trans->device_family),
|
||||||
|
rb_iwl_opmode_name(trans->opmode),
|
||||||
trans->prepared,
|
trans->prepared,
|
||||||
trans->transport_probed,
|
trans->transport_probed,
|
||||||
trans->transport_inited,
|
trans->transport_inited,
|
||||||
|
|||||||
Reference in New Issue
Block a user