svn commit: r206173 - projects/ppc64/sys/boot/powerpc/ps3
Nathan Whitehorn
nwhitehorn at FreeBSD.org
Mon Apr 5 01:51:11 UTC 2010
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 at 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);
+}
+
More information about the svn-src-projects
mailing list