Index: sys/lib/libsa/dev_net.h =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/dev_net.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -I $NetBSD: -r1.4 -r1.5 --- sys/lib/libsa/dev_net.h 26 Mar 1999 15:41:38 -0000 1.4 +++ sys/lib/libsa/dev_net.h 27 Oct 2007 12:21:17 -0000 1.5 @@ -4,3 +4,7 @@ int net_close __P((struct open_file *)); int net_ioctl __P((struct open_file *, u_long, void *)); int net_strategy __P((void *, int , daddr_t , size_t, void *, size_t *)); + +#ifdef SUPPORT_BOOTP +extern int try_bootp; +#endif Index: sys/arch/cobalt/stand/boot/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/Makefile,v retrieving revision 1.11 diff -u -r1.11 Makefile --- sys/arch/cobalt/stand/boot/Makefile 12 Aug 2006 11:38:11 -0000 1.11 +++ sys/arch/cobalt/stand/boot/Makefile 30 Oct 2007 14:04:50 -0000 @@ -8,6 +8,7 @@ S= ${.CURDIR}/../../../.. MIPS= ${S}/arch/mips COBALT= ${S}/arch/cobalt +LIBSADIR= ${S}/lib/libsa # .PATH: ${.CURDIR}/../common @@ -52,9 +53,12 @@ # -I${.CURDIR}/../.. done by Makefile.inc CPPFLAGS+= -nostdinc -D_STANDALONE -DNO_ABICALLS -D_NO_PROM_DEFINES # CPPFLAGS+= -D_DEBUG -CPPFLAGS+= -I${.OBJDIR} -I${S} -I${S}/lib/libsa +CPPFLAGS+= -I${.OBJDIR} -I${S} -I${LIBSADIR} CPPFLAGS+= -DCONS_SERIAL -DCOMBASE=${COMBASE} -DCOMPORT=${COMPORT} CPPFLAGS+= -DCOMSPEED=${COMSPEED} -DCOMPROBE=${COMPROBE} +CPPFLAGS+= -DSUPPORT_DHCP -DSUPPORT_BOOTP +#CPPFLAGS+= -DBOOTP_DEBUG -DNETIF_DEBUG -DETHER_DEBUG -DNFS_DEBUG +#CPPFLAGS+= -DRPC_DEBUG -DRARP_DEBUG -DNET_DEBUG -DDEBUG -DPARANOID # compiler flags for smallest code size CFLAGS= -Os -mmemcpy -ffreestanding -mno-abicalls -msoft-float -G 128 @@ -68,6 +72,12 @@ # common sources SRCS+= start.S boot.c devopen.c conf.c clock.c bootinfo.c SRCS+= prf.c com.c cons.c ns16550.c pciide.c tgets.c wdc.c wd.c +SRCS+= cache.c nif_tlp.c tlp.c + +# XXX dev_net.c should really be in libsa, but it doesn't +# declare ip_convertaddr correctly. +.PATH: ${LIBSADIR} +SRCS+= dev_net.c SRCS+= vers.c CLEANFILES+= vers.c Index: sys/arch/cobalt/stand/boot/boot.c =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/boot.c,v retrieving revision 1.9 diff -u -r1.9 boot.c --- sys/arch/cobalt/stand/boot/boot.c 17 Oct 2007 19:54:09 -0000 1.9 +++ sys/arch/cobalt/stand/boot/boot.c 30 Oct 2007 14:04:50 -0000 @@ -75,6 +75,7 @@ #include #include +#include #include #include @@ -108,22 +109,23 @@ static char *bootstring; -static int patch_bootstring (char *bootspec); +static int patch_bootstring(char *bootspec); static int get_bsdbootname(char **, char **, int *); static int parse_bootname(char *, int, char **, char **); -static int prominit (unsigned int memsize); -static int print_banner (unsigned int memsize); +static void prominit(unsigned int memsize); +static void print_banner(unsigned int memsize); -int cpu_reboot(void); +void cpu_reboot(void); int main(unsigned int memsize); /* * Perform CPU reboot. */ -int +void cpu_reboot(void) { + printf("rebooting...\n\n"); *(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; @@ -141,7 +143,7 @@ { char *sp = bootstring; uint8_t unit, part; - int dev, error; + int dev; char *file; DPRINTF(("patch_bootstring: %s\n", bootspec)); @@ -150,7 +152,7 @@ if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0) unit = part = 0; - DPRINTF(("patch_bootstring: %d, %d\n", unit, part)); + DPRINTF(("patch_bootstring: unit = %d, part = %d\n", unit, part)); /* take out the 'root=xxx' parameter */ if ((sp = strstr(bootstring, "root=")) != NULL) { @@ -171,10 +173,27 @@ DPRINTF(("patch_bootstring: [%s]\n", bootstring)); #define DEVNAMESIZE (MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a")) - /* bsd notation -> linux notation (wd0a -> hda1) */ - if (strlen(bootstring) <= (511 - DEVNAMESIZE)) { + if (strcmp(devsw[dev].dv_name, "wd") == 0 && + strlen(bootstring) <= (511 - DEVNAMESIZE)) { int len; + /* omit "nfsroot=" arg on wd boot */ + if ((sp = strstr(bootstring, "nfsroot=")) != NULL) { + const char *end; + + end = strchr(sp, ' '); + + /* strip off leading spaces */ + for (--sp; (sp > bootstring) && (*sp == ' '); --sp) + ; + + if (end != NULL) + strcpy(++sp, end); + else + *++sp = '\0'; + } + + /* bsd notation -> linux notation (wd0a -> hda1) */ strcat(bootstring, " root=/dev/hd"); len = strlen(bootstring); @@ -193,19 +212,21 @@ static int get_bsdbootname(char **dev, char **kname, int *howtop) { - int len, error; + int len; int bootunit, bootpart; char *bootstr_dev, *bootstr_kname; char *prompt_dev, *prompt_kname; char *ptr, *spec; char c, namebuf[PATH_MAX]; static char bootdev[] = "wd0a"; + static char nfsbootdev[] = "nfs"; bootstr_dev = prompt_dev = NULL; bootstr_kname = prompt_kname = NULL; /* first, get root device specified by the firmware */ spec = bootstring; + /* assume the last one is valid */ while ((spec = strstr(spec, "root=")) != NULL) { spec += 5; /* skip 'root=' */ @@ -239,6 +260,11 @@ } } + /* third, check if netboot */ + if (strstr(bootstring, "nfsroot=") != NULL) { + bootstr_dev = nfsbootdev; + } + DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n", bootstr_dev ? bootstr_dev : "", bootstr_kname ? bootstr_kname : "")); @@ -325,7 +351,7 @@ /* * Get the bootstring from PROM. */ -int +void prominit(unsigned int memsize) { @@ -336,7 +362,7 @@ /* * Print boot message. */ -int +void print_banner(unsigned int memsize) { @@ -365,9 +391,10 @@ struct btinfo_symtab bi_syms; struct btinfo_bootpath bi_bpath; struct btinfo_howto bi_howto; - int addr, speed, howto; + try_bootp = 1; + /* Initialize boot info early */ howto = 0x0; bi_flags.bi_flags = 0x0; Index: sys/arch/cobalt/stand/boot/boot.h =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/boot.h,v retrieving revision 1.5 diff -u -r1.5 boot.h --- sys/arch/cobalt/stand/boot/boot.h 17 Oct 2007 19:54:09 -0000 1.5 +++ sys/arch/cobalt/stand/boot/boot.h 30 Oct 2007 14:04:50 -0000 @@ -71,8 +71,29 @@ int wdclose(struct open_file *); /* + * tlp + */ +void *tlp_init(void *); +int tlp_send(void *, char *, u_int); +int tlp_recv(void *, char *, u_int, u_int); + +extern struct netif_driver ether_tlp_driver; + +/* * devopen */ int devparse(const char *, int *, uint8_t *, uint8_t *, const char **); +/* + * tgetc + */ int tgets(char *); + +/* + * cache + */ +#define CACHELINESIZE 32 + +void pdcache_wb(uint32_t, u_int); +void pdcache_inv(uint32_t, u_int); +void pdcache_wbinv(uint32_t, u_int); Index: sys/arch/cobalt/stand/boot/clock.c =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/clock.c,v retrieving revision 1.1 diff -u -r1.1 clock.c --- sys/arch/cobalt/stand/boot/clock.c 25 Jun 2003 17:24:22 -0000 1.1 +++ sys/arch/cobalt/stand/boot/clock.c 30 Oct 2007 14:04:50 -0000 @@ -36,13 +36,27 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include +#include + +#include +#include +#include + +#include + +#include #include "boot.h" #define DELAY_CALIBRATE 1000 +#define MCCLOCK_BASE 0x10000070 +#define MCCLOCK_REG 0 +#define MCCLOCK_DATA 1 + void delay(int ms) { @@ -51,5 +65,24 @@ */ volatile register int N = ms * DELAY_CALIBRATE; for (; --N;) - ; + __insn_barrier(); +} + +time_t +getsecs(void) +{ + volatile uint8_t *mcclock_reg, *mcclock_data; + u_int sec; + + mcclock_reg = (void *)MIPS_PHYS_TO_KSEG1(MCCLOCK_BASE + MCCLOCK_REG); + mcclock_data = (void *)MIPS_PHYS_TO_KSEG1(MCCLOCK_BASE + MCCLOCK_DATA); + + *mcclock_reg = MC_SEC; + sec = bcdtobin(*mcclock_data); + *mcclock_reg = MC_MIN; + sec += bcdtobin(*mcclock_data) * 60; + *mcclock_reg = MC_HOUR; + sec += bcdtobin(*mcclock_data) * 60 * 60; + + return (time_t)sec; } Index: sys/arch/cobalt/stand/boot/conf.c =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/conf.c,v retrieving revision 1.4 diff -u -r1.4 conf.c --- sys/arch/cobalt/stand/boot/conf.c 11 Dec 2005 12:17:06 -0000 1.4 +++ sys/arch/cobalt/stand/boot/conf.c 30 Oct 2007 14:04:50 -0000 @@ -52,6 +52,7 @@ */ struct devsw devsw[] = { { "wd", wdstrategy, wdopen, wdclose, noioctl }, + { "nfs", net_strategy, net_open, net_close, net_ioctl } }; int ndevs = (sizeof(devsw)/sizeof(devsw[0])); @@ -61,19 +62,15 @@ */ struct fs_ops file_system[] = { FS_OPS(ufs), -#if 0 FS_OPS(nfs), -#endif }; int nfsys = sizeof(file_system) / sizeof(file_system[0]); -#if 0 extern struct netif_driver en_driver; struct netif_driver *netif_drivers[] = { - &en_driver, + ðer_tlp_driver, }; int n_netif_drivers = sizeof(netif_drivers) / sizeof(netif_drivers[0]); -#endif Index: sys/arch/cobalt/stand/boot/devopen.c =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/devopen.c,v retrieving revision 1.3 diff -u -r1.3 devopen.c --- sys/arch/cobalt/stand/boot/devopen.c 17 Oct 2007 19:54:09 -0000 1.3 +++ sys/arch/cobalt/stand/boot/devopen.c 30 Oct 2007 14:04:50 -0000 @@ -77,24 +77,31 @@ /* extract device name */ for (i = 0; isalpha(fname[i]) && (i < devlen); i++) devname[i] = fname[i]; - devname[i] = 0; + devname[i] = '\0'; - if (!isnum(fname[i])) - return EUNIT; + if (strcmp(devname, "nfs") == 0) { + /* no unit number or partition suffix on netboot */ + u = 0; + p = 0; + } else { + /* parse [disk][unit][part] (ex. wd0a) strings */ + if (!isnum(fname[i])) + return EUNIT; + + /* device number */ + for (u = 0; isnum(fname[i]) && (i < devlen); i++) + u = u * 10 + (fname[i] - '0'); + + if (!isalpha(fname[i])) + return EPART; + + /* partition number */ + if (i < devlen) + p = fname[i++] - 'a'; - /* device number */ - for (u = 0; isnum(fname[i]) && (i < devlen); i++) - u = u * 10 + (fname[i] - '0'); - - if (!isalpha(fname[i])) - return EPART; - - /* partition number */ - if (i < devlen) - p = fname[i++] - 'a'; - - if (i != devlen) - return ENXIO; + if (i != devlen) + return ENXIO; + } /* check device name */ for (dp = devsw, i = 0; i < ndevs; dp++, i++) { @@ -132,7 +139,7 @@ dp = &devsw[dev]; if ((void *)dp->dv_open == (void *)nodev) - return ENXIO; + return ENXIO; f->f_dev = dp; Index: sys/arch/cobalt/stand/boot/start.S =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/start.S,v retrieving revision 1.5 diff -u -r1.5 start.S --- sys/arch/cobalt/stand/boot/start.S 17 Oct 2007 19:54:09 -0000 1.5 +++ sys/arch/cobalt/stand/boot/start.S 30 Oct 2007 14:04:50 -0000 @@ -64,7 +64,7 @@ jal _C_LABEL(main) # main(unsigned int) move a1, s1 # restore argv -XLEAF(_xtt) +XLEAF(_rtt) jal _C_LABEL(cpu_reboot) # failed, reboot nop END(start) Index: sys/arch/cobalt/stand/boot/version =================================================================== RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/version,v retrieving revision 1.5 diff -u -r1.5 version --- sys/arch/cobalt/stand/boot/version 17 Oct 2007 19:54:09 -0000 1.5 +++ sys/arch/cobalt/stand/boot/version 30 Oct 2007 14:04:50 -0000 @@ -9,3 +9,4 @@ 0.3: Parse boot_flags and pass boothowto value via bootinfo 0.4: parse "root=/dev/hdXN" args passed from the firmware and set default boot device accordingly +0.5: Add support for netboot via tlp0 --- /dev/null 2007-10-31 21:27:07.000000000 +0900 +++ sys/arch/cobalt/stand/boot/cache.c 2007-10-31 01:38:54.000000000 +0900 @@ -0,0 +1,91 @@ +/* $NetBSD: cache.c,v 1.2 2007/10/30 16:38:54 tsutsui Exp $ */ + +/* + * Copyright 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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 +#include + +#include +#include + +#include "boot.h" + +#define round_line(x) (((x) + (CACHELINESIZE - 1)) & ~(CACHELINESIZE - 1)) +#define trunc_line(x) ((x) & ~(CACHELINESIZE - 1)) + +__asm(".set mips3"); + +void +pdcache_inv(uint32_t va, u_int size) +{ + uint32_t eva; + + eva = round_line(va + size); + va = trunc_line(va); + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += CACHELINESIZE; + } +} + +void +pdcache_wb(uint32_t va, u_int size) +{ + uint32_t eva; + + eva = round_line(va + size); + va = trunc_line(va); + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += CACHELINESIZE; + } +} + +void +pdcache_wbinv(uint32_t va, u_int size) +{ + uint32_t eva; + + eva = round_line(va + size); + va = trunc_line(va); + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += CACHELINESIZE; + } +} --- /dev/null 2007-10-31 21:27:07.000000000 +0900 +++ sys/arch/cobalt/stand/boot/nif_tlp.c 2007-10-31 00:07:08.000000000 +0900 @@ -0,0 +1,153 @@ +/* $NetBSD: nif_tlp.c,v 1.1 2007/10/30 15:07:08 tsutsui Exp $ */ + +/*- + * Copyright (c) 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "boot.h" + +static int tlp_match(struct netif *, void *); +static int tlp_probe(struct netif *, void *); +static void tlp_attach(struct iodesc *, void *); +static int tlp_get(struct iodesc *, void *, size_t, time_t); +static int tlp_put(struct iodesc *, void *, size_t); +static void tlp_end(struct netif *); + +#define MIN_LEN 60 /* ETHER_MIN_LEN - ETHER_CRC_LEN */ + +static struct netif_stats tlp_stats[1]; + +static struct netif_dif tlp_ifs[] = { + { 0, 1, &tlp_stats[0], NULL, 0 }, +}; + +struct netif_driver ether_tlp_driver = { + "tlp", + tlp_match, + tlp_probe, + tlp_attach, + tlp_get, + tlp_put, + tlp_end, + tlp_ifs, + 1, +}; + +#ifdef DEBUG +int debug = 1; /* referred in various libsa net sources */ +#endif + +int +tlp_match(struct netif *netif, void *hint) +{ + + /* always match for onboard tlp */ + return 1; +} + +int +tlp_probe(struct netif *netif, void *hint) +{ + + /* XXX */ + return 0; +} + +void +tlp_attach(struct iodesc *desc, void *hint) +{ + struct netif *nif = desc->io_netif; + struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit]; + + dif->dif_private = tlp_init(&desc->myea); +} + +int +tlp_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout) +{ + int len; + struct netif *nif = desc->io_netif; + struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit]; + void *l = dif->dif_private; + + len = tlp_recv(l, pkt, maxlen, timeout); + if (len == -1) { + printf("tlp: receive timeout\n"); + /* XXX */ + } + + if (len < MIN_LEN) + len = -1; + + return len; +} + +int +tlp_put(struct iodesc *desc, void *pkt, size_t len) +{ + struct netif *nif = desc->io_netif; + struct netif_dif *dif = &nif->nif_driver->netif_ifs[nif->nif_unit]; + void *l = dif->dif_private; + int rv; + size_t sendlen; + + sendlen = len; + if (sendlen < MIN_LEN) + sendlen = MIN_LEN; /* XXX */ + + rv = tlp_send(l, pkt, sendlen); + + return rv; +} + +void +tlp_end(struct netif *netif) +{ +} --- /dev/null 2007-10-31 21:27:07.000000000 +0900 +++ sys/arch/cobalt/stand/boot/tlp.c 2007-10-31 22:30:46.000000000 +0900 @@ -0,0 +1,472 @@ +/* $NetBSD: tlp.c,v 1.3 2007/10/31 13:30:46 tsutsui Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Tohru Nishimura. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#include + +#include +#include + +#include +#include + +#include + +#include "boot.h" + +/* + * - little endian access for CSR register. + * - assume KSEG0 on vtophys() translation. + * - PIPT writeback cache aware. + */ +#define CSR_WRITE(l, r, v) \ +do { \ + *(volatile uint32_t *)((l)->csr + (r)) = (v); \ +} while (0) +#define CSR_READ(l, r) (*(volatile uint32_t *)((l)->csr + (r))) +#define VTOPHYS(va) MIPS_KSEG0_TO_PHYS(va) +#define wb(adr, siz) pdcache_wb((uint32_t)(adr), (u_int)(siz)) +#define wbinv(adr, siz) pdcache_wbinv((uint32_t)(adr), (u_int)(siz)) +#define inv(adr, siz) pdcache_inv((uint32_t)(adr), (u_int)(siz)) +#define DELAY(n) delay(n) +#define ALLOC(T, A) (T *)((uint32_t)alloc(sizeof(T) + (A)) & ~((A) - 1)) + +#define T0_OWN (1U<<31) /* desc is ready to tx */ +#define T0_ES (1U<<15) /* Tx error summary */ +#define T1_LS (1U<<30) /* last segment */ +#define T1_FS (1U<<29) /* first segment */ +#define T1_SET (1U<<27) /* "setup packet" */ +#define T1_TER (1U<<25) /* end of ring mark */ +#define T1_TBS_MASK 0x7ff /* segment size 10:0 */ +#define R0_OWN (1U<<31) /* desc is empty */ +#define R0_FS (1U<<30) /* first desc of frame */ +#define R0_LS (1U<<8) /* last desc of frame */ +#define R0_ES (1U<<15) /* Rx error summary */ +#define R1_RCH (1U<<24) /* Second address chained */ +#define R1_RER (1U<<25) /* end of ring mark */ +#define R0_FL_MASK 0x3fff0000 /* frame length 29:16 */ +#define R1_RBS_MASK 0x7ff /* segment size 10:0 */ + +#define DESCSIZE 16 +struct desc { + volatile uint32_t xd0, xd1, xd2, xd3; +#if CACHELINESIZE > DESCSIZE + uint8_t pad[CACHELINESIZE - DESCSIZE]; +#endif +}; + +#define TLP_BMR 0x000 /* 0: bus mode */ +#define BMR_RST (1U<< 0) /* software reset */ +#define TLP_TPD 0x008 /* 1: instruct Tx to start */ +#define TPD_POLL (1U<< 0) /* transmit poll demand */ +#define TLP_RPD 0x010 /* 2: instruct Rx to start */ +#define RPD_POLL (1U<< 0) /* receive poll demand */ +#define TLP_RRBA 0x018 /* 3: Rx descriptor base */ +#define TLP_TRBA 0x020 /* 4: Tx descriptor base */ +#define TLP_STS 0x028 /* 5: status */ +#define STS_TS 0x00700000 /* Tx status */ +#define STS_RS 0x000e0000 /* Rx status */ +#define TLP_OMR 0x030 /* 6: operation mode */ +#define OMR_SDP (1U<<25) /* always ON */ +#define OMR_PS (1U<<18) /* port select */ +#define OMR_PM (1U<< 6) /* promicuous */ +#define OMR_TEN (1U<<13) /* instruct start/stop Tx */ +#define OMR_REN (1U<< 1) /* instruct start/stop Rx */ +#define OMR_FD (1U<< 9) /* FDX */ +#define TLP_IEN 0x38 /* 7: interrupt enable mask */ +#define TLP_APROM 0x048 /* 9: SEEPROM and MII management */ +#define SROM_RD (1U <<14) /* read operation */ +#define SROM_WR (1U <<13) /* write openration */ +#define SROM_SR (1U <<11) /* SEEPROM select */ +#define TLP_CSR12 0x60 /* SIA status */ + +#define TLP_CSR15 0x78 /* SIA general register */ +#define SIAGEN_MD0 (1U<<16) +#define SIAGEN_CWE (1U<<28) + +#define FRAMESIZE 1536 +#define BUFSIZE 2048 +#define NRXBUF 2 +#define NEXT_RXBUF(x) (((x) + 1) & (NRXBUF - 1)) + +struct local { + struct desc TxD; + struct desc RxD[NRXBUF]; + uint8_t txstore[BUFSIZE]; + uint8_t rxstore[NRXBUF][BUFSIZE]; + uint32_t csr, omr; + u_int rx; + u_int sromsft; + u_int phy; + uint32_t bmsr, anlpar; +}; + +#define COBALT_TLP0_BASE 0x10100000 +#define SROM_MAC_OFFSET 0 + +static void size_srom(struct local *); +static u_int read_srom(struct local *, int); +#if 0 +static u_int tlp_mii_read(struct local *, int, int); +static void tlp_mii_write(struct local *, int, int, int); +static void mii_initphy(struct local *); +#endif + +void * +tlp_init(void *cookie) +{ + uint32_t val; + struct local *l; + struct desc *TxD, *RxD; + uint8_t *en; + int i; + + l = ALLOC(struct local, CACHELINESIZE); + memset(l, 0, sizeof(struct local)); + + DPRINTF(("tlp: l = %p, TxD = %p, RxD[0] = %p, RxD[1] = %p\n", + l, &l->TxD, &l->RxD[0], &l->RxD[1])); + DPRINTF(("tlp: txstore = %p, rxstore[0] = %p, rxstore[1] = %p\n", + l->txstore, l->rxstore[0], l->rxstore[1])); + +#if 0 + /* XXX assume tlp0 at pci0 dev 7 function 0 */ + tag = (0 << 16) | ( 7 << 11) | (0 << 8); + /* memory map is not initialized by the firmware on cobalt */ + l->csr = MIPS_PHYS_TO_KSEG1(pcicfgread(tag, 0x10) & 0xfffffffc); + DPRINTF(("%s: CSR = 0x%x\n", __func__, l->csr)); +#else + l->csr = MIPS_PHYS_TO_KSEG1(COBALT_TLP0_BASE); +#endif + + val = CSR_READ(l, TLP_BMR); + CSR_WRITE(l, TLP_BMR, val | BMR_RST); + DELAY(1000); + CSR_WRITE(l, TLP_BMR, val); + DELAY(1000); + (void)CSR_READ(l, TLP_BMR); + + l->omr = OMR_PS | OMR_SDP; + CSR_WRITE(l, TLP_OMR, l->omr); + CSR_WRITE(l, TLP_STS, ~0); + CSR_WRITE(l, TLP_IEN, 0); + +#if 0 + mii_initphy(l); +#endif + size_srom(l); + + en = cookie; + /* MAC address is stored at offset 0 in SROM on cobalt */ + val = read_srom(l, SROM_MAC_OFFSET / 2 + 0); + en[0] = val; + en[1] = val >> 8; + val = read_srom(l, SROM_MAC_OFFSET / 2 + 1); + en[2] = val; + en[3] = val >> 8; + val = read_srom(l, SROM_MAC_OFFSET / 2 + 2); + en[4] = val; + en[5] = val >> 8; + + DPRINTF(("tlp: MAC address %x:%x:%x:%x:%x:%x\n", + en[0], en[1], en[2], en[3], en[4], en[5])); + + RxD = &l->RxD[0]; + for (i = 0; i < NRXBUF; i++) { + RxD[i].xd3 = htole32(VTOPHYS(&RxD[NEXT_RXBUF(i)])); + RxD[i].xd2 = htole32(VTOPHYS(l->rxstore[i])); + RxD[i].xd1 = htole32(R1_RCH|FRAMESIZE); + RxD[i].xd0 = htole32(R0_OWN); + } + CSR_WRITE(l, TLP_RRBA, VTOPHYS(RxD)); + + /* "setup packet" to have own station address */ + TxD = &l->TxD; + TxD->xd3 = htole32(VTOPHYS(TxD)); + TxD->xd2 = htole32(VTOPHYS(l->txstore)); + TxD->xd1 = htole32(T1_SET | T1_TER); + TxD->xd0 = htole32(0); + CSR_WRITE(l, TLP_TRBA, VTOPHYS(TxD)); + + memset(l->txstore, 0, FRAMESIZE); + + /* make sure the entire descriptors transfered to memory */ + wbinv(l, sizeof(struct local)); + + l->rx = 0; + l->omr |= OMR_FD | OMR_TEN | OMR_REN; + +#if 1 + /* reset PHY (cobalt quirk from if_tlp_pci.c) */ + CSR_WRITE(l, TLP_CSR15, SIAGEN_CWE | SIAGEN_MD0); + DELAY(10); + CSR_WRITE(l, TLP_CSR15, SIAGEN_CWE); + DELAY(10); +#endif + + /* start Tx/Rx */ + CSR_WRITE(l, TLP_OMR, l->omr); +#if 0 + CSR_WRITE(l, TLP_TPD, TPD_POLL); +#endif + CSR_WRITE(l, TLP_RPD, RPD_POLL); + + return l; +} + +int +tlp_send(void *dev, char *buf, u_int len) +{ + struct local *l = dev; + struct desc *TxD; + u_int loop; + +#if 1 + wb(buf, len); + TxD = &l->TxD; + TxD->xd3 = htole32(VTOPHYS(TxD)); + TxD->xd2 = htole32(VTOPHYS(buf)); + TxD->xd1 = htole32(T1_FS | T1_LS | T1_TER | (len & T1_TBS_MASK)); +#else + memcpy(l->txstore, buf, len); + wb(l->txstore, len); + TxD = &l->TxD; + TxD->xd3 = htole32(VTOPHYS(TxD)); + TxD->xd2 = htole32(VTOPHYS(l->txstore)); + TxD->xd1 = htole32(T1_FS | T1_LS | T1_TER | (len & T1_TBS_MASK)); +#endif + TxD->xd0 = htole32(T0_OWN); + wbinv(TxD, sizeof(struct desc)); + CSR_WRITE(l, TLP_TPD, TPD_POLL); + loop = 100; + do { + if ((le32toh(TxD->xd0) & T0_OWN) == 0) + goto done; + inv(TxD, sizeof(struct desc)); + DELAY(10); + } while (--loop > 0); + printf("xmit failed\n"); + return -1; + done: + return len; +} + +int +tlp_recv(void *dev, char *buf, u_int maxlen, u_int timo) +{ + struct local *l = dev; + struct desc *RxD; + u_int bound, len; + uint32_t rxstat; + uint8_t *ptr; + + bound = 1000 * timo; + + again: + RxD = &l->RxD[l->rx]; + do { + rxstat = le32toh(RxD->xd0); + inv(RxD, sizeof(struct desc)); + if ((rxstat & R0_OWN) == 0) + goto gotone; + DELAY(1000); /* 1 milli second */ + } while (--bound > 0); + errno = 0; + CSR_WRITE(l, TLP_RPD, RPD_POLL); + return -1; + gotone: + if (rxstat & R0_ES) { + RxD->xd0 = htole32(R0_OWN); + wbinv(RxD, sizeof(struct desc)); + l->rx = NEXT_RXBUF(l->rx); + CSR_WRITE(l, TLP_RPD, RPD_POLL); + goto again; + } + /* good frame */ + len = ((rxstat & R0_FL_MASK) >> 16) - 4; /* HASFCS */ + if (len > maxlen) + len = maxlen; + ptr = l->rxstore[l->rx]; + memcpy(buf, ptr, len); + inv(ptr, FRAMESIZE); + RxD->xd0 = htole32(R0_OWN); + wbinv(RxD, sizeof(struct desc)); + l->rx = NEXT_RXBUF(l->rx); + CSR_WRITE(l, TLP_OMR, l->omr); /* necessary? */ + return len; +} + +static void +size_srom(struct local *l) +{ + /* determine 8/6 bit addressing SEEPROM */ + l->sromsft = 8; + l->sromsft = (read_srom(l, 255) & 0x40000) ? 8 : 6; +} + +/* + * bare SEEPROM access with bitbang'ing + */ +#define R110 6 /* SEEPROM read op */ +#define CS (1U << 0) /* hold chip select */ +#define CLK (1U << 1) /* clk bit */ +#define D1 (1U << 2) /* bit existence */ +#define D0 0 /* bit absence */ +#define VV (1U << 3) /* taken 0/1 from SEEPROM */ + +static u_int +read_srom(struct local *l, int off) +{ + u_int idx, cnt, ret; + uint32_t val, x1, x0, bit; + + idx = off & 0xff; /* A7-A0 */ + idx |= R110 << l->sromsft; /* 110 for READ */ + + val = SROM_RD | SROM_SR; + CSR_WRITE(l, TLP_APROM, val); + val |= CS; /* hold CS */ + CSR_WRITE(l, TLP_APROM, val); + + x1 = val | D1; /* 1 */ + x0 = val | D0; /* 0 */ + /* instruct R110 op. at off in MSB first order */ + for (cnt = (1 << (l->sromsft + 2)); cnt > 0; cnt >>= 1) { + bit = (idx & cnt) ? x1 : x0; + CSR_WRITE(l, TLP_APROM, bit); + DELAY(10); + CSR_WRITE(l, TLP_APROM, bit | CLK); + DELAY(10); + } + /* read 16bit quantity in MSB first order */ + ret = 0; + for (cnt = 16; cnt > 0; cnt--) { + CSR_WRITE(l, TLP_APROM, val); + DELAY(10); + CSR_WRITE(l, TLP_APROM, val | CLK); + DELAY(10); + ret = (ret << 1) | !!(CSR_READ(l, TLP_APROM) & VV); + } + val &= ~CS; /* turn off chip select */ + CSR_WRITE(l, TLP_APROM, val); + + return ret; +} + +#if 0 + +static u_int +tlp_mii_read(struct local *l, int phy, int reg) +{ + /* later ... */ + return 0; +} + +static void +tlp_mii_write(struct local *l, int phy, int reg, int val) +{ + /* later ... */ +} + +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define BMCR_RESET 0x8000 /* reset */ +#define BMCR_AUTOEN 0x1000 /* autonegotiation enable */ +#define BMCR_ISO 0x0400 /* isolate */ +#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */ +#define MII_BMSR 0x01 /* Basic mode status register (ro) */ + +static void +mii_initphy(struct local *l) +{ + int phy, bound; + uint32_t ctl, sts; + + for (phy = 0; phy < 32; phy++) { + ctl = tlp_mii_read(l, phy, MII_BMCR); + sts = tlp_mii_read(l, phy, MII_BMSR); + if (ctl != 0xffff && sts != 0xffff) + goto found; + } + printf("MII: no PHY found\n"); + return; + found: + ctl = tlp_mii_read(l, phy, MII_BMCR); + tlp_mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET); + bound = 100; + do { + DELAY(10); + ctl = tlp_mii_read(l, phy, MII_BMCR); + if (ctl == 0xffff) { + printf("MII: PHY %d has died after reset\n", phy); + return; + } + } while (bound-- > 0 && (ctl & BMCR_RESET)); + if (bound == 0) { + printf("PHY %d reset failed\n", phy); + } + ctl &= ~BMCR_ISO; + tlp_mii_write(l, phy, MII_BMCR, ctl); + sts = tlp_mii_read(l, phy, MII_BMSR) | + tlp_mii_read(l, phy, MII_BMSR); /* read twice */ + l->phy = phy; + l->bmsr = sts; +} + +static void +mii_dealan(struct local *, u_int timo) +{ + uint32_t anar; + u_int bound; + + anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA; + tlp_mii_write(l, l->phy, MII_ANAR, anar); + tlp_mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); + l->anlpar = 0; + bound = getsecs() + timo; + do { + l->bmsr = tlp_mii_read(l, l->phy, MII_BMSR) | + tlp_mii_read(l, l->phy, MII_BMSR); /* read twice */ + if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) { + l->anlpar = tlp_mii_read(l, l->phy, MII_ANLPAR); + break; + } + DELAY(10 * 1000); + } while (getsecs() < bound); + return; +} +#endif