priv->shrd = trans->shrd;
priv->shrd->priv = priv;
+ iwl_trans_configure(trans(priv), op_mode);
+
/* At this point both hw and priv are allocated. */
SET_IEEE80211_DEV(priv->hw, trans(priv)->dev);
const struct iwl_op_mode_ops iwl_dvm_ops = {
.start = iwl_op_mode_dvm_start,
.stop = iwl_op_mode_dvm_stop,
+ .free_skb = iwl_free_skb,
};
/*****************************************************************************
void iwl_down(struct iwl_priv *priv);
void iwl_cancel_deferred_work(struct iwl_priv *priv);
void iwlagn_prepare_restart(struct iwl_priv *priv);
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
/* MAC80211 */
struct ieee80211_hw *iwl_alloc_all(void);
#include "iwl-shared.h"
#include "iwl-agn.h"
#include "iwl-trans.h"
+#include "iwl-wifi.h"
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
cfg(priv)->lib->nic_config(priv);
}
-void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb)
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
{
+ struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
struct ieee80211_tx_info *info;
info = IEEE80211_SKB_CB(skb);
struct iwl_op_mode;
struct iwl_trans;
+struct sk_buff;
/**
* struct iwl_op_mode_ops - op_mode specific operations
* May sleep
* @stop: stop the op_mode
* May sleep
+ * @free_skb: allows the transport layer to free skbs that haven't been
+ * reclaimed by the op_mode. This can happen when the driver is freed and
+ * there are Tx packets pending in the transport layer.
+ * Must be atomic
*/
struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans);
void (*stop)(struct iwl_op_mode *op_mode);
+ void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
};
/**
op_mode->ops->stop(op_mode);
}
+static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
+ struct sk_buff *skb)
+{
+ op_mode->ops->free_skb(op_mode, skb);
+}
+
/*****************************************************
* Op mode layers implementations
******************************************************/
int iwlagn_hw_valid_rtc_data_addr(u32 addr);
void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
void iwl_nic_config(struct iwl_priv *priv);
-void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
const char *get_cmd_string(u8 cmd);
bool iwl_check_for_ct_kill(struct iwl_priv *priv);
#include "iwl-prph.h"
#include "iwl-io.h"
#include "iwl-agn-hw.h"
+#include "iwl-op-mode.h"
#include "iwl-trans-pcie-int.h"
#define IWL_TX_CRC_SIZE 4
* freed and that the queue is not empty - free the skb
*/
if (skb) {
- iwl_free_skb(priv(trans), skb);
+ iwl_op_mode_free_skb(trans->op_mode, skb);
txq->skbs[index] = NULL;
}
}
struct iwl_priv;
struct iwl_shared;
+struct iwl_op_mode;
/**
* DOC: Host command section
* struct iwl_trans - transport common data
*
* @ops - pointer to iwl_trans_ops
+ * @op_mode - pointer to the op_mode
* @shrd - pointer to iwl_shared which holds shared data from the upper layer
* @hcmd_lock: protects HCMD
* @reg_lock - protect hw register access
*/
struct iwl_trans {
const struct iwl_trans_ops *ops;
+ struct iwl_op_mode *op_mode;
struct iwl_shared *shrd;
enum iwl_trans_state state;
spinlock_t hcmd_lock;
char trans_specific[0] __aligned(sizeof(void *));
};
+static inline void iwl_trans_configure(struct iwl_trans *trans,
+ struct iwl_op_mode *op_mode)
+{
+ /*
+ * only set the op_mode for the moment. Later on, this function will do
+ * more
+ */
+ trans->op_mode = op_mode;
+}
+
static inline int iwl_trans_start_hw(struct iwl_trans *trans)
{
might_sleep();