2 * Copyright (C) 2010 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/types.h>
30 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/if_ether.h>
36 #include <netinet/ip.h>
39 #include <machine/cpufunc.h>
44 #include "bootstrap.h"
48 #define GELIC_DESCR_OWNED 0xa0000000
49 #define GELIC_CMDSTAT_NOIPSEC 0x00080000
50 #define GELIC_CMDSTAT_LAST 0x00040000
51 #define GELIC_RXERRORS 0x7def8000
53 #define GELIC_POLL_PERIOD 100 /* microseconds */
55 static int ps3net_probe(struct netif *, void *);
56 static int ps3net_match(struct netif *, void *);
57 static void ps3net_init(struct iodesc *, void *);
58 static int ps3net_get(struct iodesc *, void *, size_t, time_t);
59 static int ps3net_put(struct iodesc *, void *, size_t);
60 static void ps3net_end(struct netif *);
62 struct netif_stats ps3net_stats[1];
63 struct netif_dif ps3net_ifs[] = {{0, 1, ps3net_stats, 0}};
65 /* XXX: Get from firmware, not hardcoding */
69 static uint64_t dma_base;
71 struct gelic_dmadesc {
82 struct netif_driver ps3net = {
94 ps3net_match(struct netif *nif, void *machdep_hint)
100 ps3net_probe(struct netif *nif, void *machdep_hint)
106 ps3net_put(struct iodesc *desc, void *pkt, size_t len)
108 volatile static struct gelic_dmadesc txdesc __aligned(32);
109 volatile static char txbuf[1536] __aligned(128);
113 #if defined(NETIF_DEBUG)
114 struct ether_header *eh;
116 printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len);
118 printf("dst: %s ", ether_sprintf(eh->ether_dhost));
119 printf("src: %s ", ether_sprintf(eh->ether_shost));
120 printf("type: 0x%x\n", eh->ether_type & 0xffff);
123 while (txdesc.cmd_stat & GELIC_DESCR_OWNED) {
124 printf("Stalled XMIT!\n");
129 * We must add 4 extra bytes to this packet to store the destination
132 memcpy(txbuf, pkt, 12);
137 ((uint8_t *)txbuf)[12] = 0x81;
138 ((uint8_t *)txbuf)[13] = 0x00;
139 ((uint8_t *)txbuf)[14] = vlan >> 8;
140 ((uint8_t *)txbuf)[15] = vlan & 0xff;
142 memcpy((void *)txbuf + sendlen, pkt + 12, len - 12);
145 bzero(&txdesc, sizeof(txdesc));
146 txdesc.paddr = dma_base + (uint32_t)txbuf;
147 txdesc.len = sendlen;
148 txdesc.cmd_stat = GELIC_CMDSTAT_NOIPSEC | GELIC_CMDSTAT_LAST |
154 err = lv1_net_start_tx_dma(busid, devid,
155 dma_base + (uint32_t)&txdesc, 0);
158 printf("TX Error: %d\n",err);
165 ps3net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
167 volatile static struct gelic_dmadesc rxdesc __aligned(32);
168 volatile static char rxbuf[1536] __aligned(128);
174 timeout *= 1000000; /* convert to microseconds */
175 while (rxdesc.cmd_stat & GELIC_DESCR_OWNED) {
176 if (timeout < GELIC_POLL_PERIOD)
178 delay(GELIC_POLL_PERIOD);
179 timeout -= GELIC_POLL_PERIOD;
183 if (rxdesc.rxerror & GELIC_RXERRORS) {
189 * Copy the packet to the receive buffer, leaving out the
190 * 2 byte VLAN header.
192 len = min(len, rxdesc.valid_size - 2);
193 memcpy(pkt, (u_char *)rxbuf + 2, len);
196 #if defined(NETIF_DEBUG)
198 struct ether_header *eh;
200 printf("net_get: desc %p, pkt %p, len %d\n", desc, pkt, len);
202 printf("dst: %s ", ether_sprintf(eh->ether_dhost));
203 printf("src: %s ", ether_sprintf(eh->ether_shost));
204 printf("type: 0x%x\n", eh->ether_type & 0xffff);
209 lv1_net_stop_rx_dma(busid, devid, 0);
212 bzero(&rxdesc, sizeof(rxdesc));
213 rxdesc.paddr = dma_base + (uint32_t)rxbuf;
214 rxdesc.len = sizeof(rxbuf);
216 rxdesc.cmd_stat = GELIC_DESCR_OWNED;
219 lv1_net_start_rx_dma(busid, devid, dma_base + (uint32_t)&rxdesc, 0);
225 ps3net_init(struct iodesc *desc, void *machdep_hint)
230 err = lv1_open_device(busid, devid, 0);
232 lv1_net_stop_tx_dma(busid, devid, 0);
233 lv1_net_stop_rx_dma(busid, devid, 0);
236 * Wait for link to come up
239 for (i = 0; i < 1000; i++) {
240 lv1_net_control(busid, devid, GELIC_GET_LINK_STATUS, 2, 0,
242 if (val & GELIC_LINK_UP)
248 * Set up DMA IOMMU entries
251 err = lv1_setup_dma(busid, devid, &dma_base);
254 * Get MAC address and VLAN IDs
257 lv1_net_control(busid, devid, GELIC_GET_MAC_ADDRESS, 0, 0, 0, &mac);
258 bcopy(&((uint8_t *)&mac)[2], desc->myea, sizeof(desc->myea));
261 err = lv1_net_control(busid, devid, GELIC_GET_VLAN_ID, 2, 0,
267 * Start RX DMA engine
270 ps3net_get(NULL, NULL, 0, 0);
274 ps3net_end(struct netif *nif)
276 lv1_close_device(busid, devid);