xref: /netbsd/sys/arch/sandpoint/stand/altboot/fxp.c (revision 6550d01e)
1 /* $NetBSD: fxp.c,v 1.2 2011/01/27 17:38:04 phx Exp $ */
2 
3 /*
4  * most of the following code was imported from dev/ic/i82557.c; the
5  * original copyright notice is as below.
6  */
7 
8 /*-
9  * Copyright (c) 1997, 1998, 1999, 2001, 2002 The NetBSD Foundation, Inc.
10  * All rights reserved.
11  *
12  * This code is derived from software contributed to The NetBSD Foundation
13  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
14  * NASA Ames Research Center.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Copyright (c) 1995, David Greenman
40  * Copyright (c) 2001 Jonathan Lemon <jlemon@freebsd.org>
41  * All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice unmodified, this list of conditions, and the following
48  *    disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *	Id: if_fxp.c,v 1.113 2001/05/17 23:50:24 jlemon
66  */
67 
68 #include <sys/param.h>
69 
70 #include <netinet/in.h>
71 #include <netinet/in_systm.h>
72 
73 #include <lib/libsa/stand.h>
74 #include <lib/libsa/net.h>
75 
76 #include <dev/ic/i82557reg.h>
77 
78 #include "globals.h"
79 
80 #define FRAMESIZE 1536
81 
82 /*
83  * 82559ER 8086.1209/1229
84  *
85  * - reverse endian access for 16bit/32bit register.
86  * - no vtophys() translation, vaddr_t == paddr_t.
87  * - PIPT writeback cache aware.
88  */
89 #define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->iobase+(r)) = (v)
90 #define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->iobase+(r))
91 #define CSR_WRITE_2(l, r, v)	out16rb((l)->iobase+(r), (v))
92 #define CSR_READ_2(l, r)	in16rb((l)->iobase+(r))
93 #define CSR_WRITE_4(l, r, v) 	out32rb((l)->iobase+(r), (v))
94 #define CSR_READ_4(l, r)	in32rb((l)->iobase+(r))
95 #define VTOPHYS(va) 		(uint32_t)(va)
96 #define DEVTOV(pa) 		(uint32_t)(pa)
97 #define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
98 #define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
99 #define DELAY(n)		delay(n)
100 #define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))
101 
102 struct txdesc {
103 	volatile uint16_t cb_status;
104 	volatile uint16_t cb_command;
105 	volatile uint32_t link_addr;
106 	volatile uint32_t tbd_array_addr;
107 	volatile uint16_t byte_count;
108 	volatile uint8_t tx_threshold;
109 	volatile uint8_t tbd_number;
110 	volatile uint32_t tx_buf_addr0;
111 	volatile uint32_t tx_buf_size0;
112 	volatile uint32_t tx_buf_addr1;
113 	volatile uint32_t tx_buf_size1;
114 }; /* mimic extended TxCB layout */
115 
116 struct rxdesc {
117 	volatile uint16_t rfa_status;
118 	volatile uint16_t rfa_control;
119 	volatile uint32_t link_addr;
120 	volatile uint32_t rbd_addr;
121 	volatile uint16_t actual_size;
122 	volatile uint16_t size;
123 }; /* 16B rfa */
124 
125 struct local {
126 	struct txdesc txd;
127 	uint8_t store[sizeof(struct rxdesc) + FRAMESIZE];
128 	unsigned iobase;
129 	unsigned eeprom_addr;
130 };
131 
132 static void autosize_eeprom(struct local *);
133 static int read_eeprom(struct local *, int);
134 static void fxp_scb_wait(struct local *);
135 #ifdef DEBUG
136 static int fxp_mdi_read(struct local *, int, int);
137 #endif
138 
139 /*
140  * Template for default configuration parameters.
141  * See struct fxp_cb_config for the bit definitions.
142  */
143 static uint8_t fxp_cb_config_template[] = {
144 	0x0, 0x0,		/* cb_status */
145 	0x80, 0x2,		/* cb_command */
146 	0xff, 0xff, 0xff, 0xff, /* link_addr */
147 	0x16,	/*  0 */
148 	0x8,	/*  1 */
149 	0x0,	/*  2 */
150 	0x0,	/*  3 */
151 	0x0,	/*  4 */
152 	0x80,	/*  5 */
153 	0xb2,	/*  6 */
154 	0x3,	/*  7 */
155 	0x1,	/*  8 */
156 	0x0,	/*  9 */
157 	0x26,	/* 10 */
158 	0x0,	/* 11 */
159 	0x60,	/* 12 */
160 	0x0,	/* 13 */
161 	0xf2,	/* 14 */
162 	0x48,	/* 15 */
163 	0x0,	/* 16 */
164 	0x40,	/* 17 */
165 	0xf3,	/* 18 */
166 	0x0,	/* 19 */
167 	0x3f,	/* 20 */
168 	0x5	/* 21 */
169 };
170 
171 static struct fxp_cb_config store_cbc;
172 static struct fxp_cb_ias store_cbi;
173 
174 int
175 fxp_match(unsigned tag, void *data)
176 {
177 	unsigned v;
178 
179 	v = pcicfgread(tag, PCI_ID_REG);
180 	switch (v) {
181 	case PCI_DEVICE(0x8086, 0x1209):
182 	case PCI_DEVICE(0x8086, 0x1229):
183 		return 1;
184 	}
185 	return 0;
186 }
187 
188 void *
189 fxp_init(unsigned tag, void *data)
190 {
191 	struct local *sc;
192 	uint8_t *en = data;
193 	struct fxp_cb_config *cbp = &store_cbc;
194 	struct fxp_cb_ias *cb_ias = &store_cbi;
195 	struct rxdesc *rfa;
196 	unsigned v, i;
197 
198 	sc = ALLOC(struct local, sizeof(struct txdesc)); /* desc alignment */
199 	memset(sc, 0, sizeof(struct local));
200 	sc->iobase = DEVTOV(pcicfgread(tag, 0x10)); /* use mem space */
201 
202 	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
203 	DELAY(100);
204 
205 	autosize_eeprom(sc);
206 	v = read_eeprom(sc, 0); en[0] = v; en[1] = v >> 8;
207 	v = read_eeprom(sc, 1); en[2] = v; en[3] = v >> 8;
208 	v = read_eeprom(sc, 2); en[4] = v; en[5] = v >> 8;
209 
210 	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x, ",
211 		en[0], en[1], en[2], en[3], en[4], en[5]);
212 
213 	DPRINTF(("PHY %d (%04x.%04x)\n", fxp_mdi_read(sc, 1, 18),
214 	   fxp_mdi_read(sc, 1, 2), fxp_mdi_read(sc, 1, 3)));
215 
216 	/*
217 	 * Initialize base of CBL and RFA memory. Loading with zero
218 	 * sets it up for regular linear addressing.
219 	 */
220 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
221 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
222 
223 	fxp_scb_wait(sc);
224 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
225 
226 	/*
227 	 * This memcpy is kind of disgusting, but there are a bunch of must be
228 	 * zero and must be one bits in this structure and this is the easiest
229 	 * way to initialize them all to proper values.
230 	 */
231 	memcpy(cbp, fxp_cb_config_template, sizeof(fxp_cb_config_template));
232 
233 #define prm 0
234 #define phy_10Mbps_only 0
235 #define all_mcasts 0
236 	cbp->cb_status =	0;
237 	cbp->cb_command =	htole16(FXP_CB_COMMAND_CONFIG |
238 				    FXP_CB_COMMAND_EL);
239 	cbp->link_addr =	-1;	/* (no) next command */
240 	cbp->byte_count =	22;	/* (22) bytes to config */
241 	cbp->rx_fifo_limit =	8;	/* rx fifo threshold (32 bytes) */
242 	cbp->tx_fifo_limit =	0;	/* tx fifo threshold (0 bytes) */
243 	cbp->adaptive_ifs =	0;	/* (no) adaptive interframe spacing */
244 	cbp->rx_dma_bytecount = 0;	/* (no) rx DMA max */
245 	cbp->tx_dma_bytecount = 0;	/* (no) tx DMA max */
246 	cbp->dma_mbce =		0;	/* (disable) dma max counters */
247 	cbp->late_scb =		0;	/* (don't) defer SCB update */
248 	cbp->tno_int_or_tco_en = 0;	/* (disable) tx not okay interrupt */
249 	cbp->ci_int =		0;	/* interrupt on CU not active */
250 	cbp->save_bf =		prm;	/* save bad frames */
251 	cbp->disc_short_rx =	!prm;	/* discard short packets */
252 	cbp->underrun_retry =	1;	/* retry mode (1) on DMA underrun */
253 	cbp->mediatype =	!phy_10Mbps_only; /* interface mode */
254 	cbp->nsai =		1;     /* (don't) disable source addr insert */
255 	cbp->preamble_length =	2;	/* (7 byte) preamble */
256 	cbp->loopback =		0;	/* (don't) loopback */
257 	cbp->linear_priority =	0;	/* (normal CSMA/CD operation) */
258 	cbp->linear_pri_mode =	0;	/* (wait after xmit only) */
259 	cbp->interfrm_spacing = 6;	/* (96 bits of) interframe spacing */
260 	cbp->promiscuous =	prm;	/* promiscuous mode */
261 	cbp->bcast_disable =	0;	/* (don't) disable broadcasts */
262 	cbp->crscdt =		0;	/* (CRS only) */
263 	cbp->stripping =	!prm;	/* truncate rx packet to byte count */
264 	cbp->padding =		1;	/* (do) pad short tx packets */
265 	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */
266 	cbp->force_fdx =	0;	/* (don't) force full duplex */
267 	cbp->fdx_pin_en =	1;	/* (enable) FDX# pin */
268 	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */
269 	cbp->mc_all =		all_mcasts;/* accept all multicasts */
270 #undef prm
271 #undef phy_10Mbps_only
272 #undef all_mcasts
273 
274 	wbinv(cbp, sizeof(*cbp));
275 	fxp_scb_wait(sc);
276 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(cbp));
277 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
278 	i = 1000;
279 	while (!(le16toh(cbp->cb_status) & FXP_CB_STATUS_C) && --i > 0) {
280 		DELAY(1);
281 		inv(&cbp->cb_status, sizeof(cbp->cb_status));
282 	}
283 	if (i == 0)
284 		printf("cbp config timeout\n");
285 
286 	/*
287 	 * Initialize the station address.
288 	 */
289 	cb_ias->cb_status = 0;
290 	cb_ias->cb_command = htole16(FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL);
291 	cb_ias->link_addr = -1;
292 	memcpy(cb_ias->macaddr, en, 6);
293 
294 	/*
295 	 * Start the IAS (Individual Address Setup) command/DMA.
296 	 */
297 	wbinv(cb_ias, sizeof(*cb_ias));
298 	fxp_scb_wait(sc);
299 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(cb_ias));
300 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
301 
302 	i = 1000;
303 	while (!(le16toh(cb_ias->cb_status) & FXP_CB_STATUS_C) && --i > 0) {
304 		DELAY(1);
305 		inv(&cb_ias->cb_status, sizeof(cb_ias->cb_status));
306 	}
307 	if (i == 0)
308 		printf("ias config timeout\n");
309 
310 	rfa = (struct rxdesc *)sc->store;
311 	rfa->rfa_status = 0;
312 	rfa->rfa_control = htole16(FXP_RFA_CONTROL_S);
313 	rfa->link_addr = htole32(VTOPHYS(rfa));
314 	rfa->rbd_addr = -1;
315 	rfa->actual_size = 0;
316 	rfa->size = htole16(sizeof(sc->store) - sizeof(struct rxdesc));
317 	wbinv(rfa, sizeof(sc->store));
318 
319 	fxp_scb_wait(sc);
320 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(rfa));
321 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
322 
323 	return sc;
324 }
325 
326 int
327 fxp_send(void *dev, char *buf, unsigned len)
328 {
329 	struct local *l = dev;
330 	struct txdesc *txd;
331 	int loop;
332 
333 	if (len > 1520)
334 		printf("fxp_send: len > 1520 (%u)\n", len);
335 
336 	txd = &l->txd;
337 	txd->cb_status = 0;
338 	txd->cb_command =
339 	    htole16(FXP_CB_COMMAND_XMIT|FXP_CB_COMMAND_SF|FXP_CB_COMMAND_EL);
340 	txd->link_addr = -1;
341 	txd->tbd_array_addr = htole32(VTOPHYS(&txd->tx_buf_addr0));
342 	txd->tx_buf_addr0 = htole32(VTOPHYS(buf));
343 	txd->tx_buf_size0 = htole32(len);
344 	txd->byte_count = htole16(0x8000);
345 	txd->tx_threshold = 0x20;
346 	txd->tbd_number = 1;
347 	wbinv(buf, len);
348 	wbinv(txd, sizeof(*txd));
349 
350 	fxp_scb_wait(l);
351 	CSR_WRITE_4(l, FXP_CSR_SCB_GENERAL, VTOPHYS(txd));
352 	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
353 
354 	loop = 10000;
355 	while (!(le16toh(txd->cb_status) & FXP_CB_STATUS_C) && --loop > 0) {
356 		DELAY(1);
357 		inv(txd, sizeof(struct txdesc));
358 	}
359 	if (loop == 0)
360 		printf("send timeout\n");
361 
362 	return len;
363 }
364 
365 int
366 fxp_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
367 {
368 	struct local *l = dev;
369 	struct rxdesc *rfa;
370 	unsigned bound, ruscus, len;
371 
372 	fxp_scb_wait(l);
373 	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);
374 
375 	bound = 1000 * timo;
376 	do {
377 		ruscus = CSR_READ_1(l, FXP_CSR_SCB_RUSCUS);
378 		if (((ruscus >> 2) & 0x0f) != FXP_SCB_RUS_READY
379 		    && (((ruscus >> 2) & 0x0f) == FXP_SCB_RUS_SUSPENDED))
380 			goto gotone;
381 		DELAY(1000);	/* 1 milli second */
382 	} while (--bound > 0);
383 	errno = 0;
384 	return -1;
385   gotone:
386 	rfa = (struct rxdesc *)l->store;
387 	inv(rfa, sizeof(l->store)); /* whole including received frame */
388 	if ((le16toh(rfa->rfa_status) & FXP_RFA_STATUS_C) == 0)
389 		return 0;
390 	len = le16toh(rfa->actual_size) & 0x7ff;
391 	if (len > maxlen)
392 		len = maxlen;
393 	memcpy(buf, &l->store[sizeof(struct rxdesc)], len);
394 
395 	rfa->rfa_status = 0;
396 	rfa->rfa_control = htole16(FXP_RFA_CONTROL_S);
397 	rfa->actual_size = 0;
398 	wbinv(rfa, sizeof(struct rxdesc));
399 #if 0
400 	fxp_scb_wait(l);
401 	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);
402 #endif
403 	return len;
404 }
405 
406 static void
407 eeprom_shiftin(struct local *sc, int data, int len)
408 {
409 	uint16_t reg;
410 	int x;
411 
412 	for (x = 1 << (len - 1); x != 0; x >>= 1) {
413 		DELAY(40);
414 		if (data & x)
415 			reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
416 		else
417 			reg = FXP_EEPROM_EECS;
418 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
419 		DELAY(40);
420 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
421 		    reg | FXP_EEPROM_EESK);
422 		DELAY(40);
423 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
424 	}
425 	DELAY(40);
426 }
427 
428 void
429 autosize_eeprom(struct local *sc)
430 {
431 	int x;
432 
433 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
434 	DELAY(40);
435 
436 	/* Shift in read opcode. */
437 	eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);
438 
439 	/*
440 	 * Shift in address, wait for the dummy zero following a correct
441 	 * address shift.
442 	 */
443 	for (x = 1; x <= 8; x++) {
444 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
445 		DELAY(40);
446 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
447 		    FXP_EEPROM_EECS | FXP_EEPROM_EESK);
448 		DELAY(40);
449 		if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
450 		    FXP_EEPROM_EEDO) == 0)
451 			break;
452 		DELAY(40);
453 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
454 		DELAY(40);
455 	}
456 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
457 	DELAY(40);
458 	if (x != 6 && x != 8)
459 		printf("fxp: strange EEPROM address size (%d)\n", x);
460 	else
461 		sc->eeprom_addr = x;
462 }
463 
464 static int
465 read_eeprom(struct local *sc, int offset)
466 {
467 	uint16_t reg;
468 	int x, val;
469 
470 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
471 
472 	/* Shift in read opcode. */
473 	eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);
474 
475 	/* Shift in address. */
476 	eeprom_shiftin(sc, offset, sc->eeprom_addr);
477 
478 	reg = FXP_EEPROM_EECS;
479 	val = 0;
480 	/*
481 	 * Shift out data.
482 	 */
483 	for (x = 16; x > 0; x--) {
484 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
485 		    reg | FXP_EEPROM_EESK);
486 		DELAY(1);
487 		if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
488 		    FXP_EEPROM_EEDO)
489 			val |= (1 << (x - 1));
490 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
491 		DELAY(1);
492 	}
493 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
494 	DELAY(1);
495 
496 	return val;
497 }
498 
499 static void
500 fxp_scb_wait(struct local *sc)
501 {
502 	int loop = 5000;
503 
504 	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --loop > 0)
505 		DELAY(2);
506 	if (loop == 0)
507 		printf("SCB timeout\n");
508 }
509 
510 #ifdef DEBUG
511 static int
512 fxp_mdi_read(struct local *sc, int phy, int reg)
513 {
514 	int count = 10000;
515 	int value;
516 
517 	CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
518 	    (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
519 
520 	while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) &
521 	    0x10000000) == 0 && count--)
522 		DELAY(10);
523 
524 	if (count <= 0)
525 		printf("fxp_mdi_read: timed out\n");
526 
527 	return (value & 0xffff);
528 }
529 #endif
530