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>
28 #include "lwip/pbuf.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. */
38 #define NUM_RX_BUFS 16
41 volatile struct gelic_descr
*descr
;
47 * Helper struct to hold private data used to operate your ethernet interface.
50 /* Add whatever per-interface state that is needed here. */
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) {
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
;
81 gelicif
->last_rx
%= NUM_RX_BUFS
;
86 * In this function, the hardware should be initialized.
87 * Called from gelicif_init().
89 * @param netif the already initialized lwip network interface structure
93 low_level_init(struct netif
*netif
)
95 struct gelicif
*gelicif
= netif
->state
;
100 printf("gelicif: low_level_init()\n");
102 /* maximum transfer unit */
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
);
110 fatal("gelicif: failed to find device");
112 printf("gelicif: device is on bus %d, device %d\n", gelicif
->bus_id
, gelicif
->dev_id
);
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 */
130 result
= lv1_net_control(gelicif
->bus_id
, gelicif
->dev_id
, \
131 GELIC_LV1_GET_MAC_ADDRESS
, 0, 0, 0, &mac
, &v2
);
133 fatal("gelicif: lv1_net_control(GELIC_LV1_GET_MAC_ADDRESS) failed");
135 printf("gelicif: ethernet MAC is %012lx\n", mac
);
137 memcpy(netif
->hwaddr
, &mac
, 6);
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
);
143 gelicif
->need_vlan
= 1;
144 gelicif
->vlan_id
= vlan_id
;
145 printf("gelicif: VLAN ID is 0x%04x\n", gelicif
->vlan_id
);
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
);
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
);
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);
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
;
208 printf("gelicif: low_level_shutdown()\n");
210 result
= lv1_net_stop_rx_dma(gelicif
->bus_id
, gelicif
->dev_id
);
212 printf("gelicif: WARNING: failed to stop RX DMA, will not free buffer\n");
214 printf("gelicif: stopped RX DMA\n");
215 result
= unmap_dma_mem(gelicif
->bus_id
, gelicif
->dev_id
, gelicif
->bus_addr
, gelicif
->buf_size
);
217 printf("gelicif: WARNING: failed to unmap DMA mem, will not free buffer\n");
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
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).
244 low_level_output(struct netif
*netif
, struct pbuf
*p
)
246 struct gelicif
*gelicif
= netif
->state
;
249 //printf("gelicif: transmitting packet\n");
251 u8
*pkt
= gelicif
->txd
.pkt
;
255 pbuf_header(p
, -ETH_PAD_SIZE
); /* drop the padding word */
258 if (gelicif
->need_vlan
) {
259 total_len
= pbuf_copy_partial(p
, pkt
, 12, 0);
260 /* Insert the VLAN tag */
263 pkt
[14] = gelicif
->vlan_id
>> 8;
264 pkt
[15] = gelicif
->vlan_id
;
266 total_len
+= pbuf_copy_partial(p
, &pkt
[16], netif
->mtu
+ 2, 12);
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);
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
);
284 pbuf_header(p
, ETH_PAD_SIZE
); /* reclaim the padding word */
287 LINK_STATS_INC(link
.xmit
);
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
301 low_level_input(struct netif
*netif
)
303 struct gelicif
*gelicif
= netif
->state
;
304 struct pbuf
*p
= NULL
;
305 u16_t len
, alloc_len
;
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
)
314 //printf("gelicif: packet received (idx %d, status 0x%08x)\n", gelicif->next_rx, status);
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);
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"
331 len
= gelicif
->rxd
[idx
].descr
->valid_size
;
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
);
340 /* Gelic puts the vlan tag in front of the frame, so strip it */
342 u8
*pkt
= &gelicif
->rxd
[idx
].pkt
[2];
348 alloc_len
+= ETH_PAD_SIZE
; /* allow room for Ethernet padding */
351 /* We allocate a pbuf chain of pbufs from the pool. */
352 p
= pbuf_alloc(PBUF_RAW
, alloc_len
, PBUF_POOL
);
357 pbuf_header(p
, -ETH_PAD_SIZE
); /* drop the padding word */
359 pbuf_take(p
, pkt
, len
);
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]);
370 pbuf_header(p
, ETH_PAD_SIZE
); /* reclaim the padding word */
373 LINK_STATS_INC(link
.recv
);
375 printf("gelicif: Could not alloc pbuf!\n");
377 LINK_STATS_INC(link
.memerr
);
378 LINK_STATS_INC(link
.drop
);
380 chain_rx(gelicif
, idx
);
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
;
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 */
410 switch (htons(ethhdr
->type
)) {
411 /* IP or ARP packet? */
416 case ETHTYPE_PPPOEDISC
:
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"));
429 printf("gelicif: unknown packet type 0x%04x\n", ethhdr
->type
);
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
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");
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
);
486 gelicif_shutdown(struct netif
*netif
)
488 /* deinitialize the hardware */
489 low_level_shutdown(netif
);
492 fatal("gelicif: interface already freed");