1 /* 2 * Copyright (c) 2015-2016 Quantenna Communications, Inc. 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 2 8 * of the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17 #include <linux/types.h> 18 #include <linux/export.h> 19 #include <linux/slab.h> 20 21 #include "core.h" 22 #include "commands.h" 23 #include "event.h" 24 #include "bus.h" 25 26 #define QTNF_DEF_SYNC_CMD_TIMEOUT (5 * HZ) 27 28 int qtnf_trans_send_cmd_with_resp(struct qtnf_bus *bus, struct sk_buff *cmd_skb, 29 struct sk_buff **response_skb) 30 { 31 struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; 32 struct qlink_cmd *cmd = (void *)cmd_skb->data; 33 int ret = 0; 34 long status; 35 bool resp_not_handled = true; 36 struct sk_buff *resp_skb = NULL; 37 38 if (unlikely(!response_skb)) { 39 dev_kfree_skb(cmd_skb); 40 return -EFAULT; 41 } 42 43 spin_lock(&ctl_node->resp_lock); 44 ctl_node->seq_num++; 45 cmd->seq_num = cpu_to_le16(ctl_node->seq_num); 46 WARN(ctl_node->resp_skb, "qtnfmac: response skb not empty\n"); 47 ctl_node->waiting_for_resp = true; 48 spin_unlock(&ctl_node->resp_lock); 49 50 ret = qtnf_bus_control_tx(bus, cmd_skb); 51 dev_kfree_skb(cmd_skb); 52 53 if (unlikely(ret)) 54 goto out; 55 56 status = wait_for_completion_interruptible_timeout( 57 &ctl_node->cmd_resp_completion, 58 QTNF_DEF_SYNC_CMD_TIMEOUT); 59 60 spin_lock(&ctl_node->resp_lock); 61 resp_not_handled = ctl_node->waiting_for_resp; 62 resp_skb = ctl_node->resp_skb; 63 ctl_node->resp_skb = NULL; 64 ctl_node->waiting_for_resp = false; 65 spin_unlock(&ctl_node->resp_lock); 66 67 if (unlikely(status <= 0)) { 68 if (status == 0) { 69 ret = -ETIMEDOUT; 70 pr_err("response timeout\n"); 71 } else { 72 ret = -EINTR; 73 pr_debug("interrupted\n"); 74 } 75 } 76 77 if (unlikely(!resp_skb || resp_not_handled)) { 78 if (!ret) 79 ret = -EFAULT; 80 81 goto out; 82 } 83 84 ret = 0; 85 *response_skb = resp_skb; 86 87 out: 88 if (unlikely(resp_skb && resp_not_handled)) 89 dev_kfree_skb(resp_skb); 90 91 return ret; 92 } 93 94 static void qtnf_trans_signal_cmdresp(struct qtnf_bus *bus, struct sk_buff *skb) 95 { 96 struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; 97 const struct qlink_resp *resp = (const struct qlink_resp *)skb->data; 98 const u16 recvd_seq_num = le16_to_cpu(resp->seq_num); 99 100 spin_lock(&ctl_node->resp_lock); 101 102 if (unlikely(!ctl_node->waiting_for_resp)) { 103 pr_err("unexpected response\n"); 104 goto out_err; 105 } 106 107 if (unlikely(recvd_seq_num != ctl_node->seq_num)) { 108 pr_err("seq num mismatch\n"); 109 goto out_err; 110 } 111 112 ctl_node->resp_skb = skb; 113 ctl_node->waiting_for_resp = false; 114 115 spin_unlock(&ctl_node->resp_lock); 116 117 complete(&ctl_node->cmd_resp_completion); 118 return; 119 120 out_err: 121 spin_unlock(&ctl_node->resp_lock); 122 dev_kfree_skb(skb); 123 } 124 125 static int qtnf_trans_event_enqueue(struct qtnf_bus *bus, struct sk_buff *skb) 126 { 127 struct qtnf_qlink_transport *trans = &bus->trans; 128 129 if (likely(skb_queue_len(&trans->event_queue) < 130 trans->event_queue_max_len)) { 131 skb_queue_tail(&trans->event_queue, skb); 132 queue_work(bus->workqueue, &bus->event_work); 133 } else { 134 pr_warn("event dropped due to queue overflow\n"); 135 dev_kfree_skb(skb); 136 return -1; 137 } 138 139 return 0; 140 } 141 142 void qtnf_trans_init(struct qtnf_bus *bus) 143 { 144 struct qtnf_qlink_transport *trans = &bus->trans; 145 146 init_completion(&trans->curr_cmd.cmd_resp_completion); 147 spin_lock_init(&trans->curr_cmd.resp_lock); 148 149 spin_lock(&trans->curr_cmd.resp_lock); 150 trans->curr_cmd.seq_num = 0; 151 trans->curr_cmd.waiting_for_resp = false; 152 trans->curr_cmd.resp_skb = NULL; 153 spin_unlock(&trans->curr_cmd.resp_lock); 154 155 /* Init event handling related fields */ 156 skb_queue_head_init(&trans->event_queue); 157 trans->event_queue_max_len = QTNF_MAX_EVENT_QUEUE_LEN; 158 } 159 160 static void qtnf_trans_free_events(struct qtnf_bus *bus) 161 { 162 struct sk_buff_head *event_queue = &bus->trans.event_queue; 163 struct sk_buff *current_event_skb = skb_dequeue(event_queue); 164 165 while (current_event_skb) { 166 dev_kfree_skb_any(current_event_skb); 167 current_event_skb = skb_dequeue(event_queue); 168 } 169 } 170 171 void qtnf_trans_free(struct qtnf_bus *bus) 172 { 173 if (!bus) { 174 pr_err("invalid bus pointer\n"); 175 return; 176 } 177 178 qtnf_trans_free_events(bus); 179 } 180 181 int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus *bus, struct sk_buff *skb) 182 { 183 const struct qlink_msg_header *header = (void *)skb->data; 184 int ret = -1; 185 186 if (unlikely(skb->len < sizeof(*header))) { 187 pr_warn("packet is too small: %u\n", skb->len); 188 dev_kfree_skb(skb); 189 return -EINVAL; 190 } 191 192 if (unlikely(skb->len != le16_to_cpu(header->len))) { 193 pr_warn("cmd reply length mismatch: %u != %u\n", 194 skb->len, le16_to_cpu(header->len)); 195 dev_kfree_skb(skb); 196 return -EFAULT; 197 } 198 199 switch (le16_to_cpu(header->type)) { 200 case QLINK_MSG_TYPE_CMDRSP: 201 if (unlikely(skb->len < sizeof(struct qlink_cmd))) { 202 pr_warn("cmd reply too short: %u\n", skb->len); 203 dev_kfree_skb(skb); 204 break; 205 } 206 207 qtnf_trans_signal_cmdresp(bus, skb); 208 break; 209 case QLINK_MSG_TYPE_EVENT: 210 if (unlikely(skb->len < sizeof(struct qlink_event))) { 211 pr_warn("event too short: %u\n", skb->len); 212 dev_kfree_skb(skb); 213 break; 214 } 215 216 ret = qtnf_trans_event_enqueue(bus, skb); 217 break; 218 default: 219 pr_warn("unknown packet type: %x\n", le16_to_cpu(header->type)); 220 dev_kfree_skb(skb); 221 break; 222 } 223 224 return ret; 225 } 226 EXPORT_SYMBOL_GPL(qtnf_trans_handle_rx_ctl_packet); 227