Statistics
| Branch: | Tag: | Revision:

root / firmware / microblaze / apps / app_passthru_v2.c @ aab51fa4

History | View | Annotate | Download (6.28 KB)

1 d088a11b Josh Blum
/* -*- 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
#ifdef HAVE_CONFIG_H
20
#include "config.h"
21
#endif
22
23
#include "app_passthru_v2.h"
24
#include "buffer_pool.h"
25
#include "memcpy_wa.h"
26
#include "ethernet.h"
27
#include "nonstdio.h"
28
#include "print_rmon_regs.h"
29
#include "db.h"
30
#include "clocks.h"
31
#include <string.h>
32
33
volatile bool link_is_up = false;        // eth handler sets this
34
35
36
// If this is non-zero, this dbsm could be writing to the ethernet
37
dbsm_t *ac_could_be_sending_to_eth;
38
39
//static unsigned char exp_seqno = 0;
40
41
void
42
set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt)
43
{
44
  reply_pkt->ehdr.dst = cmd_pkt->ehdr.src;
45
  reply_pkt->ehdr.src = *ethernet_mac_addr();
46
  reply_pkt->ehdr.ethertype = U2_ETHERTYPE;
47
  reply_pkt->thdr.flags = 0;
48
  reply_pkt->thdr.fifo_status = 0;        // written by protocol engine
49
  reply_pkt->thdr.seqno = 0;                // written by protocol engine
50
  reply_pkt->thdr.ack = 0;                // written by protocol engine
51
  u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN);
52
  reply_pkt->fixed.timestamp = timer_regs->time;
53
}
54
55
static void
56
send_reply(unsigned char *reply, size_t reply_len)
57
{
58
  if (reply_len < 64)
59
    reply_len = 64;
60
61
  // wait for buffer to become idle
62
  hal_set_leds(0x4, 0x4);
63
  while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0)
64
    ;
65
  hal_set_leds(0x0, 0x4);
66
67
  // copy reply into CPU_TX_BUF
68
  memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len);
69
70
  // wait until nobody else is sending to the ethernet
71
  if (ac_could_be_sending_to_eth){
72
    hal_set_leds(0x8, 0x8);
73
    dbsm_wait_for_opening(ac_could_be_sending_to_eth);
74
    hal_set_leds(0x0, 0x8);
75
  }
76
77
  // fire it off
78
  bp_send_from_buf(CPU_TX_BUF, PORT_ETH, 1, 0, reply_len/4);
79
80
  // wait for it to complete (not long, it's a small pkt)
81
  while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0)
82
    ;
83
84
  bp_clear_buf(CPU_TX_BUF);
85
}
86
87
88
static size_t
89
op_id_cmd(const op_generic_t *p,
90
          void *reply_payload, size_t reply_payload_space)
91
{
92
  op_id_reply_t *r = (op_id_reply_t *) reply_payload;
93
  if (reply_payload_space < sizeof(*r))        // no room
94
    return 0;
95
96
  // Build reply subpacket
97
98
  r->opcode = OP_ID_REPLY;
99
  r->len = sizeof(op_id_reply_t);
100
  r->rid = p->rid;
101
  r->addr = *ethernet_mac_addr();
102
  r->hw_rev = 0x0000;        // FIXME
103
  // r->fpga_md5sum = ;        // FIXME
104
  // r->sw_md5sum = ;        // FIXME
105
106
  // FIXME Add d'board info, including dbid, min/max gain, min/max freq
107
108
  return r->len;
109
}
110
111
static size_t
112
add_eop(void *reply_payload, size_t reply_payload_space)
113
{
114
  op_generic_t *r = (op_generic_t *) reply_payload;
115
  if (reply_payload_space < sizeof(*r))                
116
    return 0;                                        // no room
117
118
  r->opcode = OP_EOP;
119
  r->len = sizeof(*r);
120
  r->rid = 0;
121
  r->ok =  0;
122
123
  return r->len;
124
}
125
126
bool
127
handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
128
{
129
  unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4;
130
  unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)];
131
  int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t);
132
133
  bool handled_it = false;
134
135
  // initialize reply
136
  memset(reply, 0, sizeof(reply));
137
  set_reply_hdr((u2_eth_packet_t *) reply, pkt);
138
139
  // point to beginning of payload (subpackets)
140
  unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t);
141
  int payload_len = len - sizeof(u2_eth_packet_t);
142
143
  size_t subpktlen = 0;
144
145
  while (payload_len >= sizeof(op_generic_t)){
146
    const op_generic_t *gp = (const op_generic_t *) payload;
147
    subpktlen = 0;
148
149
    switch(gp->opcode){
150
    case OP_EOP:                // end of subpackets
151
      goto end_of_subpackets;
152
153
    case OP_ID:
154
      subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space);
155
      handled_it = true;
156
      break;
157
158
    default:
159
      if (0){
160
        printf("\npassing on %d\n", gp->opcode);
161
      }
162
      break;
163
    }
164
165
    int t = (gp->len + 3) & ~3;                // bump to a multiple of 4
166
    payload += t;
167
    payload_len -= t;
168
169
    subpktlen = (subpktlen + 3) & ~3;        // bump to a multiple of 4
170
    reply_payload += subpktlen;
171
    reply_payload_space -= subpktlen;
172
  }
173
174
 end_of_subpackets:
175
176
  if (handled_it){
177
    // add the EOP marker
178
    subpktlen = add_eop(reply_payload, reply_payload_space);
179
    subpktlen = (subpktlen + 3) & ~3;        // bump to a multiple of 4
180
    reply_payload += subpktlen;
181
    reply_payload_space -= subpktlen;
182
183
    send_reply(reply, reply_payload - reply);
184
  }
185
186
  return handled_it;
187
}
188
189
190
/*
191
 * Called when an ethernet packet is received.
192
 * Return true if we handled it here, otherwise
193
 * it'll be passed on to the DSP Tx pipe
194
 */
195
bool
196
eth_pkt_inspector(dbsm_t *sm, int bufno)
197
{
198
  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno);
199
  size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4;
200
201
  //static size_t last_len = 0;
202
203
  // hal_toggle_leds(0x1);
204
205
  // inspect rcvd frame and figure out what do do.
206
207
  if (pkt->ehdr.ethertype != U2_ETHERTYPE)
208
    return true;        // ignore, probably bogus PAUSE frame from MAC
209
210
  int chan = u2p_chan(&pkt->fixed);
211
212
  switch (chan){
213
  case CONTROL_CHAN:
214
    return handle_control_chan_frame(pkt, byte_len);
215
    break;
216
217
  case 0:
218
  default:
219
#if 0
220
    if (last_len != 0){
221
      if (byte_len != last_len){
222
        printf("Len: %d last: %d\n", byte_len, last_len);
223
      }
224
    }
225
    last_len = byte_len;
226

227
    if((pkt->thdr.seqno) == exp_seqno){
228
      exp_seqno++;
229
      //putchar('.');
230
    }
231
    else {
232
      // putchar('S');
233
      //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
234
      exp_seqno = pkt->thdr.seqno + 1;
235
    }
236
#endif
237
    return false;        // pass it on to Tx DSP
238
    break;
239
  }
240
}
241
242
/*
243
 * Called when eth phy state changes (w/ interrupts disabled)
244
 */
245
void
246
link_changed_callback(int speed)
247
{
248
  link_is_up = speed != 0;
249
  hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45);
250
  printf("\neth link changed: speed = %d\n", speed);
251
}