source: rtems/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 *  RTEMS driver for Minimac2 ethernet IP-core of Milkymist SoC
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.com/license/LICENSE.
7 *
8 *  COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010)
9 *  Telecom SudParis, France
10 *  Copyright (C) 2011 Sebastien Bourdeauducq
11 */
12
13#define RTEMS_STATUS_CHECKS_USE_PRINTK
14
15#include <bsp.h>
16#include <bsp/irq-generic.h>
17#include <stdio.h>
18#include <string.h>
19#include <rtems/rtems_bsdnet.h>
20#include <rtems/status-checks.h>
21#include <sys/param.h>
22#include <sys/mbuf.h>
23#include <sys/socket.h>
24#include <sys/sockio.h>
25#include <net/if.h>
26#include <net/ethernet.h>
27#include <netinet/in.h>
28#include <netinet/if_ether.h>
29#include <rtems.h>
30#include "bspopts.h"
31#include "../include/system_conf.h"
32#include "network.h"
33
34#define CTS_EVENT             RTEMS_EVENT_1
35#define RX_EVENT              RTEMS_EVENT_1
36#define START_TRANSMIT_EVENT  RTEMS_EVENT_2
37
38static struct arpcom arpcom;
39static rtems_id rx_daemon_id;
40static rtems_id tx_daemon_id;
41
42static void minimac_init(void *arg);
43static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command,
44  caddr_t data);
45static void minimac_start(struct ifnet *ifp);
46
47static void rx_daemon(void *arg);
48static void tx_daemon(void *arg);
49static rtems_isr rx_interrupt_handler(rtems_vector_number vector);
50static rtems_isr tx_interrupt_handler(rtems_vector_number vector);
51
52static bool validate_mac(const char *m)
53{
54  int i;
55 
56  for(i=0;i<6;i++)
57    if((m[i] != 0x00) && (m[i] != 0xff))
58      return true;
59  return false;
60}
61
62static const char *get_mac_address(void)
63{
64  const char *flash_mac = (const char *)FLASH_OFFSET_MAC_ADDRESS;
65  static const char fallback_mac[6] = { 0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00 };
66 
67  if(validate_mac(flash_mac))
68    return flash_mac;
69  else {
70    printk("Warning: using fallback MAC address\n");
71    return fallback_mac;
72  }
73}
74
75int rtems_minimac_driver_attach(struct rtems_bsdnet_ifconfig *config,
76  int attaching)
77{
78  struct ifnet *ifp;
79  rtems_isr_entry dummy;
80  int i;
81  static int registered;
82  uint8_t *tx_buffer = (uint8_t *)MINIMAC_TX_BASE;
83
84  if(!attaching) {
85    printk("Minimac driver cannot be detached.\n");
86    return 0;
87  }
88
89  ifp = &(arpcom.ac_if);
90
91  if(registered) {
92    printk("Minimac driver already in use.\n");
93    return 0;
94  }
95  registered = 1;
96
97  memcpy(arpcom.ac_enaddr, get_mac_address(), 6);
98  ifp->if_mtu = ETHERMTU;
99  ifp->if_unit = 0;
100  ifp->if_name = "minimac";
101  ifp->if_init = minimac_init;
102  ifp->if_ioctl = minimac_ioctl;
103  ifp->if_start = minimac_start;
104  ifp->if_output = ether_output;
105  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
106  ifp->if_snd.ifq_maxlen = ifqmaxlen;
107
108  if_attach(ifp);
109  ether_ifattach(ifp);
110
111  rx_daemon_id = rtems_bsdnet_newproc("mrxd", 4096, rx_daemon, NULL);
112  tx_daemon_id = rtems_bsdnet_newproc("mtxd", 4096, tx_daemon, NULL);
113  rtems_interrupt_catch(rx_interrupt_handler, MM_IRQ_ETHRX, &dummy);
114  rtems_interrupt_catch(tx_interrupt_handler, MM_IRQ_ETHTX, &dummy);
115 
116  MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_LOADED);
117  MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_LOADED);
118
119  for(i=0;i<7; i++)
120    tx_buffer[i] = 0x55;
121  tx_buffer[7] = 0xd5;
122  MM_WRITE(MM_MINIMAC_SETUP, 0);
123  rtems_event_send(tx_daemon_id, CTS_EVENT);
124 
125  bsp_interrupt_vector_enable(MM_IRQ_ETHRX);
126  bsp_interrupt_vector_enable(MM_IRQ_ETHTX);
127
128  return 1;
129}
130
131static void minimac_start(struct ifnet *ifp)
132{
133  rtems_event_send(tx_daemon_id, START_TRANSMIT_EVENT);
134  ifp->if_flags |= IFF_OACTIVE;
135}
136
137static void minimac_init(void *arg)
138{
139  struct ifnet *ifp = &arpcom.ac_if;
140  ifp->if_flags |= IFF_RUNNING;
141}
142
143static void minimac_stop(void)
144{
145  struct ifnet *ifp = &arpcom.ac_if;
146  ifp->if_flags &= ~IFF_RUNNING;
147}
148
149static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command,
150  caddr_t data)
151{
152  int error;
153 
154  error = 0;
155  switch (command) {
156    case SIOCGIFADDR:
157    case SIOCSIFADDR:
158      ether_ioctl(ifp, command, data);
159      break;
160
161    case SIOCSIFFLAGS:
162      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
163        case IFF_RUNNING:
164          minimac_stop();
165          break;
166        case IFF_UP:
167          minimac_init(NULL);
168          break;
169        case IFF_UP | IFF_RUNNING:
170          minimac_stop();
171          minimac_init(NULL);
172          break;
173        default:
174          break;
175      }
176      break;
177
178    default:
179      error = EINVAL;
180      break;
181  }
182  return error;
183}
184
185
186static rtems_isr rx_interrupt_handler(rtems_vector_number vector)
187{
188  /* Deassert IRQ line.
189   * The RX daemon will then read all the slots we marked as empty.
190   */
191  if(MM_READ(MM_MINIMAC_STATE0) == MINIMAC_STATE_PENDING)
192    MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_EMPTY);
193  if(MM_READ(MM_MINIMAC_STATE1) == MINIMAC_STATE_PENDING)
194    MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_EMPTY);
195
196  rtems_event_send(rx_daemon_id, RX_EVENT);
197
198  lm32_interrupt_ack(1 << MM_IRQ_ETHRX);
199}
200
201static void receive_packet(uint8_t *buffer, int length)
202{
203  struct ifnet *ifp = &arpcom.ac_if;
204  struct mbuf *m;
205  struct ether_header *eh;
206  uint32_t computed_crc, net_crc;
207 
208  if(length < 64) {
209    printk("Warning: Ethernet packet too short\n");
210    return;
211  }
212
213  length -= 4; /* strip CRC */
214  net_crc = ((uint32_t)buffer[length])
215    | ((uint32_t)buffer[length+1] << 8)
216    | ((uint32_t)buffer[length+2] << 16)
217    | ((uint32_t)buffer[length+3] << 24);
218  length -= 8; /* strip preamble */
219  computed_crc = ether_crc32_le(&buffer[8], length) ^ 0xffffffff;
220  if(computed_crc == net_crc) {
221    MGETHDR(m, M_WAIT, MT_DATA);
222    MCLGET(m, M_WAIT);
223    length -= sizeof(struct ether_header); /* strip Ethernet header */
224    memcpy(m->m_data, &buffer[8+sizeof(struct ether_header)], length);
225    m->m_len = m->m_pkthdr.len = length;
226    m->m_pkthdr.rcvif = ifp;
227    eh = (struct ether_header *)&buffer[8];
228    ether_input(ifp, eh, m);
229  } else
230    printk("Ethernet CRC error: got %08x expected %08x (len=%d)\n",
231      net_crc, computed_crc, length);
232}
233
234static void rx_daemon(void *arg)
235{
236  rtems_event_set events;
237 
238  while(1) {
239    rtems_bsdnet_event_receive(RX_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT,
240      RTEMS_NO_TIMEOUT, &events);
241
242    if(MM_READ(MM_MINIMAC_STATE0) == MINIMAC_STATE_EMPTY) {
243      receive_packet((uint8_t *)MINIMAC_RX0_BASE, MM_READ(MM_MINIMAC_COUNT0));
244      MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_LOADED);
245    }
246    if(MM_READ(MM_MINIMAC_STATE1) == MINIMAC_STATE_EMPTY) {
247      receive_packet((uint8_t *)MINIMAC_RX1_BASE, MM_READ(MM_MINIMAC_COUNT1));
248      MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_LOADED);
249    }
250  }
251}
252
253/* RTEMS apparently doesn't support m_length() ... */
254static int copy_mbuf_chain(struct mbuf *m, uint8_t *target)
255{
256  int len;
257
258  len = 0;
259  while(m != NULL) {
260    if(m->m_len > 0) {
261      m_copydata(m, 0, m->m_len, (caddr_t)(target + len));
262      len += m->m_len;
263    }
264    m = m->m_next;
265  }
266  return len;
267}
268
269static void send_packet(struct ifnet *ifp, struct mbuf *m)
270{
271  unsigned int len;
272  unsigned int crc;
273  uint8_t *tx_buffer = (uint8_t *)(MINIMAC_TX_BASE+8);
274 
275  len = copy_mbuf_chain(m, tx_buffer);
276  for(;len<60;len++)
277    tx_buffer[len] = 0x00; // Padding
278
279  crc = ether_crc32_le(tx_buffer, len) ^ 0xffffffff;
280
281  tx_buffer[len] = crc & 0xff;
282  tx_buffer[len+1] = (crc & 0xff00) >> 8;
283  tx_buffer[len+2] = (crc & 0xff0000) >> 16;
284  tx_buffer[len+3] = crc >> 24;
285
286  len += 4; // We add 4 bytes of CRC32
287
288  MM_WRITE(MM_MINIMAC_TXCOUNT, len + 8);
289}
290
291static rtems_isr tx_interrupt_handler(rtems_vector_number vector)
292{
293  lm32_interrupt_ack(1 << MM_IRQ_ETHTX);
294  rtems_event_send(tx_daemon_id, CTS_EVENT);
295}
296
297static void tx_daemon(void *arg)
298{
299  struct ifnet *ifp = &arpcom.ac_if;
300  rtems_event_set events;
301  struct mbuf *m;
302 
303  while(1) {
304    rtems_bsdnet_event_receive(START_TRANSMIT_EVENT,
305      RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
306    while(1) {
307      IF_DEQUEUE(&ifp->if_snd, m);
308      if(m == NULL)
309        break;
310      rtems_bsdnet_event_receive(CTS_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT,
311        RTEMS_NO_TIMEOUT, &events);
312      send_packet(ifp, m);
313      m_freem(m);
314    }
315    ifp->if_flags &= ~IFF_OACTIVE;
316  }
317}
Note: See TracBrowser for help on using the repository browser.