Home | History | Annotate | Download | only in netboot
      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