HACK
[asbestos.git] / stage2 / gelic_netif.c
blob22886805a273df3210e23aea450f26e10d906cd9
1 /* gelic_netif.c - lwIP device driver for the Gelic PS3 Ethernet device
3 Copyright (C) 2010-2011 Hector Martin "marcan" <hector@marcansoft.com>
5 This code is licensed to you under the terms of the GNU GPL, version 2;
6 see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
8 Based on ethernetif.c from lwIP:
9 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * Author: Adam Dunkels <adam@sics.se>
15 #include <stddef.h>
16 #include "string.h"
17 #include "debug.h"
18 #include "device.h"
19 #include "malloc.h"
21 #include "gelic.h"
22 #include "lv1call.h"
24 #include "lwip/opt.h"
26 #include "lwip/def.h"
27 #include "lwip/mem.h"
28 #include "lwip/pbuf.h"
29 #include "lwip/sys.h"
30 #include "lwip/stats.h"
31 #include "lwip/snmp.h"
32 #include "netif/etharp.h"
34 /* Define those to better describe your network interface. */
35 #define IFNAME0 'e'
36 #define IFNAME1 'n'
38 #define NUM_RX_BUFS 16
40 struct gelicif_buf {
41 volatile struct gelic_descr *descr;
42 u64 bus_addr;
43 u8 *pkt;
46 /**
47 * Helper struct to hold private data used to operate your ethernet interface.
49 struct gelicif {
50 /* Add whatever per-interface state that is needed here. */
51 int bus_id;
52 int dev_id;
53 u64 bus_addr;
54 void *dma_buf;
55 u64 buf_size;
56 int need_vlan;
57 u16 vlan_id;
58 int last_rx;
59 int next_rx;
60 struct gelicif_buf txd;
61 struct gelicif_buf rxd[NUM_RX_BUFS];
65 static void chain_rx(struct gelicif *gelicif, int i)
67 //printf("gelicif: chain_rx(%d)\n", i);
68 gelicif->rxd[i].descr->next_descr_addr = 0;
69 gelicif->rxd[i].descr->result_size = 0;
70 gelicif->rxd[i].descr->result_size = 0;
71 gelicif->rxd[i].descr->valid_size = 0;
72 gelicif->rxd[i].descr->data_error = 0;
73 gelicif->rxd[i].descr->dmac_cmd_status = GELIC_DESCR_DMA_CARDOWNED;
74 if (gelicif->last_rx == -1) {
75 gelicif->last_rx = i;
76 } else {
77 if (gelicif->rxd[gelicif->last_rx].descr->next_descr_addr)
78 fatal("gelicif: last RX packet was already chained");
79 gelicif->rxd[gelicif->last_rx].descr->next_descr_addr = gelicif->rxd[i].bus_addr;
80 gelicif->last_rx++;
81 gelicif->last_rx %= NUM_RX_BUFS;
85 /**
86 * In this function, the hardware should be initialized.
87 * Called from gelicif_init().
89 * @param netif the already initialized lwip network interface structure
90 * for this gelicif
92 static void
93 low_level_init(struct netif *netif)
95 struct gelicif *gelicif = netif->state;
96 s64 result;
97 u64 v2;
98 int i;
100 printf("gelicif: low_level_init()\n");
102 /* maximum transfer unit */
103 netif->mtu = 1500;
105 u64 pktbuf_size = netif->mtu + 18;
106 pktbuf_size = (pktbuf_size+127)&(~127);
108 result = find_device_by_type(BUS_TYPE_SB, DEV_TYPE_ETH, 0, &gelicif->bus_id, &gelicif->dev_id, NULL);
109 if (result)
110 fatal("gelicif: failed to find device");
112 printf("gelicif: device is on bus %d, device %d\n", gelicif->bus_id, gelicif->dev_id);
114 gelicif->bus_id = 1;
115 gelicif->dev_id = 0;
116 gelicif->buf_size = (NUM_RX_BUFS + 1) * (sizeof(struct gelic_descr) + pktbuf_size);
117 gelicif->dma_buf = memalign(32, gelicif->buf_size);
118 if (!gelicif->dma_buf)
119 fatal("gelicif: DMA buffer alloc failed");
121 printf("gelicif: allocated 0x%lx bytes for DMA buffer\n", gelicif->buf_size);
123 memset(gelicif->dma_buf, 0, gelicif->buf_size);
125 /* set MAC hardware address length */
126 netif->hwaddr_len = ETHARP_HWADDR_LEN;
128 /* set MAC hardware address */
129 u64 mac;
130 result = lv1_net_control(gelicif->bus_id, gelicif->dev_id, \
131 GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0, &mac, &v2);
132 if (result)
133 fatal("gelicif: lv1_net_control(GELIC_LV1_GET_MAC_ADDRESS) failed");
135 printf("gelicif: ethernet MAC is %012lx\n", mac);
136 mac <<= 16;
137 memcpy(netif->hwaddr, &mac, 6);
139 u64 vlan_id;
140 result = lv1_net_control(gelicif->bus_id, gelicif->dev_id, GELIC_LV1_GET_VLAN_ID, \
141 GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, &vlan_id, &v2);
142 if (result == 0) {
143 gelicif->need_vlan = 1;
144 gelicif->vlan_id = vlan_id;
145 printf("gelicif: VLAN ID is 0x%04x\n", gelicif->vlan_id);
146 } else {
147 gelicif->need_vlan = 0;
148 printf("gelicif: no VLAN in use\n");
151 result = map_dma_mem(gelicif->bus_id, gelicif->dev_id, gelicif->dma_buf, \
152 gelicif->buf_size, &gelicif->bus_addr);
153 if (result)
154 fatal("gelicif: map_dma_mem failed");
156 printf("gelicif: base bus address is 0x%lx\n", gelicif->bus_addr);
158 u64 bus_addr = gelicif->bus_addr;
159 u8 *mem_addr = gelicif->dma_buf;
161 gelicif->txd.descr = (void*)mem_addr;
162 gelicif->txd.bus_addr = bus_addr;
163 mem_addr += sizeof(struct gelic_descr);
164 bus_addr += sizeof(struct gelic_descr);
165 for (i=0; i<NUM_RX_BUFS; i++) {
166 gelicif->rxd[i].descr = (void*)mem_addr;
167 gelicif->rxd[i].bus_addr = bus_addr;
168 mem_addr += sizeof(struct gelic_descr);
169 bus_addr += sizeof(struct gelic_descr);
171 gelicif->txd.descr->buf_addr = bus_addr;
172 gelicif->txd.pkt = mem_addr;
173 bus_addr += pktbuf_size;
174 mem_addr += pktbuf_size;
176 gelicif->last_rx = -1;
177 gelicif->next_rx = 0;
178 for (i=0; i<NUM_RX_BUFS; i++) {
179 gelicif->rxd[i].descr->buf_addr = bus_addr;
180 gelicif->rxd[i].descr->buf_size = pktbuf_size;
181 gelicif->rxd[i].pkt = mem_addr;
182 bus_addr += pktbuf_size;
183 mem_addr += pktbuf_size;
184 chain_rx(gelicif, i);
187 /* device capabilities */
188 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
189 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
191 /* clear any existing RX DMA */
192 result = lv1_net_stop_rx_dma(gelicif->bus_id, gelicif->dev_id);
193 if (result == 0)
194 printf("gelicif: cleared old RX DMA job\n");
196 /* start the RX DMA */
197 result = lv1_net_start_rx_dma(gelicif->bus_id, gelicif->dev_id, gelicif->rxd[0].bus_addr, 0);
198 if (result)
199 fatal("gelicif: lv1_net_start_rx_dma failed");
200 printf("gelicif: started RX DMA\n");
203 static void low_level_shutdown(struct netif *netif)
205 struct gelicif *gelicif = netif->state;
206 s32 result;
208 printf("gelicif: low_level_shutdown()\n");
210 result = lv1_net_stop_rx_dma(gelicif->bus_id, gelicif->dev_id);
211 if (result) {
212 printf("gelicif: WARNING: failed to stop RX DMA, will not free buffer\n");
213 } else {
214 printf("gelicif: stopped RX DMA\n");
215 result = unmap_dma_mem(gelicif->bus_id, gelicif->dev_id, gelicif->bus_addr, gelicif->buf_size);
216 if (result) {
217 printf("gelicif: WARNING: failed to unmap DMA mem, will not free buffer\n");
218 } else {
219 printf("gelicif: unmapped DMA memory\n");
220 free(gelicif->dma_buf);
224 printf("gelicif: low_level_shutdown() complete\n");
228 * This function should do the actual transmission of the packet. The packet is
229 * contained in the pbuf that is passed to the function. This pbuf
230 * might be chained.
232 * @param netif the lwip network interface structure for this gelicif
233 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
234 * @return ERR_OK if the packet could be sent
235 * an err_t value if the packet couldn't be sent
237 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
238 * strange results. You might consider waiting for space in the DMA queue
239 * to become availale since the stack doesn't retry to send a packet
240 * dropped because of memory failure (except for the TCP timers).
243 static err_t
244 low_level_output(struct netif *netif, struct pbuf *p)
246 struct gelicif *gelicif = netif->state;
247 s64 result;
249 //printf("gelicif: transmitting packet\n");
251 u8 *pkt = gelicif->txd.pkt;
252 u64 total_len = 0;
254 #if ETH_PAD_SIZE
255 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
256 #endif
258 if (gelicif->need_vlan) {
259 total_len = pbuf_copy_partial(p, pkt, 12, 0);
260 /* Insert the VLAN tag */
261 pkt[12] = 0x81;
262 pkt[13] = 0x00;
263 pkt[14] = gelicif->vlan_id >> 8;
264 pkt[15] = gelicif->vlan_id;
265 total_len += 4;
266 total_len += pbuf_copy_partial(p, &pkt[16], netif->mtu + 2, 12);
267 } else {
268 total_len = pbuf_copy_partial(p, pkt, netif->mtu + 14, 0);
271 /* build the descriptor */
272 gelicif->txd.descr->buf_size = total_len;
273 gelicif->txd.descr->dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM | GELIC_DESCR_TX_DMA_FRAME_TAIL;
274 gelicif->txd.descr->result_size = 0;
275 gelicif->txd.descr->data_status = 0;
277 /* send it and block until done */
278 result = lv1_net_start_tx_dma(gelicif->bus_id, gelicif->dev_id, gelicif->txd.bus_addr, 0);
279 if (result)
280 fatal("gelicif: lv1_net_start_tx_dma failed");
281 while ((gelicif->txd.descr->dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) == GELIC_DESCR_DMA_CARDOWNED);
283 #if ETH_PAD_SIZE
284 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
285 #endif
287 LINK_STATS_INC(link.xmit);
289 return ERR_OK;
293 * Should allocate a pbuf and transfer the bytes of the incoming
294 * packet from the interface into the pbuf.
296 * @param netif the lwip network interface structure for this gelicif
297 * @return a pbuf filled with the received packet (including MAC header)
298 * NULL on memory error
300 static struct pbuf *
301 low_level_input(struct netif *netif)
303 struct gelicif *gelicif = netif->state;
304 struct pbuf *p = NULL;
305 u16_t len, alloc_len;
306 s64 result;
307 int idx;
309 idx = gelicif->next_rx;
310 u32 status = gelicif->rxd[idx].descr->dmac_cmd_status;
311 if ((status & GELIC_DESCR_DMA_STAT_MASK) == GELIC_DESCR_DMA_CARDOWNED)
312 return NULL;
314 //printf("gelicif: packet received (idx %d, status 0x%08x)\n", gelicif->next_rx, status);
316 gelicif->next_rx++;
317 gelicif->next_rx %= NUM_RX_BUFS;
318 if (status & GELIC_DESCR_RX_DMA_CHAIN_END) {
319 printf("gelicif: DMA chain ended, restarting RX DMA\n");
320 result = lv1_net_start_rx_dma(gelicif->bus_id, gelicif->dev_id,
321 gelicif->rxd[gelicif->next_rx].bus_addr, 0);
322 if (result)
323 fatal("gelicif: lv1_net_start_rx_dma failed");
326 if (!(status & GELIC_DESCR_DMA_FRAME_END))
327 printf("gelicif: FRAME_END not set?\n");
329 /* Obtain the size of the packet and put it into the "len"
330 variable. */
331 len = gelicif->rxd[idx].descr->valid_size;
332 if (!len) {
333 printf("gelicif: RX buffer overflow? 0x%x 0x%x\n", \
334 gelicif->rxd[idx].descr->result_size,
335 gelicif->rxd[idx].descr->buf_size);
336 chain_rx(gelicif, idx);
337 return NULL;
340 /* Gelic puts the vlan tag in front of the frame, so strip it */
342 u8 *pkt = &gelicif->rxd[idx].pkt[2];
343 len -= 2;
345 alloc_len = len;
347 #if ETH_PAD_SIZE
348 alloc_len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
349 #endif
351 /* We allocate a pbuf chain of pbufs from the pool. */
352 p = pbuf_alloc(PBUF_RAW, alloc_len, PBUF_POOL);
354 if (p != NULL) {
356 #if ETH_PAD_SIZE
357 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
358 #endif
359 pbuf_take(p, pkt, len);
361 int i;
362 for (i=0; i<64; i+=8) {
363 printf("%02x %02x %02x %02x %02x %02x %02x %02x\n",
364 ((u8*)p->payload)[i+0], ((u8*)p->payload)[i+1], ((u8*)p->payload)[i+2], ((u8*)p->payload)[i+3],
365 ((u8*)p->payload)[i+4], ((u8*)p->payload)[i+5], ((u8*)p->payload)[i+6], ((u8*)p->payload)[i+7]);
369 #if ETH_PAD_SIZE
370 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
371 #endif
373 LINK_STATS_INC(link.recv);
374 } else {
375 printf("gelicif: Could not alloc pbuf!\n");
376 //drop packet();
377 LINK_STATS_INC(link.memerr);
378 LINK_STATS_INC(link.drop);
380 chain_rx(gelicif, idx);
382 return p;
386 * This function should be called when a packet is ready to be read
387 * from the interface. It uses the function low_level_input() that
388 * should handle the actual reception of bytes from the network
389 * interface. Then the type of the received packet is determined and
390 * the appropriate input function is called.
392 * @param netif the lwip network interface structure for this gelicif
395 gelicif_input(struct netif *netif)
397 struct gelicif *gelicif;
398 struct eth_hdr *ethhdr;
399 struct pbuf *p;
401 gelicif = netif->state;
403 /* move received packet into a new pbuf */
404 p = low_level_input(netif);
405 /* no packet could be read, silently ignore this */
406 if (p == NULL) return 0;
407 /* points to packet payload, which starts with an Ethernet header */
408 ethhdr = p->payload;
410 switch (htons(ethhdr->type)) {
411 /* IP or ARP packet? */
412 case ETHTYPE_IP:
413 case ETHTYPE_ARP:
414 #if PPPOE_SUPPORT
415 /* PPPoE packet? */
416 case ETHTYPE_PPPOEDISC:
417 case ETHTYPE_PPPOE:
418 #endif /* PPPOE_SUPPORT */
419 /* full packet send to tcpip_thread to process */
420 if (netif->input(p, netif)!=ERR_OK)
422 LWIP_DEBUGF(NETIF_DEBUG, ("gelicif_input: IP input error\n"));
423 pbuf_free(p);
424 p = NULL;
426 break;
428 default:
429 printf("gelicif: unknown packet type 0x%04x\n", ethhdr->type);
430 pbuf_free(p);
431 p = NULL;
432 break;
434 return 1;
438 * Should be called at the beginning of the program to set up the
439 * network interface. It calls the function low_level_init() to do the
440 * actual setup of the hardware.
442 * This function should be passed as a parameter to netif_add().
444 * @param netif the lwip network interface structure for this gelicif
445 * @return ERR_OK if the loopif is initialized
446 * ERR_MEM if private data couldn't be allocated
447 * any other err_t on error
449 err_t
450 gelicif_init(struct netif *netif)
452 struct gelicif *gelicif;
454 LWIP_ASSERT("netif != NULL", (netif != NULL));
456 printf("gelicif: gelicif_init()\n");
458 gelicif = mem_malloc(sizeof(struct gelicif));
459 if (gelicif == NULL) {
460 fatal("gelicif: out of memory");
461 return ERR_MEM;
464 #if LWIP_NETIF_HOSTNAME
465 /* Initialize interface hostname */
466 netif->hostname = "ps3";
467 #endif /* LWIP_NETIF_HOSTNAME */
469 netif->state = gelicif;
470 netif->name[0] = IFNAME0;
471 netif->name[1] = IFNAME1;
472 /* We directly use etharp_output() here to save a function call.
473 * You can instead declare your own function an call etharp_output()
474 * from it if you have to do some checks before sending (e.g. if link
475 * is available...) */
476 netif->output = etharp_output;
477 netif->linkoutput = low_level_output;
479 /* initialize the hardware */
480 low_level_init(netif);
482 return ERR_OK;
485 err_t
486 gelicif_shutdown(struct netif *netif)
488 /* deinitialize the hardware */
489 low_level_shutdown(netif);
491 if (!netif->state)
492 fatal("gelicif: interface already freed");
494 free(netif->state);
495 netif->state = NULL;
497 return ERR_OK;