carl9170 firmware: add cmake helpers
[carl9170fw.git] / tools / carlu / src / tx.c
1 /*
2  * carlu - userspace testing utility for ar9170 devices
3  *
4  * xmit - related functions
5  *
6  * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include "libusb.h"
34
35 #include "carlu.h"
36 #include "debug.h"
37 #include "frame.h"
38 #include "usb.h"
39 #include "ieee80211.h"
40 #include "wlan.h"
41
42 struct frame *carlu_alloc_frame(struct carlu *ar, unsigned int size)
43 {
44         struct frame *tmp;
45         unsigned int total_len;
46
47         total_len = ar->extra_headroom + sizeof(struct _carl9170_tx_superframe) + size;
48
49         tmp = frame_alloc(total_len);
50         if (!tmp)
51                 return NULL;
52
53         frame_reserve(tmp, sizeof(struct _carl9170_tx_superframe) + ar->extra_headroom);
54
55         tmp->queue = 2;
56
57         return tmp;
58 }
59
60 static int carlu_alloc_dev_mem(struct carlu *ar,
61                                 struct frame *frame)
62 {
63         struct _carl9170_tx_superframe *txp = (void *)frame->data;
64         unsigned int len, chunks;
65
66         len = roundup(frame->len, ar->dma_chunk_size);
67         chunks = len / ar->dma_chunk_size;
68
69         SDL_mutexP(ar->mem_lock);
70         if (ar->tx_pending >= ar->dma_chunks ||
71             ar->used_dma_chunks + chunks >= ar->dma_chunks) {
72                 SDL_mutexV(ar->mem_lock);
73                 return -ENOSPC;
74         }
75
76         ar->used_dma_chunks += chunks;
77         ar->tx_pending++;
78         txp->s.cookie = ar->cookie++;
79         SDL_mutexV(ar->mem_lock);
80
81         return 0;
82 }
83
84 static void carlu_free_dev_mem(struct carlu *ar,
85                                  struct frame *frame)
86 {
87         struct _carl9170_tx_superframe *txp = (void *)frame->data;
88         unsigned int len, chunks;
89
90         len = roundup(frame->len, ar->dma_chunk_size);
91         chunks = len / ar->dma_chunk_size;
92
93         SDL_mutexP(ar->mem_lock);
94         ar->used_dma_chunks -= chunks;
95         ar->tx_pending--;
96         SDL_mutexV(ar->mem_lock);
97 }
98
99 void carlu_free_frame(struct carlu *ar __unused,
100                          struct frame *frame)
101 {
102         frame_free(frame);
103 }
104
105 static struct frame *carlu_find_frame(struct carlu *ar,
106                                          unsigned int queue, uint8_t cookie)
107 {
108         struct frame *frame = NULL;
109
110         BUG_ON(queue >= __AR9170_NUM_TXQ);
111         BUG_ON(SDL_mutexP(ar->tx_sent_queue[queue].lock) != 0);
112         FRAME_WALK(frame, &ar->tx_sent_queue[queue]) {
113                 struct _carl9170_tx_superframe *super;
114
115                 super = (void *) frame->data;
116                 if (super->s.cookie == cookie) {
117                         __frame_unlink(&ar->tx_sent_queue[queue], frame);
118                         SDL_mutexV(ar->tx_sent_queue[queue].lock);
119                         return frame;
120                 }
121         }
122         SDL_mutexV(ar->tx_sent_queue[queue].lock);
123
124         return NULL;
125 }
126
127 static void carlu_tx_fb_cb(struct carlu *ar,
128                               struct frame *frame)
129 {
130         if (ar->tx_fb_cb)
131                 ar->tx_fb_cb(ar, frame);
132         else
133                 carlu_free_frame(ar, frame);
134
135 }
136
137 void carlu_tx_feedback(struct carlu *ar,
138                        struct carl9170_rsp *cmd)
139 {
140         unsigned int i, n, k, q;
141         struct frame *frame;
142         struct carlu_tx_info *tx_info;
143
144         n = cmd->hdr.ext;
145
146         for (i = 0; i < n; i++) {
147                 q = (cmd->_tx_status[i].info >> CARL9170_TX_STATUS_QUEUE_S) &
148                     CARL9170_TX_STATUS_QUEUE;
149                 frame = carlu_find_frame(ar, q, cmd->_tx_status[i].cookie);
150                 if (frame) {
151                         carlu_free_dev_mem(ar, frame);
152                         tx_info = get_tx_info(frame);
153
154                         k = (cmd->_tx_status[i].info >> CARL9170_TX_STATUS_RIX)
155                             & CARL9170_TX_STATUS_RIX_S;
156                         tx_info->rates[k].cnt = (cmd->_tx_status[i].info >>
157                                                  CARL9170_TX_STATUS_TRIES_S) &
158                                                 CARL9170_TX_STATUS_TRIES;
159                         for (k++; k < CARL9170_TX_MAX_RATES; k++) {
160                                 tx_info->rates[k].rix = -1;
161                                 tx_info->rates[k].cnt = -1;
162                         }
163
164                         carlu_tx_fb_cb(ar, frame);
165                 } else {
166                         err("Found no frame for cookie %d.\n",
167                             cmd->_tx_status[i].cookie);
168                 }
169         }
170 }
171
172 int carlu_tx(struct carlu *ar, struct frame *frame)
173 {
174         struct _carl9170_tx_superframe *txp;
175         unsigned int len, queue;
176         int cookie, err;
177
178         len = frame->len;
179
180         txp = (void *) frame_push(frame, sizeof(struct _carl9170_tx_superframe));
181
182         if (txp->s.rix)
183                 goto err_out;
184
185         err = carlu_alloc_dev_mem(ar, frame);
186         if (err)
187                 goto err_out;
188
189         txp->s.len = cpu_to_le16(frame->len);
190
191         queue = (frame->queue % __AR9170_NUM_TXQ);
192
193         SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, txp->s.misc, queue);
194
195         txp->f.length = len + FCS_LEN; /* + I(C)V_LEN */
196
197         txp->f.mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
198                                          AR9170_TX_MAC_BACKOFF);
199         txp->f.mac_control |= cpu_to_le16(queue << AR9170_TX_MAC_QOS_S);
200
201         txp->f.phy_control = cpu_to_le32(AR9170_TX_PHY_MOD_CCK | AR9170_TX_PHY_BW_20MHZ |
202                                          ((17 * 2) << AR9170_TX_PHY_TX_PWR_S) |
203                                          (AR9170_TX_PHY_TXCHAIN_1 << AR9170_TX_PHY_TXCHAIN_S) |
204                                          (11 << AR9170_TX_PHY_MCS_S));
205
206         frame_queue_tail(&ar->tx_sent_queue[queue], frame);
207         carlusb_tx(ar, frame);
208         return 0;
209
210 err_out:
211         frame_pull(frame, sizeof(struct _carl9170_tx_superframe));
212         return err;
213 }