1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2010-2011 Atheros Communications Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
5*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
6*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*4882a593Smuzhiyun * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*4882a593Smuzhiyun * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*4882a593Smuzhiyun * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "htc.h"
20*4882a593Smuzhiyun
htc_issue_send(struct htc_target * target,struct sk_buff * skb,u16 len,u8 flags,u8 epid)21*4882a593Smuzhiyun static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
22*4882a593Smuzhiyun u16 len, u8 flags, u8 epid)
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun struct htc_frame_hdr *hdr;
26*4882a593Smuzhiyun struct htc_endpoint *endpoint = &target->endpoint[epid];
27*4882a593Smuzhiyun int status;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun hdr = skb_push(skb, sizeof(struct htc_frame_hdr));
30*4882a593Smuzhiyun hdr->endpoint_id = epid;
31*4882a593Smuzhiyun hdr->flags = flags;
32*4882a593Smuzhiyun hdr->payload_len = cpu_to_be16(len);
33*4882a593Smuzhiyun memset(hdr->control, 0, sizeof(hdr->control));
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun return status;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
get_next_avail_ep(struct htc_endpoint * endpoint)40*4882a593Smuzhiyun static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun enum htc_endpoint_id avail_epid;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
45*4882a593Smuzhiyun if (endpoint[avail_epid].service_id == 0)
46*4882a593Smuzhiyun return &endpoint[avail_epid];
47*4882a593Smuzhiyun return NULL;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
service_to_ulpipe(u16 service_id)50*4882a593Smuzhiyun static u8 service_to_ulpipe(u16 service_id)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun switch (service_id) {
53*4882a593Smuzhiyun case WMI_CONTROL_SVC:
54*4882a593Smuzhiyun return 4;
55*4882a593Smuzhiyun case WMI_BEACON_SVC:
56*4882a593Smuzhiyun case WMI_CAB_SVC:
57*4882a593Smuzhiyun case WMI_UAPSD_SVC:
58*4882a593Smuzhiyun case WMI_MGMT_SVC:
59*4882a593Smuzhiyun case WMI_DATA_VO_SVC:
60*4882a593Smuzhiyun case WMI_DATA_VI_SVC:
61*4882a593Smuzhiyun case WMI_DATA_BE_SVC:
62*4882a593Smuzhiyun case WMI_DATA_BK_SVC:
63*4882a593Smuzhiyun return 1;
64*4882a593Smuzhiyun default:
65*4882a593Smuzhiyun return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
service_to_dlpipe(u16 service_id)69*4882a593Smuzhiyun static u8 service_to_dlpipe(u16 service_id)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun switch (service_id) {
72*4882a593Smuzhiyun case WMI_CONTROL_SVC:
73*4882a593Smuzhiyun return 3;
74*4882a593Smuzhiyun case WMI_BEACON_SVC:
75*4882a593Smuzhiyun case WMI_CAB_SVC:
76*4882a593Smuzhiyun case WMI_UAPSD_SVC:
77*4882a593Smuzhiyun case WMI_MGMT_SVC:
78*4882a593Smuzhiyun case WMI_DATA_VO_SVC:
79*4882a593Smuzhiyun case WMI_DATA_VI_SVC:
80*4882a593Smuzhiyun case WMI_DATA_BE_SVC:
81*4882a593Smuzhiyun case WMI_DATA_BK_SVC:
82*4882a593Smuzhiyun return 2;
83*4882a593Smuzhiyun default:
84*4882a593Smuzhiyun return 0;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
htc_process_target_rdy(struct htc_target * target,void * buf)88*4882a593Smuzhiyun static void htc_process_target_rdy(struct htc_target *target,
89*4882a593Smuzhiyun void *buf)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun struct htc_endpoint *endpoint;
92*4882a593Smuzhiyun struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun endpoint = &target->endpoint[ENDPOINT0];
97*4882a593Smuzhiyun endpoint->service_id = HTC_CTRL_RSVD_SVC;
98*4882a593Smuzhiyun endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
99*4882a593Smuzhiyun atomic_inc(&target->tgt_ready);
100*4882a593Smuzhiyun complete(&target->target_wait);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
htc_process_conn_rsp(struct htc_target * target,struct htc_frame_hdr * htc_hdr)103*4882a593Smuzhiyun static void htc_process_conn_rsp(struct htc_target *target,
104*4882a593Smuzhiyun struct htc_frame_hdr *htc_hdr)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct htc_conn_svc_rspmsg *svc_rspmsg;
107*4882a593Smuzhiyun struct htc_endpoint *endpoint, *tmp_endpoint = NULL;
108*4882a593Smuzhiyun u16 service_id;
109*4882a593Smuzhiyun u16 max_msglen;
110*4882a593Smuzhiyun enum htc_endpoint_id epid, tepid;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun svc_rspmsg = (struct htc_conn_svc_rspmsg *)
113*4882a593Smuzhiyun ((void *) htc_hdr + sizeof(struct htc_frame_hdr));
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
116*4882a593Smuzhiyun epid = svc_rspmsg->endpoint_id;
117*4882a593Smuzhiyun if (epid < 0 || epid >= ENDPOINT_MAX)
118*4882a593Smuzhiyun return;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun service_id = be16_to_cpu(svc_rspmsg->service_id);
121*4882a593Smuzhiyun max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
122*4882a593Smuzhiyun endpoint = &target->endpoint[epid];
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
125*4882a593Smuzhiyun tmp_endpoint = &target->endpoint[tepid];
126*4882a593Smuzhiyun if (tmp_endpoint->service_id == service_id) {
127*4882a593Smuzhiyun tmp_endpoint->service_id = 0;
128*4882a593Smuzhiyun break;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (tepid == ENDPOINT0)
133*4882a593Smuzhiyun return;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun endpoint->service_id = service_id;
136*4882a593Smuzhiyun endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
137*4882a593Smuzhiyun endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
138*4882a593Smuzhiyun endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
139*4882a593Smuzhiyun endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
140*4882a593Smuzhiyun endpoint->max_msglen = max_msglen;
141*4882a593Smuzhiyun target->conn_rsp_epid = epid;
142*4882a593Smuzhiyun complete(&target->cmd_wait);
143*4882a593Smuzhiyun } else {
144*4882a593Smuzhiyun target->conn_rsp_epid = ENDPOINT_UNUSED;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
htc_config_pipe_credits(struct htc_target * target)148*4882a593Smuzhiyun static int htc_config_pipe_credits(struct htc_target *target)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct sk_buff *skb;
151*4882a593Smuzhiyun struct htc_config_pipe_msg *cp_msg;
152*4882a593Smuzhiyun int ret;
153*4882a593Smuzhiyun unsigned long time_left;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
156*4882a593Smuzhiyun if (!skb) {
157*4882a593Smuzhiyun dev_err(target->dev, "failed to allocate send buffer\n");
158*4882a593Smuzhiyun return -ENOMEM;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun skb_reserve(skb, sizeof(struct htc_frame_hdr));
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg));
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
165*4882a593Smuzhiyun cp_msg->pipe_id = USB_WLAN_TX_PIPE;
166*4882a593Smuzhiyun cp_msg->credits = target->credits;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
171*4882a593Smuzhiyun if (ret)
172*4882a593Smuzhiyun goto err;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
175*4882a593Smuzhiyun if (!time_left) {
176*4882a593Smuzhiyun dev_err(target->dev, "HTC credit config timeout\n");
177*4882a593Smuzhiyun return -ETIMEDOUT;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return 0;
181*4882a593Smuzhiyun err:
182*4882a593Smuzhiyun kfree_skb(skb);
183*4882a593Smuzhiyun return -EINVAL;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
htc_setup_complete(struct htc_target * target)186*4882a593Smuzhiyun static int htc_setup_complete(struct htc_target *target)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun struct sk_buff *skb;
189*4882a593Smuzhiyun struct htc_comp_msg *comp_msg;
190*4882a593Smuzhiyun int ret = 0;
191*4882a593Smuzhiyun unsigned long time_left;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
194*4882a593Smuzhiyun if (!skb) {
195*4882a593Smuzhiyun dev_err(target->dev, "failed to allocate send buffer\n");
196*4882a593Smuzhiyun return -ENOMEM;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun skb_reserve(skb, sizeof(struct htc_frame_hdr));
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun comp_msg = skb_put(skb, sizeof(struct htc_comp_msg));
201*4882a593Smuzhiyun comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun target->htc_flags |= HTC_OP_START_WAIT;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
206*4882a593Smuzhiyun if (ret)
207*4882a593Smuzhiyun goto err;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
210*4882a593Smuzhiyun if (!time_left) {
211*4882a593Smuzhiyun dev_err(target->dev, "HTC start timeout\n");
212*4882a593Smuzhiyun return -ETIMEDOUT;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun return 0;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun err:
218*4882a593Smuzhiyun kfree_skb(skb);
219*4882a593Smuzhiyun return -EINVAL;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* HTC APIs */
223*4882a593Smuzhiyun
htc_init(struct htc_target * target)224*4882a593Smuzhiyun int htc_init(struct htc_target *target)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun int ret;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun ret = htc_config_pipe_credits(target);
229*4882a593Smuzhiyun if (ret)
230*4882a593Smuzhiyun return ret;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return htc_setup_complete(target);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
htc_connect_service(struct htc_target * target,struct htc_service_connreq * service_connreq,enum htc_endpoint_id * conn_rsp_epid)235*4882a593Smuzhiyun int htc_connect_service(struct htc_target *target,
236*4882a593Smuzhiyun struct htc_service_connreq *service_connreq,
237*4882a593Smuzhiyun enum htc_endpoint_id *conn_rsp_epid)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun struct sk_buff *skb;
240*4882a593Smuzhiyun struct htc_endpoint *endpoint;
241*4882a593Smuzhiyun struct htc_conn_svc_msg *conn_msg;
242*4882a593Smuzhiyun int ret;
243*4882a593Smuzhiyun unsigned long time_left;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* Find an available endpoint */
246*4882a593Smuzhiyun endpoint = get_next_avail_ep(target->endpoint);
247*4882a593Smuzhiyun if (!endpoint) {
248*4882a593Smuzhiyun dev_err(target->dev, "Endpoint is not available for service %d\n",
249*4882a593Smuzhiyun service_connreq->service_id);
250*4882a593Smuzhiyun return -EINVAL;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun endpoint->service_id = service_connreq->service_id;
254*4882a593Smuzhiyun endpoint->max_txqdepth = service_connreq->max_send_qdepth;
255*4882a593Smuzhiyun endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id);
256*4882a593Smuzhiyun endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
257*4882a593Smuzhiyun endpoint->ep_callbacks = service_connreq->ep_callbacks;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
260*4882a593Smuzhiyun sizeof(struct htc_frame_hdr), GFP_ATOMIC);
261*4882a593Smuzhiyun if (!skb) {
262*4882a593Smuzhiyun dev_err(target->dev, "Failed to allocate buf to send"
263*4882a593Smuzhiyun "service connect req\n");
264*4882a593Smuzhiyun return -ENOMEM;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun skb_reserve(skb, sizeof(struct htc_frame_hdr));
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg));
270*4882a593Smuzhiyun conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
271*4882a593Smuzhiyun conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
272*4882a593Smuzhiyun conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
273*4882a593Smuzhiyun conn_msg->dl_pipeid = endpoint->dl_pipeid;
274*4882a593Smuzhiyun conn_msg->ul_pipeid = endpoint->ul_pipeid;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* To prevent infoleak */
277*4882a593Smuzhiyun conn_msg->svc_meta_len = 0;
278*4882a593Smuzhiyun conn_msg->pad = 0;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
281*4882a593Smuzhiyun if (ret)
282*4882a593Smuzhiyun goto err;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
285*4882a593Smuzhiyun if (!time_left) {
286*4882a593Smuzhiyun dev_err(target->dev, "Service connection timeout for: %d\n",
287*4882a593Smuzhiyun service_connreq->service_id);
288*4882a593Smuzhiyun return -ETIMEDOUT;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun *conn_rsp_epid = target->conn_rsp_epid;
292*4882a593Smuzhiyun return 0;
293*4882a593Smuzhiyun err:
294*4882a593Smuzhiyun kfree_skb(skb);
295*4882a593Smuzhiyun return ret;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
htc_send(struct htc_target * target,struct sk_buff * skb)298*4882a593Smuzhiyun int htc_send(struct htc_target *target, struct sk_buff *skb)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun struct ath9k_htc_tx_ctl *tx_ctl;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun tx_ctl = HTC_SKB_CB(skb);
303*4882a593Smuzhiyun return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
htc_send_epid(struct htc_target * target,struct sk_buff * skb,enum htc_endpoint_id epid)306*4882a593Smuzhiyun int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
307*4882a593Smuzhiyun enum htc_endpoint_id epid)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun return htc_issue_send(target, skb, skb->len, 0, epid);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
htc_stop(struct htc_target * target)312*4882a593Smuzhiyun void htc_stop(struct htc_target *target)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun target->hif->stop(target->hif_dev);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
htc_start(struct htc_target * target)317*4882a593Smuzhiyun void htc_start(struct htc_target *target)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun target->hif->start(target->hif_dev);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
htc_sta_drain(struct htc_target * target,u8 idx)322*4882a593Smuzhiyun void htc_sta_drain(struct htc_target *target, u8 idx)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun target->hif->sta_drain(target->hif_dev, idx);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
ath9k_htc_txcompletion_cb(struct htc_target * htc_handle,struct sk_buff * skb,bool txok)327*4882a593Smuzhiyun void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
328*4882a593Smuzhiyun struct sk_buff *skb, bool txok)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun struct htc_endpoint *endpoint;
331*4882a593Smuzhiyun struct htc_frame_hdr *htc_hdr = NULL;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
334*4882a593Smuzhiyun complete(&htc_handle->cmd_wait);
335*4882a593Smuzhiyun htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
336*4882a593Smuzhiyun goto ret;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
340*4882a593Smuzhiyun complete(&htc_handle->cmd_wait);
341*4882a593Smuzhiyun htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
342*4882a593Smuzhiyun goto ret;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (skb) {
346*4882a593Smuzhiyun htc_hdr = (struct htc_frame_hdr *) skb->data;
347*4882a593Smuzhiyun if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint))
348*4882a593Smuzhiyun goto ret;
349*4882a593Smuzhiyun endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
350*4882a593Smuzhiyun skb_pull(skb, sizeof(struct htc_frame_hdr));
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun if (endpoint->ep_callbacks.tx) {
353*4882a593Smuzhiyun endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
354*4882a593Smuzhiyun skb, htc_hdr->endpoint_id,
355*4882a593Smuzhiyun txok);
356*4882a593Smuzhiyun } else {
357*4882a593Smuzhiyun kfree_skb(skb);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun return;
362*4882a593Smuzhiyun ret:
363*4882a593Smuzhiyun kfree_skb(skb);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
ath9k_htc_fw_panic_report(struct htc_target * htc_handle,struct sk_buff * skb,u32 len)366*4882a593Smuzhiyun static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
367*4882a593Smuzhiyun struct sk_buff *skb, u32 len)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun uint32_t *pattern = (uint32_t *)skb->data;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (*pattern == 0x33221199 && len >= sizeof(struct htc_panic_bad_vaddr)) {
372*4882a593Smuzhiyun struct htc_panic_bad_vaddr *htc_panic;
373*4882a593Smuzhiyun htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
374*4882a593Smuzhiyun dev_err(htc_handle->dev, "ath: firmware panic! "
375*4882a593Smuzhiyun "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
376*4882a593Smuzhiyun htc_panic->exccause, htc_panic->pc,
377*4882a593Smuzhiyun htc_panic->badvaddr);
378*4882a593Smuzhiyun return;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun if (*pattern == 0x33221299) {
381*4882a593Smuzhiyun struct htc_panic_bad_epid *htc_panic;
382*4882a593Smuzhiyun htc_panic = (struct htc_panic_bad_epid *) skb->data;
383*4882a593Smuzhiyun dev_err(htc_handle->dev, "ath: firmware panic! "
384*4882a593Smuzhiyun "bad epid: 0x%08x\n", htc_panic->epid);
385*4882a593Smuzhiyun return;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /*
391*4882a593Smuzhiyun * HTC Messages are handled directly here and the obtained SKB
392*4882a593Smuzhiyun * is freed.
393*4882a593Smuzhiyun *
394*4882a593Smuzhiyun * Service messages (Data, WMI) passed to the corresponding
395*4882a593Smuzhiyun * endpoint RX handlers, which have to free the SKB.
396*4882a593Smuzhiyun */
ath9k_htc_rx_msg(struct htc_target * htc_handle,struct sk_buff * skb,u32 len,u8 pipe_id)397*4882a593Smuzhiyun void ath9k_htc_rx_msg(struct htc_target *htc_handle,
398*4882a593Smuzhiyun struct sk_buff *skb, u32 len, u8 pipe_id)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun struct htc_frame_hdr *htc_hdr;
401*4882a593Smuzhiyun enum htc_endpoint_id epid;
402*4882a593Smuzhiyun struct htc_endpoint *endpoint;
403*4882a593Smuzhiyun __be16 *msg_id;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (!htc_handle || !skb)
406*4882a593Smuzhiyun return;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /* A valid message requires len >= 8.
409*4882a593Smuzhiyun *
410*4882a593Smuzhiyun * sizeof(struct htc_frame_hdr) == 8
411*4882a593Smuzhiyun * sizeof(struct htc_ready_msg) == 8
412*4882a593Smuzhiyun * sizeof(struct htc_panic_bad_vaddr) == 16
413*4882a593Smuzhiyun * sizeof(struct htc_panic_bad_epid) == 8
414*4882a593Smuzhiyun */
415*4882a593Smuzhiyun if (unlikely(len < sizeof(struct htc_frame_hdr)))
416*4882a593Smuzhiyun goto invalid;
417*4882a593Smuzhiyun htc_hdr = (struct htc_frame_hdr *) skb->data;
418*4882a593Smuzhiyun epid = htc_hdr->endpoint_id;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun if (epid == 0x99) {
421*4882a593Smuzhiyun ath9k_htc_fw_panic_report(htc_handle, skb, len);
422*4882a593Smuzhiyun kfree_skb(skb);
423*4882a593Smuzhiyun return;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (epid < 0 || epid >= ENDPOINT_MAX) {
427*4882a593Smuzhiyun invalid:
428*4882a593Smuzhiyun if (pipe_id != USB_REG_IN_PIPE)
429*4882a593Smuzhiyun dev_kfree_skb_any(skb);
430*4882a593Smuzhiyun else
431*4882a593Smuzhiyun kfree_skb(skb);
432*4882a593Smuzhiyun return;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun if (epid == ENDPOINT0) {
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Handle trailer */
438*4882a593Smuzhiyun if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
439*4882a593Smuzhiyun if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) {
440*4882a593Smuzhiyun /* Move past the Watchdog pattern */
441*4882a593Smuzhiyun htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
442*4882a593Smuzhiyun len -= 4;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun /* Get the message ID */
447*4882a593Smuzhiyun if (unlikely(len < sizeof(struct htc_frame_hdr) + sizeof(__be16)))
448*4882a593Smuzhiyun goto invalid;
449*4882a593Smuzhiyun msg_id = (__be16 *) ((void *) htc_hdr +
450*4882a593Smuzhiyun sizeof(struct htc_frame_hdr));
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* Now process HTC messages */
453*4882a593Smuzhiyun switch (be16_to_cpu(*msg_id)) {
454*4882a593Smuzhiyun case HTC_MSG_READY_ID:
455*4882a593Smuzhiyun if (unlikely(len < sizeof(struct htc_ready_msg)))
456*4882a593Smuzhiyun goto invalid;
457*4882a593Smuzhiyun htc_process_target_rdy(htc_handle, htc_hdr);
458*4882a593Smuzhiyun break;
459*4882a593Smuzhiyun case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
460*4882a593Smuzhiyun if (unlikely(len < sizeof(struct htc_frame_hdr) +
461*4882a593Smuzhiyun sizeof(struct htc_conn_svc_rspmsg)))
462*4882a593Smuzhiyun goto invalid;
463*4882a593Smuzhiyun htc_process_conn_rsp(htc_handle, htc_hdr);
464*4882a593Smuzhiyun break;
465*4882a593Smuzhiyun default:
466*4882a593Smuzhiyun break;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun kfree_skb(skb);
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun } else {
472*4882a593Smuzhiyun if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
473*4882a593Smuzhiyun skb_trim(skb, len - htc_hdr->control[0]);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun skb_pull(skb, sizeof(struct htc_frame_hdr));
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun endpoint = &htc_handle->endpoint[epid];
478*4882a593Smuzhiyun if (endpoint->ep_callbacks.rx)
479*4882a593Smuzhiyun endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
480*4882a593Smuzhiyun skb, epid);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
ath9k_htc_hw_alloc(void * hif_handle,struct ath9k_htc_hif * hif,struct device * dev)484*4882a593Smuzhiyun struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
485*4882a593Smuzhiyun struct ath9k_htc_hif *hif,
486*4882a593Smuzhiyun struct device *dev)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun struct htc_endpoint *endpoint;
489*4882a593Smuzhiyun struct htc_target *target;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
492*4882a593Smuzhiyun if (!target)
493*4882a593Smuzhiyun return NULL;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun init_completion(&target->target_wait);
496*4882a593Smuzhiyun init_completion(&target->cmd_wait);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun target->hif = hif;
499*4882a593Smuzhiyun target->hif_dev = hif_handle;
500*4882a593Smuzhiyun target->dev = dev;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* Assign control endpoint pipe IDs */
503*4882a593Smuzhiyun endpoint = &target->endpoint[ENDPOINT0];
504*4882a593Smuzhiyun endpoint->ul_pipeid = hif->control_ul_pipe;
505*4882a593Smuzhiyun endpoint->dl_pipeid = hif->control_dl_pipe;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun atomic_set(&target->tgt_ready, 0);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun return target;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
ath9k_htc_hw_free(struct htc_target * htc)512*4882a593Smuzhiyun void ath9k_htc_hw_free(struct htc_target *htc)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun kfree(htc);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
ath9k_htc_hw_init(struct htc_target * target,struct device * dev,u16 devid,char * product,u32 drv_info)517*4882a593Smuzhiyun int ath9k_htc_hw_init(struct htc_target *target,
518*4882a593Smuzhiyun struct device *dev, u16 devid,
519*4882a593Smuzhiyun char *product, u32 drv_info)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
522*4882a593Smuzhiyun pr_err("Failed to initialize the device\n");
523*4882a593Smuzhiyun return -ENODEV;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
ath9k_htc_hw_deinit(struct htc_target * target,bool hot_unplug)529*4882a593Smuzhiyun void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun if (target)
532*4882a593Smuzhiyun ath9k_htc_disconnect_device(target, hot_unplug);
533*4882a593Smuzhiyun }
534