Skip site navigation (1)Skip section navigation (2)
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>