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 return -EFAULT; 40 41 spin_lock(&ctl_node->resp_lock); 42 ctl_node->seq_num++; 43 cmd->seq_num = cpu_to_le16(ctl_node->seq_num); 44 WARN(ctl_node->resp_skb, "qtnfmac: response skb not empty\n"); 45 ctl_node->waiting_for_resp = true; 46 spin_unlock(&ctl_node->resp_lock); 47 48 ret = qtnf_bus_control_tx(bus, cmd_skb); 49 dev_kfree_skb(cmd_skb); 50 51 if (unlikely(ret)) 52 goto out; 53 54 status = wait_for_completion_interruptible_timeout( 55 &ctl_node->cmd_resp_completion, 56 QTNF_DEF_SYNC_CMD_TIMEOUT); 57 58 spin_lock(&ctl_node->resp_lock); 59 resp_not_handled = ctl_node->waiting_for_resp; 60 resp_skb = ctl_node->resp_skb; 61 ctl_node->resp_skb = NULL; 62 ctl_node->waiting_for_resp = false; 63 spin_unlock(&ctl_node->resp_lock); 64 65 if (unlikely(status <= 0)) { 66 if (status == 0) { 67 ret = -ETIMEDOUT; 68 pr_err("response timeout\n"); 69 } else { 70 ret = -EINTR; 71 pr_debug("interrupted\n"); 72 } 73 } 74 75 if (unlikely(!resp_skb || resp_not_handled)) { 76 if (!ret) 77 ret = -EFAULT; 78 79 goto out; 80 } 81 82 ret = 0; 83 *response_skb = resp_skb; 84 85 out: 86 if (unlikely(resp_skb && resp_not_handled)) 87 dev_kfree_skb(resp_skb); 88 89 return ret; 90 } 91 92 static void qtnf_trans_signal_cmdresp(struct qtnf_bus *bus, struct sk_buff *skb) 93 { 94 struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; 95 const struct qlink_resp *resp = (const struct qlink_resp *)skb->data; 96 const u16 recvd_seq_num = le16_to_cpu(resp->seq_num); 97 98 spin_lock(&ctl_node->resp_lock); 99 100 if (unlikely(!ctl_node->waiting_for_resp)) { 101 pr_err("unexpected response\n"); 102 goto out_err; 103 } 104 105 if (unlikely(recvd_seq_num != ctl_node->seq_num)) { 106 pr_err("seq num mismatch\n"); 107 goto out_err; 108 } 109 110 ctl_node->resp_skb = skb; 111 ctl_node->waiting_for_resp = false; 112 113 spin_unlock(&ctl_node->resp_lock); 114 115 complete(&ctl_node->cmd_resp_completion); 116 return; 117 118 out_err: 119 spin_unlock(&ctl_node->resp_lock); 120 dev_kfree_skb(skb); 121 } 122 123 static int qtnf_trans_event_enqueue(struct qtnf_bus *bus, struct sk_buff *skb) 124 { 125 struct qtnf_qlink_transport *trans = &bus->trans; 126 127 if (likely(skb_queue_len(&trans->event_queue) < 128 trans->event_queue_max_len)) { 129 skb_queue_tail(&trans->event_queue, skb); 130 queue_work(bus->workqueue, &bus->event_work); 131 } else { 132 pr_warn("event dropped due to queue overflow\n"); 133 dev_kfree_skb(skb); 134 return -1; 135 } 136 137 return 0; 138 } 139 140 void qtnf_trans_init(struct qtnf_bus *bus) 141 { 142 struct qtnf_qlink_transport *trans = &bus->trans; 143 144 init_completion(&trans->curr_cmd.cmd_resp_completion); 145 spin_lock_init(&trans->curr_cmd.resp_lock); 146 147 spin_lock(&trans->curr_cmd.resp_lock); 148 trans->curr_cmd.seq_num = 0; 149 trans->curr_cmd.waiting_for_resp = false; 150 trans->curr_cmd.resp_skb = NULL; 151 spin_unlock(&trans->curr_cmd.resp_lock); 152 153 /* Init event handling related fields */ 154 skb_queue_head_init(&trans->event_queue); 155 trans->event_queue_max_len = QTNF_MAX_EVENT_QUEUE_LEN; 156 } 157 158 static void qtnf_trans_free_events(struct qtnf_bus *bus) 159 { 160 struct sk_buff_head *event_queue = &bus->trans.event_queue; 161 struct sk_buff *current_event_skb = skb_dequeue(event_queue); 162 163 while (current_event_skb) { 164 dev_kfree_skb_any(current_event_skb); 165 current_event_skb = skb_dequeue(event_queue); 166 } 167 } 168 169 void qtnf_trans_free(struct qtnf_bus *bus) 170 { 171 if (!bus) { 172 pr_err("invalid bus pointer\n"); 173 return; 174 } 175 176 qtnf_trans_free_events(bus); 177 } 178 179 int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus *bus, struct sk_buff *skb) 180 { 181 const struct qlink_msg_header *header = (void *)skb->data; 182 int ret = -1; 183 184 if (unlikely(skb->len < sizeof(*header))) { 185 pr_warn("packet is too small: %u\n", skb->len); 186 dev_kfree_skb(skb); 187 return -EINVAL; 188 } 189 190 if (unlikely(skb->len != le16_to_cpu(header->len))) { 191 pr_warn("cmd reply length mismatch: %u != %u\n", 192 skb->len, le16_to_cpu(header->len)); 193 dev_kfree_skb(skb); 194 return -EFAULT; 195 } 196 197 switch (le16_to_cpu(header->type)) { 198 case QLINK_MSG_TYPE_CMDRSP: 199 if (unlikely(skb->len < sizeof(struct qlink_cmd))) { 200 pr_warn("cmd reply too short: %u\n", skb->len); 201 dev_kfree_skb(skb); 202 break; 203 } 204 205 qtnf_trans_signal_cmdresp(bus, skb); 206 break; 207 case QLINK_MSG_TYPE_EVENT: 208 if (unlikely(skb->len < sizeof(struct qlink_event))) { 209 pr_warn("event too short: %u\n", skb->len); 210 dev_kfree_skb(skb); 211 break; 212 } 213 214 ret = qtnf_trans_event_enqueue(bus, skb); 215 break; 216 default: 217 pr_warn("unknown packet type: %x\n", le16_to_cpu(header->type)); 218 dev_kfree_skb(skb); 219 break; 220 } 221 222 return ret; 223 } 224 EXPORT_SYMBOL_GPL(qtnf_trans_handle_rx_ctl_packet); 225