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