dp8390.c revision 1.1.2.2 1 /* $NetBSD: dp8390.c,v 1.1.2.2 2012/10/30 17:20:31 yamt Exp $ */
2 /* Id: dp8390.c,v 1.14 2011/10/05 13:16:20 isaki Exp */
3
4 /*
5 * This file is derived from sys/arch/i386/stand/lib/netif/dp8390.c
6 * NetBSD: dp8390.c,v 1.6 2008/12/14 18:46:33 christos Exp
7 */
8
9 /*
10 * Polling driver for National Semiconductor DS8390/WD83C690 based
11 * ethernet adapters.
12 *
13 * Copyright (c) 1998 Matthias Drochner. All rights reserved.
14 *
15 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
16 *
17 * Copyright (C) 1993, David Greenman. This software may be used, modified,
18 * copied, distributed, and sold, in both source and binary form provided that
19 * the above copyright and these terms are retained. Under no circumstances is
20 * the author responsible for the proper functioning of this software, nor does
21 * the author assume any responsibility for damages incurred with its use.
22 */
23
24
25 #include <sys/types.h>
26
27 #include <lib/libsa/stand.h>
28 #include <libx68k.h>
29
30 #include <dev/ic/dp8390reg.h>
31 #include "dp8390.h"
32 #include "ne.h"
33
34 int dp8390_iobase, dp8390_membase, dp8390_memsize;
35 #if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA)
36 int dp8390_is790;
37 #endif
38 uint8_t dp8390_cr_proto;
39 uint8_t dp8390_dcr_reg;
40
41 #define WE_IOBASE dp8390_iobase
42
43 static u_short rec_page_start;
44 static u_short rec_page_stop;
45 static u_short next_packet;
46
47 extern u_char eth_myaddr[6];
48
49 static void dp8390_read(int, char *, u_short);
50
51 #define NIC_GET(reg) inb(WE_IOBASE + (reg) * 2)
52 #define NIC_PUT(reg, val) outb(WE_IOBASE + (reg) * 2, val)
53
54 static void
55 dp8390_init(void)
56 {
57 int i;
58
59 /*
60 * Initialize the NIC in the exact order outlined in the NS manual.
61 * This init procedure is "mandatory"...don't change what or when
62 * things happen.
63 */
64
65 /* Set interface for page 0, remote DMA complete, stopped. */
66 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
67
68 if ((dp8390_dcr_reg & ED_DCR_LS)) {
69 NIC_PUT(ED_P0_DCR, dp8390_dcr_reg);
70 } else {
71 /*
72 * Set FIFO threshold to 8, No auto-init Remote DMA, byte
73 * order=80x86, byte-wide DMA xfers,
74 */
75 NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
76 }
77
78 /* Clear remote byte count registers. */
79 NIC_PUT(ED_P0_RBCR0, 0);
80 NIC_PUT(ED_P0_RBCR1, 0);
81
82 /* Tell RCR to do nothing for now. */
83 NIC_PUT(ED_P0_RCR, ED_RCR_MON);
84
85 /* Place NIC in internal loopback mode. */
86 NIC_PUT(ED_P0_TCR, ED_TCR_LB0);
87
88 /* Set lower bits of byte addressable framing to 0. */
89 if (dp8390_is790)
90 NIC_PUT(0x09, 0);
91
92 /* Initialize receive buffer ring. */
93 NIC_PUT(ED_P0_BNRY, rec_page_start);
94 NIC_PUT(ED_P0_PSTART, rec_page_start);
95 NIC_PUT(ED_P0_PSTOP, rec_page_stop);
96
97 /*
98 * Clear all interrupts. A '1' in each bit position clears the
99 * corresponding flag.
100 */
101 NIC_PUT(ED_P0_ISR, 0xff);
102
103 /*
104 * Disable all interrupts.
105 */
106 NIC_PUT(ED_P0_IMR, 0);
107
108 /* Program command register for page 1. */
109 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP);
110
111 /* Copy out our station address. */
112 for (i = 0; i < 6; i++)
113 NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]);
114
115 /*
116 * Set current page pointer to one page after the boundary pointer, as
117 * recommended in the National manual.
118 */
119 next_packet = rec_page_start + 1;
120 NIC_PUT(ED_P1_CURR, next_packet);
121
122 /* Program command register for page 0. */
123 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
124
125 /* directed and broadcast */
126 NIC_PUT(ED_P0_RCR, ED_RCR_AB);
127
128 /* Take interface out of loopback. */
129 NIC_PUT(ED_P0_TCR, 0);
130
131 /* Fire up the interface. */
132 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
133 }
134
135 int
136 dp8390_config(void)
137 {
138
139 rec_page_start = TX_PAGE_START + ED_TXBUF_SIZE;
140 rec_page_stop = TX_PAGE_START + (dp8390_memsize >> ED_PAGE_SHIFT);
141
142 dp8390_init();
143
144 return 0;
145 }
146
147 void
148 dp8390_stop(void)
149 {
150 int n = 5000;
151
152 /* Stop everything on the interface, and select page 0 registers. */
153 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
154
155 /*
156 * Wait for interface to enter stopped state, but limit # of checks to
157 * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
158 * just in case it's an old one.
159 */
160 while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n)
161 continue;
162 }
163
164 int
165 EtherSend(char *pkt, int len)
166 {
167 ne2000_writemem(pkt, dp8390_membase, len);
168
169 /* Set TX buffer start page. */
170 NIC_PUT(ED_P0_TPSR, TX_PAGE_START);
171
172 /* Set TX length. */
173 NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len);
174 NIC_PUT(ED_P0_TBCR1, len >> 8);
175
176 /* Set page 0, remote DMA complete, transmit packet, and *start*. */
177 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA);
178
179 return len;
180 }
181
182 static void
183 dp8390_read(int buf, char *dest, u_short len)
184 {
185 u_short tmp_amount;
186
187 /* Does copy wrap to lower addr in ring buffer? */
188 if (buf + len > dp8390_membase + dp8390_memsize) {
189 tmp_amount = dp8390_membase + dp8390_memsize - buf;
190
191 /* Copy amount up to end of NIC memory. */
192 ne2000_readmem(buf, dest, tmp_amount);
193
194 len -= tmp_amount;
195 buf = RX_BUFBASE + (rec_page_start << ED_PAGE_SHIFT);
196 dest += tmp_amount;
197 }
198 ne2000_readmem(buf, dest, len);
199 }
200
201 int
202 EtherReceive(char *pkt, int maxlen)
203 {
204 struct dp8390_ring packet_hdr;
205 int packet_ptr;
206 u_short len;
207 u_char boundary, current;
208 #ifdef DP8390_OLDCHIPS
209 u_char nlen;
210 #endif
211
212 if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX))
213 return 0; /* XXX error handling */
214
215 /* Set NIC to page 1 registers to get 'current' pointer. */
216 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STA);
217
218 /*
219 * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
220 * it points to where new data has been buffered. The 'CURR' (current)
221 * register points to the logical end of the ring-buffer - i.e. it
222 * points to where additional new data will be added. We loop here
223 * until the logical beginning equals the logical end (or in other
224 * words, until the ring-buffer is empty).
225 */
226 current = NIC_GET(ED_P1_CURR);
227
228 /* Set NIC to page 0 registers to update boundary register. */
229 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
230
231 if (next_packet == current)
232 return 0;
233
234 /* Get pointer to this buffer's header structure. */
235 packet_ptr = RX_BUFBASE + (next_packet << ED_PAGE_SHIFT);
236
237 /*
238 * The byte count includes a 4 byte header that was added by
239 * the NIC.
240 */
241 ne2000_readmem(packet_ptr, (void *)&packet_hdr, 4);
242
243 len = le16toh(packet_hdr.count);
244
245 #ifdef DP8390_OLDCHIPS
246 /*
247 * Try do deal with old, buggy chips that sometimes duplicate
248 * the low byte of the length into the high byte. We do this
249 * by simply ignoring the high byte of the length and always
250 * recalculating it.
251 *
252 * NOTE: sc->next_packet is pointing at the current packet.
253 */
254 if (packet_hdr.next_packet >= next_packet)
255 nlen = (packet_hdr.next_packet - next_packet);
256 else
257 nlen = ((packet_hdr.next_packet - rec_page_start) +
258 (rec_page_stop - next_packet));
259 --nlen;
260 if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE)
261 --nlen;
262 len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT);
263 #ifdef DIAGNOSTIC
264 if (len != packet_hdr.count) {
265 printf(IFNAME ": length does not match next packet pointer\n");
266 printf(IFNAME ": len %04x nlen %04x start %02x "
267 "first %02x curr %02x next %02x stop %02x\n",
268 packet_hdr.count, len,
269 rec_page_start, next_packet, current,
270 packet_hdr.next_packet, rec_page_stop);
271 }
272 #endif
273 #endif
274
275 if (packet_hdr.next_packet < rec_page_start ||
276 packet_hdr.next_packet >= rec_page_stop)
277 panic(IFNAME ": RAM corrupt");
278
279 len -= sizeof(struct dp8390_ring);
280 if (len <= maxlen) {
281 /* Go get packet. */
282 dp8390_read(packet_ptr + sizeof(struct dp8390_ring),
283 pkt, len);
284 } else
285 len = 0;
286
287 /* Update next packet pointer. */
288 next_packet = packet_hdr.next_packet;
289
290 /*
291 * Update NIC boundary pointer - being careful to keep it one
292 * buffer behind (as recommended by NS databook).
293 */
294 boundary = next_packet - 1;
295 if (boundary < rec_page_start)
296 boundary = rec_page_stop - 1;
297 NIC_PUT(ED_P0_BNRY, boundary);
298
299 return len;
300 }
301