~ubuntu-branches/ubuntu/trusty/gnuradio/trusty

« back to all changes in this revision

Viewing changes to usrp2/firmware/lib/dbsm.c

  • Committer: Bazaar Package Importer
  • Author(s): Kamal Mostafa
  • Date: 2010-03-13 07:46:01 UTC
  • mfrom: (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100313074601-zjsa893a87bozyh7
Tags: 3.2.2.dfsg-1ubuntu1
* Fix build for Ubuntu lucid (LP: #260406)
  - add binary package dep for libusrp0, libusrp2-0: adduser
  - debian/rules clean: remove pre-built Qt moc files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- c++ -*- */
 
2
/*
 
3
 * Copyright 2007,2008 Free Software Foundation, Inc.
 
4
 *
 
5
 * This program is free software: you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation, either version 3 of the License, or
 
8
 * (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
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
/*
 
20
 * Double Buffering State Machine
 
21
 */
 
22
 
 
23
#include "dbsm.h"
 
24
#include "memory_map.h"
 
25
#include "buffer_pool.h"
 
26
#include "bool.h"
 
27
#include "nonstdio.h"
 
28
#include <stdlib.h>
 
29
 
 
30
typedef enum {
 
31
  BS_EMPTY,
 
32
  BS_FILLING,
 
33
  BS_FULL,
 
34
  BS_EMPTYING,
 
35
} buffer_state_t;
 
36
 
 
37
static buffer_state_t buffer_state[NBUFFERS];
 
38
 
 
39
bool
 
40
dbsm_nop_inspector(dbsm_t *sm, int buf_this)
 
41
{
 
42
  return false;
 
43
}
 
44
 
 
45
void
 
46
dbsm_init(dbsm_t *sm, int buf0,
 
47
          const buf_cmd_args_t *recv, const buf_cmd_args_t *send,
 
48
          inspector_t inspect)
 
49
{
 
50
  if (buf0 & 0x1)       // must be even
 
51
    abort();
 
52
 
 
53
  sm->buf0 = buf0;
 
54
  sm->running = false;
 
55
  sm->recv_args = *recv;
 
56
  sm->send_args = *send;
 
57
 
 
58
  sm->rx_idle = true;
 
59
  sm->tx_idle = true;
 
60
 
 
61
  sm->inspect = inspect;
 
62
 
 
63
  // How much to adjust the last_line register.
 
64
  // It's 1 for everything but the ethernet.
 
65
  sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1;
 
66
 
 
67
  buffer_state[sm->buf0] = BS_EMPTY;
 
68
  buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
 
69
 
 
70
  sm->precomputed_receive_to_buf_ctrl_word[0] =
 
71
    (BPC_READ
 
72
     | BPC_BUFFER(sm->buf0)
 
73
     | BPC_PORT(sm->recv_args.port)
 
74
     | BPC_STEP(1)
 
75
     | BPC_FIRST_LINE(sm->recv_args.first_line)
 
76
     | BPC_LAST_LINE(sm->recv_args.last_line));
 
77
    
 
78
  sm->precomputed_receive_to_buf_ctrl_word[1] =
 
79
    (BPC_READ
 
80
     | BPC_BUFFER(sm->buf0 ^ 1)
 
81
     | BPC_PORT(sm->recv_args.port)
 
82
     | BPC_STEP(1)
 
83
     | BPC_FIRST_LINE(sm->recv_args.first_line)
 
84
     | BPC_LAST_LINE(sm->recv_args.last_line));
 
85
    
 
86
  sm->precomputed_send_from_buf_ctrl_word[0] =
 
87
    (BPC_WRITE
 
88
     | BPC_BUFFER(sm->buf0)
 
89
     | BPC_PORT(sm->send_args.port)
 
90
     | BPC_STEP(1)
 
91
     | BPC_FIRST_LINE(sm->send_args.first_line)
 
92
     | BPC_LAST_LINE(0));               // last line filled in at runtime
 
93
    
 
94
  sm->precomputed_send_from_buf_ctrl_word[1] =
 
95
    (BPC_WRITE
 
96
     | BPC_BUFFER(sm->buf0 ^ 1)
 
97
     | BPC_PORT(sm->send_args.port)
 
98
     | BPC_STEP(1)
 
99
     | BPC_FIRST_LINE(sm->send_args.first_line)
 
100
     | BPC_LAST_LINE(0));               // last line filled in at runtime
 
101
    
 
102
}
 
103
 
 
104
static inline void
 
105
dbsm_receive_to_buf(dbsm_t *sm, int bufno)
 
106
{
 
107
  buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 1];
 
108
}
 
109
 
 
110
static inline void
 
111
dbsm_send_from_buf(dbsm_t *sm, int bufno)
 
112
{
 
113
  buffer_pool_ctrl->ctrl =
 
114
    (sm->precomputed_send_from_buf_ctrl_word[bufno & 1]
 
115
     | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj));
 
116
}
 
117
 
 
118
void
 
119
dbsm_start(dbsm_t *sm)
 
120
{
 
121
  // printf("dbsm_start: buf0 = %d, recv_port = %d\n", sm->buf0, sm->recv_args.port);
 
122
 
 
123
  sm->running = true;
 
124
 
 
125
  buffer_state[sm->buf0] = BS_EMPTY;
 
126
  buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
 
127
 
 
128
  bp_clear_buf(sm->buf0);
 
129
  bp_clear_buf(sm->buf0 ^ 1);
 
130
 
 
131
  sm->tx_idle = true;
 
132
  sm->rx_idle = false;
 
133
  dbsm_receive_to_buf(sm, sm->buf0);
 
134
  buffer_state[sm->buf0] = BS_FILLING;
 
135
 
 
136
}
 
137
 
 
138
 
 
139
void
 
140
dbsm_stop(dbsm_t *sm)
 
141
{
 
142
  sm->running = false;
 
143
  bp_clear_buf(sm->buf0);
 
144
  bp_clear_buf(sm->buf0 ^ 1);
 
145
  buffer_state[sm->buf0] = BS_EMPTY;
 
146
  buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
 
147
}
 
148
 
 
149
static void dbsm_process_helper(dbsm_t *sm, int buf_this);
 
150
static void dbsm_error_helper(dbsm_t *sm, int buf_this);
 
151
 
 
152
void
 
153
dbsm_process_status(dbsm_t *sm, uint32_t status)
 
154
{
 
155
  if (!sm->running)
 
156
    return;
 
157
 
 
158
  if (status & (BPS_ERROR(sm->buf0) | BPS_ERROR(sm->buf0 ^ 1))){
 
159
    putchar('E');
 
160
    // Most likely an ethernet Rx error.  We just restart the transfer.
 
161
    if (status & (BPS_ERROR(sm->buf0)))
 
162
      dbsm_error_helper(sm, sm->buf0);
 
163
 
 
164
    if (status & (BPS_ERROR(sm->buf0 ^ 1)))
 
165
      dbsm_error_helper(sm, sm->buf0 ^ 1);
 
166
  }
 
167
 
 
168
  if (status & BPS_DONE(sm->buf0))
 
169
    dbsm_process_helper(sm, sm->buf0);
 
170
 
 
171
  if (status & BPS_DONE(sm->buf0 ^ 1))
 
172
    dbsm_process_helper(sm, sm->buf0 ^ 1);
 
173
}
 
174
 
 
175
static void
 
176
dbsm_process_helper(dbsm_t *sm, int buf_this)
 
177
{
 
178
  int buf_other = buf_this ^ 1;
 
179
 
 
180
  bp_clear_buf(buf_this);
 
181
 
 
182
  if (buffer_state[buf_this] == BS_FILLING){
 
183
    buffer_state[buf_this] = BS_FULL;
 
184
    //
 
185
    // does s/w handle this packet?
 
186
    //
 
187
    if (sm->inspect(sm, buf_this)){
 
188
      // s/w handled the packet; refill the buffer
 
189
      dbsm_receive_to_buf(sm, buf_this);
 
190
      buffer_state[buf_this] = BS_FILLING;
 
191
    }
 
192
 
 
193
    else {      // s/w didn't handle this; pass it on
 
194
 
 
195
      if(buffer_state[buf_other] == BS_EMPTY){
 
196
        dbsm_receive_to_buf(sm, buf_other);
 
197
        buffer_state[buf_other] = BS_FILLING;
 
198
      }
 
199
      else
 
200
        sm->rx_idle = true;
 
201
 
 
202
      if (sm->tx_idle){
 
203
        sm->tx_idle = false;
 
204
        dbsm_send_from_buf(sm, buf_this);
 
205
        buffer_state[buf_this] = BS_EMPTYING;
 
206
      }
 
207
    }
 
208
  }
 
209
  else {  // buffer was emptying
 
210
    buffer_state[buf_this] = BS_EMPTY;
 
211
    if (sm->rx_idle){
 
212
      sm->rx_idle = false;
 
213
      dbsm_receive_to_buf(sm, buf_this);
 
214
      buffer_state[buf_this] = BS_FILLING;
 
215
    }
 
216
    if (buffer_state[buf_other] == BS_FULL){
 
217
      dbsm_send_from_buf(sm, buf_other);
 
218
      buffer_state[buf_other] = BS_EMPTYING;
 
219
    }
 
220
    else
 
221
      sm->tx_idle = true;
 
222
  }
 
223
}
 
224
 
 
225
static void
 
226
dbsm_error_helper(dbsm_t *sm, int buf_this)
 
227
{
 
228
  bp_clear_buf(buf_this);               // clears ERROR flag
 
229
 
 
230
  if (buffer_state[buf_this] == BS_FILLING){
 
231
    dbsm_receive_to_buf(sm, buf_this);    // restart the xfer
 
232
  }
 
233
  else { // buffer was emptying
 
234
    dbsm_send_from_buf(sm, buf_this);     // restart the xfer
 
235
  }
 
236
}
 
237
 
 
238
/*
 
239
 * Handle DSP Tx underrun
 
240
 */
 
241
void
 
242
dbsm_handle_tx_underrun(dbsm_t *sm)
 
243
{
 
244
  // clear the DSP Tx state machine
 
245
  dsp_tx_regs->clear_state = 1;
 
246
 
 
247
  // If there's a buffer that's empyting, clear it & flush xfer
 
248
 
 
249
  if (buffer_state[sm->buf0] == BS_EMPTYING){
 
250
    bp_clear_buf(sm->buf0);
 
251
    dsp_tx_regs->clear_state = 1;       // flush partial packet
 
252
    // drop frame in progress on ground.  Pretend it finished
 
253
    dbsm_process_helper(sm, sm->buf0);
 
254
  }
 
255
  else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
 
256
    bp_clear_buf(sm->buf0 ^ 1);
 
257
    dsp_tx_regs->clear_state = 1;       // flush partial packet
 
258
    // drop frame in progress on ground.  Pretend it finished
 
259
    dbsm_process_helper(sm, sm->buf0 ^ 1);
 
260
  }
 
261
}
 
262
 
 
263
/*
 
264
 * Handle DSP Rx overrun
 
265
 */
 
266
void
 
267
dbsm_handle_rx_overrun(dbsm_t *sm)
 
268
{
 
269
  dsp_rx_regs->clear_state = 1;
 
270
 
 
271
  // If there's a buffer that's filling, clear it.
 
272
  // Any restart will be the job of the caller.
 
273
  
 
274
  if (buffer_state[sm->buf0] == BS_FILLING)
 
275
    bp_clear_buf(sm->buf0);
 
276
 
 
277
  if (buffer_state[sm->buf0 ^1] == BS_FILLING)
 
278
    bp_clear_buf(sm->buf0 ^ 1);
 
279
}
 
280
 
 
281
void 
 
282
dbsm_wait_for_opening(dbsm_t *sm)
 
283
{
 
284
  if (buffer_state[sm->buf0] == BS_EMPTYING){
 
285
    // wait for xfer to complete
 
286
    int mask = BPS_DONE(sm->buf0) | BPS_ERROR(sm->buf0) | BPS_IDLE(sm->buf0);
 
287
    while ((buffer_pool_status->status & mask) == 0)
 
288
      ;
 
289
  }
 
290
  else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
 
291
    // wait for xfer to complete
 
292
    int mask = BPS_DONE(sm->buf0 ^ 1) | BPS_ERROR(sm->buf0 ^ 1) | BPS_IDLE(sm->buf0 ^ 1);
 
293
    while ((buffer_pool_status->status & mask) == 0)
 
294
      ;
 
295
  }
 
296
}