diff --git a/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c b/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c
new file mode 100644
index 000000000000..9ba8407a1306
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+#include "fw/msg_tx.h"
+#include "rsrc_mgmt.h"
+#include "rx/rx_amsdu.h"
+#include "prot_mode.h"
+#include "env_det.h"
+
+#ifndef ETYPE2STR
+#define ETYPE2STR(_e) case _e: return # _e
+#endif
+
+static const char *subtype2str(enum mm_rsrc_mgmt_subtype subtype)
+{
+       switch (subtype) {
+       ETYPE2STR(MM_RSRC_MGMT_API_SANITY);
+       ETYPE2STR(MM_RSRC_MGMT_TRAFFIC_START);
+       ETYPE2STR(MM_RSRC_MGMT_TRAFFIC_STOP);
+       ETYPE2STR(MM_RSRC_MGMT_RATES_UPDATE);
+       ETYPE2STR(MM_RSRC_MGMT_CECLI_HINT);
+
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_HINT);
+       ETYPE2STR(MM_RSRC_MGMT_ENV_CHANGE);
+       ETYPE2STR(MM_RSRC_MGMT_STATS);
+       ETYPE2STR(MM_RSRC_MGMT_CONFIG_QUERY);
+       ETYPE2STR(MM_RSRC_MGMT_NOTIF_POLICY_SET);
+       ETYPE2STR(MM_RSRC_MGMT_MAX);
+       default: return "UNKNOWN_SUBTYPE";
+       }
+}
+
+static const char *action2str(enum mm_rsrc_mgmt_action_hint action)
+{
+       switch (action) {
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_ENABLE);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_DISABLE);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_SET);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_GET);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_MAX);
+       default: return "UNKNOWN_ACTION";
+       }
+}
+
+static const char *control2str(enum mm_rsrc_mgmt_control_of control_of)
+{
+       switch (control_of) {
+       ETYPE2STR(MM_RSRC_MGMT_OF_TX_AMSDU);
+       ETYPE2STR(MM_RSRC_MGMT_OF_RX_AMSDU);
+       ETYPE2STR(MM_RSRC_MGMT_OF_PROT_MODE);
+       ETYPE2STR(MM_RSRC_MGMT_OF_CCA);
+       default: return "UNKNOWN_CONTROL_OF";
+       }
+}
+
+static inline bool is_in_low_range(s8 th, s8 v)
+{
+       if (th != -1)
+               return th >= v;
+       return true;
+}
+
+static inline bool is_in_high_range(s8 th, s8 v)
+{
+       if (th != -1)
+               return th <= v;
+       return true;
+}
+
+/*
+ * DRV <- FW: notification_policy.
+ *
+ * Notification filters:
+ * 1. on/off (enabled/disabled);
+ * 2. active sta count (lower and upper);
+ * 3. TODO: frequency (once per 100msec etc);
+ * 4. TODO: amount of failures in feedback;
+ */
+static bool must_notify(struct cl_hw *cl_hw, u8 event_type, u8 active_sta_cnt)
+{
+       struct mm_rsrc_mgmt_notif_policy *p = &cl_hw->rsrc_mgmt_db.notif_policies[event_type];
+
+       return p->enabled &&
+               is_in_low_range(p->active_sta.low_th, active_sta_cnt) &&
+               is_in_high_range(p->active_sta.high_th, active_sta_cnt);
+}
+
+/*
+ * Public API
+ */
+void cl_rsrc_mgmt_init(struct cl_hw *cl_hw)
+{
+       BUILD_BUG_ON(TRAFFIC_LEVEL_MAX >
+                    BITS_PER_TYPE(typeof_member(struct mm_rsrc_mgmt_notif_policy,
+                                                level_mask)));
+       BUILD_BUG_ON(TRAFFIC_DIRECTION_MAX >
+                    BITS_PER_TYPE(typeof_member(struct mm_rsrc_mgmt_notif_policy,
+                                                direction_mask)));
+
+       cl_dbg_trace(cl_hw, "RSRC MGMT Init: sizeof(req):%zu, sizeof(ind):%zu, sizeof(cfm):%zu\n",
+                    sizeof(struct mm_rsrc_mgmt_req),
+                    sizeof(struct mm_rsrc_mgmt_ind),
+                    sizeof(struct mm_rsrc_mgmt_cfm));
+}
+
+/*
+ * Direction: DRV -> FW: Requests/Notifications
+ */
+void cl_rsrc_mgmt_traffic_start(struct cl_hw *cl_hw, enum cl_traffic_level level,
+                               enum cl_traffic_direction direction)
+{
+       u8 event_type = MM_RSRC_MGMT_TRAFFIC_START;
+       u8 active_sta_cnt = cl_hw->traffic_db.num_active_sta_dir[direction][level];
+
+       if (!must_notify(cl_hw, event_type, active_sta_cnt))
+               return;
+
+       cl_msg_tx_rsrc_mgmt_traffic_event(cl_hw, event_type, level, direction,
+                                         active_sta_cnt);
+}
+
+void cl_rsrc_mgmt_traffic_stop(struct cl_hw *cl_hw, enum cl_traffic_level level,
+                              enum cl_traffic_direction direction)
+{
+       u8 event_type = MM_RSRC_MGMT_TRAFFIC_STOP;
+       u8 active_sta_cnt = cl_hw->traffic_db.num_active_sta_dir[direction][level];
+
+       if (!must_notify(cl_hw, event_type, active_sta_cnt))
+               return;
+
+       cl_msg_tx_rsrc_mgmt_traffic_event(cl_hw, event_type, level, direction,
+                                         active_sta_cnt);
+}
+
+void cl_rsrc_mgmt_rates_update(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       u8 event_type = MM_RSRC_MGMT_RATES_UPDATE;
+       u8 active_sta_cnt = cl_traffic_num_active_sta(cl_hw);
+
+       if (!must_notify(cl_hw, event_type, active_sta_cnt))
+               return;
+
+       cl_msg_tx_rsrc_mgmt_rates_event(cl_hw, event_type, cl_sta);
+}
+
+void cl_rsrc_mgmt_process_cfm(struct cl_hw *cl_hw, struct mm_rsrc_mgmt_cfm *cfm)
+{
+       cl_dbg_trace(cl_hw, "CFM: subtype:%s(%u), status:%d\n",
+                    subtype2str(cfm->subtype), cfm->subtype, cfm->status);
+}
+
+/*
+ * DRV <- FW: Indications processings
+ */
+static void process_env_change(struct cl_hw *cl_hw, enum cl_env_type type)
+{
+       cl_env_det_set_type(cl_hw, type);
+}
+
+static void process_notif_policy(struct cl_hw *cl_hw, u8 subtype,
+                                struct mm_rsrc_mgmt_notif_policy *np)
+{
+       struct cl_rsrc_mgmt_db *db = &cl_hw->rsrc_mgmt_db;
+
+       cl_dbg_trace(cl_hw, "[%s(%u)] enabled:%u, sta.low_th:%d, sta.high_th:%d\n",
+                    subtype2str(subtype), subtype, np->enabled,
+                    np->active_sta.low_th, np->active_sta.high_th);
+
+       if (subtype < ARRAY_SIZE(db->notif_policies))
+               db->notif_policies[subtype] = *np;
+       else
+               cl_dbg_err(cl_hw, "Invalid subtype index:%s(%u)\n",
+                          subtype2str(subtype), subtype);
+}
+
+static void process_action_hint(struct cl_hw *cl_hw, uint16_t target, uint8_t action)
+{
+       int rc = 0;
+
+       cl_dbg_info(cl_hw, "Processing hint: target - %s(%u), action - %s(%u)\n",
+                   control2str(target), target, action2str(action), action);
+
+       switch (target) {
+       case MM_RSRC_MGMT_OF_TX_AMSDU:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+                       cl_hw->txamsdu_en = 1;
+                       break;
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_hw->txamsdu_en = 0;
+                       break;
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_hw->txamsdu_en = cl_hw->conf->ce_txamsdu_en;
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       case MM_RSRC_MGMT_OF_RX_AMSDU:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+                       cl_rx_amsdu_hw_en(cl_hw->hw, true);
+                       break;
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_rx_amsdu_hw_en(cl_hw->hw, false);
+                       break;
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_rx_amsdu_hw_en(cl_hw->hw, cl_hw->conf->ce_rxamsdu_en);
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       case MM_RSRC_MGMT_OF_PROT_MODE:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+                       cl_prot_mode_enable(cl_hw);
+                       break;
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_prot_mode_disable(cl_hw);
+                       break;
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_prot_mode_restore_default(cl_hw);
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       case MM_RSRC_MGMT_OF_CCA:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_msg_tx_config_cca(cl_hw, false);
+                       break;
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_msg_tx_config_cca(cl_hw, true);
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       default:
+               rc = -EOPNOTSUPP;
+               break;
+       };
+
+       if (rc) {
+               cl_dbg_err(cl_hw, "Hint process failure, rc:%d [%s(%u):%s(%u)]\n",
+                          rc, control2str(target), target, action2str(action),
+                          action);
+       }
+}
+
+void cl_rsrc_mgmt_process_ind(struct cl_hw *cl_hw, struct mm_rsrc_mgmt_ind *ind)
+{
+       switch (ind->subtype) {
+       case MM_RSRC_MGMT_ACTION_HINT:
+               process_action_hint(cl_hw,
+                                   le16_to_cpu(ind->u.action_hint.target),
+                                   ind->u.action_hint.action);
+               break;
+       case MM_RSRC_MGMT_ENV_CHANGE:
+               process_env_change(cl_hw, ind->u.env_event.state);
+               break;
+       case MM_RSRC_MGMT_NOTIF_POLICY_SET:
+               process_notif_policy(cl_hw,
+                                    ind->u.notif_policy_set.subtype,
+                                    &ind->u.notif_policy_set.settings);
+               break;
+       case MM_RSRC_MGMT_STATS:
+       case MM_RSRC_MGMT_CONFIG_QUERY:
+       case MM_RSRC_MGMT_MAX:
+       default:
+               cl_dbg_err(cl_hw, "Invalid subtype %s(%u)\n",
+                          subtype2str(ind->subtype), ind->subtype);
+               break;
+       }
+}
+
