1/************************************************************************** 2Etherboot - BOOTP/TFTP Bootstrap Program 3 4TIARA (Fujitsu Etherstar) NIC driver for Etherboot 5Copyright (c) Ken Yap 1998 6 7Information gleaned from: 8 9TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario 10Fujitsu MB86960 spec sheet (different chip but same family) 11***************************************************************************/ 12 13/* 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License as 16 * published by the Free Software Foundation; either version 2, or (at 17 * your option) any later version. 18 */ 19 20/* to get some global routines like printf */ 21#include "etherboot.h" 22/* to get the interface to the body of the program */ 23#include "nic.h" 24#include "cards.h" 25 26/* 27 EtherStar I/O Register offsets 28*/ 29 30/* Offsets of registers */ 31#define DLCR_XMIT_STAT 0x00 32#define DLCR_XMIT_MASK 0x01 33#define DLCR_RECV_STAT 0x02 34#define DLCR_RECV_MASK 0x03 35#define DLCR_XMIT_MODE 0x04 36#define DLCR_RECV_MODE 0x05 37#define DLCR_ENABLE 0x06 38#define DLCR_TDR_LOW 0x07 39#define DLCR_NODE_ID 0x08 40#define DLCR_TDR_HIGH 0x0F 41#define BMPR_MEM_PORT 0x10 42#define BMPR_PKT_LEN 0x12 43#define BMPR_DMA_ENABLE 0x14 44#define PROM_ID 0x18 45 46#define TMST 0x80 47#define TMT_OK 0x80 48#define TMT_16COLL 0x02 49#define BUF_EMPTY 0x40 50 51#define CARD_DISABLE 0x80 /* written to DLCR_ENABLE to disable card */ 52#define CARD_ENABLE 0 /* written to DLCR_ENABLE to enable card */ 53 54#define CLEAR_STATUS 0x0F /* used to clear status info */ 55/* 56 00001111B 57 !!!!!!!!-------- 58 !!!!!!!+--------CLEAR BUS WRITE ERROR 59 !!!!!!+---------CLEAR 16 COLLISION 60 !!!!!+----------CLEAR COLLISION 61 !!!!+-----------CLEAR UNDERFLOW 62 !!!+------------NC 63 !!+-------------NC 64 !+--------------NC 65 +---------------NC 66*/ 67 68#define NO_TX_IRQS 0 /* written to clear transmit IRQs */ 69 70#define CLR_RCV_STATUS 0xCF /* clears receive status */ 71 72#define EN_RCV_IRQS 0x80 /* enable receive interrupts */ 73/* 74 10000000B 75 !!!!!!!!-------- 76 !!!!!!!+--------ENABLE OVERFLOW 77 !!!!!!+---------ENABLE CRC 78 !!!!!+----------ENABLE ALIGN 79 !!!!+-----------ENABLE SHORT PKT 80 !!!+------------DISABLE REMOTE RESET 81 !!+-------------RESERVED 82 !+--------------RESERVED 83 +---------------ENABLE PKT READY 84*/ 85 86#define XMIT_MODE 0x02 87/* 88 00000010B 89 !!!!!!!!---------ENABLE CARRIER DETECT 90 !!!!!!!+---------DISABLE LOOPBACK 91*/ 92 93#define RECV_MODE 0x02 94/* 95 00000010B 96 !!!!!!!!---------ACCEPT ALL PACKETS 97 !!!!!!!+---------ACCEPT PHYSICAL, MULTICAST, AND 98 !!!!!!+----------BROADCAST PACKETS 99 !!!!!+-----------DISABLE REMOTE RESET 100 !!!!+------------DISABLE SHORT PACKETS 101 !!!+-------------USE 6 BYTE ADDRESS 102 !!+--------------NC 103 !+---------------NC 104 +----------------DISABLE CRC TEST MODE 105*/ 106 107/* NIC specific static variables go here */ 108 109static unsigned short ioaddr; 110 111/************************************************************************** 112RESET - Reset adapter 113***************************************************************************/ 114static void tiara_reset(struct nic *nic) 115{ 116 int i; 117 118 outb(CARD_DISABLE, ioaddr + DLCR_ENABLE); 119 outb(CLEAR_STATUS, ioaddr + DLCR_XMIT_STAT); 120 outb(NO_TX_IRQS, ioaddr + DLCR_XMIT_MASK); 121 outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT); 122 outb(XMIT_MODE, ioaddr + DLCR_XMIT_MODE); 123 outb(RECV_MODE, ioaddr + DLCR_RECV_MODE); 124 /* Vacuum recv buffer */ 125 while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0) 126 inb(ioaddr + BMPR_MEM_PORT); 127 /* Set node address */ 128 for (i = 0; i < ETH_ALEN; ++i) 129 outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i); 130 outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT); 131 outb(CARD_ENABLE, ioaddr + DLCR_ENABLE); 132} 133 134/************************************************************************** 135POLL - Wait for a frame 136***************************************************************************/ 137static int tiara_poll(struct nic *nic) 138{ 139 unsigned int len; 140 141 if (inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) 142 return (0); 143 /* Ack packet */ 144 outw(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT); 145 len = inw(ioaddr + BMPR_MEM_PORT); /* throw away status */ 146 len = inw(ioaddr + BMPR_MEM_PORT); 147 /* Drop overlength packets */ 148 if (len > ETH_FRAME_LEN) 149 return (0); /* should we drain the buffer? */ 150 insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2); 151 /* If it's our own, drop it */ 152 if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0) 153 return (0); 154 nic->packetlen = len; 155 return (1); 156} 157 158/************************************************************************** 159TRANSMIT - Transmit a frame 160***************************************************************************/ 161static void tiara_transmit( 162struct nic *nic, 163const char *d, /* Destination */ 164unsigned int t, /* Type */ 165unsigned int s, /* size */ 166const char *p) /* Packet */ 167{ 168 unsigned int len; 169 unsigned long time; 170 171 len = s + ETH_HLEN; 172 if (len < ETH_ZLEN) 173 len = ETH_ZLEN; 174 t = htons(t); 175 outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2); 176 outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2); 177 outw(t, ioaddr + BMPR_MEM_PORT); 178 outsw(ioaddr + BMPR_MEM_PORT, p, s / 2); 179 if (s & 1) /* last byte */ 180 outb(p[s-1], ioaddr + BMPR_MEM_PORT); 181 while (s++ < ETH_ZLEN - ETH_HLEN) /* pad */ 182 outb(0, ioaddr + BMPR_MEM_PORT); 183 outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN); 184 /* wait for transmit complete */ 185 time = currticks() + TICKS_PER_SEC; /* wait one second */ 186 while (currticks() < time && (inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0) 187 ; 188 if ((inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0) 189 printf("Tiara timed out on transmit\n"); 190 /* Do we need to ack the transmit? */ 191} 192 193/************************************************************************** 194DISABLE - Turn off ethernet interface 195***************************************************************************/ 196static void tiara_disable(struct nic *nic) 197{ 198 /* Apparently only a power down can do this properly */ 199 outb(CARD_DISABLE, ioaddr + DLCR_ENABLE); 200} 201 202static int tiara_probe1(struct nic *nic) 203{ 204 /* Hope all the Tiara cards have this vendor prefix */ 205 static char vendor_prefix[] = { 0x08, 0x00, 0x1A }; 206 static char all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 207 int i; 208 209 for (i = 0; i < ETH_ALEN; ++i) 210 nic->node_addr[i] = inb(ioaddr + PROM_ID + i); 211 if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0) 212 return (0); 213 if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0) 214 return (0); 215 printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr); 216 return (1); 217} 218 219/************************************************************************** 220PROBE - Look for an adapter, this routine's visible to the outside 221***************************************************************************/ 222struct nic *tiara_probe(struct nic *nic, unsigned short *probe_addrs) 223{ 224 /* missing entries are addresses usually already used */ 225 static unsigned short io_addrs[] = { 226 0x100, 0x120, 0x140, 0x160, 227 0x180, 0x1A0, 0x1C0, 0x1E0, 228 0x200, 0x220, 0x240, /*Par*/ 229 0x280, 0x2A0, 0x2C0, /*Ser*/ 230 0x300, 0x320, 0x340, /*Par*/ 231 0x380, /*Vid,Par*/ 0x3C0, /*Ser*/ 232 0x0 233 }; 234 unsigned short *p; 235 236 /* if probe_addrs is 0, then routine can use a hardwired default */ 237 if (probe_addrs == 0) 238 probe_addrs = io_addrs; 239 for (p = probe_addrs; (ioaddr = *p) != 0; ++p) 240 if (tiara_probe1(nic)) 241 break; 242 /* if board found */ 243 if (ioaddr != 0) 244 { 245 tiara_reset(nic); 246 /* point to NIC specific routines */ 247 nic->reset = tiara_reset; 248 nic->poll = tiara_poll; 249 nic->transmit = tiara_transmit; 250 nic->disable = tiara_disable; 251 return nic; 252 } 253 else 254 return (0); 255} 256