Date: Mon, 5 Apr 2010 01:51:11 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r206173 - projects/ppc64/sys/boot/powerpc/ps3 Message-ID: <201004050151.o351pBf9086437@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Mon Apr 5 01:51:11 2010 New Revision: 206173 URL: http://svn.freebsd.org/changeset/base/206173 Log: Checkpoint netboot support. The PS3 loader will now get a DHCP lease, load some files from NFS, and then mysteriously stall. Added: projects/ppc64/sys/boot/powerpc/ps3/devicename.c projects/ppc64/sys/boot/powerpc/ps3/ps3net.c Modified: projects/ppc64/sys/boot/powerpc/ps3/Makefile projects/ppc64/sys/boot/powerpc/ps3/conf.c projects/ppc64/sys/boot/powerpc/ps3/lv1call.S projects/ppc64/sys/boot/powerpc/ps3/lv1call.h projects/ppc64/sys/boot/powerpc/ps3/main.c projects/ppc64/sys/boot/powerpc/ps3/ps3cons.c Modified: projects/ppc64/sys/boot/powerpc/ps3/Makefile ============================================================================== --- projects/ppc64/sys/boot/powerpc/ps3/Makefile Sun Apr 4 23:45:13 2010 (r206172) +++ projects/ppc64/sys/boot/powerpc/ps3/Makefile Mon Apr 5 01:51:11 2010 (r206173) @@ -9,18 +9,18 @@ BINDIR?= /boot INSTALLFLAGS= -b # Architecture-specific loader code -SRCS= start.S conf.c metadata.c vers.c main.c lv1call.S -SRCS+= ps3cons.c font.h ps3mmu.c +SRCS= start.S conf.c metadata.c vers.c main.c devicename.c +SRCS+= lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c SRCS+= ucmpdi2.c -LOADER_DISK_SUPPORT?= no -LOADER_UFS_SUPPORT?= no -LOADER_CD9660_SUPPORT?= no +LOADER_DISK_SUPPORT?= yes +LOADER_UFS_SUPPORT?= yes +LOADER_CD9660_SUPPORT?= yes LOADER_EXT2FS_SUPPORT?= no -LOADER_NET_SUPPORT?= no -LOADER_NFS_SUPPORT?= no +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes LOADER_TFTP_SUPPORT?= no -LOADER_GZIP_SUPPORT?= no +LOADER_GZIP_SUPPORT?= yes LOADER_BZIP2_SUPPORT?= no .if ${LOADER_DISK_SUPPORT} == "yes" Modified: projects/ppc64/sys/boot/powerpc/ps3/conf.c ============================================================================== --- projects/ppc64/sys/boot/powerpc/ps3/conf.c Sun Apr 4 23:45:13 2010 (r206172) +++ projects/ppc64/sys/boot/powerpc/ps3/conf.c Mon Apr 5 01:51:11 2010 (r206173) @@ -46,7 +46,9 @@ __FBSDID("$FreeBSD: projects/ppc64/sys/b /* Exported for libstand */ struct devsw *devsw[] = { #if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT) - &ofwdisk, +#ifdef NOTYET + &ps3disk, +#endif #endif #if defined(LOADER_NET_SUPPORT) &netdev, @@ -79,9 +81,11 @@ struct fs_ops *file_system[] = { NULL }; +extern struct netif_driver ps3net; + struct netif_driver *netif_drivers[] = { #if defined(LOADER_NET_SUPPORT) - &ofwnet, + &ps3net, #endif NULL, }; Added: projects/ppc64/sys/boot/powerpc/ps3/devicename.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/ppc64/sys/boot/powerpc/ps3/devicename.c Mon Apr 5 01:51:11 2010 (r206173) @@ -0,0 +1,249 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: projects/ppc64/sys/boot/ps3/lib/devicename.c 191829 2009-05-05 16:29:08Z raj $"); + +#include <sys/disklabel.h> + +#include <stand.h> +#include <string.h> + +#include "bootstrap.h" + +static int ps3_parsedev(struct devdesc **dev, const char *devspec, + const char **path); + +/* + * Point (dev) at an allocated device specifier for the device matching the + * path in (devspec). If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +ps3_getdev(void **vdev, const char *devspec, const char **path) +{ + struct devdesc **dev = (struct devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no + * device, go with the current device. + */ + if ((devspec == NULL) || (devspec[0] == '/') || + (strchr(devspec, ':') == NULL)) { + + if (((rv = ps3_parsedev(dev, getenv("currdev"), NULL)) == 0) + && (path != NULL)) + *path = devspec; + return(rv); + } + + /* + * Try to parse the device name off the beginning of the devspec. + */ + return (ps3_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * disk<unit>[<partition>]: + * + */ +static int +ps3_parsedev(struct devdesc **dev, const char *devspec, const char **path) +{ + struct devdesc *idev; + struct devsw *dv; + char *cp; + const char *np; + int i, unit, pnum, ptype, err; + + /* minimum length check */ + if (strlen(devspec) < 2) + return(EINVAL); + + /* look for a device that matches */ + for (i = 0, dv = NULL; devsw[i] != NULL; i++) { + if (!strncmp(devspec, devsw[i]->dv_name, + strlen(devsw[i]->dv_name))) { + dv = devsw[i]; + break; + } + } + if (dv == NULL) + return(ENOENT); + idev = malloc(sizeof(struct devdesc)); + err = 0; + np = (devspec + strlen(dv->dv_name)); + + switch(dv->dv_type) { + case DEVT_NONE: + break; + +#ifdef NOTYET + case DEVT_DISK: + unit = -1; + pnum = -1; + ptype = -1; + if (*np && (*np != ':')) { + /* next comes the unit number */ + unit = strtol(np, &cp, 10); + if (cp == np) { + err = EUNIT; + goto fail; + } + if (*cp && (*cp != ':')) { + /* get partition */ + if (*cp == 'p' && *(cp + 1) && + *(cp + 1) != ':') { + pnum = strtol(cp + 1, &cp, 10); + ptype = PTYPE_GPT; + } else { + pnum = *cp - 'a'; + ptype = PTYPE_BSDLABEL; + if ((pnum < 0) || + (pnum >= MAXPARTITIONS)) { + err = EPART; + goto fail; + } + cp++; + } + } + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + idev->d_disk.pnum = pnum; + idev->d_disk.ptype = ptype; + idev->d_disk.data = NULL; + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; +#endif + + case DEVT_NET: + unit = 0; + + if (*np && (*np != ':')) { + /* get unit number if present */ + unit = strtol(np, &cp, 0); + if (cp == np) { + err = EUNIT; + goto fail; + } + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + idev->d_unit = unit; + + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + + default: + err = EINVAL; + goto fail; + } + idev->d_dev = dv; + idev->d_type = dv->dv_type; + if (dev == NULL) { + free(idev); + } else { + *dev = idev; + } + return (0); + +fail: + free(idev); + return (err); +} + + +char * +ps3_fmtdev(void *vdev) +{ + struct devdesc *dev = (struct devdesc *)vdev; + char *cp; + static char buf[128]; + + switch(dev->d_type) { + case DEVT_NONE: + strcpy(buf, "(no device)"); + break; + +#ifdef NOTYET + case DEVT_DISK: + cp = buf; + cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit); + if (dev->d_kind.disk.pnum >= 0) { + if (dev->d_kind.disk.ptype == PTYPE_BSDLABEL) + cp += sprintf(cp, "%c", + dev->d_kind.disk.pnum + 'a'); + else if (dev->d_kind.disk.ptype == PTYPE_GPT) + cp += sprintf(cp, "p%i", + dev->d_kind.disk.pnum); + } + + strcat(cp, ":"); + break; +#endif + + case DEVT_NET: + sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); + break; + } + return(buf); +} + +/* + * Set currdev to suit the value being supplied in (value). + */ +int +ps3_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct devdesc *ncurr; + int rv; + + if ((rv = ps3_parsedev(&ncurr, value, NULL)) != 0) + return (rv); + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (0); +} Modified: projects/ppc64/sys/boot/powerpc/ps3/lv1call.S ============================================================================== --- projects/ppc64/sys/boot/powerpc/ps3/lv1call.S Sun Apr 4 23:45:13 2010 (r206172) +++ projects/ppc64/sys/boot/powerpc/ps3/lv1call.S Mon Apr 5 01:51:11 2010 (r206173) @@ -9,6 +9,36 @@ addis r,r,high; \ addi r,r,low; +#define SIMPLE_HVCALL(x, c) \ +.global x; \ +x: \ + mflr %r0; \ + stw %r0,4(%r1); \ + clrldi %r3,%r3,32; \ + clrldi %r4,%r4,32; \ + clrldi %r5,%r5,32; \ + clrldi %r6,%r6,32; \ + clrldi %r7,%r7,32; \ + clrldi %r8,%r8,32; \ + clrldi %r9,%r9,32; \ + clrldi %r10,%r10,32; \ + li %r11,c; \ + hc; \ + extsw %r3,%r3; \ + lwz %r0,4(%r1); \ + mtlr %r0; \ + blr + +SIMPLE_HVCALL(lv1_open_device, 170) +SIMPLE_HVCALL(lv1_close_device, 171) +SIMPLE_HVCALL(lv1_gpu_open, 210) +SIMPLE_HVCALL(lv1_gpu_context_attribute, 225) +SIMPLE_HVCALL(lv1_panic, 255) +SIMPLE_HVCALL(lv1_net_start_tx_dma, 187) +SIMPLE_HVCALL(lv1_net_stop_tx_dma, 188) +SIMPLE_HVCALL(lv1_net_start_rx_dma, 189) +SIMPLE_HVCALL(lv1_net_stop_rx_dma, 190) + .global lv1_get_physmem lv1_get_physmem: mflr %r0 @@ -98,45 +128,6 @@ lv1_insert_pte: mtlr %r0 blr -.global lv1_panic -lv1_panic: - mflr %r0 - stw %r0,4(%r1) - - li %r11,255 - hc - extsw %r3,%r3 - - lwz %r0,4(%r1) - mtlr %r0 - blr - -.global lv1_gpu_open -lv1_gpu_open: - mflr %r0 - stw %r0,4(%r1) - - li %r11,210 - hc - extsw %r3,%r3 - - lwz %r0,4(%r1) - mtlr %r0 - blr - -.global lv1_gpu_context_attribute -lv1_gpu_context_attribute: - mflr %r0 - stw %r0,4(%r1) - - li %r11,225 - hc - extsw %r3,%r3 - - lwz %r0,4(%r1) - mtlr %r0 - blr - .global lv1_gpu_context_allocate lv1_gpu_context_allocate: mflr %r0 @@ -180,3 +171,59 @@ lv1_gpu_memory_allocate: mtlr %r0 blr +.global lv1_net_control +lv1_net_control: + mflr %r0 + stw %r0,4(%r1) + stw %r9,-4(%r1) + + li %r11,194 + hc + extsw %r3,%r3 + + lwz %r8,-4(%r1) + std %r4,0(%r8) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_setup_dma +lv1_setup_dma: + mflr %r0 + stw %r0,4(%r1) + stw %r3,-4(%r1) + stw %r4,-8(%r1) + stw %r5,-12(%r1) + + lwz %r3,-4(%r1) + lwz %r4,-8(%r1) + lis %r5,0x0800 /* 128 MB */ + li %r6,24 /* log2(IO_PAGESIZE) */ + li %r7,0 /* flags */ + li %r11,174 /* lv1_allocate_device_dma_region */ + hc + extsw %r3,%r3 + cmpdi %r3,0 + bne 1f + std %r4,-24(%r1) + + lwz %r3,-4(%r1) + lwz %r4,-8(%r1) + li %r5,0 + ld %r6,-24(%r1) + lis %r7,0x0800 /* 128 MB */ + lis %r8,0xf800 /* flags */ + sldi %r8,%r8,32 + li %r11,176 /* lv1_map_device_dma_region */ + hc + extsw %r3,%r3 + + lwz %r9,-12(%r1) + ld %r6,-24(%r1) + std %r6,0(%r9) + +1: lwz %r0,4(%r1) + mtlr %r0 + blr + Modified: projects/ppc64/sys/boot/powerpc/ps3/lv1call.h ============================================================================== --- projects/ppc64/sys/boot/powerpc/ps3/lv1call.h Sun Apr 4 23:45:13 2010 (r206172) +++ projects/ppc64/sys/boot/powerpc/ps3/lv1call.h Mon Apr 5 01:51:11 2010 (r206173) @@ -45,5 +45,26 @@ int lv1_gpu_memory_allocate(int size, in uint64_t *paddr); int lv1_gpu_context_allocate(uint64_t handle, int, uint64_t *context); +int lv1_open_device(int, int, int /* 0 */); +int lv1_close_device(int, int); +int lv1_setup_dma(int, int, uint64_t *dmabase); + +#define GELIC_GET_MAC_ADDRESS 0x0001 +#define GELIC_GET_LINK_STATUS 0x0002 +#define GELIC_LINK_UP 0x0001 +#define GELIC_FULL_DUPLEX 0x0002 +#define GELIC_AUTO_NEG 0x0004 +#define GELIC_SPEED_10 0x0010 +#define GELIC_SPEED_100 0x0020 +#define GELIC_SPEED_1000 0x0040 +#define GELIC_GET_VLAN_ID 0x0004 + +int lv1_net_init(int bus, int dev); +int lv1_net_control(int bus, int dev, int, int, int, int, uint64_t *); +int lv1_net_start_tx_dma(int bus, int dev, uint32_t addr, int); +int lv1_net_start_rx_dma(int bus, int dev, uint32_t addr, int); +int lv1_net_stop_tx_dma(int bus, int dev, int); +int lv1_net_stop_rx_dma(int bus, int dev, int); + #endif Modified: projects/ppc64/sys/boot/powerpc/ps3/main.c ============================================================================== --- projects/ppc64/sys/boot/powerpc/ps3/main.c Sun Apr 4 23:45:13 2010 (r206172) +++ projects/ppc64/sys/boot/powerpc/ps3/main.c Mon Apr 5 01:51:11 2010 (r206173) @@ -29,6 +29,9 @@ __FBSDID("$FreeBSD: head/sys/boot/powerp #include <stand.h> #include <sys/param.h> +#define _KERNEL +#include <machine/cpufunc.h> + #include "bootstrap.h" #include "lv1call.h" #include "ps3.h" @@ -41,6 +44,10 @@ extern char bootprog_rev[]; extern char bootprog_date[]; extern char bootprog_maker[]; +int ps3_getdev(void **vdev, const char *devspec, const char **path); + +static uint64_t basetb; + int main(void) { @@ -70,16 +77,28 @@ main(void) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); + /* + * Get timebase at boot. + */ + basetb = mftb(); + + archsw.arch_getdev = ps3_getdev; + printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); printf("Memory: %lldKB\n", maxmem / 1024); + env_setenv("currdev", EV_VOLATILE, "net", NULL, NULL); + env_setenv("loaddev", EV_VOLATILE, "net", NULL, NULL); + interact(); /* doesn't return */ return (0); } +const u_int ns_per_tick = 12; + void exit(int code) { @@ -88,12 +107,18 @@ exit(int code) void delay(int usecs) { + uint64_t tb,ttb; + tb = mftb(); + + ttb = tb + (usecs * 1000 + ns_per_tick - 1) / ns_per_tick; + while (tb < ttb) + tb = mftb(); } int getsecs() { - return (0); + return ((mftb() - basetb)*ns_per_tick/1000000000); } time_t @@ -102,4 +127,3 @@ time(time_t *tloc) return (0); } - Modified: projects/ppc64/sys/boot/powerpc/ps3/ps3cons.c ============================================================================== --- projects/ppc64/sys/boot/powerpc/ps3/ps3cons.c Sun Apr 4 23:45:13 2010 (r206172) +++ projects/ppc64/sys/boot/powerpc/ps3/ps3cons.c Mon Apr 5 01:51:11 2010 (r206173) @@ -115,41 +115,44 @@ ps3cons_putchar(int c) int i, j, k; u_char *p; - if (c == 0 || c == '\r') - return; - - /* Move down on newlines */ - if (c == '\n') { - y += FONT_SIZE; - x = 0; - return; - } + fg = FG_COLOR; + bg = BG_COLOR; - /* Wrap long lines */ - if (x + XMARGIN + FONT_SIZE > fb_width - XMARGIN) { + switch (c) { + case '\0': + case '\r': + break; + case '\n': y += FONT_SIZE; x = 0; - } + break; + case '\b': + x = max(0, x - 8); + break; + default: + /* Wrap long lines */ + if (x + XMARGIN + FONT_SIZE > fb_width - XMARGIN) { + y += FONT_SIZE; + x = 0; + } + addr = fb_vaddr + (y + YMARGIN)*fb_width + (x + XMARGIN); + p = FONT + c*FONT_SIZE; - fg = FG_COLOR; - bg = BG_COLOR; - - addr = fb_vaddr + (y + YMARGIN)*fb_width + (x + XMARGIN); - p = FONT + c*FONT_SIZE; + for (i = 0; i < FONT_SIZE; i++) { + for (j = 0, k = 7; j < 8; j++, k--) { + if ((p[i] & (1 << k)) == 0) + *(addr + j) = bg; + else + *(addr + j) = fg; + } - for (i = 0; i < FONT_SIZE; i++) { - for (j = 0, k = 7; j < 8; j++, k--) { - if ((p[i] & (1 << k)) == 0) - *(addr + j) = bg; - else - *(addr + j) = fg; + addr += fb_width; } - addr += fb_width; + x += 8; + break; } - - x += 8; } static int Added: projects/ppc64/sys/boot/powerpc/ps3/ps3net.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/ppc64/sys/boot/powerpc/ps3/ps3net.c Mon Apr 5 01:51:11 2010 (r206173) @@ -0,0 +1,271 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: head/sys/boot/powerpc/ofw/start.c 174722 2007-12-17 22:18:07Z marcel $"); + +#include <sys/types.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> + +#define _KERNEL +#include <machine/cpufunc.h> + +#include <stand.h> +#include <net.h> +#include <netif.h> +#include "bootstrap.h" +#include "lv1call.h" +#include "ps3.h" + +#define GELIC_DESCR_OWNED 0xa0000000 +#define GELIC_CMDSTAT_NOIPSEC 0x00080000 +#define GELIC_CMDSTAT_LAST 0x00040000 +#define GELIC_RXERRORS 0x7def8000 + +#define GELIC_POLL_PERIOD 100 /* microseconds */ + +static int ps3net_probe(struct netif *, void *); +static int ps3net_match(struct netif *, void *); +static void ps3net_init(struct iodesc *, void *); +static int ps3net_get(struct iodesc *, void *, size_t, time_t); +static int ps3net_put(struct iodesc *, void *, size_t); +static void ps3net_end(struct netif *); + +struct netif_stats ps3net_stats[1]; +struct netif_dif ps3net_ifs[] = {{0, 1, ps3net_stats, 0}}; + +/* XXX: Get from firmware, not hardcoding */ +static int busid = 1; +static int devid = 0; +static int vlan; +static uint64_t dma_base; + +struct gelic_dmadesc { + uint32_t paddr; + uint32_t len; + uint32_t next; + uint32_t cmd_stat; + uint32_t result_size; + uint32_t valid_size; + uint32_t data_stat; + uint32_t rxerror; +}; + +struct netif_driver ps3net = { + "net", + ps3net_match, + ps3net_probe, + ps3net_init, + ps3net_get, + ps3net_put, + ps3net_end, + ps3net_ifs, 1 +}; + +static int +ps3net_match(struct netif *nif, void *machdep_hint) +{ + return (1); +} + +static int +ps3net_probe(struct netif *nif, void *machdep_hint) +{ + return (0); +} + +static int +ps3net_put(struct iodesc *desc, void *pkt, size_t len) +{ + volatile static struct gelic_dmadesc txdesc __aligned(32); + volatile static uint64_t txbuf[200] __aligned(128); + size_t sendlen; + int err; + +#if defined(NETIF_DEBUG) + struct ether_header *eh; + + printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len); + eh = pkt; + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xffff); +#endif + + while (txdesc.cmd_stat & GELIC_DESCR_OWNED) + delay(10); + + /* + * We must add 4 extra bytes to this packet to store the destination + * VLAN. + */ + memcpy(txbuf, pkt, 12); + sendlen = 12; + + if (vlan >= 0) { + sendlen += 4; + ((uint8_t *)txbuf)[12] = 0x81; + ((uint8_t *)txbuf)[13] = 0x00; + ((uint8_t *)txbuf)[14] = vlan >> 8; + ((uint8_t *)txbuf)[15] = vlan & 0xff; + } + memcpy((void *)txbuf + sendlen, pkt + 12, len - 12); + sendlen += len - 12; + + bzero(&txdesc, sizeof(txdesc)); + txdesc.paddr = dma_base + (uint32_t)txbuf; + txdesc.len = sendlen; + txdesc.cmd_stat = GELIC_CMDSTAT_NOIPSEC | GELIC_CMDSTAT_LAST | + GELIC_DESCR_OWNED; + + powerpc_sync(); + + do { + err = lv1_net_start_tx_dma(busid, devid, + dma_base + (uint32_t)&txdesc, 0); + delay(1); + } while (err != 0); + + return (len); +} + +static int +ps3net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +{ + volatile static struct gelic_dmadesc rxdesc __aligned(32); + volatile static uint64_t rxbuf[200] __aligned(128); + int err = 0; + + if (len == 0) + goto restartdma; + + timeout *= 1000000; /* convert to microseconds */ + while (rxdesc.cmd_stat & GELIC_DESCR_OWNED) { + if (timeout < GELIC_POLL_PERIOD) + return (ETIMEDOUT); + delay(GELIC_POLL_PERIOD); + timeout -= GELIC_POLL_PERIOD; + } + + delay(200); + if (rxdesc.rxerror & GELIC_RXERRORS) { + err = -1; + goto restartdma; + } + + /* + * Copy the packet to the receive buffer, leaving out the + * 2 byte VLAN header. + */ + len = min(len, rxdesc.valid_size - 2); + memcpy(pkt, (u_char *)rxbuf + 2, len); + err = len; + +#if defined(NETIF_DEBUG) +{ + struct ether_header *eh; + + printf("net_get: desc %p, pkt %p, len %d\n", desc, pkt, len); + eh = pkt; + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xffff); +} +#endif + +restartdma: + bzero(&rxdesc, sizeof(rxdesc)); + rxdesc.paddr = dma_base + (uint32_t)rxbuf; + rxdesc.len = sizeof(rxbuf); + rxdesc.cmd_stat = GELIC_DESCR_OWNED; + + powerpc_sync(); + + lv1_net_start_rx_dma(busid, devid, dma_base + (uint32_t)&rxdesc, 0); + + return (err); +} + +static void +ps3net_init(struct iodesc *desc, void *machdep_hint) +{ + uint64_t mac, val; + int i,err; + + err = lv1_open_device(busid, devid, 0); + + lv1_net_stop_tx_dma(busid, devid, 0); + lv1_net_stop_rx_dma(busid, devid, 0); + + /* + * Wait for link to come up + */ + + for (i = 0; i < 1000; i++) { + lv1_net_control(busid, devid, GELIC_GET_LINK_STATUS, 2, 0, + 0, &val); + if (val & GELIC_LINK_UP) + break; + delay(500); + } + + /* + * Set up DMA IOMMU entries + */ + + err = lv1_setup_dma(busid, devid, &dma_base); + + /* + * Get MAC address and VLAN IDs + */ + + lv1_net_control(busid, devid, GELIC_GET_MAC_ADDRESS, 0, 0, 0, &mac); + bcopy(&((uint8_t *)&mac)[2], desc->myea, sizeof(desc->myea)); + + vlan = -1; + err = lv1_net_control(busid, devid, GELIC_GET_VLAN_ID, 2, 0, + 0, &val); + if (err == 0) + vlan = val; + + /* + * Start RX DMA engine + */ + + ps3net_get(NULL, NULL, 0, 0); +} + +static void +ps3net_end(struct netif *nif) +{ + lv1_close_device(busid, devid); +} +
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004050151.o351pBf9086437>