Subject: Re: netboot via native bootloader
To: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
From: Erik Berls <cyber@ono-sendai.com>
List: port-cobalt
Date: 10/27/2007 11:47:02
Izumi,
Excellent work!
I'd like to get this submitted as a pullup request to the netbsd-4
branch, but I'm 3000 miles from home.  I'll submit the request when I
get back in a week if no-one beats me to it.  [;-)

They probably won't accept it for 4.0, but it should be in 4.1.

-=erik.


On 10/27/07, Izumi Tsutsui <tsutsui@ceres.dti.ne.jp> wrote:
> I wrote:
>
> > Today I've been trying to add netboot support to the cobalt
> > native bootloader, using a standalone tulip (2114x Ethernet)
> > driver for sandpoint which has been committed by Tohru Nishimura:
>  :
> > Current my working sources are too ugly so I'll post
> > a patch after some more cleanup in a few days.
>
> A patch to be committed is attached.
>
> I've also put a bootloader binary here:
> http://www.ceres.dti.ne.jp/~tsutsui/netbsd/boot-cobalt-20071028.gz
>
> To test netboot, refer this FAQ entry
> http://www.netbsd.org/ports/cobalt/faq.html#netboot
> and specify bootloader's name (boot.gz or so) instead of kernel.
>
> Note if bootloader is loaded from wd disk it can't load a kernel
> from tlp0, so some more initialization might be required.
> ---
> Izumi Tsutsui
>
>
> Index: stand/boot/Makefile
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/Makefile,v
> retrieving revision 1.11
> diff -u -r1.11 Makefile
> --- stand/boot/Makefile 12 Aug 2006 11:38:11 -0000      1.11
> +++ stand/boot/Makefile 27 Oct 2007 15:50:03 -0000
> @@ -8,8 +8,10 @@
>  S=     ${.CURDIR}/../../../..
>  MIPS=  ${S}/arch/mips
>  COBALT=        ${S}/arch/cobalt
> +LIBSADIR=      ${S}/lib/libsa
>
>  # .PATH:       ${.CURDIR}/../common
> +.PATH:         ${LIBSADIR}
>
>  BINMODE?= 444
>
> @@ -55,6 +57,9 @@
>  CPPFLAGS+=     -I${.OBJDIR} -I${S} -I${S}/lib/libsa
>  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 +73,10 @@
>  # 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 if_tlp.c tlp.c
> +
> +# ${S}/lib/libsa
> +SRCS+=         dev_net.c
>
>  SRCS+=         vers.c
>  CLEANFILES+=   vers.c
> Index: 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
> --- stand/boot/boot.c   17 Oct 2007 19:54:09 -0000      1.9
> +++ stand/boot/boot.c   27 Oct 2007 15:50:03 -0000
> @@ -75,6 +75,7 @@
>
>  #include <lib/libsa/stand.h>
>  #include <lib/libsa/loadfile.h>
> +#include <lib/libsa/dev_net.h>
>  #include <lib/libkern/libkern.h>
>
>  #include <sys/param.h>
> @@ -171,10 +172,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);
> @@ -200,12 +218,14 @@
>         char *ptr, *spec;
>         char c, namebuf[PATH_MAX];
>         static char bootdev[] = "wd0a";
> +       static const 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 +259,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 : "<NULL>",
>             bootstr_kname ? bootstr_kname : "<NULL>"));
> @@ -365,9 +390,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: 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
> --- stand/boot/boot.h   17 Oct 2007 19:54:09 -0000      1.5
> +++ stand/boot/boot.h   27 Oct 2007 15:50:03 -0000
> @@ -71,8 +71,27 @@
>  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
> + */
> +void pdcache_wb(uint32_t, u_int);
> +void pdcache_inv(uint32_t, u_int);
> +void pdcache_wbinv(uint32_t, u_int);
> Index: 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
> --- stand/boot/clock.c  25 Jun 2003 17:24:22 -0000      1.1
> +++ stand/boot/clock.c  27 Oct 2007 15:50:03 -0000
> @@ -39,10 +39,20 @@
>  #include <sys/types.h>
>  #include <lib/libsa/stand.h>
>
> +#include <netinet/in.h>
> +#include <netinet/in_systm.h>
> +#include <lib/libsa/net.h>
> +
> +#include <dev/ic/mc146818reg.h>
> +
>  #include "boot.h"
>
>  #define DELAY_CALIBRATE        1000
>
> +#define MCCLOCK_BASE   0xa0000070
> +#define MCCLOCK_REG    0
> +#define MCCLOCK_DATA   1
> +
>  void
>  delay(int ms)
>  {
> @@ -51,5 +61,20 @@
>          */
>         volatile register int N = ms * DELAY_CALIBRATE;
>         for (; --N;)
> -               ;
> +               __insn_barrier();
> +}
> +
> +time_t
> +getsecs(void)
> +{
> +       u_int sec;
> +
> +       *(volatile uint8_t *)(MCCLOCK_BASE + MCCLOCK_REG) = MC_SEC;
> +       sec  = *(volatile uint8_t *)(MCCLOCK_BASE + MCCLOCK_DATA);
> +       *(volatile uint8_t *)(MCCLOCK_BASE + MCCLOCK_REG) = MC_MIN;
> +       sec += *(volatile uint8_t *)(MCCLOCK_BASE + MCCLOCK_DATA) * 60;
> +       *(volatile uint8_t *)(MCCLOCK_BASE + MCCLOCK_REG) = MC_HOUR;
> +       sec += *(volatile uint8_t *)(MCCLOCK_BASE + MCCLOCK_DATA) * 60 * 60;
> +
> +       return (time_t)sec;
>  }
> Index: 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
> --- stand/boot/conf.c   11 Dec 2005 12:17:06 -0000      1.4
> +++ stand/boot/conf.c   27 Oct 2007 15:50:03 -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,
> +       &ether_tlp_driver,
>  };
>
>  int n_netif_drivers = sizeof(netif_drivers) / sizeof(netif_drivers[0]);
> -#endif
> Index: 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
> --- stand/boot/devopen.c        17 Oct 2007 19:54:09 -0000      1.3
> +++ stand/boot/devopen.c        27 Oct 2007 15:50:03 -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: 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
> --- stand/boot/start.S  17 Oct 2007 19:54:09 -0000      1.5
> +++ stand/boot/start.S  27 Oct 2007 15:50:03 -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: stand/boot/version
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/version,v
> retrieving revision 1.5
> diff -u -r1.5 version
> --- stand/boot/version  17 Oct 2007 19:54:09 -0000      1.5
> +++ stand/boot/version  27 Oct 2007 15:50:03 -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-28 00:31:10.000000000 +0900
> +++ stand/boot/cache.c  2007-10-28 00:49:18.000000000 +0900
> @@ -0,0 +1,92 @@
> +/*     $NetBSD$        */
> +
> +/*
> + * 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 <lib/libsa/stand.h>
> +#include <lib/libkern/libkern.h>
> +
> +#include <mips/cpuregs.h>
> +#include <mips/cache_r4k.h>
> +
> +#include "boot.h"
> +
> +#define        CACHELINESIZE   16
> +#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;
> +
> +       va  = trunc_line(va);
> +       eva = round_line(va + size);
> +
> +       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;
> +
> +       va  = trunc_line(va);
> +       eva = round_line(va + size);
> +
> +       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;
> +
> +       va  = trunc_line(va);
> +       eva = round_line(va + size);
> +
> +       while (va < eva) {
> +               cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
> +               va += CACHELINESIZE;
> +       }
> +}
> --- /dev/null   2007-10-28 00:31:10.000000000 +0900
> +++ stand/boot/if_tlp.c 2007-10-27 15:25:18.000000000 +0900
> @@ -0,0 +1,153 @@
> +/*     $NetBSD$        */
> +
> +/*-
> + * Copyright (c) 2004 The NetBSD Foundation, Inc.
> + * All rights reserved.
> + *
> + * This code is derived from software contributed to The NetBSD Foundation
> + * by UCHIYAMA Yashusi.
> + *
> + * 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 <sys/param.h>
> +#include <sys/socket.h>
> +
> +#include <lib/libsa/stand.h>
> +#include <lib/libkern/libkern.h>
> +
> +#include <sys/socket.h>
> +#include <net/if.h>
> +#include <netinet/in.h>
> +#include <netinet/in_systm.h>
> +
> +#include <lib/libsa/net.h>
> +#include <lib/libsa/netif.h>
> +#include <lib/libsa/dev_net.h>
> +
> +#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];
> +       struct local *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];
> +       struct local *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-28 00:31:10.000000000 +0900
> +++ stand/boot/tlp.c    2007-10-27 23:04:34.000000000 +0900
> @@ -0,0 +1,463 @@
> +/*     $NetBSD$        */
> +
> +/*-
> + * 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 <sys/param.h>
> +#include <sys/socket.h>
> +
> +#include <netinet/in.h>
> +#include <netinet/in_systm.h>
> +
> +#include <lib/libsa/stand.h>
> +#include <lib/libsa/net.h>
> +
> +#include <mips/cpuregs.h>
> +
> +#include "boot.h"
> +
> +/*
> + * - little endian access for CSR register.
> + * - assume KSEG0 for vtophys() translation.
> + * - PIPT writeback cache aware.
> + */
> +#define CSR_WRITE(l, r, v)                                             \
> +do {                                                                   \
> +       *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1((l)->csr + (r)) = (v); \
> +} while (0)
> +#define CSR_READ(l, r)                                                 \
> +       *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1((l)->csr + (r))
> +#define VTOPHYS(va)            MIPS_KSEG0_TO_PHYS(va)
> +#define wb(adr, siz)           pdcache_wb((uint32_t)(adr), (uint32_t)(siz))
> +#define wbinv(adr, siz)                pdcache_wbinv((uint32_t)(adr), (uint32_t)(siz))
> +#define inv(adr, siz)          pdcache_inv((uint32_t)(adr), (uint32_t)(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_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 */
> +
> +struct desc {
> +       volatile uint32_t xd0, xd1, xd2, xd3;
> +};
> +
> +
> +#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, rx;
> +       u_int sromsft;
> +       u_int phy, bmsr, anlpar;
> +};
> +
> +#define COBALT_TLP0_BASE       0x10100000
> +#define EEP_MAC_OFFSET         0
> +
> +static void size_srom(struct local *);
> +static 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 tag, val;
> +       struct local *l;
> +       struct desc *TxD, *RxD;
> +       uint8_t *en;
> +       int i;
> +
> +       l = ALLOC(struct local, sizeof(struct desc));
> +       memset(l, 0, sizeof(struct local));
> +
> +#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 = pcicfgread(tag, 0x10);
> +       l->csr &= 0xfffffffc;
> +       DPRINTF(("%s: CSR = 0x%x\n", __func__, l->csr));
> +#else
> +
> +       l->csr = 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, EEP_MAC_OFFSET / 2 + 0);
> +       en[0] = val;
> +       en[1] = val >> 8;
> +       val = read_srom(l, EEP_MAC_OFFSET / 2 + 1);
> +       en[2] = val;
> +       en[3] = val >> 8;
> +       val = read_srom(l, EEP_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].xd0 = htole32(R0_OWN);
> +               RxD[i].xd1 = htole32(FRAMESIZE);
> +               RxD[i].xd2 = htole32(VTOPHYS(l->rxstore[i]));
> +               RxD[i].xd3 = htole32(VTOPHYS(&RxD[NEXT_RXBUF(i)]));
> +       }
> +       RxD[NRXBUF - 1].xd1 |= htole32(R1_RER);
> +       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);
> +       CSR_WRITE(l, TLP_TPD, TPD_POLL);
> +       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
> +       wbinv(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;
> +               DELAY(10);
> +               inv(TxD, sizeof(struct desc));
> +       } 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, rxstat, len;
> +       uint8_t *ptr;
> +
> +       bound = 1000 * timo;
> +#if 0
> +printf("recving with %u sec. timeout\n", timo);
> +#endif
> +
> +  again:
> +       RxD = &l->RxD[l->rx];
> +       do {
> +               inv(RxD, sizeof(struct desc));
> +               rxstat = le32toh(RxD->xd0);
> +               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, len);
> +       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 int
> +read_srom(struct local *l, int off)
> +{
> +       u_int idx, val, x1, x0, cnt, bit, ret;
> +
> +       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, ctl, sts, bound;
> +
> +       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)
> +{
> +       u_int anar, 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
>


-- 
"Too bad $VOLUNTEERS don't get their act together and provide
$SOLUTION_TO_VERY_DIFFICULT_PROBLEM in a decent fashion"  -- from IRC,
#netbsd, EFNet