1 /************************************************************************** 2 Etherboot - BOOTP/TFTP Bootstrap Program 3 Driver for NI5010. 4 Code freely taken from Jan-Pascal van Best and Andreas Mohr's 5 Linux NI5010 driver. 6 ***************************************************************************/ 7 8 /* 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2, or (at 12 * your option) any later version. 13 */ 14 15 /* to get some global routines like printf */ 16 #include "etherboot.h" 17 /* to get the interface to the body of the program */ 18 #include "nic.h" 19 /* to get our own prototype */ 20 #include "cards.h" 21 22 /* ni5010.h file included verbatim */ 23 /* 24 * Racal-Interlan ni5010 Ethernet definitions 25 * 26 * This is an extension to the Linux operating system, and is covered by the 27 * same Gnu Public License that covers that work. 28 * 29 * copyrights (c) 1996 by Jan-Pascal van Best (jvbest (at) wi.leidenuniv.nl) 30 * 31 * I have done a look in the following sources: 32 * crynwr-packet-driver by Russ Nelson 33 */ 34 35 #define NI5010_BUFSIZE 2048 /* number of bytes in a buffer */ 36 37 #define NI5010_MAGICVAL0 0x00 /* magic-values for ni5010 card */ 38 #define NI5010_MAGICVAL1 0x55 39 #define NI5010_MAGICVAL2 0xAA 40 41 #define SA_ADDR0 0x02 42 #define SA_ADDR1 0x07 43 #define SA_ADDR2 0x01 44 45 /* The number of low I/O ports used by the ni5010 ethercard. */ 46 #define NI5010_IO_EXTENT 32 47 48 #define PRINTK(x) if (NI5010_DEBUG) printk x 49 #define PRINTK2(x) if (NI5010_DEBUG>=2) printk x 50 #define PRINTK3(x) if (NI5010_DEBUG>=3) printk x 51 52 /* The various IE command registers */ 53 #define EDLC_XSTAT (ioaddr + 0x00) /* EDLC transmit csr */ 54 #define EDLC_XCLR (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */ 55 #define EDLC_XMASK (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */ 56 #define EDLC_RSTAT (ioaddr + 0x02) /* EDLC receive csr */ 57 #define EDLC_RCLR (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */ 58 #define EDLC_RMASK (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */ 59 #define EDLC_XMODE (ioaddr + 0x04) /* EDLC transmit Mode */ 60 #define EDLC_RMODE (ioaddr + 0x05) /* EDLC receive Mode */ 61 #define EDLC_RESET (ioaddr + 0x06) /* EDLC RESET register */ 62 #define EDLC_TDR1 (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */ 63 #define EDLC_ADDR (ioaddr + 0x08) /* EDLC station address, 6 bytes */ 64 /* 0x0E doesn't exist for r/w */ 65 #define EDLC_TDR2 (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */ 66 #define IE_GP (ioaddr + 0x10) /* GP pointer (word register) */ 67 /* 0x11 is 2nd byte of GP Pointer */ 68 #define IE_RCNT (ioaddr + 0x10) /* Count of bytes in rcv'd packet */ 69 /* 0x11 is 2nd byte of "Byte Count" */ 70 #define IE_MMODE (ioaddr + 0x12) /* Memory Mode register */ 71 #define IE_DMA_RST (ioaddr + 0x13) /* IE DMA Reset. write only */ 72 #define IE_ISTAT (ioaddr + 0x13) /* IE Interrupt Status. read only */ 73 #define IE_RBUF (ioaddr + 0x14) /* IE Receive Buffer port */ 74 #define IE_XBUF (ioaddr + 0x15) /* IE Transmit Buffer port */ 75 #define IE_SAPROM (ioaddr + 0x16) /* window on station addr prom */ 76 #define IE_RESET (ioaddr + 0x17) /* any write causes Board Reset */ 77 78 /* bits in EDLC_XSTAT, interrupt clear on write, status when read */ 79 #define XS_TPOK 0x80 /* transmit packet successful */ 80 #define XS_CS 0x40 /* carrier sense */ 81 #define XS_RCVD 0x20 /* transmitted packet received */ 82 #define XS_SHORT 0x10 /* transmission media is shorted */ 83 #define XS_UFLW 0x08 /* underflow. iff failed board */ 84 #define XS_COLL 0x04 /* collision occurred */ 85 #define XS_16COLL 0x02 /* 16th collision occurred */ 86 #define XS_PERR 0x01 /* parity error */ 87 88 #define XS_CLR_UFLW 0x08 /* clear underflow */ 89 #define XS_CLR_COLL 0x04 /* clear collision */ 90 #define XS_CLR_16COLL 0x02 /* clear 16th collision */ 91 #define XS_CLR_PERR 0x01 /* clear parity error */ 92 93 /* bits in EDLC_XMASK, mask/enable transmit interrupts. register is r/w */ 94 #define XM_TPOK 0x80 /* =1 to enable Xmt Pkt OK interrupts */ 95 #define XM_RCVD 0x20 /* =1 to enable Xmt Pkt Rcvd ints */ 96 #define XM_UFLW 0x08 /* =1 to enable Xmt Underflow ints */ 97 #define XM_COLL 0x04 /* =1 to enable Xmt Collision ints */ 98 #define XM_COLL16 0x02 /* =1 to enable Xmt 16th Coll ints */ 99 #define XM_PERR 0x01 /* =1 to enable Xmt Parity Error ints */ 100 /* note: always clear this bit */ 101 #define XM_ALL (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16) 102 103 /* bits in EDLC_RSTAT, interrupt clear on write, status when read */ 104 #define RS_PKT_OK 0x80 /* received good packet */ 105 #define RS_RST_PKT 0x10 /* RESET packet received */ 106 #define RS_RUNT 0x08 /* Runt Pkt rcvd. Len < 64 Bytes */ 107 #define RS_ALIGN 0x04 /* Alignment error. not 8 bit aligned */ 108 #define RS_CRC_ERR 0x02 /* Bad CRC on rcvd pkt */ 109 #define RS_OFLW 0x01 /* overflow for rcv FIFO */ 110 #define RS_VALID_BITS ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW ) 111 /* all valid RSTAT bits */ 112 113 #define RS_CLR_PKT_OK 0x80 /* clear rcvd packet interrupt */ 114 #define RS_CLR_RST_PKT 0x10 /* clear RESET packet received */ 115 #define RS_CLR_RUNT 0x08 /* clear Runt Pckt received */ 116 #define RS_CLR_ALIGN 0x04 /* clear Alignment error */ 117 #define RS_CLR_CRC_ERR 0x02 /* clear CRC error */ 118 #define RS_CLR_OFLW 0x01 /* clear rcv FIFO Overflow */ 119 120 /* bits in EDLC_RMASK, mask/enable receive interrupts. register is r/w */ 121 #define RM_PKT_OK 0x80 /* =1 to enable rcvd good packet ints */ 122 #define RM_RST_PKT 0x10 /* =1 to enable RESET packet ints */ 123 #define RM_RUNT 0x08 /* =1 to enable Runt Pkt rcvd ints */ 124 #define RM_ALIGN 0x04 /* =1 to enable Alignment error ints */ 125 #define RM_CRC_ERR 0x02 /* =1 to enable Bad CRC error ints */ 126 #define RM_OFLW 0x01 /* =1 to enable overflow error ints */ 127 128 /* bits in EDLC_RMODE, set Receive Packet mode. register is r/w */ 129 #define RMD_TEST 0x80 /* =1 for Chip testing. normally 0 */ 130 #define RMD_ADD_SIZ 0x10 /* =1 5-byte addr match. normally 0 */ 131 #define RMD_EN_RUNT 0x08 /* =1 enable runt rcv. normally 0 */ 132 #define RMD_EN_RST 0x04 /* =1 to rcv RESET pkt. normally 0 */ 133 134 #define RMD_PROMISC 0x03 /* receive *all* packets. unusual */ 135 #define RMD_MULTICAST 0x02 /* receive multicasts too. unusual */ 136 #define RMD_BROADCAST 0x01 /* receive broadcasts & normal. usual */ 137 #define RMD_NO_PACKETS 0x00 /* don't receive any packets. unusual */ 138 139 /* bits in EDLC_XMODE, set Transmit Packet mode. register is r/w */ 140 #define XMD_COLL_CNT 0xf0 /* coll's since success. read-only */ 141 #define XMD_IG_PAR 0x08 /* =1 to ignore parity. ALWAYS set */ 142 #define XMD_T_MODE 0x04 /* =1 to power xcvr. ALWAYS set this */ 143 #define XMD_LBC 0x02 /* =1 for loopback. normally set */ 144 #define XMD_DIS_C 0x01 /* =1 disables contention. normally 0 */ 145 146 /* bits in EDLC_RESET, write only */ 147 #define RS_RESET 0x80 /* =1 to hold EDLC in reset state */ 148 149 /* bits in IE_MMODE, write only */ 150 #define MM_EN_DMA 0x80 /* =1 begin DMA xfer, Cplt clrs it */ 151 #define MM_EN_RCV 0x40 /* =1 allows Pkt rcv. clr'd by rcv */ 152 #define MM_EN_XMT 0x20 /* =1 begin Xmt pkt. Cplt clrs it */ 153 #define MM_BUS_PAGE 0x18 /* =00 ALWAYS. Used when MUX=1 */ 154 #define MM_NET_PAGE 0x06 /* =00 ALWAYS. Used when MUX=0 */ 155 #define MM_MUX 0x01 /* =1 means Rcv Buff on system bus */ 156 /* =0 means Xmt Buff on system bus */ 157 158 /* bits in IE_ISTAT, read only */ 159 #define IS_TDIAG 0x80 /* =1 if Diagnostic problem */ 160 #define IS_EN_RCV 0x20 /* =1 until frame is rcv'd cplt */ 161 #define IS_EN_XMT 0x10 /* =1 until frame is xmt'd cplt */ 162 #define IS_EN_DMA 0x08 /* =1 until DMA is cplt or aborted */ 163 #define IS_DMA_INT 0x04 /* =0 iff DMA done interrupt. */ 164 #define IS_R_INT 0x02 /* =0 iff unmasked Rcv interrupt */ 165 #define IS_X_INT 0x01 /* =0 iff unmasked Xmt interrupt */ 166 167 /* NIC specific static variables go here */ 168 169 static unsigned short ioaddr = 0; 170 static unsigned int bufsize_rcv = 0; 171 172 #if 0 173 static void show_registers(void) 174 { 175 printf("XSTAT %hhX ", inb(EDLC_XSTAT)); 176 printf("XMASK %hhX ", inb(EDLC_XMASK)); 177 printf("RSTAT %hhX ", inb(EDLC_RSTAT)); 178 printf("RMASK %hhX ", inb(EDLC_RMASK)); 179 printf("RMODE %hhX ", inb(EDLC_RMODE)); 180 printf("XMODE %hhX ", inb(EDLC_XMODE)); 181 printf("ISTAT %hhX\n", inb(IE_ISTAT)); 182 } 183 #endif 184 185 static void reset_receiver(void) 186 { 187 outw(0, IE_GP); /* Receive packet at start of buffer */ 188 outb(RS_VALID_BITS, EDLC_RCLR); /* Clear all pending Rcv interrupts */ 189 outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */ 190 } 191 192 /************************************************************************** 193 RESET - Reset adapter 194 ***************************************************************************/ 195 static void ni5010_reset(struct nic *nic) 196 { 197 int i; 198 199 /* Reset the hardware here. Don't forget to set the station address. */ 200 outb(RS_RESET, EDLC_RESET); /* Hold up EDLC_RESET while configing board */ 201 outb(0, IE_RESET); /* Hardware reset of ni5010 board */ 202 outb(0, EDLC_XMASK); /* Disable all Xmt interrupts */ 203 outb(0, EDLC_RMASK); /* Disable all Rcv interrupt */ 204 outb(0xFF, EDLC_XCLR); /* Clear all pending Xmt interrupts */ 205 outb(0xFF, EDLC_RCLR); /* Clear all pending Rcv interrupts */ 206 outb(XMD_LBC, EDLC_XMODE); /* Only loopback xmits */ 207 /* Set the station address */ 208 for(i = 0; i < ETH_ALEN; i++) 209 outb(nic->node_addr[i], EDLC_ADDR + i); 210 outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE); 211 /* Normal packet xmit mode */ 212 outb(RMD_BROADCAST, EDLC_RMODE); 213 /* Receive broadcast and normal packets */ 214 reset_receiver(); 215 outb(0x00, EDLC_RESET); /* Un-reset the ni5010 */ 216 } 217 218 /************************************************************************** 219 POLL - Wait for a frame 220 ***************************************************************************/ 221 static int ni5010_poll(struct nic *nic) 222 { 223 int rcv_stat; 224 225 if (((rcv_stat = inb(EDLC_RSTAT)) & RS_VALID_BITS) != RS_PKT_OK) { 226 outb(rcv_stat, EDLC_RSTAT); /* Clear the status */ 227 return (0); 228 } 229 outb(rcv_stat, EDLC_RCLR); /* Clear the status */ 230 nic->packetlen = inw(IE_RCNT); 231 /* Read packet into buffer */ 232 outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ 233 outw(0, IE_GP); /* Seek to beginning of packet */ 234 insb(IE_RBUF, nic->packet, nic->packetlen); 235 return (1); 236 } 237 238 /************************************************************************** 239 TRANSMIT - Transmit a frame 240 ***************************************************************************/ 241 static void ni5010_transmit(struct nic *nic, 242 const char *d, /* Destination */ 243 unsigned int t, /* Type */ 244 unsigned int s, /* size */ 245 const char *p) /* Packet */ 246 { 247 unsigned int len; 248 int buf_offs, xmt_stat; 249 unsigned long time; 250 251 len = s + ETH_HLEN; 252 if (len < ETH_ZLEN) 253 len = ETH_ZLEN; 254 buf_offs = NI5010_BUFSIZE - len; 255 outb(0, EDLC_RMASK); /* Mask all receive interrupts */ 256 outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ 257 outb(0xFF, EDLC_RCLR); /* Clear out pending rcv interrupts */ 258 outw(buf_offs, IE_GP); /* Point GP at start of packet */ 259 outsb(IE_XBUF, d, ETH_ALEN); /* Put dst in buffer */ 260 outsb(IE_XBUF, nic->node_addr, ETH_ALEN);/* Put src in buffer */ 261 outb(t >> 8, IE_XBUF); 262 outb(t, IE_XBUF); 263 outsb(IE_XBUF, p, s); /* Put data in buffer */ 264 while (s++ < ETH_ZLEN - ETH_HLEN) /* Pad to min size */ 265 outb(0, IE_XBUF); 266 outw(buf_offs, IE_GP); /* Rewrite where packet starts */ 267 /* should work without that outb() (Crynwr used it) */ 268 /*outb(MM_MUX, IE_MMODE);*/ 269 /* Xmt buffer to EDLC bus */ 270 outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */ 271 /* wait for transmit complete */ 272 while (((xmt_stat = inb(IE_ISTAT)) & IS_EN_XMT) != 0) 273 ; 274 reset_receiver(); /* Immediately switch to receive */ 275 } 276 277 /************************************************************************** 278 DISABLE - Turn off ethernet interface 279 ***************************************************************************/ 280 static void ni5010_disable(struct nic *nic) 281 { 282 outb(0, IE_MMODE); 283 outb(RS_RESET, EDLC_RESET); 284 } 285 286 static inline int rd_port(void) 287 { 288 inb(IE_RBUF); 289 return inb(IE_SAPROM); 290 } 291 292 static int ni5010_probe1(struct nic *nic) 293 { 294 int i, boguscount = 40, data; 295 296 /* The tests are from the Linux NI5010 driver 297 I don't understand it all, but if it works for them... */ 298 if (inb(ioaddr) == 0xFF) 299 return (0); 300 while ((rd_port() & rd_port() & rd_port() 301 & rd_port() & rd_port() & rd_port()) != 0xFF) 302 { 303 if (boguscount-- <= 0) 304 return (0); 305 } 306 for (i = 0; i < 32; i++) 307 if ((data = rd_port()) != 0xFF) 308 break; 309 if (data == 0xFF) 310 return (0); 311 if (data == SA_ADDR0 && rd_port() == SA_ADDR1 && rd_port() == SA_ADDR2) { 312 for (i = 0; i < 4; i++) 313 rd_port(); 314 if (rd_port() != NI5010_MAGICVAL1 || rd_port() != NI5010_MAGICVAL2) 315 return (0); 316 } else 317 return (0); 318 for (i = 0; i < ETH_ALEN; i++) { 319 outw(i, IE_GP); 320 nic->node_addr[i] = inb(IE_SAPROM); 321 } 322 printf("\nNI5010 ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr); 323 /* get the size of the onboard receive buffer 324 * higher addresses than bufsize are wrapped into real buffer 325 * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer 326 */ 327 if (bufsize_rcv == 0) { 328 outb(1, IE_MMODE); /* Put Rcv buffer on system bus */ 329 outw(0, IE_GP); /* Point GP at start of packet */ 330 outb(0, IE_RBUF); /* set buffer byte 0 to 0 */ 331 for (i = 1; i < 0xFF; i++) { 332 outw(i << 8, IE_GP); /* Point GP at packet size to be tested */ 333 outb(i, IE_RBUF); 334 outw(0x0, IE_GP); /* Point GP at start of packet */ 335 data = inb(IE_RBUF); 336 if (data == i) break; 337 } 338 bufsize_rcv = i << 8; 339 outw(0, IE_GP); /* Point GP at start of packet */ 340 outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */ 341 } 342 printf("Bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); 343 return (1); 344 } 345 346 /************************************************************************** 347 PROBE - Look for an adapter, this routine's visible to the outside 348 ***************************************************************************/ 349 struct nic *ni5010_probe(struct nic *nic, unsigned short *probe_addrs) 350 { 351 static unsigned short io_addrs[] = { 352 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; 353 unsigned short *p; 354 355 /* if probe_addrs is 0, then use list above */ 356 if (probe_addrs == 0 || *probe_addrs == 0) 357 probe_addrs = io_addrs; 358 for (p = probe_addrs; (ioaddr = *p) != 0; p++) { 359 if (ni5010_probe1(nic)) 360 break; 361 } 362 if (ioaddr == 0) 363 return (0); 364 ni5010_reset(nic); 365 /* point to NIC specific routines */ 366 nic->reset = ni5010_reset; 367 nic->poll = ni5010_poll; 368 nic->transmit = ni5010_transmit; 369 nic->disable = ni5010_disable; 370 return (nic); 371 } 372