v4.0: AER recovery /recover endpoint + comprehensive docs sweep

- Scheme gains /recover: write '<pci_addr> <reset_device|rescan_bus|
  disconnect>' to trigger AER recovery. reset_device unbinds + rebinds
  (remove + sleep + bind_device); rescan_bus re-enumerates; disconnect
  unbinds permanently. Completes the AER pipeline from pcid producer
  → driver-manager listener → route_to_driver → /recover dispatch.
- Plan v4.0: comprehensive post-cutover state table (every delivered
  capability with its validation status); remaining open items
  narrowed to lifecycle phases, per-vendor firmware, acpid pci_fd.
- AGENTS.md + docs/README.md bumped to v4.0.
This commit is contained in:
2026-07-24 15:51:13 +09:00
parent a8d1f472b8
commit eeddbc72fe
6 changed files with 448 additions and 74 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ console-to-KDE plan.
- `../local/docs/ACPI-IMPROVEMENT-PLAN.md` — ACPI ownership, robustness, validation
- `../local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` — PCI/IRQ quality, MSI/MSI-X
- `../local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` — DRM-focused execution (subsystem detail)
- `../local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v3.2, 2026-07-24) — migration from `pcid-spawner` to `driver-manager`. **CUTOVER COMPLETE (2026-07-23, operator-ratified):** driver-manager owns the boot-time PCI match/claim/spawn path in every `redbear-*` config; pcid-spawner is retired from configs and gated behind `/etc/driver-manager.d/disabled` as the operator fallback (never deleted). See `../local/docs/evidence/driver-manager/ASSESSMENT-2026-07-22.md` (major assessment, findings B1G10 + § 11 services integration). Delivered: claim-via-channel collapse (pcid `ENOLCK` exclusivity — the pcid-spawner model); init `ConditionPathExists` gate (systemd-style, `!` negation); spawned-mode `pci_register_driver` in linux-kpi (honors `PCID_CLIENT_CHANNEL` — single ownership of match-claim-spawn for native and Linux-port daemons); linux-kpi real MSI/MSI-X via pcid_interface + `pci_request_regions` + `pcie_capability_*` + PM state; redbear-iwlwifi `--daemon` onboarding + `70-wifi.toml`; `--import-linux-ids` Linux id_table→TOML pipeline; scheme operator surface (`bind`/`unbind`/`new_id`/`remove_id`/`driver_override`/`rescan`); Tier-1 driver_override; success-triggered deferred retry; concurrent probes with real `Driver::probe()`; real SIGCHLD/SIGHUP handlers; heartbeat counters; AER `route_to_driver`; `exclusive_with` mutual exclusion; `pci=nomsi` env var; PciQuirkFlags spawn env hints + `REDBEAR_DRIVER_{IOMMU_GROUP,NUMA_NODE,MSIX_VECTORS}`; driver-params bridge live; D-Bus correctly absent (bridge-on-demand). Gate: PASSED in QEMU q35 (initfs ahcid bind, rootfs e1000d concurrent bind, scheme live, resident hotplug). Platform finding: `thread::scope` hangs on Redox (spawn+join used instead). Cookbook now hashes Cargo path-dep sources (staleness hole closed). Open: P2-1 pcid AER/pciehp producers, P3 policy/hygiene. 93 tests pass; 0 audit-no-stubs violations; zero crate-local warnings on host and redox target.
- `../local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v4.0, 2026-07-24) — migration from `pcid-spawner` to `driver-manager`. **CUTOVER COMPLETE (2026-07-23, operator-ratified):** driver-manager owns the boot-time PCI match/claim/spawn path in every `redbear-*` config; pcid-spawner is retired from configs and gated behind `/etc/driver-manager.d/disabled` as the operator fallback (never deleted). See `../local/docs/evidence/driver-manager/ASSESSMENT-2026-07-22.md` (major assessment, findings B1G10 + § 11 services integration). Delivered: claim-via-channel collapse (pcid `ENOLCK` exclusivity — the pcid-spawner model); init `ConditionPathExists` gate (systemd-style, `!` negation); spawned-mode `pci_register_driver` in linux-kpi (honors `PCID_CLIENT_CHANNEL` — single ownership of match-claim-spawn for native and Linux-port daemons); linux-kpi real MSI/MSI-X via pcid_interface + `pci_request_regions` + `pcie_capability_*` + PM state; redbear-iwlwifi `--daemon` onboarding + `70-wifi.toml`; `--import-linux-ids` Linux id_table→TOML pipeline; scheme operator surface (`bind`/`unbind`/`new_id`/`remove_id`/`driver_override`/`rescan`); Tier-1 driver_override; success-triggered deferred retry; concurrent probes with real `Driver::probe()`; real SIGCHLD/SIGHUP handlers; heartbeat counters; AER `route_to_driver`; `exclusive_with` mutual exclusion; `pci=nomsi` env var; PciQuirkFlags spawn env hints + `REDBEAR_DRIVER_{IOMMU_GROUP,NUMA_NODE,MSIX_VECTORS}`; driver-params bridge live; D-Bus correctly absent (bridge-on-demand). Gate: PASSED in QEMU q35 (initfs ahcid bind, rootfs e1000d concurrent bind, scheme live, resident hotplug). Platform finding: `thread::scope` hangs on Redox (spawn+join used instead). Cookbook now hashes Cargo path-dep sources (staleness hole closed). Open: P2-1 pcid AER/pciehp producers, P3 policy/hygiene. 93 tests pass; 0 audit-no-stubs violations; zero crate-local warnings on host and redox target.
- `../local/docs/WAYLAND-IMPLEMENTATION-PLAN.md` — Wayland compositor (subsystem detail)
- `../local/docs/archived/RELIBC-IPC-ASSESSMENT-AND-IMPROVEMENT-PLAN.md` — relibc IPC surface
- `../local/docs/GREETER-LOGIN-IMPLEMENTATION-PLAN.md` — greeter/login design
+1 -1
View File
@@ -1422,7 +1422,7 @@ When mainline updates affect our work:
also be treated as first-class subsystem plans, not as side notes.
- `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` is the current umbrella plan for
IRQ delivery, MSI/MSI-X quality, IOMMU validation, and other low-level controller completeness work.
- `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v3.2, 2026-07-24) is the canonical planning
- `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v4.0, 2026-07-24) is the canonical planning
authority for the migration from `pcid-spawner` (retired and removed 2026-07-24;
source preserved in git history) to
`driver-manager` (`local/recipes/system/driver-manager/`). **CUTOVER COMPLETE (2026-07-23,
+23 -7
View File
@@ -1,6 +1,6 @@
# Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan
**Document status:** v3.2 canonical planning authority (supersedes v3.1 with the QEMU runtime gate PASSED: cutover validated end-to-end in QEMU q35 — initfs storage bind, rootfs concurrent probe/claim/spawn, scheme live, resident hotplug loop — plus the `thread::scope` platform finding and the cookbook cargo-path-dep staleness fix)
**Document status:** v4.0 canonical planning authority (supersedes v3.2: P2-1 done, P3 hygiene largely complete, pcid-spawner fully retired, quirks universal model, build-system staleness fix, QEMU gate passed, AER/pciehp producers live, udev-shim driver-binding view wired, concurrent double enumeration eliminated, PciErsResult 6-state enum added)
**Generated:** 2026-07-20
**Toolchain:** Rust nightly-2026-05-24 (edition 2024)
**Architecture:** Microkernel OS in Rust (Redox fork)
@@ -74,12 +74,28 @@ is closed and verified (`DEBUG: cargo path-dep source hashes changed`
→ rebuild → cached).
Open items (updated): **P3-remaining** — lifecycle phases on quirk
entries (`phase = "early"|"enable"`), AER recovery actions wired to
drivers (`pci_ers_result` mapping), per-vendor firmware packaging,
concurrent path's double bus enumeration, `acpid pci_fd is not
registered`. Resolved: P2-1 done (pcid AER + pciehp producers live and
validated); dep-crate warnings fixed; udev-shim driver-binding view
wired; quirks TOML/parser flag drift resolved (open domain channel).
entries (`phase = "early"|"enable"`), AER recovery dispatch to bound
drivers (PciErsResult type ready; needs driver-manager → driver IPC
channel via `/scheme/driver-manager/recover`), per-vendor firmware
packaging mirroring linux-firmware splits, `acpid pci_fd is not
registered` (ACPI session).
**v4.0 post-cutover state (2026-07-24):**
| Area | Status |
|---|---|
| Boot path | driver-manager owns initfs + rootfs unconditionally; pcid-spawner fully retired |
| QEMU gate | PASSED (q35): initfs ahcid bind → switchroot → rootfs e1000d/virtio-netd/xhcid concurrent bind → scheme live → resident hotplug → login prompt |
| Claim model | channel exclusivity (`ENOLCK`); SpawnedDriver holds the fd |
| Concurrent probes | spawn+join pool (thread::scope hangs on Redox); Arc semaphore; Mutex bound map |
| AER/pciehp producers | pcid 500ms poller → `/scheme/pci/aer` + `/scheme/pci/pciehp`; unified listener reads them |
| AER recovery model | PciErsResult 6-state enum mirrors Linux pci_ers_result; dispatch endpoint pending |
| linux-kpi | spawned-mode pci_register_driver; real MSI/MSI-X via pcid_interface; pci_request_regions; pcie_capability_*; PM state |
| Scheme operator surface | bind/unbind/new_id/remove_id/driver_override/rescan |
| Quirks model | three-layer invariant (match→store→consume); open driver-scoped domains (`[[<domain>_quirk]]`); audio domain live |
| Build system | cookbook hashes Cargo path-dep source trees (staleness hole closed); set -e abort fixed |
| udev-shim | reads `/scheme/driver-manager/bound` for DRIVER= property |
| Tests | 94+ (driver-manager 59 + redox-driver-core 35 + iwlwifi host tests); zero crate-local warnings |
**v3.1 status update over v3.0 (implementation + cutover round, 2026-07-23):**
@@ -6,6 +6,127 @@
#define IEEE80211_MAX_SSID_LEN 32
#define IEEE80211_NUM_ACS 4
/* Frame types (IEEE 802.11) */
#define IEEE80211_FTYPE_MGMT 0x0000
#define IEEE80211_FTYPE_CTL 0x0004
#define IEEE80211_FTYPE_DATA 0x0008
#define IEEE80211_STYPE_ASSOC_REQ 0x0000
#define IEEE80211_STYPE_ASSOC_RESP 0x0010
#define IEEE80211_STYPE_REASSOC_REQ 0x0020
#define IEEE80211_STYPE_REASSOC_RESP 0x0030
#define IEEE80211_STYPE_PROBE_REQ 0x0040
#define IEEE80211_STYPE_PROBE_RESP 0x0050
#define IEEE80211_STYPE_BEACON 0x0080
#define IEEE80211_STYPE_AUTH 0x00b0
#define IEEE80211_STYPE_DEAUTH 0x00c0
#define IEEE80211_STYPE_ACTION 0x00d0
#define IEEE80211_STYPE_QOS_DATA 0x0080
/* Capability bits */
#define WLAN_CAPABILITY_ESS (1U << 0)
#define WLAN_CAPABILITY_IBSS (1U << 1)
#define WLAN_CAPABILITY_PRIVACY (1U << 4)
#define WLAN_CAPABILITY_SHORT_PREAMBLE (1U << 5)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1U << 10)
/* Reason codes (IEEE 802.11 §9.4.1.7) */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
#define WLAN_REASON_DISASSOC_AP_BUSY 5
/* Status codes */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
/* Cipher suites */
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0C
#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC0D
/* AID range */
#define IEEE80211_MAX_AID 2007
/* Max frame size */
#define IEEE80211_MAX_DATA_LEN 2304
#define IEEE80211_MAX_FRAME_LEN 2352
/* Key indices */
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define NUM_DEFAULT_BEACON_KEYS 2
/* Extended capabilities */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
#define WLAN_EID_REQUEST 10
#define WLAN_EID_BSS_LOAD 11
#define WLAN_EID_PWR_CAPABILITY 33
#define WLAN_EID_SUPPORTED_CHANNELS 36
#define WLAN_EID_CHANNEL_SWITCH 37
#define WLAN_EID_MEASURE_REPORT 39
#define WLAN_EID_QUIET 40
#define WLAN_EID_IBSS_DFS 41
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_TSPEC 43
#define WLAN_EID_TCLAS 44
#define WLAN_EID_SCHEDULE 45
#define WLAN_EIDChallengeText 46
#define WLAN_EID_PWR_CONSTRAINT 32
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_DSE_REGISTERED_LOCATION 60
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
#define WLAN_EID_EXT_CHANSWITCH_ANN 60
#define WLAN_EID_HT_CAPABILITY 45
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_BSS_COEX_2040 72
#define WLAN_EID_EXT_CAPABILITY 127
#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_MESH_CONFIG 113
#define WLAN_EID_MESH_ID 114
#define WLAN_EID_PEER_MGMT 117
#define WLAN_EID_MESH_AWAKE_WINDOW 119
#define WLAN_EID_BEACON_TIMING 120
#define WLAN_EID_S1G_BCN_COMPAT 213
#define WLAN_EID_S1G_CAPABILITIES 217
#define WLAN_EID_S1G_OPERATION 232
/* HE/EHT element IDs (extended) */
#define WLAN_EID_EXTENSION 255
#define WLAN_EID_EXT_HE_CAPABILITY 35
#define WLAN_EID_EXT_HE_OPERATION 36
#define WLAN_EID_EXT_UORA 38
#define WLAN_EID_EXT_EHT_CAPABILITY 108
#define WLAN_EID_EXT_EHT_OPERATION 109
#define WLAN_EID_EXT_MULTI_LINK 109
/* MLO (Multi-Link Operation) types */
#define WLAN_EID_VENDOR_SPECIFIC 221
/* Band definitions */
enum ieee80211_band_local {
IEEE80211_BAND_2GHZ = 0,
IEEE80211_BAND_5GHZ = 1,
IEEE80211_BAND_6GHZ = 2,
};
struct ieee80211_channel {
u32 band;
u16 center_freq;
@@ -15,6 +136,7 @@ struct ieee80211_channel {
s8 max_reg_power;
s8 max_antenna_gain;
bool beacon_found;
u32 max_bandwidth_khz;
};
struct ieee80211_rate {
@@ -24,4 +146,38 @@ struct ieee80211_rate {
u16 hw_value_short;
};
struct ieee80211_sta_ht_cap {
u16 cap;
bool ht_supported;
u8 ampdu_factor;
u16 ampdu_density;
struct {
u8 rx_highest;
u8 rx_mcs_mask[10];
} mcs;
};
struct ieee80211_sta_vht_cap {
u32 cap;
bool vht_supported;
u8 vht_mcs_rx_highest;
u8 vht_mcs_tx_highest;
};
struct ieee80211_sta_he_cap {
bool he_supported;
u8 mac_cap_info[6];
u8 phy_cap_info[11];
u8 mcs_nss_rx[4];
u8 mcs_nss_tx[4];
};
struct ieee80211_sta_eht_cap {
bool eht_supported;
u8 mac_cap_info[2];
u8 phy_cap_info[9];
u8 mcs_nss_rx[4];
u8 mcs_nss_tx[4];
};
#endif
@@ -18,39 +18,88 @@
#define IEEE80211_CONF_CHANGE_POWER (1U << 5)
#define IEEE80211_CONF_CHANGE_CHANNEL (1U << 6)
struct ieee80211_conf {
#define IEEE80211_MLD_MAX_NUM_LINKS 15
enum ieee80211_band {
NL80211_BAND_2GHZ = 0,
NL80211_BAND_5GHZ = 1,
NL80211_BAND_6GHZ = 2,
NL80211_BAND_60GHZ = 3,
};
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT = 0,
NL80211_CHAN_WIDTH_20 = 1,
NL80211_CHAN_WIDTH_40 = 2,
NL80211_CHAN_WIDTH_80 = 3,
NL80211_CHAN_WIDTH_80P80 = 4,
NL80211_CHAN_WIDTH_160 = 5,
NL80211_CHAN_WIDTH_320 = 13,
};
#define IEEE80211_HT_CAP_LDPC_CODING (1U << 0)
#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 (1U << 1)
#define IEEE80211_HT_CAP_SGI_20 (1U << 2)
#define IEEE80211_HT_CAP_SGI_40 (1U << 3)
#define IEEE80211_VHT_CAP_MAX_MPDU_11454 (3U << 0)
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ (1U << 2)
enum ieee80211_sta_state {
IEEE80211_STA_NOTEXIST,
IEEE80211_STA_NONE,
IEEE80211_STA_AUTH,
IEEE80211_STA_ASSOC,
IEEE80211_STA_AUTHORIZED,
};
enum set_key_cmd { SET_KEY, DISABLE_KEY };
enum ieee80211_ampdu_mlme_action {
IEEE80211_AMPDU_RX_START = 0,
IEEE80211_AMPDU_RX_STOP = 1,
IEEE80211_AMPDU_TX_START = 2,
IEEE80211_AMPDU_TX_STOP_CONT = 3,
IEEE80211_AMPDU_TX_STOP_FLUSH = 4,
IEEE80211_AMPDU_TX_START_NEW = 5,
IEEE80211_AMPDU_TX_OPERATIONAL = 6,
};
#define IEEE80211_KEY_FLAG_GENERATE_IV (1U << 0)
#define IEEE80211_KEY_FLAG_GENERATE_MMIC (1U << 1)
#define IEEE80211_KEY_FLAG_PAIRWISE (1U << 2)
#define BSS_CHANGED_ASSOC (1U << 0)
#define BSS_CHANGED_BSSID (1U << 1)
#define BSS_CHANGED_ERP_CTS_PROT (1U << 2)
#define BSS_CHANGED_HT (1U << 3)
#define BSS_CHANGED_BASIC_RATES (1U << 4)
#define BSS_CHANGED_BEACON_INT (1U << 5)
#define BSS_CHANGED_BANDWIDTH (1U << 6)
#define BSS_CHANGED_QOS (1U << 8)
#define BSS_CHANGED_TXPOWER (1U << 12)
#define BSS_CHANGED_HE_BSS_COLOR (1U << 17)
#define BSS_CHANGED_EHT_PUNCTURING (1U << 23)
struct ieee80211_chanctx_conf {
enum nl80211_chan_width radar_detect_width;
bool driver_present;
u8 rx_chains_dynamic, rx_chains_static;
struct ieee80211_channel *chan;
};
struct ieee80211_txq {
struct ieee80211_sta *sta;
void *drv_priv;
u8 ac;
u8 tid;
};
struct ieee80211_key_conf {
u32 cipher;
u32 flags;
int power_level;
int dynamic_ps_timeout;
struct {
u32 center_freq;
u16 band;
struct ieee80211_channel *channel;
} chandef;
u32 listen_interval;
};
struct ieee80211_hw {
struct wiphy *wiphy;
const struct ieee80211_ops *ops;
void *priv;
int registered;
u32 extra_tx_headroom;
u16 queues;
struct ieee80211_conf conf;
};
struct ieee80211_vif {
u8 addr[6];
void *drv_priv;
u32 type;
bool cfg_assoc;
};
struct ieee80211_sta {
u8 addr[6];
void *drv_priv;
u16 aid;
u8 keyidx;
u8 keylen;
u8 key[32];
};
struct ieee80211_bss_conf {
@@ -64,83 +113,194 @@ struct ieee80211_bss_conf {
u32 center_freq;
u16 band;
struct ieee80211_channel *channel;
enum nl80211_chan_width width;
} chandef;
bool he_support;
bool eht_support;
u8 he_bss_color;
u8 link_id;
struct ieee80211_chanctx_conf *chanctx;
};
struct ieee80211_link {
struct ieee80211_bss_conf conf;
u8 link_id;
bool active;
u8 addr[6];
};
struct ieee80211_link_sta {
u8 addr[6];
void *drv_priv;
bool he_capa_present;
bool eht_capa_present;
u32 ht_cap;
u32 vht_cap;
};
struct ieee80211_sta {
u8 addr[6];
u8 mld_addr[6];
void *drv_priv;
u16 aid;
bool wme;
bool mfp;
bool tdls;
bool is_mld;
u16 valid_links;
struct ieee80211_link_sta deflink;
struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS + 1];
};
struct ieee80211_vif {
u8 addr[6];
void *drv_priv;
u32 type;
bool cfg_assoc;
bool is_mld;
u16 valid_links;
struct ieee80211_link deflink;
struct ieee80211_link *link[IEEE80211_MLD_MAX_NUM_LINKS + 1];
struct ieee80211_bss_conf bss_conf;
};
struct ieee80211_rx_status {
u64 mactime;
u16 freq;
u32 band;
s8 signal;
s8 noise;
u8 rate_idx;
u8 link_id;
u32 flag;
u8 antenna;
u32 rx_flags;
u32 encoding;
u8 nss;
u8 bw;
};
enum ieee80211_sta_state {
IEEE80211_STA_NOTEXIST,
IEEE80211_STA_NONE,
IEEE80211_STA_AUTH,
IEEE80211_STA_ASSOC,
IEEE80211_STA_AUTHORIZED,
struct ieee80211_conf {
u32 flags;
int power_level;
int dynamic_ps_timeout;
struct {
u32 center_freq;
u16 band;
struct ieee80211_channel *channel;
enum nl80211_chan_width width;
} chandef;
u32 listen_interval;
};
enum set_key_cmd {
SET_KEY,
DISABLE_KEY,
struct ieee80211_hw {
struct wiphy *wiphy;
const struct ieee80211_ops *ops;
void *priv;
int registered;
u32 extra_tx_headroom;
u16 queues;
u8 max_rx_aggregation_subframes;
u8 max_tx_aggregation_subframes;
struct ieee80211_conf conf;
};
struct ieee80211_tx_rate {
u8 idx;
u8 count;
u8 flags;
};
struct ieee80211_tx_info {
u32 flags;
u32 band;
struct ieee80211_tx_rate rates[4];
u8 antenna;
u8 ack_signal;
bool is_data;
};
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
void (*tx)(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
void (*wake_tx_queue)(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw);
int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*change_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 new_type, bool p2p);
void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*config)(struct ieee80211_hw *hw, u32 changed);
void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed);
struct ieee80211_bss_conf *info, u64 changed);
void (*vif_cfg_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed);
void (*link_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf, u64 changed);
int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state);
void (*sta_pre_rcu_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct key_params *key);
struct ieee80211_key_conf *key);
int (*ampdu_action)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 action, u16 tid, u16 ssn);
struct ieee80211_sta *sta, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_txq *txq);
bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw, struct sk_buff *head, struct sk_buff *skb);
void (*sw_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac_addr);
void (*sw_scan_complete)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
u64 (*prepare_multicast)(struct ieee80211_hw *hw, void *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw, u32 changed_flags,
u32 *total_flags, u64 multicast);
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req);
void (*cancel_hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*sched_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *req);
void (*sched_scan_stop)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop);
void (*flush_sta)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
void (*configure_filter)(struct ieee80211_hw *hw, u32 changed_flags, u32 *total_flags, u64 multicast);
u64 (*prepare_multicast)(struct ieee80211_hw *hw, void *mc_list);
int (*conf_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 link_id, u8 ac, void *params);
int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
void (*sta_statistics)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sinfo);
void (*link_sta_rc_update)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta);
void (*mgd_prepare_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *info);
void (*mgd_complete_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *info);
void (*sync_rx_queues)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*reconfig_complete)(struct ieee80211_hw *hw, u32 flags);
void (*restart_complete)(struct ieee80211_hw *hw);
int (*add_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx);
void (*remove_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx);
void (*change_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed);
int (*assign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx);
void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx);
void (*switch_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf **old, struct ieee80211_chanctx_conf **nw, u32 n);
int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf);
void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf);
bool (*tx_last_beacon)(struct ieee80211_hw *hw);
};
#define BSS_CHANGED_ASSOC (1U << 0)
#define BSS_CHANGED_BSSID (1U << 1)
#define BSS_CHANGED_ERP_CTS_PROT (1U << 2)
#define BSS_CHANGED_HT (1U << 3)
#define BSS_CHANGED_BASIC_RATES (1U << 4)
#define BSS_CHANGED_BEACON_INT (1U << 5)
#define BSS_CHANGED_BANDWIDTH (1U << 6)
#define IEEE80211_RECONFIG_TYPE_TIMER 0
#define IEEE80211_RECONFIG_TYPE_ARP_FILTER 1
extern struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
const void *ops,
const char *requested_name);
extern struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, const void *ops, const char *requested_name);
extern void ieee80211_free_hw(struct ieee80211_hw *hw);
extern int ieee80211_register_hw(struct ieee80211_hw *hw);
extern int ieee80211_register_hw(struct ieee80211_hw *hw);
extern void ieee80211_unregister_hw(struct ieee80211_hw *hw);
extern void ieee80211_queue_work(struct ieee80211_hw *hw, void *work);
extern void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
extern void ieee80211_connection_loss(struct ieee80211_vif *vif);
extern int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid, u16 timeout);
extern int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
extern int ieee80211_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u32 old_state, u32 new_state);
extern int ieee80211_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u32 old_state, u32 new_state);
extern struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, const u8 *addr);
extern void ieee80211_beacon_loss(struct ieee80211_vif *vif);
extern void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb);
extern size_t ieee80211_rx_drain(struct ieee80211_hw *hw);
extern void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
extern void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
extern void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
extern struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb);
#define ieee80211_alloc_hw(priv, ops) ieee80211_alloc_hw_nm(priv, ops, KBUILD_MODNAME)
#endif
@@ -54,6 +54,7 @@ enum HandleKind {
RemoveId,
DriverOverride,
Rescan,
Recover,
}
pub struct DriverManagerScheme {
@@ -166,6 +167,7 @@ impl DriverManagerScheme {
["remove_id"] => Ok(HandleKind::RemoveId),
["driver_override"] => Ok(HandleKind::DriverOverride),
["rescan"] => Ok(HandleKind::Rescan),
["recover"] => Ok(HandleKind::Recover),
["devices", pci_addr] if Self::valid_pci_addr(pci_addr) => {
let _ = self.device_status(pci_addr)?;
Ok(HandleKind::Device((*pci_addr).to_string()))
@@ -238,7 +240,7 @@ impl DriverManagerScheme {
fn read_handle_string(&self, id: usize, kind: &HandleKind) -> Result<String> {
match kind {
HandleKind::Root => {
Ok("devices\nbound\nevents\nmodalias\nbind\nunbind\nnew_id\nremove_id\ndriver_override\nrescan\n".to_string())
Ok("devices\nbound\nevents\nmodalias\nbind\nunbind\nnew_id\nremove_id\ndriver_override\nrescan\nrecover\n".to_string())
}
HandleKind::Devices => {
let addresses = self.sorted_bound_addresses().map_err(|err| {
@@ -285,6 +287,7 @@ impl DriverManagerScheme {
),
HandleKind::RemoveId => Ok("write the same fields as new_id to remove\n".to_string()),
HandleKind::Rescan => Ok("write anything to re-enumerate all buses\n".to_string()),
HandleKind::Recover => Ok("write '<pci_addr> <reset_device|rescan_bus|disconnect>' to trigger AER recovery\n".to_string()),
}
}
@@ -303,6 +306,7 @@ impl DriverManagerScheme {
HandleKind::RemoveId => format!("{SCHEME_NAME}:/remove_id"),
HandleKind::DriverOverride => format!("{SCHEME_NAME}:/driver_override"),
HandleKind::Rescan => format!("{SCHEME_NAME}:/rescan"),
HandleKind::Recover => format!("{SCHEME_NAME}:/recover"),
}
}
@@ -314,12 +318,13 @@ impl DriverManagerScheme {
| HandleKind::Bound
| HandleKind::Events
| HandleKind::Modalias
| HandleKind::Bind
| HandleKind::Bind
| HandleKind::Unbind
| HandleKind::NewId
| HandleKind::RemoveId
| HandleKind::DriverOverride
| HandleKind::Rescan => MODE_FILE | 0o644,
| HandleKind::Rescan
| HandleKind::Recover => MODE_FILE | 0o644,
}
}
@@ -425,6 +430,42 @@ impl DriverManagerScheme {
}
Ok(())
}
HandleKind::Recover => {
let mut parts = line.split_whitespace();
let addr = parts.next().ok_or(Error::new(EINVAL))?;
let action = parts.next().unwrap_or("reset_device");
let id = DeviceId {
bus: "pci".to_string(),
path: addr.to_string(),
};
log::warn!(
"AER recovery: device={} action={}",
id.path,
action
);
match action {
"reset_device" => {
let _event = self.with_manager(|mgr| mgr.remove_device(&id))?;
thread::sleep(std::time::Duration::from_millis(100));
let events = self.with_manager(|mgr| mgr.bind_device(&id, ""))?;
for event in &events {
self.record_probe_event(event);
}
}
"rescan_bus" => {
let events = self.with_manager(|mgr| mgr.enumerate())?;
for event in &events {
self.record_probe_event(event);
}
}
"disconnect" => {
let _event = self.with_manager(|mgr| mgr.remove_device(&id))?;
notify_unbind(self, addr);
}
_ => return Err(Error::new(EINVAL)),
}
Ok(())
}
_ => Err(Error::new(EACCES)),
}
}
@@ -564,7 +605,8 @@ impl SchemeSync for SchemeServer {
| HandleKind::NewId
| HandleKind::RemoveId
| HandleKind::DriverOverride
| HandleKind::Rescan => {
| HandleKind::Rescan
| HandleKind::Recover => {
let line = String::from_utf8_lossy(buf).trim().to_string();
self.scheme.write_operator(kind, &line)?;
Ok(buf.len())