1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
4 #include <linux/types.h>
5 #include <linux/export.h>
6 #include <linux/slab.h>
13 #define QTNF_DEF_SYNC_CMD_TIMEOUT (5 * HZ)
15 int qtnf_trans_send_cmd_with_resp(struct qtnf_bus
*bus
, struct sk_buff
*cmd_skb
,
16 struct sk_buff
**response_skb
)
18 struct qtnf_cmd_ctl_node
*ctl_node
= &bus
->trans
.curr_cmd
;
19 struct qlink_cmd
*cmd
= (void *)cmd_skb
->data
;
22 bool resp_not_handled
= true;
23 struct sk_buff
*resp_skb
= NULL
;
25 if (unlikely(!response_skb
)) {
26 dev_kfree_skb(cmd_skb
);
30 spin_lock(&ctl_node
->resp_lock
);
32 cmd
->seq_num
= cpu_to_le16(ctl_node
->seq_num
);
33 WARN(ctl_node
->resp_skb
, "qtnfmac: response skb not empty\n");
34 ctl_node
->waiting_for_resp
= true;
35 spin_unlock(&ctl_node
->resp_lock
);
37 ret
= qtnf_bus_control_tx(bus
, cmd_skb
);
38 dev_kfree_skb(cmd_skb
);
43 status
= wait_for_completion_interruptible_timeout(
44 &ctl_node
->cmd_resp_completion
,
45 QTNF_DEF_SYNC_CMD_TIMEOUT
);
47 spin_lock(&ctl_node
->resp_lock
);
48 resp_not_handled
= ctl_node
->waiting_for_resp
;
49 resp_skb
= ctl_node
->resp_skb
;
50 ctl_node
->resp_skb
= NULL
;
51 ctl_node
->waiting_for_resp
= false;
52 spin_unlock(&ctl_node
->resp_lock
);
54 if (unlikely(status
<= 0)) {
57 pr_err("response timeout\n");
60 pr_debug("interrupted\n");
64 if (unlikely(!resp_skb
|| resp_not_handled
)) {
72 *response_skb
= resp_skb
;
75 if (unlikely(resp_skb
&& resp_not_handled
))
76 dev_kfree_skb(resp_skb
);
81 static void qtnf_trans_signal_cmdresp(struct qtnf_bus
*bus
, struct sk_buff
*skb
)
83 struct qtnf_cmd_ctl_node
*ctl_node
= &bus
->trans
.curr_cmd
;
84 const struct qlink_resp
*resp
= (const struct qlink_resp
*)skb
->data
;
85 const u16 recvd_seq_num
= le16_to_cpu(resp
->seq_num
);
87 spin_lock(&ctl_node
->resp_lock
);
89 if (unlikely(!ctl_node
->waiting_for_resp
)) {
90 pr_err("unexpected response\n");
94 if (unlikely(recvd_seq_num
!= ctl_node
->seq_num
)) {
95 pr_err("seq num mismatch\n");
99 ctl_node
->resp_skb
= skb
;
100 ctl_node
->waiting_for_resp
= false;
102 spin_unlock(&ctl_node
->resp_lock
);
104 complete(&ctl_node
->cmd_resp_completion
);
108 spin_unlock(&ctl_node
->resp_lock
);
112 static int qtnf_trans_event_enqueue(struct qtnf_bus
*bus
, struct sk_buff
*skb
)
114 struct qtnf_qlink_transport
*trans
= &bus
->trans
;
116 if (likely(skb_queue_len(&trans
->event_queue
) <
117 trans
->event_queue_max_len
)) {
118 skb_queue_tail(&trans
->event_queue
, skb
);
119 queue_work(bus
->workqueue
, &bus
->event_work
);
121 pr_warn("event dropped due to queue overflow\n");
129 void qtnf_trans_init(struct qtnf_bus
*bus
)
131 struct qtnf_qlink_transport
*trans
= &bus
->trans
;
133 init_completion(&trans
->curr_cmd
.cmd_resp_completion
);
134 spin_lock_init(&trans
->curr_cmd
.resp_lock
);
136 spin_lock(&trans
->curr_cmd
.resp_lock
);
137 trans
->curr_cmd
.seq_num
= 0;
138 trans
->curr_cmd
.waiting_for_resp
= false;
139 trans
->curr_cmd
.resp_skb
= NULL
;
140 spin_unlock(&trans
->curr_cmd
.resp_lock
);
142 /* Init event handling related fields */
143 skb_queue_head_init(&trans
->event_queue
);
144 trans
->event_queue_max_len
= QTNF_MAX_EVENT_QUEUE_LEN
;
147 static void qtnf_trans_free_events(struct qtnf_bus
*bus
)
149 struct sk_buff_head
*event_queue
= &bus
->trans
.event_queue
;
150 struct sk_buff
*current_event_skb
= skb_dequeue(event_queue
);
152 while (current_event_skb
) {
153 dev_kfree_skb_any(current_event_skb
);
154 current_event_skb
= skb_dequeue(event_queue
);
158 void qtnf_trans_free(struct qtnf_bus
*bus
)
161 pr_err("invalid bus pointer\n");
165 qtnf_trans_free_events(bus
);
168 int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus
*bus
, struct sk_buff
*skb
)
170 const struct qlink_msg_header
*header
= (void *)skb
->data
;
173 if (unlikely(skb
->len
< sizeof(*header
))) {
174 pr_warn("packet is too small: %u\n", skb
->len
);
179 if (unlikely(skb
->len
!= le16_to_cpu(header
->len
))) {
180 pr_warn("cmd reply length mismatch: %u != %u\n",
181 skb
->len
, le16_to_cpu(header
->len
));
186 switch (le16_to_cpu(header
->type
)) {
187 case QLINK_MSG_TYPE_CMDRSP
:
188 if (unlikely(skb
->len
< sizeof(struct qlink_cmd
))) {
189 pr_warn("cmd reply too short: %u\n", skb
->len
);
194 qtnf_trans_signal_cmdresp(bus
, skb
);
196 case QLINK_MSG_TYPE_EVENT
:
197 if (unlikely(skb
->len
< sizeof(struct qlink_event
))) {
198 pr_warn("event too short: %u\n", skb
->len
);
203 ret
= qtnf_trans_event_enqueue(bus
, skb
);
206 pr_warn("unknown packet type: %x\n", le16_to_cpu(header
->type
));
213 EXPORT_SYMBOL_GPL(qtnf_trans_handle_rx_ctl_packet
);