1 /************************************************************************** 2 Etherboot - BOOTP/TFTP Bootstrap Program 3 4 TIARA (Fujitsu Etherstar) NIC driver for Etherboot 5 Copyright (c) Ken Yap 1998 6 7 Information gleaned from: 8 9 TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario 10 Fujitsu 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 109 static unsigned short ioaddr; 110 111 /************************************************************************** 112 RESET - Reset adapter 113 ***************************************************************************/ 114 static 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 /************************************************************************** 135 POLL - Wait for a frame 136 ***************************************************************************/ 137 static 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 /************************************************************************** 159 TRANSMIT - Transmit a frame 160 ***************************************************************************/ 161 static void tiara_transmit( 162 struct nic *nic, 163 const char *d, /* Destination */ 164 unsigned int t, /* Type */ 165 unsigned int s, /* size */ 166 const 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 /************************************************************************** 194 DISABLE - Turn off ethernet interface 195 ***************************************************************************/ 196 static 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 202 static 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 /************************************************************************** 220 PROBE - Look for an adapter, this routine's visible to the outside 221 ***************************************************************************/ 222 struct 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