Home | History | Annotate | Line # | Download | only in altboot
fxp.c revision 1.1
      1 /* $NetBSD: fxp.c,v 1.1 2011/01/23 01:05:30 nisimura 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 (at) 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 static int fxp_mdi_read(struct local *, int, int);
    136 
    137 /*
    138  * Template for default configuration parameters.
    139  * See struct fxp_cb_config for the bit definitions.
    140  */
    141 static uint8_t fxp_cb_config_template[] = {
    142 	0x0, 0x0,		/* cb_status */
    143 	0x80, 0x2,		/* cb_command */
    144 	0xff, 0xff, 0xff, 0xff, /* link_addr */
    145 	0x16,	/*  0 */
    146 	0x8,	/*  1 */
    147 	0x0,	/*  2 */
    148 	0x0,	/*  3 */
    149 	0x0,	/*  4 */
    150 	0x80,	/*  5 */
    151 	0xb2,	/*  6 */
    152 	0x3,	/*  7 */
    153 	0x1,	/*  8 */
    154 	0x0,	/*  9 */
    155 	0x26,	/* 10 */
    156 	0x0,	/* 11 */
    157 	0x60,	/* 12 */
    158 	0x0,	/* 13 */
    159 	0xf2,	/* 14 */
    160 	0x48,	/* 15 */
    161 	0x0,	/* 16 */
    162 	0x40,	/* 17 */
    163 	0xf3,	/* 18 */
    164 	0x0,	/* 19 */
    165 	0x3f,	/* 20 */
    166 	0x5	/* 21 */
    167 };
    168 
    169 static struct fxp_cb_config store_cbc;
    170 static struct fxp_cb_ias store_cbi;
    171 
    172 int
    173 fxp_match(unsigned tag, void *data)
    174 {
    175 	unsigned v;
    176 
    177 	v = pcicfgread(tag, PCI_ID_REG);
    178 	switch (v) {
    179 	case PCI_DEVICE(0x8086, 0x1209):
    180 	case PCI_DEVICE(0x8086, 0x1229):
    181 		return 1;
    182 	}
    183 	return 0;
    184 }
    185 
    186 void *
    187 fxp_init(unsigned tag, void *data)
    188 {
    189 	struct local *sc;
    190 	uint8_t *en = data;
    191 	struct fxp_cb_config *cbp = &store_cbc;
    192 	struct fxp_cb_ias *cb_ias = &store_cbi;
    193 	struct rxdesc *rfa;
    194 	unsigned v, i;
    195 
    196 	sc = ALLOC(struct local, sizeof(struct txdesc)); /* desc alignment */
    197 	memset(sc, 0, sizeof(struct local));
    198 	sc->iobase = DEVTOV(pcicfgread(tag, 0x10)); /* use mem space */
    199 
    200 	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
    201 	DELAY(100);
    202 
    203 	autosize_eeprom(sc);
    204 	v = read_eeprom(sc, 0); en[0] = v; en[1] = v >> 8;
    205 	v = read_eeprom(sc, 1); en[2] = v; en[3] = v >> 8;
    206 	v = read_eeprom(sc, 2); en[4] = v; en[5] = v >> 8;
    207 
    208 	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x, ",
    209 		en[0], en[1], en[2], en[3], en[4], en[5]);
    210 
    211 	printf("PHY %d (%04x.%04x)\n", fxp_mdi_read(sc, 1, 18),
    212 	   fxp_mdi_read(sc, 1, 2), fxp_mdi_read(sc, 1, 3));
    213 
    214 	/*
    215 	 * Initialize base of CBL and RFA memory. Loading with zero
    216 	 * sets it up for regular linear addressing.
    217 	 */
    218 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
    219 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
    220 
    221 	fxp_scb_wait(sc);
    222 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
    223 
    224 	/*
    225 	 * This memcpy is kind of disgusting, but there are a bunch of must be
    226 	 * zero and must be one bits in this structure and this is the easiest
    227 	 * way to initialize them all to proper values.
    228 	 */
    229 	memcpy(cbp, fxp_cb_config_template, sizeof(fxp_cb_config_template));
    230 
    231 #define prm 0
    232 #define phy_10Mbps_only 0
    233 #define all_mcasts 0
    234 	cbp->cb_status =	0;
    235 	cbp->cb_command =	htole16(FXP_CB_COMMAND_CONFIG |
    236 				    FXP_CB_COMMAND_EL);
    237 	cbp->link_addr =	-1;	/* (no) next command */
    238 	cbp->byte_count =	22;	/* (22) bytes to config */
    239 	cbp->rx_fifo_limit =	8;	/* rx fifo threshold (32 bytes) */
    240 	cbp->tx_fifo_limit =	0;	/* tx fifo threshold (0 bytes) */
    241 	cbp->adaptive_ifs =	0;	/* (no) adaptive interframe spacing */
    242 	cbp->rx_dma_bytecount = 0;	/* (no) rx DMA max */
    243 	cbp->tx_dma_bytecount = 0;	/* (no) tx DMA max */
    244 	cbp->dma_mbce =		0;	/* (disable) dma max counters */
    245 	cbp->late_scb =		0;	/* (don't) defer SCB update */
    246 	cbp->tno_int_or_tco_en = 0;	/* (disable) tx not okay interrupt */
    247 	cbp->ci_int =		0;	/* interrupt on CU not active */
    248 	cbp->save_bf =		prm;	/* save bad frames */
    249 	cbp->disc_short_rx =	!prm;	/* discard short packets */
    250 	cbp->underrun_retry =	1;	/* retry mode (1) on DMA underrun */
    251 	cbp->mediatype =	!phy_10Mbps_only; /* interface mode */
    252 	cbp->nsai =		1;     /* (don't) disable source addr insert */
    253 	cbp->preamble_length =	2;	/* (7 byte) preamble */
    254 	cbp->loopback =		0;	/* (don't) loopback */
    255 	cbp->linear_priority =	0;	/* (normal CSMA/CD operation) */
    256 	cbp->linear_pri_mode =	0;	/* (wait after xmit only) */
    257 	cbp->interfrm_spacing = 6;	/* (96 bits of) interframe spacing */
    258 	cbp->promiscuous =	prm;	/* promiscuous mode */
    259 	cbp->bcast_disable =	0;	/* (don't) disable broadcasts */
    260 	cbp->crscdt =		0;	/* (CRS only) */
    261 	cbp->stripping =	!prm;	/* truncate rx packet to byte count */
    262 	cbp->padding =		1;	/* (do) pad short tx packets */
    263 	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */
    264 	cbp->force_fdx =	0;	/* (don't) force full duplex */
    265 	cbp->fdx_pin_en =	1;	/* (enable) FDX# pin */
    266 	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */
    267 	cbp->mc_all =		all_mcasts;/* accept all multicasts */
    268 #undef prm
    269 #undef phy_10Mbps_only
    270 #undef all_mcasts
    271 
    272 	wbinv(cbp, sizeof(*cbp));
    273 	fxp_scb_wait(sc);
    274 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(cbp));
    275 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
    276 	i = 1000;
    277 	while (!(le16toh(cbp->cb_status) & FXP_CB_STATUS_C) && --i > 0) {
    278 		DELAY(1);
    279 		inv(&cbp->cb_status, sizeof(cbp->cb_status));
    280 	}
    281 	if (i == 0)
    282 		printf("cbp config timeout\n");
    283 
    284 	/*
    285 	 * Initialize the station address.
    286 	 */
    287 	cb_ias->cb_status = 0;
    288 	cb_ias->cb_command = htole16(FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL);
    289 	cb_ias->link_addr = -1;
    290 	memcpy(cb_ias->macaddr, en, 6);
    291 
    292 	/*
    293 	 * Start the IAS (Individual Address Setup) command/DMA.
    294 	 */
    295 	wbinv(cb_ias, sizeof(*cb_ias));
    296 	fxp_scb_wait(sc);
    297 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(cb_ias));
    298 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
    299 
    300 	i = 1000;
    301 	while (!(le16toh(cb_ias->cb_status) & FXP_CB_STATUS_C) && --i > 0) {
    302 		DELAY(1);
    303 		inv(&cb_ias->cb_status, sizeof(cb_ias->cb_status));
    304 	}
    305 	if (i == 0)
    306 		printf("ias config timeout\n");
    307 
    308 	rfa = (struct rxdesc *)sc->store;
    309 	rfa->rfa_status = 0;
    310 	rfa->rfa_control = htole16(FXP_RFA_CONTROL_S);
    311 	rfa->link_addr = htole32(VTOPHYS(rfa));
    312 	rfa->rbd_addr = -1;
    313 	rfa->actual_size = 0;
    314 	rfa->size = htole16(sizeof(sc->store) - sizeof(struct rxdesc));
    315 	wbinv(rfa, sizeof(sc->store));
    316 
    317 	fxp_scb_wait(sc);
    318 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(rfa));
    319 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
    320 
    321 	return sc;
    322 }
    323 
    324 int
    325 fxp_send(void *dev, char *buf, unsigned len)
    326 {
    327 	struct local *l = dev;
    328 	struct txdesc *txd;
    329 	int loop;
    330 
    331 	if (len > 1520)
    332 		printf("fxp_send: len > 1520 (%u)\n", len);
    333 
    334 	txd = &l->txd;
    335 	txd->cb_status = 0;
    336 	txd->cb_command =
    337 	    htole16(FXP_CB_COMMAND_XMIT|FXP_CB_COMMAND_SF|FXP_CB_COMMAND_EL);
    338 	txd->link_addr = -1;
    339 	txd->tbd_array_addr = htole32(VTOPHYS(&txd->tx_buf_addr0));
    340 	txd->tx_buf_addr0 = htole32(VTOPHYS(buf));
    341 	txd->tx_buf_size0 = htole32(len);
    342 	txd->byte_count = htole16(0x8000);
    343 	txd->tx_threshold = 0x20;
    344 	txd->tbd_number = 1;
    345 	wbinv(buf, len);
    346 	wbinv(txd, sizeof(*txd));
    347 
    348 	fxp_scb_wait(l);
    349 	CSR_WRITE_4(l, FXP_CSR_SCB_GENERAL, VTOPHYS(txd));
    350 	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
    351 
    352 	loop = 10000;
    353 	while (!(le16toh(txd->cb_status) & FXP_CB_STATUS_C) && --loop > 0) {
    354 		DELAY(1);
    355 		inv(txd, sizeof(struct txdesc));
    356 	}
    357 	if (loop == 0)
    358 		printf("send timeout\n");
    359 
    360 	return len;
    361 }
    362 
    363 int
    364 fxp_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
    365 {
    366 	struct local *l = dev;
    367 	struct rxdesc *rfa;
    368 	unsigned bound, ruscus, len;
    369 
    370 	fxp_scb_wait(l);
    371 	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);
    372 
    373 	bound = 1000 * timo;
    374 	do {
    375 		ruscus = CSR_READ_1(l, FXP_CSR_SCB_RUSCUS);
    376 		if (((ruscus >> 2) & 0x0f) != FXP_SCB_RUS_READY
    377 		    && (((ruscus >> 2) & 0x0f) == FXP_SCB_RUS_SUSPENDED))
    378 			goto gotone;
    379 		DELAY(1000);	/* 1 milli second */
    380 	} while (--bound > 0);
    381 	errno = 0;
    382 	return -1;
    383   gotone:
    384 	rfa = (struct rxdesc *)l->store;
    385 	inv(rfa, sizeof(l->store)); /* whole including received frame */
    386 	if ((le16toh(rfa->rfa_status) & FXP_RFA_STATUS_C) == 0)
    387 		return 0;
    388 	len = le16toh(rfa->actual_size) & 0x7ff;
    389 	if (len > maxlen)
    390 		len = maxlen;
    391 	memcpy(buf, &l->store[sizeof(struct rxdesc)], len);
    392 
    393 	rfa->rfa_status = 0;
    394 	rfa->rfa_control = htole16(FXP_RFA_CONTROL_S);
    395 	rfa->actual_size = 0;
    396 	wbinv(rfa, sizeof(struct rxdesc));
    397 #if 0
    398 	fxp_scb_wait(l);
    399 	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);
    400 #endif
    401 	return len;
    402 }
    403 
    404 static void
    405 eeprom_shiftin(struct local *sc, int data, int len)
    406 {
    407 	uint16_t reg;
    408 	int x;
    409 
    410 	for (x = 1 << (len - 1); x != 0; x >>= 1) {
    411 		DELAY(40);
    412 		if (data & x)
    413 			reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
    414 		else
    415 			reg = FXP_EEPROM_EECS;
    416 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
    417 		DELAY(40);
    418 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
    419 		    reg | FXP_EEPROM_EESK);
    420 		DELAY(40);
    421 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
    422 	}
    423 	DELAY(40);
    424 }
    425 
    426 void
    427 autosize_eeprom(struct local *sc)
    428 {
    429 	int x;
    430 
    431 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
    432 	DELAY(40);
    433 
    434 	/* Shift in read opcode. */
    435 	eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);
    436 
    437 	/*
    438 	 * Shift in address, wait for the dummy zero following a correct
    439 	 * address shift.
    440 	 */
    441 	for (x = 1; x <= 8; x++) {
    442 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
    443 		DELAY(40);
    444 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
    445 		    FXP_EEPROM_EECS | FXP_EEPROM_EESK);
    446 		DELAY(40);
    447 		if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
    448 		    FXP_EEPROM_EEDO) == 0)
    449 			break;
    450 		DELAY(40);
    451 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
    452 		DELAY(40);
    453 	}
    454 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
    455 	DELAY(40);
    456 	if (x != 6 && x != 8)
    457 		printf("fxp: strange EEPROM address size (%d)\n", x);
    458 	else
    459 		sc->eeprom_addr = x;
    460 }
    461 
    462 static int
    463 read_eeprom(struct local *sc, int offset)
    464 {
    465 	uint16_t reg;
    466 	int x, val;
    467 
    468 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
    469 
    470 	/* Shift in read opcode. */
    471 	eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);
    472 
    473 	/* Shift in address. */
    474 	eeprom_shiftin(sc, offset, sc->eeprom_addr);
    475 
    476 	reg = FXP_EEPROM_EECS;
    477 	val = 0;
    478 	/*
    479 	 * Shift out data.
    480 	 */
    481 	for (x = 16; x > 0; x--) {
    482 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
    483 		    reg | FXP_EEPROM_EESK);
    484 		DELAY(1);
    485 		if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
    486 		    FXP_EEPROM_EEDO)
    487 			val |= (1 << (x - 1));
    488 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
    489 		DELAY(1);
    490 	}
    491 	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
    492 	DELAY(1);
    493 
    494 	return val;
    495 }
    496 
    497 static void
    498 fxp_scb_wait(struct local *sc)
    499 {
    500 	int loop = 5000;
    501 
    502 	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --loop > 0)
    503 		DELAY(2);
    504 	if (loop == 0)
    505 		printf("SCB timeout\n");
    506 }
    507 
    508 static int
    509 fxp_mdi_read(struct local *sc, int phy, int reg)
    510 {
    511 	int count = 10000;
    512 	int value;
    513 
    514 	CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
    515 	    (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
    516 
    517 	while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) &
    518 	    0x10000000) == 0 && count--)
    519 		DELAY(10);
    520 
    521 	if (count <= 0)
    522 		printf("fxp_mdi_read: timed out\n");
    523 
    524 	return (value & 0xffff);
    525 }
    526