1/* $NetBSD: enic.c,v 1.5 2023/01/22 21:36:12 andvar Exp $ */ 2 3/*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code was written by Alessandro Forin and Neil Pittman 8 * at Microsoft Research and contributed to The NetBSD Foundation 9 * by Microsoft Corporation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* -------------------------------------------------------------------------- 34 * 35 * Module: 36 * 37 * enic.c 38 * 39 * Purpose: 40 * 41 * Driver for the Microsoft eNIC (eMIPS system) Ethernet 42 * 43 * Author: 44 * A. Forin (sandrof) 45 * 46 * References: 47 * Internal Microsoft specifications, file eNIC_Design.docx titled 48 * "eNIC: a simple Ethernet" Revision 4/30/99 49 * 50 * Giano simulation module, file Peripherals\enic.cpp 51 * 52 * Various other drivers I wrote for said hardware 53 * -------------------------------------------------------------------------- 54 */ 55 56#include <sys/param.h> 57#include <sys/types.h> 58 59#include <net/if_ether.h> 60#include <netinet/in.h> 61#include <netinet/in_systm.h> 62#include <netinet/ip.h> 63 64#include <lib/libsa/stand.h> 65#include <lib/libsa/net.h> 66#include <lib/libsa/netif.h> 67#include <lib/libkern/libkern.h> 68 69 70#include <machine/emipsreg.h> 71 72#include "start.h" 73#include "common.h" 74 75#define the_enic ((struct _Enic *)ETHERNET_DEFAULT_ADDRESS) 76 77/* forward declarations */ 78static int enicprobe (struct netif *, void *); 79static int enicmatch (struct netif *, void *); 80static void enicinit (struct iodesc *, void *); 81static int enicget (struct iodesc *, void *, size_t, saseconds_t); 82static int enicput (struct iodesc *, void *, size_t); 83static void enicend (struct netif *); 84 85#ifdef NET_DEBUG 86static void dump_packet(void *, int); 87#endif 88 89/* BUGBUG do we have this? */ 90#define kvtophys(_v_) ((paddr_t)(_v_) & ~0x80000000) 91 92#define rpostone(_r_,_p_,_s_) \ 93 (_r_)->SizeAndFlags = ES_F_RECV | (_s_); \ 94 (_r_)->BufferAddressHi32 = 0; \ 95 (_r_)->BufferAddressLo32 = _p_; 96#define tpostone(_r_,_p_,_s_) \ 97 (_r_)->SizeAndFlags = ES_F_XMIT | (_s_); \ 98 (_r_)->BufferAddressHi32 = 0; \ 99 (_r_)->BufferAddressLo32 = _p_; 100 101 102/* Send a packet 103 */ 104static int 105enic_putpkt(struct _Enic *regs, void *buf, int bytes) 106{ 107 paddr_t phys = kvtophys(buf); 108 109 tpostone(regs,phys,bytes); 110 111 /* poll till done? */ 112 //printf("\tenic: sent %d at %x\n",bytes,phys); 113 return bytes; 114} 115 116/* Get a packet 117 */ 118static int 119enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo) 120{ 121 paddr_t phys; 122 unsigned int isr, saf, hi, lo, fl; 123 124 phys = kvtophys(buf); 125 rpostone(regs,phys,bytes); 126 127 //printf("\tenic: recv %d at %x\n",bytes,phys); 128 129 /* poll till we get some */ 130 timeo += getsecs(); 131 132 for (;;) { 133 134 /* anything there? */ 135 isr = regs->Control; 136 137 if (isr & EC_ERROR) { 138 printf("enic: internal error %x\n", isr); 139 regs->Control = EC_RESET; 140 break; 141 } 142 143 //printf("isr %x ",isr); 144 145 if ((isr & (EC_DONE|EC_OF_EMPTY)) == EC_DONE) { 146 147 /* beware, order matters */ 148 saf = regs->SizeAndFlags; 149 hi = regs->BufferAddressHi32; /* BUGBUG 64bit */ 150 lo = regs->BufferAddressLo32; /* this pops the fifo */ 151 __USE(hi); 152 153 fl = saf & (ES_F_MASK &~ ES_F_DONE); 154 155 if (fl == ES_F_RECV) 156 { 157 /* and we are done? */ 158 if (phys == lo) 159 return saf & ES_S_MASK; 160 } else if (fl == ES_F_XMIT) 161 { 162 ;/* nothing */ 163 } else if (fl != ES_F_CMD) 164 { 165 printf("enic: invalid saf=x%x (lo=%x, hi=%x)\n", saf, lo, hi); 166 } 167 } 168 169 if (getsecs() >= timeo) { 170 //printf("enic: timeout\n"); 171 regs->Control = EC_RESET; 172 break; 173 } 174 } 175 176 return 0; 177} 178 179/* 180 */ 181static int enic_getmac(struct _Enic *regs, uint8_t *mac) 182{ 183 uint8_t buffer[8]; 184 paddr_t phys = kvtophys(&buffer[0]); 185 int i; 186 187 regs->Control = EC_RESET; 188 Delay(1); 189 regs->Control = regs->Control & (~EC_RXDIS); 190 191 buffer[0] = ENIC_CMD_GET_ADDRESS; 192 193 //printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]); 194 195 regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD; 196 regs->BufferAddressHi32 = 0; 197 regs->BufferAddressLo32 = phys; /* go! */ 198 199 for (i = 0; i < 100; i++) { 200 Delay(100); 201 if (0 == (regs->Control & EC_OF_EMPTY)) 202 break; 203 } 204 if (i == 100) 205 return 0; 206 207 //printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]); 208 209 memcpy(mac,buffer,6); 210 return 1; 211} 212 213/* Exported interface 214 */ 215int 216enic_present(int unit) 217{ 218 if ((unit != 0) || (the_enic->Tag != PMTTAG_ETHERNET)) 219 return 0; 220 221 return 1; 222} 223 224extern int try_bootp; 225 226extern struct netif_stats enicstats[]; 227struct netif_dif enicifs[] = { 228/* dif_unit dif_nsel dif_stats dif_private */ 229{ 0, 1, &enicstats[0], the_enic, }, 230}; 231#define NENICIFS (sizeof(enicifs) / sizeof(enicifs[0])) 232struct netif_stats enicstats[NENICIFS]; 233 234struct netif_driver enic_netif_driver = { 235 "enic", /* netif_bname */ 236 enicmatch, /* netif_match */ 237 enicprobe, /* netif_probe */ 238 enicinit, /* netif_init */ 239 enicget, /* netif_get */ 240 enicput, /* netif_put */ 241 enicend, /* netif_end */ 242 enicifs, /* netif_ifs */ 243 NENICIFS /* netif_nifs */ 244}; 245 246static int 247enicmatch(struct netif *nif, void *machdep_hint) 248{ 249 return (1); 250} 251 252/* NB: We refuse anything but unit==0 253 */ 254static int 255enicprobe(struct netif *nif, void *machdep_hint) 256{ 257 int unit = nif->nif_unit; 258#ifdef NET_DEBUG 259 printf("enic%d: probe\n", unit); 260#endif 261 return (enic_present(unit) ? 0 : 1); 262} 263 264static void 265enicinit(struct iodesc *desc, void *machdep_hint) 266{ 267#ifdef NET_DEBUG 268 struct netif *nif = (struct netif *)desc->io_netif; 269 int unit = nif->nif_driver->netif_ifs->dif_unit; 270 printf("enic%d: init %s\n", unit, machdep_hint); 271#endif 272 273 /* 274 * Yes we want DHCP and this is our MAC 275 */ 276 try_bootp = 1; 277 enic_getmac(the_enic,desc->myea); 278 desc->xid = 0xfe63d095; 279} 280 281 282static int 283enicput(struct iodesc *desc, void *pkt, size_t len) 284{ 285#ifdef NET_DEBUG 286 if (debug) 287 dump_packet(pkt,len); 288#endif 289 290 return enic_putpkt(the_enic,pkt,len); 291} 292 293 294int 295enicget(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout) 296{ 297#ifdef NET_DEBUG 298 printf("enicget: %lx %lx\n",len,timeout); 299#endif 300 return enic_getpkt(the_enic,pkt,len,timeout); 301} 302 303 304static void 305enicend(struct netif *nif) 306{ 307 /* BUGBUG stop it in reset? */ 308} 309 310#ifdef NET_DEBUG 311static void dump_packet(void *pkt, int len) 312{ 313 struct ether_header *eh = (struct ether_header *)pkt; 314 struct ip *ih = (struct ip *)(eh + 1); 315 316 printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost)); 317 printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost)); 318 printf("ether_type = 0x%x\n", ntohs(eh->ether_type)); 319 320 if (ntohs(eh->ether_type) == 0x0800) { 321 printf("ip packet version %d\n", ih->ip_v); 322 printf("source ip: 0x%x\n", ih->ip_src.s_addr); 323 printf("dest ip: 0x%x\n", ih->ip_dst.s_addr); 324 325 } 326} 327#endif 328