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

5
Last change on this file since d8d6a08 was d8d6a08, checked in by Sebastian Huber <sebastian.huber@…>, on 01/27/18 at 10:12:44

bsps: Move network define to source files

Define INSIDE_RTEMS_BSD_TCPIP_STACK in the network interface driver
source files to avoid some build system magic.

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