提交 e755f882 编写于 作者: J Johannes Berg 提交者: John W. Linville

iwlwifi: redesign PASSIVE_NO_RX workaround

The PASSIVE_NO_RX workaround currently crosses
through the op_mode and transport layers, which
is a bit odd. This also isn't necessary, if the
transport simply reports when queues are full
(or no longer full) the op_mode can keep track
of this state, and report to mac80211 only what
*it* thinks is appropriate. What is appropriate
can then be based on whether queues should be
stopped to wait for RX or not.

This significantly simplifies the transport API,
it no longer needs to expose anything to stop a
queue, nor to wake "any" queue, this can all be
handled in the upper layer completely.

Also simplify the handling to not be dependent
on the context, that makes little sense as the
queues are shared and both contexts have to be
on the same channel anyway.
Signed-off-by: NJohannes Berg <johannes.berg@intel.com>
Signed-off-by: NWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 ea886a60
...@@ -807,16 +807,12 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, ...@@ -807,16 +807,12 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
* sometimes even after already having transmitted frames for the * sometimes even after already having transmitted frames for the
* association because the new RXON may reset the information. * association because the new RXON may reset the information.
*/ */
if (unlikely(ieee80211_is_beacon(fc))) { if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
for_each_context(priv, ctx) { for_each_context(priv, ctx) {
if (!ctx->last_tx_rejected)
continue;
if (compare_ether_addr(hdr->addr3, if (compare_ether_addr(hdr->addr3,
ctx->active.bssid_addr)) ctx->active.bssid_addr))
continue; continue;
ctx->last_tx_rejected = false; iwlagn_lift_passive_no_rx(priv);
iwl_trans_wake_any_queue(trans(priv), ctx->ctxid,
"channel got active");
} }
} }
......
...@@ -833,12 +833,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, ...@@ -833,12 +833,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
* not get stuck in this case either since it * not get stuck in this case either since it
* can happen if userspace gets confused. * can happen if userspace gets confused.
*/ */
if (ctx->last_tx_rejected) { iwlagn_lift_passive_no_rx(priv);
ctx->last_tx_rejected = false;
iwl_trans_wake_any_queue(trans(priv),
ctx->ctxid,
"Disassoc: flush queue");
}
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
if (ctx->ctxid == IWL_RXON_CTX_BSS) if (ctx->ctxid == IWL_RXON_CTX_BSS)
......
...@@ -1064,8 +1064,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, ...@@ -1064,8 +1064,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
} }
/*we can free until ssn % q.n_bd not inclusive */ /*we can free until ssn % q.n_bd not inclusive */
WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id, WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid,
ssn, status, &skbs)); txq_id, ssn, &skbs));
iwlagn_check_ratid_empty(priv, sta_id, tid); iwlagn_check_ratid_empty(priv, sta_id, tid);
freed = 0; freed = 0;
...@@ -1086,9 +1086,9 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, ...@@ -1086,9 +1086,9 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
iwl_is_associated_ctx(ctx) && ctx->vif && iwl_is_associated_ctx(ctx) && ctx->vif &&
ctx->vif->type == NL80211_IFTYPE_STATION) { ctx->vif->type == NL80211_IFTYPE_STATION) {
ctx->last_tx_rejected = true; /* block and stop all queues */
iwl_trans_stop_queue(trans(priv), txq_id, priv->passive_no_rx = true;
"Tx on passive channel"); ieee80211_stop_queues(priv->hw);
IWL_DEBUG_TX_REPLY(priv, IWL_DEBUG_TX_REPLY(priv,
"TXQ %d status %s (0x%08x) " "TXQ %d status %s (0x%08x) "
...@@ -1182,7 +1182,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, ...@@ -1182,7 +1182,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
* block-ack window (we assume that they've been successfully * block-ack window (we assume that they've been successfully
* transmitted ... if not, it's too late anyway). */ * transmitted ... if not, it's too late anyway). */
if (iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, if (iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow,
ba_resp_scd_ssn, 0, &reclaimed_skbs)) { ba_resp_scd_ssn, &reclaimed_skbs)) {
spin_unlock(&priv->sta_lock); spin_unlock(&priv->sta_lock);
return 0; return 0;
} }
......
...@@ -1427,6 +1427,39 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) ...@@ -1427,6 +1427,39 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode)
cfg(priv)->lib->nic_config(priv); cfg(priv)->lib->nic_config(priv);
} }
static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
set_bit(ac, &priv->transport_queue_stop);
ieee80211_stop_queue(priv->hw, ac);
}
static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
clear_bit(ac, &priv->transport_queue_stop);
if (!priv->passive_no_rx)
ieee80211_wake_queue(priv->hw, ac);
}
void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
{
int ac;
if (!priv->passive_no_rx)
return;
for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) {
if (!test_bit(ac, &priv->transport_queue_stop))
ieee80211_wake_queue(priv->hw, ac);
}
priv->passive_no_rx = false;
}
const struct iwl_op_mode_ops iwl_dvm_ops = { const struct iwl_op_mode_ops iwl_dvm_ops = {
.start = iwl_op_mode_dvm_start, .start = iwl_op_mode_dvm_start,
.stop = iwl_op_mode_dvm_stop, .stop = iwl_op_mode_dvm_stop,
......
...@@ -84,14 +84,13 @@ void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb); ...@@ -84,14 +84,13 @@ void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd); struct iwl_device_cmd *cmd);
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac);
void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac);
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state); void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac);
void iwl_nic_error(struct iwl_op_mode *op_mode); void iwl_nic_error(struct iwl_op_mode *op_mode);
bool iwl_check_for_ct_kill(struct iwl_priv *priv); bool iwl_check_for_ct_kill(struct iwl_priv *priv);
void iwlagn_lift_passive_no_rx(struct iwl_priv *priv);
/* MAC80211 */ /* MAC80211 */
struct ieee80211_hw *iwl_alloc_all(void); struct ieee80211_hw *iwl_alloc_all(void);
int iwlagn_mac_setup_register(struct iwl_priv *priv, int iwlagn_mac_setup_register(struct iwl_priv *priv,
......
...@@ -1477,17 +1477,3 @@ void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) ...@@ -1477,17 +1477,3 @@ void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1])); kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
ieee80211_stop_queue(priv->hw, ac);
}
void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
ieee80211_wake_queue(priv->hw, ac);
}
...@@ -670,8 +670,6 @@ struct iwl_rxon_context { ...@@ -670,8 +670,6 @@ struct iwl_rxon_context {
bool enabled, is_40mhz; bool enabled, is_40mhz;
u8 extension_chan_offset; u8 extension_chan_offset;
} ht; } ht;
bool last_tx_rejected;
}; };
enum iwl_scan_type { enum iwl_scan_type {
...@@ -720,6 +718,9 @@ struct iwl_priv { ...@@ -720,6 +718,9 @@ struct iwl_priv {
spinlock_t sta_lock; spinlock_t sta_lock;
struct mutex mutex; struct mutex mutex;
unsigned long transport_queue_stop;
bool passive_no_rx;
/* ieee device used by generic ieee processing code */ /* ieee device used by generic ieee processing code */
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct ieee80211_channel *ieee_channels; struct ieee80211_channel *ieee_channels;
......
...@@ -451,18 +451,6 @@ static inline void iwl_stop_queue(struct iwl_trans *trans, ...@@ -451,18 +451,6 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
} }
} }
#ifdef ieee80211_stop_queue
#undef ieee80211_stop_queue
#endif
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#ifdef ieee80211_wake_queue
#undef ieee80211_wake_queue
#endif
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie, static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie,
int txq_id) int txq_id)
{ {
......
...@@ -1559,8 +1559,7 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans) ...@@ -1559,8 +1559,7 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans)
} }
static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
int txq_id, int ssn, u32 status, int txq_id, int ssn, struct sk_buff_head *skbs)
struct sk_buff_head *skbs)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
...@@ -1593,9 +1592,7 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, ...@@ -1593,9 +1592,7 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr, txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
tfd_num, ssn); tfd_num, ssn);
freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs); freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
if (iwl_queue_space(&txq->q) > txq->q.low_mark && if (iwl_queue_space(&txq->q) > txq->q.low_mark)
(!txq->sched_retry ||
status != TX_STATUS_FAIL_PASSIVE_NO_RX))
iwl_wake_queue(trans, txq, "Packets reclaimed"); iwl_wake_queue(trans, txq, "Packets reclaimed");
} }
...@@ -1662,32 +1659,6 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) ...@@ -1662,32 +1659,6 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
enum iwl_rxon_context_id ctx,
const char *msg)
{
u8 ac, txq_id;
struct iwl_trans_pcie *trans_pcie =
IWL_TRANS_GET_PCIE_TRANS(trans);
for (ac = 0; ac < AC_NUM; ac++) {
txq_id = trans_pcie->ac_to_queue[ctx][ac];
IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n",
ac,
(atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
? "stopped" : "awake");
iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg);
}
}
static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id,
const char *msg)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg);
}
#define IWL_FLUSH_WAIT_MS 2000 #define IWL_FLUSH_WAIT_MS 2000
static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans) static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
...@@ -2207,8 +2178,6 @@ const struct iwl_trans_ops trans_ops_pcie = { ...@@ -2207,8 +2178,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
.wowlan_suspend = iwl_trans_pcie_wowlan_suspend, .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
.wake_any_queue = iwl_trans_pcie_wake_any_queue,
.send_cmd = iwl_trans_pcie_send_cmd, .send_cmd = iwl_trans_pcie_send_cmd,
.tx = iwl_trans_pcie_tx, .tx = iwl_trans_pcie_tx,
...@@ -2219,7 +2188,6 @@ const struct iwl_trans_ops trans_ops_pcie = { ...@@ -2219,7 +2188,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
.tx_agg_setup = iwl_trans_pcie_tx_agg_setup, .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
.free = iwl_trans_pcie_free, .free = iwl_trans_pcie_free,
.stop_queue = iwl_trans_pcie_stop_queue,
.dbgfs_register = iwl_trans_pcie_dbgfs_register, .dbgfs_register = iwl_trans_pcie_dbgfs_register,
......
...@@ -289,7 +289,6 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) ...@@ -289,7 +289,6 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
* May sleep * May sleep
* @fw_alive: called when the fw sends alive notification * @fw_alive: called when the fw sends alive notification
* May sleep * May sleep
* @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_*
* @stop_device:stops the whole device (embedded CPU put to reset) * @stop_device:stops the whole device (embedded CPU put to reset)
* May sleep * May sleep
* @wowlan_suspend: put the device into the correct mode for WoWLAN during * @wowlan_suspend: put the device into the correct mode for WoWLAN during
...@@ -312,7 +311,6 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) ...@@ -312,7 +311,6 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
* irq, tasklet etc... From this point on, the device may not issue * irq, tasklet etc... From this point on, the device may not issue
* any interrupt (incl. RFKILL). * any interrupt (incl. RFKILL).
* May sleep * May sleep
* @stop_queue: stop a specific queue
* @check_stuck_queue: check if a specific queue is stuck * @check_stuck_queue: check if a specific queue is stuck
* @wait_tx_queue_empty: wait until all tx queues are empty * @wait_tx_queue_empty: wait until all tx queues are empty
* May sleep * May sleep
...@@ -334,18 +332,13 @@ struct iwl_trans_ops { ...@@ -334,18 +332,13 @@ struct iwl_trans_ops {
void (*wowlan_suspend)(struct iwl_trans *trans); void (*wowlan_suspend)(struct iwl_trans *trans);
void (*wake_any_queue)(struct iwl_trans *trans,
enum iwl_rxon_context_id ctx,
const char *msg);
int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
int (*tx)(struct iwl_trans *trans, struct sk_buff *skb, int (*tx)(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
u8 sta_id, u8 tid); u8 sta_id, u8 tid);
int (*reclaim)(struct iwl_trans *trans, int sta_id, int tid, int (*reclaim)(struct iwl_trans *trans, int sta_id, int tid,
int txq_id, int ssn, u32 status, int txq_id, int ssn, struct sk_buff_head *skbs);
struct sk_buff_head *skbs);
int (*tx_agg_disable)(struct iwl_trans *trans, int (*tx_agg_disable)(struct iwl_trans *trans,
int sta_id, int tid); int sta_id, int tid);
...@@ -357,8 +350,6 @@ struct iwl_trans_ops { ...@@ -357,8 +350,6 @@ struct iwl_trans_ops {
void (*free)(struct iwl_trans *trans); void (*free)(struct iwl_trans *trans);
void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg);
int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
int (*check_stuck_queue)(struct iwl_trans *trans, int q); int (*check_stuck_queue)(struct iwl_trans *trans, int q);
int (*wait_tx_queue_empty)(struct iwl_trans *trans); int (*wait_tx_queue_empty)(struct iwl_trans *trans);
...@@ -474,17 +465,6 @@ static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans) ...@@ -474,17 +465,6 @@ static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
trans->ops->wowlan_suspend(trans); trans->ops->wowlan_suspend(trans);
} }
static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
enum iwl_rxon_context_id ctx,
const char *msg)
{
if (trans->state != IWL_TRANS_FW_ALIVE)
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
trans->ops->wake_any_queue(trans, ctx, msg);
}
static inline int iwl_trans_send_cmd(struct iwl_trans *trans, static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
struct iwl_host_cmd *cmd) struct iwl_host_cmd *cmd)
{ {
...@@ -505,14 +485,13 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, ...@@ -505,14 +485,13 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
} }
static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id,
int tid, int txq_id, int ssn, u32 status, int tid, int txq_id, int ssn,
struct sk_buff_head *skbs) struct sk_buff_head *skbs)
{ {
if (trans->state != IWL_TRANS_FW_ALIVE) if (trans->state != IWL_TRANS_FW_ALIVE)
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, skbs);
status, skbs);
} }
static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans,
...@@ -554,15 +533,6 @@ static inline void iwl_trans_free(struct iwl_trans *trans) ...@@ -554,15 +533,6 @@ static inline void iwl_trans_free(struct iwl_trans *trans)
trans->ops->free(trans); trans->ops->free(trans);
} }
static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q,
const char *msg)
{
if (trans->state != IWL_TRANS_FW_ALIVE)
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
trans->ops->stop_queue(trans, q, msg);
}
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
{ {
if (trans->state != IWL_TRANS_FW_ALIVE) if (trans->state != IWL_TRANS_FW_ALIVE)
......
...@@ -316,7 +316,6 @@ int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) ...@@ -316,7 +316,6 @@ int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
static int iwl_alive_notify(struct iwl_priv *priv) static int iwl_alive_notify(struct iwl_priv *priv)
{ {
struct iwl_rxon_context *ctx;
int ret; int ret;
if (!priv->tx_cmd_pool) if (!priv->tx_cmd_pool)
...@@ -329,8 +328,9 @@ static int iwl_alive_notify(struct iwl_priv *priv) ...@@ -329,8 +328,9 @@ static int iwl_alive_notify(struct iwl_priv *priv)
return -ENOMEM; return -ENOMEM;
iwl_trans_fw_alive(trans(priv)); iwl_trans_fw_alive(trans(priv));
for_each_context(priv, ctx)
ctx->last_tx_rejected = false; priv->passive_no_rx = false;
priv->transport_queue_stop = 0;
ret = iwl_send_wimax_coex(priv); ret = iwl_send_wimax_coex(priv);
if (ret) if (ret)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册