1*f41ff51fSandvar /* $NetBSD: enic.c,v 1.5 2023/01/22 21:36:12 andvar Exp $ */
25f7e80a8Spooka
35f7e80a8Spooka /*-
45f7e80a8Spooka * Copyright (c) 2010 The NetBSD Foundation, Inc.
55f7e80a8Spooka * All rights reserved.
65f7e80a8Spooka *
75f7e80a8Spooka * This code was written by Alessandro Forin and Neil Pittman
85f7e80a8Spooka * at Microsoft Research and contributed to The NetBSD Foundation
95f7e80a8Spooka * by Microsoft Corporation.
105f7e80a8Spooka *
115f7e80a8Spooka * Redistribution and use in source and binary forms, with or without
125f7e80a8Spooka * modification, are permitted provided that the following conditions
135f7e80a8Spooka * are met:
145f7e80a8Spooka * 1. Redistributions of source code must retain the above copyright
155f7e80a8Spooka * notice, this list of conditions and the following disclaimer.
165f7e80a8Spooka * 2. Redistributions in binary form must reproduce the above copyright
175f7e80a8Spooka * notice, this list of conditions and the following disclaimer in the
185f7e80a8Spooka * documentation and/or other materials provided with the distribution.
195f7e80a8Spooka *
205f7e80a8Spooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
215f7e80a8Spooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
225f7e80a8Spooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
235f7e80a8Spooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
245f7e80a8Spooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255f7e80a8Spooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265f7e80a8Spooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275f7e80a8Spooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285f7e80a8Spooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295f7e80a8Spooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305f7e80a8Spooka * POSSIBILITY OF SUCH DAMAGE.
315f7e80a8Spooka */
325f7e80a8Spooka
335f7e80a8Spooka /* --------------------------------------------------------------------------
345f7e80a8Spooka *
355f7e80a8Spooka * Module:
365f7e80a8Spooka *
375f7e80a8Spooka * enic.c
385f7e80a8Spooka *
395f7e80a8Spooka * Purpose:
405f7e80a8Spooka *
415f7e80a8Spooka * Driver for the Microsoft eNIC (eMIPS system) Ethernet
425f7e80a8Spooka *
435f7e80a8Spooka * Author:
445f7e80a8Spooka * A. Forin (sandrof)
455f7e80a8Spooka *
465f7e80a8Spooka * References:
475f7e80a8Spooka * Internal Microsoft specifications, file eNIC_Design.docx titled
485f7e80a8Spooka * "eNIC: a simple Ethernet" Revision 4/30/99
495f7e80a8Spooka *
505f7e80a8Spooka * Giano simulation module, file Peripherals\enic.cpp
515f7e80a8Spooka *
525f7e80a8Spooka * Various other drivers I wrote for said hardware
535f7e80a8Spooka * --------------------------------------------------------------------------
545f7e80a8Spooka */
555f7e80a8Spooka
565f7e80a8Spooka #include <sys/param.h>
575f7e80a8Spooka #include <sys/types.h>
585f7e80a8Spooka
595f7e80a8Spooka #include <net/if_ether.h>
605f7e80a8Spooka #include <netinet/in.h>
615f7e80a8Spooka #include <netinet/in_systm.h>
625f7e80a8Spooka #include <netinet/ip.h>
635f7e80a8Spooka
645f7e80a8Spooka #include <lib/libsa/stand.h>
655f7e80a8Spooka #include <lib/libsa/net.h>
665f7e80a8Spooka #include <lib/libsa/netif.h>
675f7e80a8Spooka #include <lib/libkern/libkern.h>
685f7e80a8Spooka
69ebb0f5eaSmartin
705f7e80a8Spooka #include <machine/emipsreg.h>
7160d0010eSchristos
7260d0010eSchristos #include "start.h"
7360d0010eSchristos #include "common.h"
7460d0010eSchristos
755f7e80a8Spooka #define the_enic ((struct _Enic *)ETHERNET_DEFAULT_ADDRESS)
765f7e80a8Spooka
775f7e80a8Spooka /* forward declarations */
785f7e80a8Spooka static int enicprobe (struct netif *, void *);
795f7e80a8Spooka static int enicmatch (struct netif *, void *);
805f7e80a8Spooka static void enicinit (struct iodesc *, void *);
815f7e80a8Spooka static int enicget (struct iodesc *, void *, size_t, saseconds_t);
825f7e80a8Spooka static int enicput (struct iodesc *, void *, size_t);
835f7e80a8Spooka static void enicend (struct netif *);
845f7e80a8Spooka
855f7e80a8Spooka #ifdef NET_DEBUG
865f7e80a8Spooka static void dump_packet(void *, int);
875f7e80a8Spooka #endif
885f7e80a8Spooka
895f7e80a8Spooka /* BUGBUG do we have this? */
905f7e80a8Spooka #define kvtophys(_v_) ((paddr_t)(_v_) & ~0x80000000)
915f7e80a8Spooka
925f7e80a8Spooka #define rpostone(_r_,_p_,_s_) \
935f7e80a8Spooka (_r_)->SizeAndFlags = ES_F_RECV | (_s_); \
945f7e80a8Spooka (_r_)->BufferAddressHi32 = 0; \
955f7e80a8Spooka (_r_)->BufferAddressLo32 = _p_;
965f7e80a8Spooka #define tpostone(_r_,_p_,_s_) \
975f7e80a8Spooka (_r_)->SizeAndFlags = ES_F_XMIT | (_s_); \
985f7e80a8Spooka (_r_)->BufferAddressHi32 = 0; \
995f7e80a8Spooka (_r_)->BufferAddressLo32 = _p_;
1005f7e80a8Spooka
1015f7e80a8Spooka
1025f7e80a8Spooka /* Send a packet
1035f7e80a8Spooka */
10460d0010eSchristos static int
enic_putpkt(struct _Enic * regs,void * buf,int bytes)10560d0010eSchristos enic_putpkt(struct _Enic *regs, void *buf, int bytes)
1065f7e80a8Spooka {
1075f7e80a8Spooka paddr_t phys = kvtophys(buf);
1085f7e80a8Spooka
1095f7e80a8Spooka tpostone(regs,phys,bytes);
1105f7e80a8Spooka
1115f7e80a8Spooka /* poll till done? */
1125f7e80a8Spooka //printf("\tenic: sent %d at %x\n",bytes,phys);
1135f7e80a8Spooka return bytes;
1145f7e80a8Spooka }
1155f7e80a8Spooka
1165f7e80a8Spooka /* Get a packet
1175f7e80a8Spooka */
11860d0010eSchristos static int
enic_getpkt(struct _Enic * regs,void * buf,int bytes,int timeo)11960d0010eSchristos enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo)
1205f7e80a8Spooka {
1215f7e80a8Spooka paddr_t phys;
1225f7e80a8Spooka unsigned int isr, saf, hi, lo, fl;
1235f7e80a8Spooka
1245f7e80a8Spooka phys = kvtophys(buf);
1255f7e80a8Spooka rpostone(regs,phys,bytes);
1265f7e80a8Spooka
1275f7e80a8Spooka //printf("\tenic: recv %d at %x\n",bytes,phys);
1285f7e80a8Spooka
1295f7e80a8Spooka /* poll till we get some */
1305f7e80a8Spooka timeo += getsecs();
1315f7e80a8Spooka
1325f7e80a8Spooka for (;;) {
1335f7e80a8Spooka
1345f7e80a8Spooka /* anything there? */
1355f7e80a8Spooka isr = regs->Control;
1365f7e80a8Spooka
1375f7e80a8Spooka if (isr & EC_ERROR) {
1385f7e80a8Spooka printf("enic: internal error %x\n", isr);
1395f7e80a8Spooka regs->Control = EC_RESET;
1405f7e80a8Spooka break;
1415f7e80a8Spooka }
1425f7e80a8Spooka
1435f7e80a8Spooka //printf("isr %x ",isr);
1445f7e80a8Spooka
1455f7e80a8Spooka if ((isr & (EC_DONE|EC_OF_EMPTY)) == EC_DONE) {
1465f7e80a8Spooka
1475f7e80a8Spooka /* beware, order matters */
1485f7e80a8Spooka saf = regs->SizeAndFlags;
1495f7e80a8Spooka hi = regs->BufferAddressHi32; /* BUGBUG 64bit */
1505f7e80a8Spooka lo = regs->BufferAddressLo32; /* this pops the fifo */
15160d0010eSchristos __USE(hi);
1525f7e80a8Spooka
1535f7e80a8Spooka fl = saf & (ES_F_MASK &~ ES_F_DONE);
1545f7e80a8Spooka
1555f7e80a8Spooka if (fl == ES_F_RECV)
1565f7e80a8Spooka {
1575f7e80a8Spooka /* and we are done? */
1585f7e80a8Spooka if (phys == lo)
1595f7e80a8Spooka return saf & ES_S_MASK;
1605f7e80a8Spooka } else if (fl == ES_F_XMIT)
1615f7e80a8Spooka {
1625f7e80a8Spooka ;/* nothing */
1635f7e80a8Spooka } else if (fl != ES_F_CMD)
1645f7e80a8Spooka {
165ebb0f5eaSmartin printf("enic: invalid saf=x%x (lo=%x, hi=%x)\n", saf, lo, hi);
1665f7e80a8Spooka }
1675f7e80a8Spooka }
1685f7e80a8Spooka
1695f7e80a8Spooka if (getsecs() >= timeo) {
1705f7e80a8Spooka //printf("enic: timeout\n");
1715f7e80a8Spooka regs->Control = EC_RESET;
1725f7e80a8Spooka break;
1735f7e80a8Spooka }
1745f7e80a8Spooka }
1755f7e80a8Spooka
1765f7e80a8Spooka return 0;
1775f7e80a8Spooka }
1785f7e80a8Spooka
1795f7e80a8Spooka /*
1805f7e80a8Spooka */
enic_getmac(struct _Enic * regs,uint8_t * mac)1815f7e80a8Spooka static int enic_getmac(struct _Enic *regs, uint8_t *mac)
1825f7e80a8Spooka {
1835f7e80a8Spooka uint8_t buffer[8];
1845f7e80a8Spooka paddr_t phys = kvtophys(&buffer[0]);
1855f7e80a8Spooka int i;
1865f7e80a8Spooka
1875f7e80a8Spooka regs->Control = EC_RESET;
1885f7e80a8Spooka Delay(1);
1895f7e80a8Spooka regs->Control = regs->Control & (~EC_RXDIS);
1905f7e80a8Spooka
1915f7e80a8Spooka buffer[0] = ENIC_CMD_GET_ADDRESS;
1925f7e80a8Spooka
1935f7e80a8Spooka //printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
1945f7e80a8Spooka
1955f7e80a8Spooka regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD;
1965f7e80a8Spooka regs->BufferAddressHi32 = 0;
1975f7e80a8Spooka regs->BufferAddressLo32 = phys; /* go! */
1985f7e80a8Spooka
1995f7e80a8Spooka for (i = 0; i < 100; i++) {
2005f7e80a8Spooka Delay(100);
2015f7e80a8Spooka if (0 == (regs->Control & EC_OF_EMPTY))
2025f7e80a8Spooka break;
2035f7e80a8Spooka }
2045f7e80a8Spooka if (i == 100)
2055f7e80a8Spooka return 0;
2065f7e80a8Spooka
2075f7e80a8Spooka //printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
2085f7e80a8Spooka
2095f7e80a8Spooka memcpy(mac,buffer,6);
2105f7e80a8Spooka return 1;
2115f7e80a8Spooka }
2125f7e80a8Spooka
2135f7e80a8Spooka /* Exported interface
2145f7e80a8Spooka */
21560d0010eSchristos int
enic_present(int unit)21660d0010eSchristos enic_present(int unit)
2175f7e80a8Spooka {
2185f7e80a8Spooka if ((unit != 0) || (the_enic->Tag != PMTTAG_ETHERNET))
2195f7e80a8Spooka return 0;
2205f7e80a8Spooka
2215f7e80a8Spooka return 1;
2225f7e80a8Spooka }
2235f7e80a8Spooka
2245f7e80a8Spooka extern int try_bootp;
2255f7e80a8Spooka
2265f7e80a8Spooka extern struct netif_stats enicstats[];
2275f7e80a8Spooka struct netif_dif enicifs[] = {
2285f7e80a8Spooka /* dif_unit dif_nsel dif_stats dif_private */
2295f7e80a8Spooka { 0, 1, &enicstats[0], the_enic, },
2305f7e80a8Spooka };
2315f7e80a8Spooka #define NENICIFS (sizeof(enicifs) / sizeof(enicifs[0]))
2325f7e80a8Spooka struct netif_stats enicstats[NENICIFS];
2335f7e80a8Spooka
2345f7e80a8Spooka struct netif_driver enic_netif_driver = {
2355f7e80a8Spooka "enic", /* netif_bname */
2365f7e80a8Spooka enicmatch, /* netif_match */
2375f7e80a8Spooka enicprobe, /* netif_probe */
2385f7e80a8Spooka enicinit, /* netif_init */
2395f7e80a8Spooka enicget, /* netif_get */
2405f7e80a8Spooka enicput, /* netif_put */
2415f7e80a8Spooka enicend, /* netif_end */
2425f7e80a8Spooka enicifs, /* netif_ifs */
2435f7e80a8Spooka NENICIFS /* netif_nifs */
2445f7e80a8Spooka };
2455f7e80a8Spooka
2465f7e80a8Spooka static int
enicmatch(struct netif * nif,void * machdep_hint)2475f7e80a8Spooka enicmatch(struct netif *nif, void *machdep_hint)
2485f7e80a8Spooka {
2495f7e80a8Spooka return (1);
2505f7e80a8Spooka }
2515f7e80a8Spooka
2525f7e80a8Spooka /* NB: We refuse anything but unit==0
2535f7e80a8Spooka */
2545f7e80a8Spooka static int
enicprobe(struct netif * nif,void * machdep_hint)2555f7e80a8Spooka enicprobe(struct netif *nif, void *machdep_hint)
2565f7e80a8Spooka {
2575f7e80a8Spooka int unit = nif->nif_unit;
2585f7e80a8Spooka #ifdef NET_DEBUG
2595f7e80a8Spooka printf("enic%d: probe\n", unit);
2605f7e80a8Spooka #endif
2615f7e80a8Spooka return (enic_present(unit) ? 0 : 1);
2625f7e80a8Spooka }
2635f7e80a8Spooka
2645f7e80a8Spooka static void
enicinit(struct iodesc * desc,void * machdep_hint)2655f7e80a8Spooka enicinit(struct iodesc *desc, void *machdep_hint)
2665f7e80a8Spooka {
2675f7e80a8Spooka #ifdef NET_DEBUG
2685f7e80a8Spooka struct netif *nif = (struct netif *)desc->io_netif;
2695f7e80a8Spooka int unit = nif->nif_driver->netif_ifs->dif_unit;
2705f7e80a8Spooka printf("enic%d: init %s\n", unit, machdep_hint);
2715f7e80a8Spooka #endif
2725f7e80a8Spooka
2735f7e80a8Spooka /*
274*f41ff51fSandvar * Yes we want DHCP and this is our MAC
2755f7e80a8Spooka */
2765f7e80a8Spooka try_bootp = 1;
2775f7e80a8Spooka enic_getmac(the_enic,desc->myea);
2785f7e80a8Spooka desc->xid = 0xfe63d095;
2795f7e80a8Spooka }
2805f7e80a8Spooka
2815f7e80a8Spooka
2825f7e80a8Spooka static int
enicput(struct iodesc * desc,void * pkt,size_t len)2835f7e80a8Spooka enicput(struct iodesc *desc, void *pkt, size_t len)
2845f7e80a8Spooka {
2855f7e80a8Spooka #ifdef NET_DEBUG
2865f7e80a8Spooka if (debug)
2875f7e80a8Spooka dump_packet(pkt,len);
2885f7e80a8Spooka #endif
2895f7e80a8Spooka
2905f7e80a8Spooka return enic_putpkt(the_enic,pkt,len);
2915f7e80a8Spooka }
2925f7e80a8Spooka
2935f7e80a8Spooka
2945f7e80a8Spooka int
enicget(struct iodesc * desc,void * pkt,size_t len,saseconds_t timeout)2955f7e80a8Spooka enicget(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
2965f7e80a8Spooka {
2975f7e80a8Spooka #ifdef NET_DEBUG
2985f7e80a8Spooka printf("enicget: %lx %lx\n",len,timeout);
2995f7e80a8Spooka #endif
3005f7e80a8Spooka return enic_getpkt(the_enic,pkt,len,timeout);
3015f7e80a8Spooka }
3025f7e80a8Spooka
3035f7e80a8Spooka
3045f7e80a8Spooka static void
enicend(struct netif * nif)3055f7e80a8Spooka enicend(struct netif *nif)
3065f7e80a8Spooka {
3075f7e80a8Spooka /* BUGBUG stop it in reset? */
3085f7e80a8Spooka }
3095f7e80a8Spooka
3105f7e80a8Spooka #ifdef NET_DEBUG
dump_packet(void * pkt,int len)3115f7e80a8Spooka static void dump_packet(void *pkt, int len)
3125f7e80a8Spooka {
3135f7e80a8Spooka struct ether_header *eh = (struct ether_header *)pkt;
3145f7e80a8Spooka struct ip *ih = (struct ip *)(eh + 1);
3155f7e80a8Spooka
3165f7e80a8Spooka printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost));
3175f7e80a8Spooka printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost));
3185f7e80a8Spooka printf("ether_type = 0x%x\n", ntohs(eh->ether_type));
3195f7e80a8Spooka
3205f7e80a8Spooka if (ntohs(eh->ether_type) == 0x0800) {
3215f7e80a8Spooka printf("ip packet version %d\n", ih->ip_v);
3225f7e80a8Spooka printf("source ip: 0x%x\n", ih->ip_src.s_addr);
3235f7e80a8Spooka printf("dest ip: 0x%x\n", ih->ip_dst.s_addr);
3245f7e80a8Spooka
3255f7e80a8Spooka }
3265f7e80a8Spooka }
3275f7e80a8Spooka #endif
328