0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "htc.h"
0018
0019 static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
0020 {
0021 switch (wmi_cmd) {
0022 case WMI_ECHO_CMDID:
0023 return "WMI_ECHO_CMDID";
0024 case WMI_ACCESS_MEMORY_CMDID:
0025 return "WMI_ACCESS_MEMORY_CMDID";
0026 case WMI_GET_FW_VERSION:
0027 return "WMI_GET_FW_VERSION";
0028 case WMI_DISABLE_INTR_CMDID:
0029 return "WMI_DISABLE_INTR_CMDID";
0030 case WMI_ENABLE_INTR_CMDID:
0031 return "WMI_ENABLE_INTR_CMDID";
0032 case WMI_ATH_INIT_CMDID:
0033 return "WMI_ATH_INIT_CMDID";
0034 case WMI_ABORT_TXQ_CMDID:
0035 return "WMI_ABORT_TXQ_CMDID";
0036 case WMI_STOP_TX_DMA_CMDID:
0037 return "WMI_STOP_TX_DMA_CMDID";
0038 case WMI_ABORT_TX_DMA_CMDID:
0039 return "WMI_ABORT_TX_DMA_CMDID";
0040 case WMI_DRAIN_TXQ_CMDID:
0041 return "WMI_DRAIN_TXQ_CMDID";
0042 case WMI_DRAIN_TXQ_ALL_CMDID:
0043 return "WMI_DRAIN_TXQ_ALL_CMDID";
0044 case WMI_START_RECV_CMDID:
0045 return "WMI_START_RECV_CMDID";
0046 case WMI_STOP_RECV_CMDID:
0047 return "WMI_STOP_RECV_CMDID";
0048 case WMI_FLUSH_RECV_CMDID:
0049 return "WMI_FLUSH_RECV_CMDID";
0050 case WMI_SET_MODE_CMDID:
0051 return "WMI_SET_MODE_CMDID";
0052 case WMI_NODE_CREATE_CMDID:
0053 return "WMI_NODE_CREATE_CMDID";
0054 case WMI_NODE_REMOVE_CMDID:
0055 return "WMI_NODE_REMOVE_CMDID";
0056 case WMI_VAP_REMOVE_CMDID:
0057 return "WMI_VAP_REMOVE_CMDID";
0058 case WMI_VAP_CREATE_CMDID:
0059 return "WMI_VAP_CREATE_CMDID";
0060 case WMI_REG_READ_CMDID:
0061 return "WMI_REG_READ_CMDID";
0062 case WMI_REG_WRITE_CMDID:
0063 return "WMI_REG_WRITE_CMDID";
0064 case WMI_REG_RMW_CMDID:
0065 return "WMI_REG_RMW_CMDID";
0066 case WMI_RC_STATE_CHANGE_CMDID:
0067 return "WMI_RC_STATE_CHANGE_CMDID";
0068 case WMI_RC_RATE_UPDATE_CMDID:
0069 return "WMI_RC_RATE_UPDATE_CMDID";
0070 case WMI_TARGET_IC_UPDATE_CMDID:
0071 return "WMI_TARGET_IC_UPDATE_CMDID";
0072 case WMI_TX_AGGR_ENABLE_CMDID:
0073 return "WMI_TX_AGGR_ENABLE_CMDID";
0074 case WMI_TGT_DETACH_CMDID:
0075 return "WMI_TGT_DETACH_CMDID";
0076 case WMI_NODE_UPDATE_CMDID:
0077 return "WMI_NODE_UPDATE_CMDID";
0078 case WMI_INT_STATS_CMDID:
0079 return "WMI_INT_STATS_CMDID";
0080 case WMI_TX_STATS_CMDID:
0081 return "WMI_TX_STATS_CMDID";
0082 case WMI_RX_STATS_CMDID:
0083 return "WMI_RX_STATS_CMDID";
0084 case WMI_BITRATE_MASK_CMDID:
0085 return "WMI_BITRATE_MASK_CMDID";
0086 }
0087
0088 return "Bogus";
0089 }
0090
0091 struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
0092 {
0093 struct wmi *wmi;
0094
0095 wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
0096 if (!wmi)
0097 return NULL;
0098
0099 wmi->drv_priv = priv;
0100 wmi->stopped = false;
0101 skb_queue_head_init(&wmi->wmi_event_queue);
0102 spin_lock_init(&wmi->wmi_lock);
0103 spin_lock_init(&wmi->event_lock);
0104 mutex_init(&wmi->op_mutex);
0105 mutex_init(&wmi->multi_write_mutex);
0106 mutex_init(&wmi->multi_rmw_mutex);
0107 init_completion(&wmi->cmd_wait);
0108 INIT_LIST_HEAD(&wmi->pending_tx_events);
0109 tasklet_setup(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet);
0110
0111 return wmi;
0112 }
0113
0114 void ath9k_stop_wmi(struct ath9k_htc_priv *priv)
0115 {
0116 struct wmi *wmi = priv->wmi;
0117
0118 mutex_lock(&wmi->op_mutex);
0119 wmi->stopped = true;
0120 mutex_unlock(&wmi->op_mutex);
0121 }
0122
0123 void ath9k_destroy_wmi(struct ath9k_htc_priv *priv)
0124 {
0125 kfree(priv->wmi);
0126 }
0127
0128 void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv)
0129 {
0130 unsigned long flags;
0131
0132 tasklet_kill(&priv->wmi->wmi_event_tasklet);
0133 spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
0134 __skb_queue_purge(&priv->wmi->wmi_event_queue);
0135 spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
0136 }
0137
0138 void ath9k_wmi_event_tasklet(struct tasklet_struct *t)
0139 {
0140 struct wmi *wmi = from_tasklet(wmi, t, wmi_event_tasklet);
0141 struct ath9k_htc_priv *priv = wmi->drv_priv;
0142 struct wmi_cmd_hdr *hdr;
0143 void *wmi_event;
0144 struct wmi_event_swba *swba;
0145 struct sk_buff *skb = NULL;
0146 unsigned long flags;
0147 u16 cmd_id;
0148
0149 do {
0150 spin_lock_irqsave(&wmi->wmi_lock, flags);
0151 skb = __skb_dequeue(&wmi->wmi_event_queue);
0152 if (!skb) {
0153 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
0154 return;
0155 }
0156 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
0157
0158 hdr = (struct wmi_cmd_hdr *) skb->data;
0159 cmd_id = be16_to_cpu(hdr->command_id);
0160 wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
0161
0162 switch (cmd_id) {
0163 case WMI_SWBA_EVENTID:
0164 swba = wmi_event;
0165 ath9k_htc_swba(priv, swba);
0166 break;
0167 case WMI_FATAL_EVENTID:
0168 ieee80211_queue_work(wmi->drv_priv->hw,
0169 &wmi->drv_priv->fatal_work);
0170 break;
0171 case WMI_TXSTATUS_EVENTID:
0172
0173 if (!data_race(priv->tx.initialized))
0174 break;
0175
0176 spin_lock_bh(&priv->tx.tx_lock);
0177 if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
0178 spin_unlock_bh(&priv->tx.tx_lock);
0179 break;
0180 }
0181 spin_unlock_bh(&priv->tx.tx_lock);
0182
0183 ath9k_htc_txstatus(priv, wmi_event);
0184 break;
0185 default:
0186 break;
0187 }
0188
0189 kfree_skb(skb);
0190 } while (1);
0191 }
0192
0193 void ath9k_fatal_work(struct work_struct *work)
0194 {
0195 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
0196 fatal_work);
0197 struct ath_common *common = ath9k_hw_common(priv->ah);
0198
0199 ath_dbg(common, FATAL, "FATAL Event received, resetting device\n");
0200 ath9k_htc_reset(priv);
0201 }
0202
0203 static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
0204 {
0205 skb_pull(skb, sizeof(struct wmi_cmd_hdr));
0206
0207 if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0)
0208 memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len);
0209
0210 complete(&wmi->cmd_wait);
0211 }
0212
0213 static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
0214 enum htc_endpoint_id epid)
0215 {
0216 struct wmi *wmi = priv;
0217 struct wmi_cmd_hdr *hdr;
0218 unsigned long flags;
0219 u16 cmd_id;
0220
0221 if (unlikely(wmi->stopped))
0222 goto free_skb;
0223
0224 hdr = (struct wmi_cmd_hdr *) skb->data;
0225 cmd_id = be16_to_cpu(hdr->command_id);
0226
0227 if (cmd_id & 0x1000) {
0228 spin_lock_irqsave(&wmi->wmi_lock, flags);
0229 __skb_queue_tail(&wmi->wmi_event_queue, skb);
0230 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
0231 tasklet_schedule(&wmi->wmi_event_tasklet);
0232 return;
0233 }
0234
0235
0236 spin_lock_irqsave(&wmi->wmi_lock, flags);
0237 if (be16_to_cpu(hdr->seq_no) != wmi->last_seq_id) {
0238 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
0239 goto free_skb;
0240 }
0241 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
0242
0243
0244 ath9k_wmi_rsp_callback(wmi, skb);
0245
0246 free_skb:
0247 kfree_skb(skb);
0248 }
0249
0250 static void ath9k_wmi_ctrl_tx(void *priv, struct sk_buff *skb,
0251 enum htc_endpoint_id epid, bool txok)
0252 {
0253 kfree_skb(skb);
0254 }
0255
0256 int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
0257 enum htc_endpoint_id *wmi_ctrl_epid)
0258 {
0259 struct htc_service_connreq connect;
0260 int ret;
0261
0262 wmi->htc = htc;
0263
0264 memset(&connect, 0, sizeof(connect));
0265
0266 connect.ep_callbacks.priv = wmi;
0267 connect.ep_callbacks.tx = ath9k_wmi_ctrl_tx;
0268 connect.ep_callbacks.rx = ath9k_wmi_ctrl_rx;
0269 connect.service_id = WMI_CONTROL_SVC;
0270
0271 ret = htc_connect_service(htc, &connect, &wmi->ctrl_epid);
0272 if (ret)
0273 return ret;
0274
0275 *wmi_ctrl_epid = wmi->ctrl_epid;
0276
0277 return 0;
0278 }
0279
0280 static int ath9k_wmi_cmd_issue(struct wmi *wmi,
0281 struct sk_buff *skb,
0282 enum wmi_cmd_id cmd, u16 len)
0283 {
0284 struct wmi_cmd_hdr *hdr;
0285 unsigned long flags;
0286
0287 hdr = skb_push(skb, sizeof(struct wmi_cmd_hdr));
0288 hdr->command_id = cpu_to_be16(cmd);
0289 hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
0290
0291 spin_lock_irqsave(&wmi->wmi_lock, flags);
0292 wmi->last_seq_id = wmi->tx_seq_id;
0293 spin_unlock_irqrestore(&wmi->wmi_lock, flags);
0294
0295 return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid);
0296 }
0297
0298 int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
0299 u8 *cmd_buf, u32 cmd_len,
0300 u8 *rsp_buf, u32 rsp_len,
0301 u32 timeout)
0302 {
0303 struct ath_hw *ah = wmi->drv_priv->ah;
0304 struct ath_common *common = ath9k_hw_common(ah);
0305 u16 headroom = sizeof(struct htc_frame_hdr) +
0306 sizeof(struct wmi_cmd_hdr);
0307 struct sk_buff *skb;
0308 unsigned long time_left;
0309 int ret = 0;
0310
0311 if (ah->ah_flags & AH_UNPLUGGED)
0312 return 0;
0313
0314 skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
0315 if (!skb)
0316 return -ENOMEM;
0317
0318 skb_reserve(skb, headroom);
0319
0320 if (cmd_len != 0 && cmd_buf != NULL) {
0321 skb_put_data(skb, cmd_buf, cmd_len);
0322 }
0323
0324 mutex_lock(&wmi->op_mutex);
0325
0326
0327 if (unlikely(wmi->stopped)) {
0328 ret = -EPROTO;
0329 goto out;
0330 }
0331
0332
0333 wmi->cmd_rsp_buf = rsp_buf;
0334 wmi->cmd_rsp_len = rsp_len;
0335
0336 ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
0337 if (ret)
0338 goto out;
0339
0340 time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
0341 if (!time_left) {
0342 ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
0343 wmi_cmd_to_name(cmd_id));
0344 mutex_unlock(&wmi->op_mutex);
0345 return -ETIMEDOUT;
0346 }
0347
0348 mutex_unlock(&wmi->op_mutex);
0349
0350 return 0;
0351
0352 out:
0353 ath_dbg(common, WMI, "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id));
0354 mutex_unlock(&wmi->op_mutex);
0355 kfree_skb(skb);
0356
0357 return ret;
0358 }