xref: /minix3/minix/drivers/net/fxp/fxp.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*
2*433d6423SLionel Sambuc  * fxp.c
3*433d6423SLionel Sambuc  *
4*433d6423SLionel Sambuc  * This file contains an ethernet device driver for Intel 82557, 82558,
5*433d6423SLionel Sambuc  * 82559, 82550, and 82562 fast ethernet controllers.
6*433d6423SLionel Sambuc  *
7*433d6423SLionel Sambuc  * Created:	Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
8*433d6423SLionel Sambuc  */
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc #include <minix/drivers.h>
11*433d6423SLionel Sambuc #include <minix/netdriver.h>
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc #include <stdlib.h>
14*433d6423SLionel Sambuc #include <net/hton.h>
15*433d6423SLionel Sambuc #include <net/gen/ether.h>
16*433d6423SLionel Sambuc #include <net/gen/eth_io.h>
17*433d6423SLionel Sambuc #include <machine/pci.h>
18*433d6423SLionel Sambuc #include <minix/ds.h>
19*433d6423SLionel Sambuc #include <minix/endpoint.h>
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc #include <minix/timers.h>
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc #define debug			0
24*433d6423SLionel Sambuc #define RAND_UPDATE		/**/
25*433d6423SLionel Sambuc #define printW()		((void)0)
26*433d6423SLionel Sambuc 
27*433d6423SLionel Sambuc #include "assert.h"
28*433d6423SLionel Sambuc #include "fxp.h"
29*433d6423SLionel Sambuc #include "mii.h"
30*433d6423SLionel Sambuc 
31*433d6423SLionel Sambuc /* Number of receive buffers */
32*433d6423SLionel Sambuc #define N_RX_BUF	40
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc /* Number of transmit buffers */
35*433d6423SLionel Sambuc #define N_TX_BUF	4
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc /* I/O vectors are handled IOVEC_NR entries at a time. */
38*433d6423SLionel Sambuc #define IOVEC_NR	16
39*433d6423SLionel Sambuc 
40*433d6423SLionel Sambuc /* Configuration */
41*433d6423SLionel Sambuc #define FXP_ENVVAR	"FXPETH"
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc typedef int irq_hook_t;
44*433d6423SLionel Sambuc 
45*433d6423SLionel Sambuc /* ignore interrupt for the moment */
46*433d6423SLionel Sambuc #define interrupt(x)	do { } while(0)
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc static union tmpbuf
49*433d6423SLionel Sambuc {
50*433d6423SLionel Sambuc 	char pad[4096];
51*433d6423SLionel Sambuc 	struct cbl_conf cc;
52*433d6423SLionel Sambuc 	struct ias ias;
53*433d6423SLionel Sambuc } *tmpbufp;
54*433d6423SLionel Sambuc 
55*433d6423SLionel Sambuc typedef struct fxp
56*433d6423SLionel Sambuc {
57*433d6423SLionel Sambuc 	port_t fxp_base_port;
58*433d6423SLionel Sambuc 	int fxp_mode;
59*433d6423SLionel Sambuc 	int fxp_got_int;
60*433d6423SLionel Sambuc 	int fxp_send_int;
61*433d6423SLionel Sambuc 	int fxp_flags;
62*433d6423SLionel Sambuc 	int fxp_client;
63*433d6423SLionel Sambuc 	int fxp_features;		/* Needed? */
64*433d6423SLionel Sambuc 	int fxp_irq;
65*433d6423SLionel Sambuc 	int fxp_type;			/* What kind of hardware */
66*433d6423SLionel Sambuc 	int fxp_ms_regs;		/* Master/slave registers */
67*433d6423SLionel Sambuc 	int fxp_ee_addrlen;		/* #EEPROM address bits */
68*433d6423SLionel Sambuc 	int fxp_tx_alive;
69*433d6423SLionel Sambuc 	int fxp_need_reset;
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc 	/* Rx */
72*433d6423SLionel Sambuc 	vir_bytes fxp_read_s;
73*433d6423SLionel Sambuc 	int fxp_rx_nbuf;
74*433d6423SLionel Sambuc 	int fxp_rx_bufsize;
75*433d6423SLionel Sambuc 	struct rfd *fxp_rx_buf;
76*433d6423SLionel Sambuc 	phys_bytes fxp_rx_busaddr;
77*433d6423SLionel Sambuc 	int fxp_rx_head;
78*433d6423SLionel Sambuc 	int fxp_rx_need_restart;
79*433d6423SLionel Sambuc 	int fxp_need_conf;		/* Re-configure after draining send
80*433d6423SLionel Sambuc 					 * queue
81*433d6423SLionel Sambuc 					 */
82*433d6423SLionel Sambuc 
83*433d6423SLionel Sambuc 	/* Tx */
84*433d6423SLionel Sambuc 	int fxp_tx_nbuf;
85*433d6423SLionel Sambuc 	int fxp_tx_bufsize;
86*433d6423SLionel Sambuc 	struct tx *fxp_tx_buf;
87*433d6423SLionel Sambuc 	phys_bytes fxp_tx_busaddr;
88*433d6423SLionel Sambuc 	int fxp_tx_idle;
89*433d6423SLionel Sambuc 	int fxp_tx_head;
90*433d6423SLionel Sambuc 	int fxp_tx_tail;
91*433d6423SLionel Sambuc 	int fxp_tx_threshold;
92*433d6423SLionel Sambuc 
93*433d6423SLionel Sambuc 	/* Link status */
94*433d6423SLionel Sambuc 	int fxp_report_link;
95*433d6423SLionel Sambuc 	int fxp_link_up;
96*433d6423SLionel Sambuc 	int fxp_mii_busy;
97*433d6423SLionel Sambuc 	u16_t fxp_mii_scr;
98*433d6423SLionel Sambuc 
99*433d6423SLionel Sambuc 	/* PCI related */
100*433d6423SLionel Sambuc 	int fxp_seen;			/* TRUE iff device available */
101*433d6423SLionel Sambuc 
102*433d6423SLionel Sambuc 	/* 'large' items */
103*433d6423SLionel Sambuc 	irq_hook_t fxp_hook;
104*433d6423SLionel Sambuc 	ether_addr_t fxp_address;
105*433d6423SLionel Sambuc 	message fxp_rx_mess;
106*433d6423SLionel Sambuc 	message fxp_tx_mess;
107*433d6423SLionel Sambuc 	struct sc fxp_stat;
108*433d6423SLionel Sambuc 	u8_t fxp_conf_bytes[CC_BYTES_NR];
109*433d6423SLionel Sambuc 	char fxp_name[sizeof("fxp#n")];
110*433d6423SLionel Sambuc 	iovec_t fxp_iovec[IOVEC_NR];
111*433d6423SLionel Sambuc 	iovec_s_t fxp_iovec_s[IOVEC_NR];
112*433d6423SLionel Sambuc }
113*433d6423SLionel Sambuc fxp_t;
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc /* fxp_mode */
116*433d6423SLionel Sambuc #define FM_DISABLED	0x0
117*433d6423SLionel Sambuc #define FM_ENABLED	0x1
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc /* fxp_flags */
120*433d6423SLionel Sambuc #define FF_EMPTY	0x000
121*433d6423SLionel Sambuc #define FF_PACK_SENT	0x001
122*433d6423SLionel Sambuc #define FF_PACK_RECV	0x002
123*433d6423SLionel Sambuc #define FF_SEND_AVAIL	0x004
124*433d6423SLionel Sambuc #define FF_READING	0x010
125*433d6423SLionel Sambuc #define FF_PROMISC	0x040
126*433d6423SLionel Sambuc #define FF_MULTI	0x080
127*433d6423SLionel Sambuc #define FF_BROAD	0x100
128*433d6423SLionel Sambuc #define FF_ENABLED	0x200
129*433d6423SLionel Sambuc 
130*433d6423SLionel Sambuc /* fxp_features */
131*433d6423SLionel Sambuc #define FFE_NONE	0x0
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc /* fxp_type */
134*433d6423SLionel Sambuc #define FT_UNKNOWN	0x0
135*433d6423SLionel Sambuc #define FT_82557	0x1
136*433d6423SLionel Sambuc #define FT_82558A	0x2
137*433d6423SLionel Sambuc #define FT_82559	0x4
138*433d6423SLionel Sambuc #define FT_82801	0x8
139*433d6423SLionel Sambuc 
140*433d6423SLionel Sambuc static int fxp_instance;
141*433d6423SLionel Sambuc 
142*433d6423SLionel Sambuc static fxp_t *fxp_state;
143*433d6423SLionel Sambuc 
144*433d6423SLionel Sambuc static minix_timer_t fxp_watchdog;
145*433d6423SLionel Sambuc 
146*433d6423SLionel Sambuc static u32_t system_hz;
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc #define fxp_inb(port, offset)	(do_inb((port) + (offset)))
149*433d6423SLionel Sambuc #define fxp_inl(port, offset)	(do_inl((port) + (offset)))
150*433d6423SLionel Sambuc #define fxp_outb(port, offset, value)	(do_outb((port) + (offset), (value)))
151*433d6423SLionel Sambuc #define fxp_outl(port, offset, value)	(do_outl((port) + (offset), (value)))
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc static void fxp_init(message *mp);
154*433d6423SLionel Sambuc static void fxp_pci_conf(void);
155*433d6423SLionel Sambuc static int fxp_probe(fxp_t *fp, int skip);
156*433d6423SLionel Sambuc static void fxp_conf_hw(fxp_t *fp);
157*433d6423SLionel Sambuc static void fxp_init_hw(fxp_t *fp);
158*433d6423SLionel Sambuc static void fxp_init_buf(fxp_t *fp);
159*433d6423SLionel Sambuc static void fxp_reset_hw(fxp_t *fp);
160*433d6423SLionel Sambuc static void fxp_confaddr(fxp_t *fp);
161*433d6423SLionel Sambuc static void fxp_rec_mode(fxp_t *fp);
162*433d6423SLionel Sambuc static void fxp_writev_s(const message *mp, int from_int);
163*433d6423SLionel Sambuc static void fxp_readv_s(message *mp, int from_int);
164*433d6423SLionel Sambuc static void fxp_do_conf(fxp_t *fp);
165*433d6423SLionel Sambuc static void fxp_cu_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int
166*433d6423SLionel Sambuc 	check_idle);
167*433d6423SLionel Sambuc static void fxp_ru_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int
168*433d6423SLionel Sambuc 	check_idle);
169*433d6423SLionel Sambuc static void fxp_restart_ru(fxp_t *fp);
170*433d6423SLionel Sambuc static void fxp_getstat_s(message *mp);
171*433d6423SLionel Sambuc static void fxp_handler(fxp_t *fp);
172*433d6423SLionel Sambuc static void fxp_check_ints(fxp_t *fp);
173*433d6423SLionel Sambuc static void fxp_watchdog_f(minix_timer_t *tp);
174*433d6423SLionel Sambuc static int fxp_link_changed(fxp_t *fp);
175*433d6423SLionel Sambuc static void fxp_report_link(fxp_t *fp);
176*433d6423SLionel Sambuc static void reply(fxp_t *fp);
177*433d6423SLionel Sambuc static void mess_reply(message *req, message *reply);
178*433d6423SLionel Sambuc static u16_t eeprom_read(fxp_t *fp, int reg);
179*433d6423SLionel Sambuc static void eeprom_addrsize(fxp_t *fp);
180*433d6423SLionel Sambuc static u16_t mii_read(fxp_t *fp, int reg);
181*433d6423SLionel Sambuc static u8_t do_inb(port_t port);
182*433d6423SLionel Sambuc static u32_t do_inl(port_t port);
183*433d6423SLionel Sambuc static void do_outb(port_t port, u8_t v);
184*433d6423SLionel Sambuc static void do_outl(port_t port, u32_t v);
185*433d6423SLionel Sambuc static void tell_dev(vir_bytes start, size_t size, int pci_bus, int
186*433d6423SLionel Sambuc 	pci_dev, int pci_func);
187*433d6423SLionel Sambuc 
188*433d6423SLionel Sambuc static void handle_hw_intr(void)
189*433d6423SLionel Sambuc {
190*433d6423SLionel Sambuc 	int r;
191*433d6423SLionel Sambuc 	fxp_t *fp;
192*433d6423SLionel Sambuc 
193*433d6423SLionel Sambuc 	fp= fxp_state;
194*433d6423SLionel Sambuc 
195*433d6423SLionel Sambuc 	if (fp->fxp_mode != FM_ENABLED)
196*433d6423SLionel Sambuc 		return;
197*433d6423SLionel Sambuc 	fxp_handler(fp);
198*433d6423SLionel Sambuc 
199*433d6423SLionel Sambuc 	r= sys_irqenable(&fp->fxp_hook);
200*433d6423SLionel Sambuc 	if (r != OK) {
201*433d6423SLionel Sambuc 		panic("unable enable interrupts: %d", r);
202*433d6423SLionel Sambuc 	}
203*433d6423SLionel Sambuc 
204*433d6423SLionel Sambuc 	if (!fp->fxp_got_int)
205*433d6423SLionel Sambuc 		return;
206*433d6423SLionel Sambuc 	fp->fxp_got_int= 0;
207*433d6423SLionel Sambuc 	assert(fp->fxp_flags & FF_ENABLED);
208*433d6423SLionel Sambuc 	fxp_check_ints(fp);
209*433d6423SLionel Sambuc }
210*433d6423SLionel Sambuc 
211*433d6423SLionel Sambuc /* SEF functions and variables. */
212*433d6423SLionel Sambuc static void sef_local_startup(void);
213*433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info);
214*433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo);
215*433d6423SLionel Sambuc 
216*433d6423SLionel Sambuc /*===========================================================================*
217*433d6423SLionel Sambuc  *				main					     *
218*433d6423SLionel Sambuc  *===========================================================================*/
219*433d6423SLionel Sambuc int main(int argc, char *argv[])
220*433d6423SLionel Sambuc {
221*433d6423SLionel Sambuc 	message m;
222*433d6423SLionel Sambuc 	int ipc_status;
223*433d6423SLionel Sambuc 	int r;
224*433d6423SLionel Sambuc 
225*433d6423SLionel Sambuc 	/* SEF local startup. */
226*433d6423SLionel Sambuc 	env_setargs(argc, argv);
227*433d6423SLionel Sambuc 	sef_local_startup();
228*433d6423SLionel Sambuc 
229*433d6423SLionel Sambuc 	while (TRUE)
230*433d6423SLionel Sambuc 	{
231*433d6423SLionel Sambuc 		if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
232*433d6423SLionel Sambuc 			panic("netdriver_receive failed: %d", r);
233*433d6423SLionel Sambuc 
234*433d6423SLionel Sambuc 		if (is_ipc_notify(ipc_status)) {
235*433d6423SLionel Sambuc 			switch (_ENDPOINT_P(m.m_source)) {
236*433d6423SLionel Sambuc 				case HARDWARE:
237*433d6423SLionel Sambuc 					handle_hw_intr();
238*433d6423SLionel Sambuc 					break;
239*433d6423SLionel Sambuc 				case CLOCK:
240*433d6423SLionel Sambuc 					expire_timers(m.m_notify.timestamp);
241*433d6423SLionel Sambuc 					break;
242*433d6423SLionel Sambuc 				default:
243*433d6423SLionel Sambuc 					panic(" illegal notify from: %d", m.m_source);
244*433d6423SLionel Sambuc 			}
245*433d6423SLionel Sambuc 
246*433d6423SLionel Sambuc 			/* get new message */
247*433d6423SLionel Sambuc 			continue;
248*433d6423SLionel Sambuc 		}
249*433d6423SLionel Sambuc 
250*433d6423SLionel Sambuc 		switch (m.m_type)
251*433d6423SLionel Sambuc 		{
252*433d6423SLionel Sambuc 		case DL_WRITEV_S: fxp_writev_s(&m, FALSE);	break;
253*433d6423SLionel Sambuc 		case DL_READV_S: fxp_readv_s(&m, FALSE);	break;
254*433d6423SLionel Sambuc 		case DL_CONF:	fxp_init(&m);			break;
255*433d6423SLionel Sambuc 		case DL_GETSTAT_S: fxp_getstat_s(&m);		break;
256*433d6423SLionel Sambuc 		default:
257*433d6423SLionel Sambuc 			panic(" illegal message: %d", m.m_type);
258*433d6423SLionel Sambuc 		}
259*433d6423SLionel Sambuc 	}
260*433d6423SLionel Sambuc }
261*433d6423SLionel Sambuc 
262*433d6423SLionel Sambuc /*===========================================================================*
263*433d6423SLionel Sambuc  *			       sef_local_startup			     *
264*433d6423SLionel Sambuc  *===========================================================================*/
265*433d6423SLionel Sambuc static void sef_local_startup()
266*433d6423SLionel Sambuc {
267*433d6423SLionel Sambuc   /* Register init callbacks. */
268*433d6423SLionel Sambuc   sef_setcb_init_fresh(sef_cb_init_fresh);
269*433d6423SLionel Sambuc   sef_setcb_init_lu(sef_cb_init_fresh);
270*433d6423SLionel Sambuc   sef_setcb_init_restart(sef_cb_init_fresh);
271*433d6423SLionel Sambuc 
272*433d6423SLionel Sambuc   /* Register live update callbacks. */
273*433d6423SLionel Sambuc   sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
274*433d6423SLionel Sambuc   sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
275*433d6423SLionel Sambuc 
276*433d6423SLionel Sambuc   /* Register signal callbacks. */
277*433d6423SLionel Sambuc   sef_setcb_signal_handler(sef_cb_signal_handler);
278*433d6423SLionel Sambuc 
279*433d6423SLionel Sambuc   /* Let SEF perform startup. */
280*433d6423SLionel Sambuc   sef_startup();
281*433d6423SLionel Sambuc }
282*433d6423SLionel Sambuc 
283*433d6423SLionel Sambuc /*===========================================================================*
284*433d6423SLionel Sambuc  *		            sef_cb_init_fresh                                *
285*433d6423SLionel Sambuc  *===========================================================================*/
286*433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
287*433d6423SLionel Sambuc {
288*433d6423SLionel Sambuc /* Initialize the fxp driver. */
289*433d6423SLionel Sambuc 	long v;
290*433d6423SLionel Sambuc 	int r;
291*433d6423SLionel Sambuc 	vir_bytes ft;
292*433d6423SLionel Sambuc 
293*433d6423SLionel Sambuc 	system_hz = sys_hz();
294*433d6423SLionel Sambuc 
295*433d6423SLionel Sambuc 	v = 0;
296*433d6423SLionel Sambuc 	(void) env_parse("instance", "d", 0, &v, 0, 255);
297*433d6423SLionel Sambuc 	fxp_instance = (int) v;
298*433d6423SLionel Sambuc 
299*433d6423SLionel Sambuc 	ft = sizeof(*fxp_state);
300*433d6423SLionel Sambuc 
301*433d6423SLionel Sambuc 	if(!(fxp_state = alloc_contig(ft, 0, NULL)))
302*433d6423SLionel Sambuc 		panic("couldn't allocate table: %d", ENOMEM);
303*433d6423SLionel Sambuc 
304*433d6423SLionel Sambuc 	memset(fxp_state, 0, ft);
305*433d6423SLionel Sambuc 
306*433d6423SLionel Sambuc 	if((r=tsc_calibrate()) != OK)
307*433d6423SLionel Sambuc 		panic("tsc_calibrate failed: %d", r);
308*433d6423SLionel Sambuc 
309*433d6423SLionel Sambuc 	/* Announce we are up! */
310*433d6423SLionel Sambuc 	netdriver_announce();
311*433d6423SLionel Sambuc 
312*433d6423SLionel Sambuc 	return(OK);
313*433d6423SLionel Sambuc }
314*433d6423SLionel Sambuc 
315*433d6423SLionel Sambuc /*===========================================================================*
316*433d6423SLionel Sambuc  *		           sef_cb_signal_handler                             *
317*433d6423SLionel Sambuc  *===========================================================================*/
318*433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo)
319*433d6423SLionel Sambuc {
320*433d6423SLionel Sambuc 	port_t port;
321*433d6423SLionel Sambuc 	fxp_t *fp;
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc 	/* Only check for termination signal, ignore anything else. */
324*433d6423SLionel Sambuc 	if (signo != SIGTERM) return;
325*433d6423SLionel Sambuc 
326*433d6423SLionel Sambuc 	fp= fxp_state;
327*433d6423SLionel Sambuc 
328*433d6423SLionel Sambuc 	if (fp->fxp_mode == FM_ENABLED && (fp->fxp_flags & FF_ENABLED)) {
329*433d6423SLionel Sambuc 		port= fp->fxp_base_port;
330*433d6423SLionel Sambuc 
331*433d6423SLionel Sambuc 		/* Reset device */
332*433d6423SLionel Sambuc 		if (debug)
333*433d6423SLionel Sambuc 			printf("%s: resetting device\n", fp->fxp_name);
334*433d6423SLionel Sambuc 		fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
335*433d6423SLionel Sambuc 	}
336*433d6423SLionel Sambuc 
337*433d6423SLionel Sambuc 	exit(0);
338*433d6423SLionel Sambuc }
339*433d6423SLionel Sambuc 
340*433d6423SLionel Sambuc /*===========================================================================*
341*433d6423SLionel Sambuc  *				fxp_init				     *
342*433d6423SLionel Sambuc  *===========================================================================*/
343*433d6423SLionel Sambuc static void fxp_init(mp)
344*433d6423SLionel Sambuc message *mp;
345*433d6423SLionel Sambuc {
346*433d6423SLionel Sambuc 	static int first_time= 1;
347*433d6423SLionel Sambuc 
348*433d6423SLionel Sambuc 	fxp_t *fp;
349*433d6423SLionel Sambuc 	message reply_mess;
350*433d6423SLionel Sambuc 
351*433d6423SLionel Sambuc 	if (first_time)
352*433d6423SLionel Sambuc 	{
353*433d6423SLionel Sambuc 		first_time= 0;
354*433d6423SLionel Sambuc 		fxp_pci_conf(); /* Configure PCI devices. */
355*433d6423SLionel Sambuc 
356*433d6423SLionel Sambuc 		init_timer(&fxp_watchdog);
357*433d6423SLionel Sambuc 		set_timer(&fxp_watchdog, system_hz, fxp_watchdog_f, 0);
358*433d6423SLionel Sambuc 	}
359*433d6423SLionel Sambuc 
360*433d6423SLionel Sambuc 	fp= fxp_state;
361*433d6423SLionel Sambuc 	if (fp->fxp_mode == FM_DISABLED)
362*433d6423SLionel Sambuc 	{
363*433d6423SLionel Sambuc 		/* This is the default, try to (re)locate the device. */
364*433d6423SLionel Sambuc 		fxp_conf_hw(fp);
365*433d6423SLionel Sambuc 		if (fp->fxp_mode == FM_DISABLED)
366*433d6423SLionel Sambuc 		{
367*433d6423SLionel Sambuc 			/* Probe failed, or the device is configured off. */
368*433d6423SLionel Sambuc 			reply_mess.m_type= DL_CONF_REPLY;
369*433d6423SLionel Sambuc 			reply_mess.m_netdrv_net_dl_conf.stat= ENXIO;
370*433d6423SLionel Sambuc 			mess_reply(mp, &reply_mess);
371*433d6423SLionel Sambuc 			return;
372*433d6423SLionel Sambuc 		}
373*433d6423SLionel Sambuc 		if (fp->fxp_mode == FM_ENABLED)
374*433d6423SLionel Sambuc 			fxp_init_hw(fp);
375*433d6423SLionel Sambuc 		fxp_report_link(fp);
376*433d6423SLionel Sambuc 	}
377*433d6423SLionel Sambuc 
378*433d6423SLionel Sambuc 	assert(fp->fxp_mode == FM_ENABLED);
379*433d6423SLionel Sambuc 	assert(fp->fxp_flags & FF_ENABLED);
380*433d6423SLionel Sambuc 
381*433d6423SLionel Sambuc 	fp->fxp_flags &= ~(FF_PROMISC | FF_MULTI | FF_BROAD);
382*433d6423SLionel Sambuc 
383*433d6423SLionel Sambuc 	if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ)
384*433d6423SLionel Sambuc 		fp->fxp_flags |= FF_PROMISC;
385*433d6423SLionel Sambuc 	if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ)
386*433d6423SLionel Sambuc 		fp->fxp_flags |= FF_MULTI;
387*433d6423SLionel Sambuc 	if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ)
388*433d6423SLionel Sambuc 		fp->fxp_flags |= FF_BROAD;
389*433d6423SLionel Sambuc 
390*433d6423SLionel Sambuc 	fxp_rec_mode(fp);
391*433d6423SLionel Sambuc 
392*433d6423SLionel Sambuc 	reply_mess.m_type = DL_CONF_REPLY;
393*433d6423SLionel Sambuc 	reply_mess.m_netdrv_net_dl_conf.stat = OK;
394*433d6423SLionel Sambuc 	memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr,
395*433d6423SLionel Sambuc 		fp->fxp_address.ea_addr,
396*433d6423SLionel Sambuc 		sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr));
397*433d6423SLionel Sambuc 
398*433d6423SLionel Sambuc 	mess_reply(mp, &reply_mess);
399*433d6423SLionel Sambuc }
400*433d6423SLionel Sambuc 
401*433d6423SLionel Sambuc /*===========================================================================*
402*433d6423SLionel Sambuc  *				fxp_pci_conf				     *
403*433d6423SLionel Sambuc  *===========================================================================*/
404*433d6423SLionel Sambuc static void fxp_pci_conf()
405*433d6423SLionel Sambuc {
406*433d6423SLionel Sambuc 	fxp_t *fp;
407*433d6423SLionel Sambuc 
408*433d6423SLionel Sambuc 	fp= fxp_state;
409*433d6423SLionel Sambuc 
410*433d6423SLionel Sambuc 	strlcpy(fp->fxp_name, "fxp#0", sizeof(fp->fxp_name));
411*433d6423SLionel Sambuc 	fp->fxp_name[4] += fxp_instance;
412*433d6423SLionel Sambuc 	fp->fxp_seen= FALSE;
413*433d6423SLionel Sambuc 	fp->fxp_features= FFE_NONE;
414*433d6423SLionel Sambuc 
415*433d6423SLionel Sambuc 	pci_init();
416*433d6423SLionel Sambuc 
417*433d6423SLionel Sambuc 	if (fxp_probe(fp, fxp_instance))
418*433d6423SLionel Sambuc 		fp->fxp_seen= TRUE;
419*433d6423SLionel Sambuc }
420*433d6423SLionel Sambuc 
421*433d6423SLionel Sambuc /*===========================================================================*
422*433d6423SLionel Sambuc  *				fxp_probe				     *
423*433d6423SLionel Sambuc  *===========================================================================*/
424*433d6423SLionel Sambuc static int fxp_probe(fxp_t *fp, int skip)
425*433d6423SLionel Sambuc {
426*433d6423SLionel Sambuc 	int r, devind;
427*433d6423SLionel Sambuc 	u16_t vid, did;
428*433d6423SLionel Sambuc 	u32_t bar;
429*433d6423SLionel Sambuc 	u8_t ilr, rev;
430*433d6423SLionel Sambuc 	char *str;
431*433d6423SLionel Sambuc #if VERBOSE
432*433d6423SLionel Sambuc 	char *dname;
433*433d6423SLionel Sambuc #endif
434*433d6423SLionel Sambuc 
435*433d6423SLionel Sambuc 	r= pci_first_dev(&devind, &vid, &did);
436*433d6423SLionel Sambuc 	if (r == 0)
437*433d6423SLionel Sambuc 		return FALSE;
438*433d6423SLionel Sambuc 
439*433d6423SLionel Sambuc 	while (skip--)
440*433d6423SLionel Sambuc 	{
441*433d6423SLionel Sambuc 		r= pci_next_dev(&devind, &vid, &did);
442*433d6423SLionel Sambuc 		if (!r)
443*433d6423SLionel Sambuc 			return FALSE;
444*433d6423SLionel Sambuc 	}
445*433d6423SLionel Sambuc 
446*433d6423SLionel Sambuc #if VERBOSE
447*433d6423SLionel Sambuc 	dname= pci_dev_name(vid, did);
448*433d6423SLionel Sambuc 	if (!dname)
449*433d6423SLionel Sambuc 		dname= "unknown device";
450*433d6423SLionel Sambuc 	printf("%s: %s (%04x/%04x) at %s\n",
451*433d6423SLionel Sambuc 		fp->fxp_name, dname, vid, did, pci_slot_name(devind));
452*433d6423SLionel Sambuc #endif
453*433d6423SLionel Sambuc 	pci_reserve(devind);
454*433d6423SLionel Sambuc 
455*433d6423SLionel Sambuc 	bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0;
456*433d6423SLionel Sambuc 	if (bar < 0x400) {
457*433d6423SLionel Sambuc 		panic("fxp_probe: base address is not properly configured");
458*433d6423SLionel Sambuc 	}
459*433d6423SLionel Sambuc 	fp->fxp_base_port= bar;
460*433d6423SLionel Sambuc 
461*433d6423SLionel Sambuc 	ilr= pci_attr_r8(devind, PCI_ILR);
462*433d6423SLionel Sambuc 	fp->fxp_irq= ilr;
463*433d6423SLionel Sambuc 	if (debug)
464*433d6423SLionel Sambuc 	{
465*433d6423SLionel Sambuc 		printf("%s: using I/O address 0x%lx, IRQ %d\n",
466*433d6423SLionel Sambuc 			fp->fxp_name, (unsigned long)bar, ilr);
467*433d6423SLionel Sambuc 	}
468*433d6423SLionel Sambuc 
469*433d6423SLionel Sambuc 	rev= pci_attr_r8(devind, PCI_REV);
470*433d6423SLionel Sambuc 	str= NULL;
471*433d6423SLionel Sambuc 	fp->fxp_type= FT_UNKNOWN;
472*433d6423SLionel Sambuc 	switch(rev)
473*433d6423SLionel Sambuc 	{
474*433d6423SLionel Sambuc 	case FXP_REV_82557A:	str= "82557A";			/* 0x01 */
475*433d6423SLionel Sambuc 				fp->fxp_type= FT_82557;
476*433d6423SLionel Sambuc 				break;
477*433d6423SLionel Sambuc 	case FXP_REV_82557B:	str= "82557B"; break;		/* 0x02 */
478*433d6423SLionel Sambuc 	case FXP_REV_82557C:	str= "82557C"; break;		/* 0x03 */
479*433d6423SLionel Sambuc 	case FXP_REV_82558A:	str= "82558A"; 			/* 0x04 */
480*433d6423SLionel Sambuc 				fp->fxp_type= FT_82558A;
481*433d6423SLionel Sambuc 				break;
482*433d6423SLionel Sambuc 	case FXP_REV_82558B:	str= "82558B"; 			/* 0x05 */
483*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
484*433d6423SLionel Sambuc 				break;
485*433d6423SLionel Sambuc 	case FXP_REV_82559A:	str= "82559A"; break;		/* 0x06 */
486*433d6423SLionel Sambuc 	case FXP_REV_82559B:	str= "82559B"; break;		/* 0x07 */
487*433d6423SLionel Sambuc 	case FXP_REV_82559C:	str= "82559C";			/* 0x08 */
488*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
489*433d6423SLionel Sambuc 				break;
490*433d6423SLionel Sambuc 	case FXP_REV_82559ERA:	str= "82559ER-A"; 		/* 0x09 */
491*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
492*433d6423SLionel Sambuc 				break;
493*433d6423SLionel Sambuc 	case FXP_REV_82550_1:	str= "82550(1)"; 		/* 0x0C */
494*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
495*433d6423SLionel Sambuc 				break;
496*433d6423SLionel Sambuc 	case FXP_REV_82550_2:	str= "82550(2)"; 		/* 0x0D */
497*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
498*433d6423SLionel Sambuc 				break;
499*433d6423SLionel Sambuc 	case FXP_REV_82550_3:	str= "82550(3)"; 		/* 0x0E */
500*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
501*433d6423SLionel Sambuc 				break;
502*433d6423SLionel Sambuc 	case FXP_REV_82551_1:	str= "82551(1)"; 		/* 0x0F */
503*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
504*433d6423SLionel Sambuc 				break;
505*433d6423SLionel Sambuc 	case FXP_REV_82551_2:	str= "82551(2)"; 		/* 0x10 */
506*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
507*433d6423SLionel Sambuc 				break;
508*433d6423SLionel Sambuc 	case FXP_REV_82801CAM:	str= "82801CAM"; 		/* 0x42 */
509*433d6423SLionel Sambuc 				fp->fxp_type= FT_82801;
510*433d6423SLionel Sambuc 				break;
511*433d6423SLionel Sambuc 	case FXP_REV_82801DB:	str= "82801DB"; 		/* 0x81 */
512*433d6423SLionel Sambuc 				fp->fxp_type= FT_82801;
513*433d6423SLionel Sambuc 				break;
514*433d6423SLionel Sambuc 	case FXP_REV_82550_4:	str= "82550(4)"; 		/* 0x83 */
515*433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
516*433d6423SLionel Sambuc 				break;
517*433d6423SLionel Sambuc 	}
518*433d6423SLionel Sambuc 
519*433d6423SLionel Sambuc #if VERBOSE
520*433d6423SLionel Sambuc 	if (str)
521*433d6423SLionel Sambuc 		printf("%s: device revision: %s\n", fp->fxp_name, str);
522*433d6423SLionel Sambuc 	else
523*433d6423SLionel Sambuc 		printf("%s: unknown revision: 0x%x\n", fp->fxp_name, rev);
524*433d6423SLionel Sambuc #endif
525*433d6423SLionel Sambuc 
526*433d6423SLionel Sambuc 	if (fp->fxp_type == FT_UNKNOWN)
527*433d6423SLionel Sambuc 	{
528*433d6423SLionel Sambuc 		printf("fxp_probe: device is not supported by this driver\n");
529*433d6423SLionel Sambuc 		return FALSE;
530*433d6423SLionel Sambuc 	}
531*433d6423SLionel Sambuc 
532*433d6423SLionel Sambuc 	return TRUE;
533*433d6423SLionel Sambuc }
534*433d6423SLionel Sambuc 
535*433d6423SLionel Sambuc /*===========================================================================*
536*433d6423SLionel Sambuc  *				fxp_conf_hw				     *
537*433d6423SLionel Sambuc  *===========================================================================*/
538*433d6423SLionel Sambuc static void fxp_conf_hw(fxp_t *fp)
539*433d6423SLionel Sambuc {
540*433d6423SLionel Sambuc #if VERBOSE
541*433d6423SLionel Sambuc 	int i;
542*433d6423SLionel Sambuc #endif
543*433d6423SLionel Sambuc 
544*433d6423SLionel Sambuc 	fp->fxp_mode= FM_DISABLED;	/* Superfluous */
545*433d6423SLionel Sambuc 
546*433d6423SLionel Sambuc 	if (!fp->fxp_seen)
547*433d6423SLionel Sambuc 		return;
548*433d6423SLionel Sambuc 
549*433d6423SLionel Sambuc 	/* PCI device is present */
550*433d6423SLionel Sambuc 	fp->fxp_mode= FM_ENABLED;
551*433d6423SLionel Sambuc 
552*433d6423SLionel Sambuc 	fp->fxp_flags= FF_EMPTY;
553*433d6423SLionel Sambuc 	fp->fxp_got_int= 0;
554*433d6423SLionel Sambuc 	fp->fxp_send_int= 0;
555*433d6423SLionel Sambuc 	fp->fxp_ee_addrlen= 0;	/* Unknown */
556*433d6423SLionel Sambuc 	fp->fxp_need_reset= 0;
557*433d6423SLionel Sambuc 	fp->fxp_report_link= 0;
558*433d6423SLionel Sambuc 	fp->fxp_link_up= -1;	/* Unknown */
559*433d6423SLionel Sambuc 	fp->fxp_mii_busy= 0;
560*433d6423SLionel Sambuc 	fp->fxp_read_s= 0;
561*433d6423SLionel Sambuc 	fp->fxp_rx_need_restart= 0;
562*433d6423SLionel Sambuc 	fp->fxp_need_conf= 0;
563*433d6423SLionel Sambuc 	fp->fxp_tx_head= 0;
564*433d6423SLionel Sambuc 	fp->fxp_tx_tail= 0;
565*433d6423SLionel Sambuc 	fp->fxp_tx_alive= 0;
566*433d6423SLionel Sambuc 	fp->fxp_tx_threshold= TXTT_MIN;
567*433d6423SLionel Sambuc 
568*433d6423SLionel Sambuc 	/* Try to come up with a sensible configuration for the current
569*433d6423SLionel Sambuc 	 * device. Unfortunately every device is different, defaults are
570*433d6423SLionel Sambuc 	 * not always zero, and some fields are re-used with a completely
571*433d6423SLionel Sambuc 	 * different interpretation. We start out with a sensible default
572*433d6423SLionel Sambuc 	 * for all devices and then add device specific changes.
573*433d6423SLionel Sambuc 	 */
574*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[0]= CC_BYTES_NR;
575*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[1]= CTL_DEFAULT | CRL_DEFAULT;
576*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[2]= CAI_DEFAULT;
577*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[3]= 0;
578*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[4]= 0;
579*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[5]= 0;
580*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[6]= CCB6_ESC | CCB6_ETCB | CCB6_RES;
581*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[7]= CUR_1;
582*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[8]= CCB8_503_MII;
583*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[9]= 0;
584*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[10]= CLB_NORMAL | CPAL_DEFAULT | CCB10_NSAI |
585*433d6423SLionel Sambuc 				CCB10_RES1;
586*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[11]= 0;
587*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[12]= CIS_DEFAULT;
588*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[13]= CCB13_DEFAULT;
589*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[14]= CCB14_DEFAULT;
590*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[15]= CCB15_RES1 | CCB15_RES2;
591*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[16]= CCB16_DEFAULT;
592*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[17]= CCB17_DEFAULT;
593*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[18]= CCB18_RES1 | CCB18_PFCT | CCB18_PE;
594*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[19]= CCB19_FDPE;
595*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[20]= CCB20_PFCL | CCB20_RES1;
596*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[21]= CCB21_RES21;
597*433d6423SLionel Sambuc 
598*433d6423SLionel Sambuc #if VERBOSE
599*433d6423SLionel Sambuc 	for (i= 0; i<CC_BYTES_NR; i++)
600*433d6423SLionel Sambuc 		printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
601*433d6423SLionel Sambuc 	printf("\n");
602*433d6423SLionel Sambuc #endif
603*433d6423SLionel Sambuc 
604*433d6423SLionel Sambuc 	switch(fp->fxp_type)
605*433d6423SLionel Sambuc 	{
606*433d6423SLionel Sambuc 	case FT_82557:
607*433d6423SLionel Sambuc 		break;
608*433d6423SLionel Sambuc 	case FT_82558A:
609*433d6423SLionel Sambuc 	case FT_82559:
610*433d6423SLionel Sambuc 	case FT_82801:
611*433d6423SLionel Sambuc 		fp->fxp_conf_bytes[18] |= CCB18_LROK;
612*433d6423SLionel Sambuc 
613*433d6423SLionel Sambuc 		if (fp->fxp_type == FT_82801)
614*433d6423SLionel Sambuc 		{
615*433d6423SLionel Sambuc 			fp->fxp_conf_bytes[6] = 0xba; /* ctrl 1 */
616*433d6423SLionel Sambuc 			fp->fxp_conf_bytes[15] = 0x48; /* promiscuous */
617*433d6423SLionel Sambuc 			fp->fxp_conf_bytes[21] = 0x05; /* mc_all */
618*433d6423SLionel Sambuc 		}
619*433d6423SLionel Sambuc 		break;
620*433d6423SLionel Sambuc 	default:
621*433d6423SLionel Sambuc 		panic("fxp_conf_hw: bad device type: %d", fp->fxp_type);
622*433d6423SLionel Sambuc 	}
623*433d6423SLionel Sambuc 
624*433d6423SLionel Sambuc 	/* Assume an 82555 (compatible) PHY. The should be changed for
625*433d6423SLionel Sambuc 	 * 82557 NICs with different PHYs
626*433d6423SLionel Sambuc 	 */
627*433d6423SLionel Sambuc 	fp->fxp_ms_regs = 0;	/* No master/slave registers. */
628*433d6423SLionel Sambuc 
629*433d6423SLionel Sambuc #if VERBOSE
630*433d6423SLionel Sambuc 	for (i= 0; i<CC_BYTES_NR; i++)
631*433d6423SLionel Sambuc 		printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
632*433d6423SLionel Sambuc 	printf("\n");
633*433d6423SLionel Sambuc #endif
634*433d6423SLionel Sambuc }
635*433d6423SLionel Sambuc 
636*433d6423SLionel Sambuc /*===========================================================================*
637*433d6423SLionel Sambuc  *				fxp_init_hw				     *
638*433d6423SLionel Sambuc  *===========================================================================*/
639*433d6423SLionel Sambuc static void fxp_init_hw(fp)
640*433d6423SLionel Sambuc fxp_t *fp;
641*433d6423SLionel Sambuc {
642*433d6423SLionel Sambuc 	int i, r, isr;
643*433d6423SLionel Sambuc 	port_t port;
644*433d6423SLionel Sambuc 	phys_bytes bus_addr;
645*433d6423SLionel Sambuc 
646*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
647*433d6423SLionel Sambuc 
648*433d6423SLionel Sambuc 	fxp_init_buf(fp);
649*433d6423SLionel Sambuc 
650*433d6423SLionel Sambuc 	fp->fxp_flags = FF_EMPTY;
651*433d6423SLionel Sambuc 	fp->fxp_flags |= FF_ENABLED;
652*433d6423SLionel Sambuc 
653*433d6423SLionel Sambuc 	/* Set the interrupt handler and policy. Do not automatically
654*433d6423SLionel Sambuc 	 * reenable interrupts. Return the IRQ line number on interrupts.
655*433d6423SLionel Sambuc  	 */
656*433d6423SLionel Sambuc  	fp->fxp_hook = fp->fxp_irq;
657*433d6423SLionel Sambuc 	r= sys_irqsetpolicy(fp->fxp_irq, 0, &fp->fxp_hook);
658*433d6423SLionel Sambuc 	if (r != OK)
659*433d6423SLionel Sambuc 		panic("sys_irqsetpolicy failed: %d", r);
660*433d6423SLionel Sambuc 
661*433d6423SLionel Sambuc 	fxp_reset_hw(fp);
662*433d6423SLionel Sambuc 
663*433d6423SLionel Sambuc 	r= sys_irqenable(&fp->fxp_hook);
664*433d6423SLionel Sambuc 	if (r != OK)
665*433d6423SLionel Sambuc 		panic("sys_irqenable failed: %d", r);
666*433d6423SLionel Sambuc 
667*433d6423SLionel Sambuc 	/* Reset PHY? */
668*433d6423SLionel Sambuc 
669*433d6423SLionel Sambuc 	fxp_do_conf(fp);
670*433d6423SLionel Sambuc 
671*433d6423SLionel Sambuc 	/* Set pointer to statistical counters */
672*433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat),
673*433d6423SLionel Sambuc 		&bus_addr);
674*433d6423SLionel Sambuc 	if (r != OK)
675*433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
676*433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_LOAD_DCA, bus_addr, TRUE /* check idle */);
677*433d6423SLionel Sambuc 
678*433d6423SLionel Sambuc 	/* Ack previous interrupts */
679*433d6423SLionel Sambuc 	isr= fxp_inb(port, SCB_INT_STAT);
680*433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_STAT, isr);
681*433d6423SLionel Sambuc 
682*433d6423SLionel Sambuc 	/* Enable interrupts */
683*433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_MASK, 0);
684*433d6423SLionel Sambuc 
685*433d6423SLionel Sambuc 	fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
686*433d6423SLionel Sambuc 		TRUE /* check idle */);
687*433d6423SLionel Sambuc 
688*433d6423SLionel Sambuc 	fxp_confaddr(fp);
689*433d6423SLionel Sambuc 	if (debug)
690*433d6423SLionel Sambuc 	{
691*433d6423SLionel Sambuc 		printf("%s: Ethernet address ", fp->fxp_name);
692*433d6423SLionel Sambuc 		for (i= 0; i < 6; i++)
693*433d6423SLionel Sambuc 		{
694*433d6423SLionel Sambuc 			printf("%x%c", fp->fxp_address.ea_addr[i],
695*433d6423SLionel Sambuc 				i < 5 ? ':' : '\n');
696*433d6423SLionel Sambuc 		}
697*433d6423SLionel Sambuc 	}
698*433d6423SLionel Sambuc }
699*433d6423SLionel Sambuc 
700*433d6423SLionel Sambuc /*===========================================================================*
701*433d6423SLionel Sambuc  *				fxp_init_buf				     *
702*433d6423SLionel Sambuc  *===========================================================================*/
703*433d6423SLionel Sambuc static void fxp_init_buf(fp)
704*433d6423SLionel Sambuc fxp_t *fp;
705*433d6423SLionel Sambuc {
706*433d6423SLionel Sambuc 	size_t rx_totbufsize, tx_totbufsize, tot_bufsize, alloc_bufsize;
707*433d6423SLionel Sambuc 	char *alloc_buf;
708*433d6423SLionel Sambuc 	phys_bytes buf, bus_addr;
709*433d6423SLionel Sambuc 	int i, r;
710*433d6423SLionel Sambuc 	struct rfd *rfdp;
711*433d6423SLionel Sambuc 	struct tx *txp;
712*433d6423SLionel Sambuc 	phys_bytes ph;
713*433d6423SLionel Sambuc 
714*433d6423SLionel Sambuc 	fp->fxp_rx_nbuf= N_RX_BUF;
715*433d6423SLionel Sambuc 	rx_totbufsize= fp->fxp_rx_nbuf * sizeof(struct rfd);
716*433d6423SLionel Sambuc 	fp->fxp_rx_bufsize= rx_totbufsize;
717*433d6423SLionel Sambuc 
718*433d6423SLionel Sambuc 	fp->fxp_tx_nbuf= N_TX_BUF;
719*433d6423SLionel Sambuc 	tx_totbufsize= fp->fxp_tx_nbuf * sizeof(struct tx);
720*433d6423SLionel Sambuc 	fp->fxp_tx_bufsize= tx_totbufsize;
721*433d6423SLionel Sambuc 
722*433d6423SLionel Sambuc 	tot_bufsize= sizeof(*tmpbufp) + tx_totbufsize + rx_totbufsize;
723*433d6423SLionel Sambuc 	if (tot_bufsize % 4096)
724*433d6423SLionel Sambuc 		tot_bufsize += 4096 - (tot_bufsize % 4096);
725*433d6423SLionel Sambuc 	alloc_bufsize= tot_bufsize;
726*433d6423SLionel Sambuc 	alloc_buf= alloc_contig(alloc_bufsize, AC_ALIGN4K, &ph);
727*433d6423SLionel Sambuc 	if (alloc_buf == NULL) {
728*433d6423SLionel Sambuc 		panic("fxp_init_buf: unable to alloc_contig size: %d", 			alloc_bufsize);
729*433d6423SLionel Sambuc 	}
730*433d6423SLionel Sambuc 
731*433d6423SLionel Sambuc 	buf= (phys_bytes)alloc_buf;
732*433d6423SLionel Sambuc 
733*433d6423SLionel Sambuc 	tell_dev((vir_bytes)buf, tot_bufsize, 0, 0, 0);
734*433d6423SLionel Sambuc 
735*433d6423SLionel Sambuc 	tmpbufp= (union tmpbuf *)buf;
736*433d6423SLionel Sambuc 
737*433d6423SLionel Sambuc 	fp->fxp_rx_buf= (struct rfd *)&tmpbufp[1];
738*433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)fp->fxp_rx_buf, rx_totbufsize,
739*433d6423SLionel Sambuc 		&bus_addr);
740*433d6423SLionel Sambuc 	if (r != OK)
741*433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
742*433d6423SLionel Sambuc 	fp->fxp_rx_busaddr= bus_addr;
743*433d6423SLionel Sambuc 
744*433d6423SLionel Sambuc #if 0
745*433d6423SLionel Sambuc 	printf("fxp_init_buf: got phys 0x%x for vir 0x%x\n",
746*433d6423SLionel Sambuc 		fp->fxp_rx_busaddr, fp->fxp_rx_buf);
747*433d6423SLionel Sambuc #endif
748*433d6423SLionel Sambuc 
749*433d6423SLionel Sambuc 	for (i= 0, rfdp= fp->fxp_rx_buf; i<fp->fxp_rx_nbuf; i++, rfdp++)
750*433d6423SLionel Sambuc 	{
751*433d6423SLionel Sambuc 		rfdp->rfd_status= 0;
752*433d6423SLionel Sambuc 		rfdp->rfd_command= 0;
753*433d6423SLionel Sambuc 		if (i != fp->fxp_rx_nbuf-1)
754*433d6423SLionel Sambuc 		{
755*433d6423SLionel Sambuc 			r= sys_umap(SELF, VM_D, (vir_bytes)&rfdp[1],
756*433d6423SLionel Sambuc 				sizeof(rfdp[1]), &bus_addr);
757*433d6423SLionel Sambuc 			if (r != OK)
758*433d6423SLionel Sambuc 				panic("sys_umap failed: %d", r);
759*433d6423SLionel Sambuc 			rfdp->rfd_linkaddr= bus_addr;
760*433d6423SLionel Sambuc 		}
761*433d6423SLionel Sambuc 		else
762*433d6423SLionel Sambuc 		{
763*433d6423SLionel Sambuc 			rfdp->rfd_linkaddr= fp->fxp_rx_busaddr;
764*433d6423SLionel Sambuc 			rfdp->rfd_command |= RFDC_EL;
765*433d6423SLionel Sambuc 		}
766*433d6423SLionel Sambuc 		rfdp->rfd_reserved= 0;
767*433d6423SLionel Sambuc 		rfdp->rfd_res= 0;
768*433d6423SLionel Sambuc 		rfdp->rfd_size= sizeof(rfdp->rfd_buf);
769*433d6423SLionel Sambuc 
770*433d6423SLionel Sambuc 	}
771*433d6423SLionel Sambuc 	fp->fxp_rx_head= 0;
772*433d6423SLionel Sambuc 
773*433d6423SLionel Sambuc 	fp->fxp_tx_buf= (struct tx *)((char *)fp->fxp_rx_buf+rx_totbufsize);
774*433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)fp->fxp_tx_buf,
775*433d6423SLionel Sambuc 		(phys_bytes)tx_totbufsize, &fp->fxp_tx_busaddr);
776*433d6423SLionel Sambuc 	if (r != OK)
777*433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
778*433d6423SLionel Sambuc 
779*433d6423SLionel Sambuc 	for (i= 0, txp= fp->fxp_tx_buf; i<fp->fxp_tx_nbuf; i++, txp++)
780*433d6423SLionel Sambuc 	{
781*433d6423SLionel Sambuc 		txp->tx_status= 0;
782*433d6423SLionel Sambuc 		txp->tx_command= TXC_EL | CBL_NOP;	/* Just in case */
783*433d6423SLionel Sambuc 		if (i != fp->fxp_tx_nbuf-1)
784*433d6423SLionel Sambuc 		{
785*433d6423SLionel Sambuc 			r= sys_umap(SELF, VM_D, (vir_bytes)&txp[1],
786*433d6423SLionel Sambuc 				(phys_bytes)sizeof(txp[1]), &bus_addr);
787*433d6423SLionel Sambuc 			if (r != OK)
788*433d6423SLionel Sambuc 				panic("sys_umap failed: %d", r);
789*433d6423SLionel Sambuc 			txp->tx_linkaddr= bus_addr;
790*433d6423SLionel Sambuc 		}
791*433d6423SLionel Sambuc 		else
792*433d6423SLionel Sambuc 		{
793*433d6423SLionel Sambuc 			txp->tx_linkaddr= fp->fxp_tx_busaddr;
794*433d6423SLionel Sambuc 		}
795*433d6423SLionel Sambuc 		txp->tx_tbda= TX_TBDA_NIL;
796*433d6423SLionel Sambuc 		txp->tx_size= 0;
797*433d6423SLionel Sambuc 		txp->tx_tthresh= fp->fxp_tx_threshold;
798*433d6423SLionel Sambuc 		txp->tx_ntbd= 0;
799*433d6423SLionel Sambuc 	}
800*433d6423SLionel Sambuc 	fp->fxp_tx_idle= 1;
801*433d6423SLionel Sambuc }
802*433d6423SLionel Sambuc 
803*433d6423SLionel Sambuc /*===========================================================================*
804*433d6423SLionel Sambuc  *				fxp_reset_hw				     *
805*433d6423SLionel Sambuc  *===========================================================================*/
806*433d6423SLionel Sambuc static void fxp_reset_hw(fp)
807*433d6423SLionel Sambuc fxp_t *fp;
808*433d6423SLionel Sambuc {
809*433d6423SLionel Sambuc /* Inline the function in init? */
810*433d6423SLionel Sambuc 	port_t port;
811*433d6423SLionel Sambuc 
812*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
813*433d6423SLionel Sambuc 
814*433d6423SLionel Sambuc 	/* Reset device */
815*433d6423SLionel Sambuc 	fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
816*433d6423SLionel Sambuc 	tickdelay(micros_to_ticks(CSR_PORT_RESET_DELAY));
817*433d6423SLionel Sambuc 
818*433d6423SLionel Sambuc 	/* Disable interrupts */
819*433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_MASK, SIM_M);
820*433d6423SLionel Sambuc 
821*433d6423SLionel Sambuc 	/* Set CU base to zero */
822*433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_LOAD_BASE, 0, TRUE /* check idle */);
823*433d6423SLionel Sambuc 
824*433d6423SLionel Sambuc 	/* Set RU base to zero */
825*433d6423SLionel Sambuc 	fxp_ru_ptr_cmd(fp, SC_RU_LOAD_BASE, 0, TRUE /* check idle */);
826*433d6423SLionel Sambuc }
827*433d6423SLionel Sambuc 
828*433d6423SLionel Sambuc /*===========================================================================*
829*433d6423SLionel Sambuc  *				fxp_confaddr				     *
830*433d6423SLionel Sambuc  *===========================================================================*/
831*433d6423SLionel Sambuc static void fxp_confaddr(fxp_t *fp)
832*433d6423SLionel Sambuc {
833*433d6423SLionel Sambuc 	static char eakey[]= FXP_ENVVAR "#_EA";
834*433d6423SLionel Sambuc 	static char eafmt[]= "x:x:x:x:x:x";
835*433d6423SLionel Sambuc 	int i, r;
836*433d6423SLionel Sambuc 	phys_bytes bus_addr;
837*433d6423SLionel Sambuc 	long v;
838*433d6423SLionel Sambuc 
839*433d6423SLionel Sambuc 	/* User defined ethernet address? */
840*433d6423SLionel Sambuc 	eakey[sizeof(FXP_ENVVAR)-1]= '0' + fxp_instance;
841*433d6423SLionel Sambuc 
842*433d6423SLionel Sambuc 	for (i= 0; i < 6; i++)
843*433d6423SLionel Sambuc 	{
844*433d6423SLionel Sambuc 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
845*433d6423SLionel Sambuc 			break;
846*433d6423SLionel Sambuc 		fp->fxp_address.ea_addr[i]= v;
847*433d6423SLionel Sambuc 	}
848*433d6423SLionel Sambuc 
849*433d6423SLionel Sambuc 	if (i != 0 && i != 6) env_panic(eakey);	/* It's all or nothing */
850*433d6423SLionel Sambuc 
851*433d6423SLionel Sambuc 	if (i == 0)
852*433d6423SLionel Sambuc 	{
853*433d6423SLionel Sambuc 		/* Get ethernet address from EEPROM */
854*433d6423SLionel Sambuc 		for (i= 0; i<3; i++)
855*433d6423SLionel Sambuc 		{
856*433d6423SLionel Sambuc 			v= eeprom_read(fp, i);
857*433d6423SLionel Sambuc 			fp->fxp_address.ea_addr[i*2]= (v & 0xff);
858*433d6423SLionel Sambuc 			fp->fxp_address.ea_addr[i*2+1]= ((v >> 8) & 0xff);
859*433d6423SLionel Sambuc 		}
860*433d6423SLionel Sambuc 	}
861*433d6423SLionel Sambuc 
862*433d6423SLionel Sambuc 	/* Tell NIC about ethernet address */
863*433d6423SLionel Sambuc 	tmpbufp->ias.ias_status= 0;
864*433d6423SLionel Sambuc 	tmpbufp->ias.ias_command= CBL_C_EL | CBL_AIS;
865*433d6423SLionel Sambuc 	tmpbufp->ias.ias_linkaddr= 0;
866*433d6423SLionel Sambuc 	memcpy(tmpbufp->ias.ias_ethaddr, fp->fxp_address.ea_addr,
867*433d6423SLionel Sambuc 		sizeof(tmpbufp->ias.ias_ethaddr));
868*433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->ias,
869*433d6423SLionel Sambuc 		(phys_bytes)sizeof(tmpbufp->ias), &bus_addr);
870*433d6423SLionel Sambuc 	if (r != OK)
871*433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
872*433d6423SLionel Sambuc 
873*433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
874*433d6423SLionel Sambuc 
875*433d6423SLionel Sambuc 	/* Wait for CU command to complete */
876*433d6423SLionel Sambuc 	SPIN_UNTIL(tmpbufp->ias.ias_status & CBL_F_C, 1000);
877*433d6423SLionel Sambuc 
878*433d6423SLionel Sambuc 	if (!(tmpbufp->ias.ias_status & CBL_F_C))
879*433d6423SLionel Sambuc 		panic("fxp_confaddr: CU command failed to complete");
880*433d6423SLionel Sambuc 	if (!(tmpbufp->ias.ias_status & CBL_F_OK))
881*433d6423SLionel Sambuc 		panic("fxp_confaddr: CU command failed");
882*433d6423SLionel Sambuc 
883*433d6423SLionel Sambuc #if VERBOSE
884*433d6423SLionel Sambuc 	printf("%s: hardware ethernet address: ", fp->fxp_name);
885*433d6423SLionel Sambuc 	for (i= 0; i<6; i++)
886*433d6423SLionel Sambuc 	{
887*433d6423SLionel Sambuc 		printf("%02x%s", fp->fxp_address.ea_addr[i],
888*433d6423SLionel Sambuc 			i < 5 ? ":" : "");
889*433d6423SLionel Sambuc 	}
890*433d6423SLionel Sambuc 	printf("\n");
891*433d6423SLionel Sambuc #endif
892*433d6423SLionel Sambuc }
893*433d6423SLionel Sambuc 
894*433d6423SLionel Sambuc /*===========================================================================*
895*433d6423SLionel Sambuc  *				fxp_rec_mode				     *
896*433d6423SLionel Sambuc  *===========================================================================*/
897*433d6423SLionel Sambuc static void fxp_rec_mode(fp)
898*433d6423SLionel Sambuc fxp_t *fp;
899*433d6423SLionel Sambuc {
900*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[0]= CC_BYTES_NR;	/* Just to be sure */
901*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM);
902*433d6423SLionel Sambuc 	fp->fxp_conf_bytes[21] &= ~CCB21_MA;
903*433d6423SLionel Sambuc 
904*433d6423SLionel Sambuc 	if (fp->fxp_flags & FF_PROMISC)
905*433d6423SLionel Sambuc 		fp->fxp_conf_bytes[15] |= CCB15_PM;
906*433d6423SLionel Sambuc 	if (fp->fxp_flags & FF_MULTI)
907*433d6423SLionel Sambuc 		fp->fxp_conf_bytes[21] |= CCB21_MA;
908*433d6423SLionel Sambuc 
909*433d6423SLionel Sambuc 	if (!(fp->fxp_flags & (FF_BROAD|FF_MULTI|FF_PROMISC)))
910*433d6423SLionel Sambuc 		fp->fxp_conf_bytes[15] |= CCB15_BD;
911*433d6423SLionel Sambuc 
912*433d6423SLionel Sambuc 	/* Queue request if not idle */
913*433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
914*433d6423SLionel Sambuc 	{
915*433d6423SLionel Sambuc 		fxp_do_conf(fp);
916*433d6423SLionel Sambuc 	}
917*433d6423SLionel Sambuc 	else
918*433d6423SLionel Sambuc 	{
919*433d6423SLionel Sambuc 		printf("fxp_rec_mode: setting fxp_need_conf\n");
920*433d6423SLionel Sambuc 		fp->fxp_need_conf= TRUE;
921*433d6423SLionel Sambuc 	}
922*433d6423SLionel Sambuc }
923*433d6423SLionel Sambuc 
924*433d6423SLionel Sambuc /*===========================================================================*
925*433d6423SLionel Sambuc  *				fxp_writev_s				     *
926*433d6423SLionel Sambuc  *===========================================================================*/
927*433d6423SLionel Sambuc static void fxp_writev_s(const message *mp, int from_int)
928*433d6423SLionel Sambuc {
929*433d6423SLionel Sambuc 	endpoint_t iov_endpt;
930*433d6423SLionel Sambuc 	cp_grant_id_t iov_grant;
931*433d6423SLionel Sambuc 	vir_bytes iov_offset;
932*433d6423SLionel Sambuc 	int i, j, n, o, r, s, count, size, prev_head;
933*433d6423SLionel Sambuc 	int fxp_tx_nbuf, fxp_tx_head;
934*433d6423SLionel Sambuc 	u16_t tx_command;
935*433d6423SLionel Sambuc 	fxp_t *fp;
936*433d6423SLionel Sambuc 	iovec_s_t *iovp;
937*433d6423SLionel Sambuc 	struct tx *txp, *prev_txp;
938*433d6423SLionel Sambuc 
939*433d6423SLionel Sambuc 	fp= fxp_state;
940*433d6423SLionel Sambuc 
941*433d6423SLionel Sambuc 	count = mp->m_net_netdrv_dl_writev_s.count;
942*433d6423SLionel Sambuc 	fp->fxp_client= mp->m_source;
943*433d6423SLionel Sambuc 
944*433d6423SLionel Sambuc 	assert(fp->fxp_mode == FM_ENABLED);
945*433d6423SLionel Sambuc 	assert(fp->fxp_flags & FF_ENABLED);
946*433d6423SLionel Sambuc 
947*433d6423SLionel Sambuc 	if (from_int)
948*433d6423SLionel Sambuc 	{
949*433d6423SLionel Sambuc 		assert(fp->fxp_flags & FF_SEND_AVAIL);
950*433d6423SLionel Sambuc 		fp->fxp_flags &= ~FF_SEND_AVAIL;
951*433d6423SLionel Sambuc 		fp->fxp_tx_alive= TRUE;
952*433d6423SLionel Sambuc 	}
953*433d6423SLionel Sambuc 
954*433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
955*433d6423SLionel Sambuc 	{
956*433d6423SLionel Sambuc 		txp= fp->fxp_tx_buf;
957*433d6423SLionel Sambuc 		fxp_tx_head= 0;	/* lint */
958*433d6423SLionel Sambuc 		prev_txp= NULL;	/* lint */
959*433d6423SLionel Sambuc 	}
960*433d6423SLionel Sambuc 	else
961*433d6423SLionel Sambuc 	{
962*433d6423SLionel Sambuc 		fxp_tx_nbuf= fp->fxp_tx_nbuf;
963*433d6423SLionel Sambuc 		prev_head= fp->fxp_tx_head;
964*433d6423SLionel Sambuc 		fxp_tx_head= prev_head+1;
965*433d6423SLionel Sambuc 		if (fxp_tx_head == fxp_tx_nbuf)
966*433d6423SLionel Sambuc 			fxp_tx_head= 0;
967*433d6423SLionel Sambuc 		assert(fxp_tx_head < fxp_tx_nbuf);
968*433d6423SLionel Sambuc 
969*433d6423SLionel Sambuc 		if (fxp_tx_head == fp->fxp_tx_tail)
970*433d6423SLionel Sambuc 		{
971*433d6423SLionel Sambuc 			/* Send queue is full */
972*433d6423SLionel Sambuc 			assert(!(fp->fxp_flags & FF_SEND_AVAIL));
973*433d6423SLionel Sambuc 			fp->fxp_flags |= FF_SEND_AVAIL;
974*433d6423SLionel Sambuc 			goto suspend;
975*433d6423SLionel Sambuc 		}
976*433d6423SLionel Sambuc 
977*433d6423SLionel Sambuc 		prev_txp= &fp->fxp_tx_buf[prev_head];
978*433d6423SLionel Sambuc 		txp= &fp->fxp_tx_buf[fxp_tx_head];
979*433d6423SLionel Sambuc 	}
980*433d6423SLionel Sambuc 
981*433d6423SLionel Sambuc 	assert(!(fp->fxp_flags & FF_SEND_AVAIL));
982*433d6423SLionel Sambuc 	assert(!(fp->fxp_flags & FF_PACK_SENT));
983*433d6423SLionel Sambuc 
984*433d6423SLionel Sambuc 	iov_endpt= mp->m_source;
985*433d6423SLionel Sambuc 	iov_grant= mp->m_net_netdrv_dl_writev_s.grant;
986*433d6423SLionel Sambuc 
987*433d6423SLionel Sambuc 	size= 0;
988*433d6423SLionel Sambuc 	o= 0;
989*433d6423SLionel Sambuc 	iov_offset= 0;
990*433d6423SLionel Sambuc 	for (i= 0; i<count; i += IOVEC_NR,
991*433d6423SLionel Sambuc 		iov_offset += IOVEC_NR * sizeof(fp->fxp_iovec_s[0]))
992*433d6423SLionel Sambuc 	{
993*433d6423SLionel Sambuc 		n= IOVEC_NR;
994*433d6423SLionel Sambuc 		if (i+n > count)
995*433d6423SLionel Sambuc 			n= count-i;
996*433d6423SLionel Sambuc 		r= sys_safecopyfrom(iov_endpt, iov_grant, iov_offset,
997*433d6423SLionel Sambuc 			(vir_bytes)fp->fxp_iovec_s,
998*433d6423SLionel Sambuc 			n * sizeof(fp->fxp_iovec_s[0]));
999*433d6423SLionel Sambuc 		if (r != OK)
1000*433d6423SLionel Sambuc 			panic("fxp_writev: sys_safecopyfrom failed: %d", r);
1001*433d6423SLionel Sambuc 
1002*433d6423SLionel Sambuc 		for (j= 0, iovp= fp->fxp_iovec_s; j<n; j++, iovp++)
1003*433d6423SLionel Sambuc 		{
1004*433d6423SLionel Sambuc 			s= iovp->iov_size;
1005*433d6423SLionel Sambuc 			if (size + s > ETH_MAX_PACK_SIZE_TAGGED) {
1006*433d6423SLionel Sambuc 				panic("fxp_writev: invalid packet size: %d", size + s);
1007*433d6423SLionel Sambuc 			}
1008*433d6423SLionel Sambuc 
1009*433d6423SLionel Sambuc 			r= sys_safecopyfrom(iov_endpt, iovp->iov_grant,
1010*433d6423SLionel Sambuc 				0, (vir_bytes)(txp->tx_buf+o), s);
1011*433d6423SLionel Sambuc 			if (r != OK) {
1012*433d6423SLionel Sambuc 				panic("fxp_writev_s: sys_safecopyfrom failed: %d", r);
1013*433d6423SLionel Sambuc 			}
1014*433d6423SLionel Sambuc 			size += s;
1015*433d6423SLionel Sambuc 			o += s;
1016*433d6423SLionel Sambuc 		}
1017*433d6423SLionel Sambuc 	}
1018*433d6423SLionel Sambuc 	if (size < ETH_MIN_PACK_SIZE)
1019*433d6423SLionel Sambuc 		panic("fxp_writev: invalid packet size: %d", size);
1020*433d6423SLionel Sambuc 
1021*433d6423SLionel Sambuc 	txp->tx_status= 0;
1022*433d6423SLionel Sambuc 	txp->tx_command= TXC_EL | CBL_XMIT;
1023*433d6423SLionel Sambuc 	txp->tx_tbda= TX_TBDA_NIL;
1024*433d6423SLionel Sambuc 	txp->tx_size= TXSZ_EOF | size;
1025*433d6423SLionel Sambuc 	txp->tx_tthresh= fp->fxp_tx_threshold;
1026*433d6423SLionel Sambuc 	txp->tx_ntbd= 0;
1027*433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
1028*433d6423SLionel Sambuc 	{
1029*433d6423SLionel Sambuc 		fp->fxp_tx_idle= 0;
1030*433d6423SLionel Sambuc 		fp->fxp_tx_head= fp->fxp_tx_tail= 0;
1031*433d6423SLionel Sambuc 
1032*433d6423SLionel Sambuc 		fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr,
1033*433d6423SLionel Sambuc 			TRUE /* check idle */);
1034*433d6423SLionel Sambuc 	}
1035*433d6423SLionel Sambuc 	else
1036*433d6423SLionel Sambuc 	{
1037*433d6423SLionel Sambuc 		/* Link new request in transmit list */
1038*433d6423SLionel Sambuc 		tx_command= prev_txp->tx_command;
1039*433d6423SLionel Sambuc 		assert(tx_command == (TXC_EL | CBL_XMIT));
1040*433d6423SLionel Sambuc 		prev_txp->tx_command= CBL_XMIT;
1041*433d6423SLionel Sambuc 		fp->fxp_tx_head= fxp_tx_head;
1042*433d6423SLionel Sambuc 	}
1043*433d6423SLionel Sambuc 
1044*433d6423SLionel Sambuc 	fp->fxp_flags |= FF_PACK_SENT;
1045*433d6423SLionel Sambuc 
1046*433d6423SLionel Sambuc 	/* If the interrupt handler called, don't send a reply. The reply
1047*433d6423SLionel Sambuc 	 * will be sent after all interrupts are handled.
1048*433d6423SLionel Sambuc 	 */
1049*433d6423SLionel Sambuc 	if (from_int)
1050*433d6423SLionel Sambuc 		return;
1051*433d6423SLionel Sambuc 	reply(fp);
1052*433d6423SLionel Sambuc 	return;
1053*433d6423SLionel Sambuc 
1054*433d6423SLionel Sambuc suspend:
1055*433d6423SLionel Sambuc 	if (from_int)
1056*433d6423SLionel Sambuc 		panic("fxp: should not be sending");
1057*433d6423SLionel Sambuc 
1058*433d6423SLionel Sambuc 	fp->fxp_tx_mess= *mp;
1059*433d6423SLionel Sambuc 	reply(fp);
1060*433d6423SLionel Sambuc }
1061*433d6423SLionel Sambuc 
1062*433d6423SLionel Sambuc /*===========================================================================*
1063*433d6423SLionel Sambuc  *				fxp_readv_s				     *
1064*433d6423SLionel Sambuc  *===========================================================================*/
1065*433d6423SLionel Sambuc static void fxp_readv_s(mp, from_int)
1066*433d6423SLionel Sambuc message *mp;
1067*433d6423SLionel Sambuc int from_int;
1068*433d6423SLionel Sambuc {
1069*433d6423SLionel Sambuc 	int i, j, n, o, r, s, count, size, fxp_rx_head, fxp_rx_nbuf;
1070*433d6423SLionel Sambuc 	endpoint_t iov_endpt;
1071*433d6423SLionel Sambuc 	cp_grant_id_t iov_grant;
1072*433d6423SLionel Sambuc 	port_t port;
1073*433d6423SLionel Sambuc 	unsigned packlen;
1074*433d6423SLionel Sambuc 	vir_bytes iov_offset;
1075*433d6423SLionel Sambuc 	u16_t rfd_status;
1076*433d6423SLionel Sambuc 	u16_t rfd_res;
1077*433d6423SLionel Sambuc 	u8_t scb_status;
1078*433d6423SLionel Sambuc 	fxp_t *fp;
1079*433d6423SLionel Sambuc 	iovec_s_t *iovp;
1080*433d6423SLionel Sambuc 	struct rfd *rfdp, *prev_rfdp;
1081*433d6423SLionel Sambuc 
1082*433d6423SLionel Sambuc 	fp= fxp_state;
1083*433d6423SLionel Sambuc 
1084*433d6423SLionel Sambuc 	count = mp->m_net_netdrv_dl_readv_s.count;
1085*433d6423SLionel Sambuc 	fp->fxp_client= mp->m_source;
1086*433d6423SLionel Sambuc 
1087*433d6423SLionel Sambuc 	assert(fp->fxp_mode == FM_ENABLED);
1088*433d6423SLionel Sambuc 	assert(fp->fxp_flags & FF_ENABLED);
1089*433d6423SLionel Sambuc 
1090*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1091*433d6423SLionel Sambuc 
1092*433d6423SLionel Sambuc 	fxp_rx_head= fp->fxp_rx_head;
1093*433d6423SLionel Sambuc 	rfdp= &fp->fxp_rx_buf[fxp_rx_head];
1094*433d6423SLionel Sambuc 
1095*433d6423SLionel Sambuc 	rfd_status= rfdp->rfd_status;
1096*433d6423SLionel Sambuc 	if (!(rfd_status & RFDS_C))
1097*433d6423SLionel Sambuc 	{
1098*433d6423SLionel Sambuc 		/* Receive buffer is empty, suspend */
1099*433d6423SLionel Sambuc 		goto suspend;
1100*433d6423SLionel Sambuc 	}
1101*433d6423SLionel Sambuc 
1102*433d6423SLionel Sambuc 	if (!(rfd_status & RFDS_OK))
1103*433d6423SLionel Sambuc 	{
1104*433d6423SLionel Sambuc 		/* Not OK? What happened? */
1105*433d6423SLionel Sambuc 		assert(0);
1106*433d6423SLionel Sambuc 	}
1107*433d6423SLionel Sambuc 	else
1108*433d6423SLionel Sambuc 	{
1109*433d6423SLionel Sambuc 		assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR |
1110*433d6423SLionel Sambuc 			RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT |
1111*433d6423SLionel Sambuc 			RFDS_RXERR)));
1112*433d6423SLionel Sambuc 	}
1113*433d6423SLionel Sambuc 	rfd_res= rfdp->rfd_res;
1114*433d6423SLionel Sambuc 	assert(rfd_res & RFDR_EOF);
1115*433d6423SLionel Sambuc 	assert(rfd_res & RFDR_F);
1116*433d6423SLionel Sambuc 
1117*433d6423SLionel Sambuc 	packlen= rfd_res & RFDSZ_SIZE;
1118*433d6423SLionel Sambuc 
1119*433d6423SLionel Sambuc 	iov_endpt = mp->m_source;
1120*433d6423SLionel Sambuc 	iov_grant = mp->m_net_netdrv_dl_readv_s.grant;
1121*433d6423SLionel Sambuc 
1122*433d6423SLionel Sambuc 	size= 0;
1123*433d6423SLionel Sambuc 	o= 0;
1124*433d6423SLionel Sambuc 	iov_offset= 0;
1125*433d6423SLionel Sambuc 	for (i= 0; i<count; i += IOVEC_NR,
1126*433d6423SLionel Sambuc 		iov_offset += IOVEC_NR * sizeof(fp->fxp_iovec_s[0]))
1127*433d6423SLionel Sambuc 	{
1128*433d6423SLionel Sambuc 		n= IOVEC_NR;
1129*433d6423SLionel Sambuc 		if (i+n > count)
1130*433d6423SLionel Sambuc 			n= count-i;
1131*433d6423SLionel Sambuc 		r= sys_safecopyfrom(iov_endpt, iov_grant, iov_offset,
1132*433d6423SLionel Sambuc 			(vir_bytes)fp->fxp_iovec_s,
1133*433d6423SLionel Sambuc 			n * sizeof(fp->fxp_iovec_s[0]));
1134*433d6423SLionel Sambuc 		if (r != OK)
1135*433d6423SLionel Sambuc 			panic("fxp_readv_s: sys_safecopyfrom failed: %d", r);
1136*433d6423SLionel Sambuc 
1137*433d6423SLionel Sambuc 		for (j= 0, iovp= fp->fxp_iovec_s; j<n; j++, iovp++)
1138*433d6423SLionel Sambuc 		{
1139*433d6423SLionel Sambuc 			s= iovp->iov_size;
1140*433d6423SLionel Sambuc 			if (size + s > packlen)
1141*433d6423SLionel Sambuc 			{
1142*433d6423SLionel Sambuc 				assert(packlen > size);
1143*433d6423SLionel Sambuc 				s= packlen-size;
1144*433d6423SLionel Sambuc 			}
1145*433d6423SLionel Sambuc 
1146*433d6423SLionel Sambuc 			r= sys_safecopyto(iov_endpt, iovp->iov_grant,
1147*433d6423SLionel Sambuc 				0, (vir_bytes)(rfdp->rfd_buf+o), s);
1148*433d6423SLionel Sambuc 			if (r != OK)
1149*433d6423SLionel Sambuc 			{
1150*433d6423SLionel Sambuc 				panic("fxp_readv: sys_safecopyto failed: %d", r);
1151*433d6423SLionel Sambuc 			}
1152*433d6423SLionel Sambuc 
1153*433d6423SLionel Sambuc 			size += s;
1154*433d6423SLionel Sambuc 			if (size == packlen)
1155*433d6423SLionel Sambuc 				break;
1156*433d6423SLionel Sambuc 			o += s;
1157*433d6423SLionel Sambuc 		}
1158*433d6423SLionel Sambuc 		if (size == packlen)
1159*433d6423SLionel Sambuc 			break;
1160*433d6423SLionel Sambuc 	}
1161*433d6423SLionel Sambuc 	if (size < packlen)
1162*433d6423SLionel Sambuc 	{
1163*433d6423SLionel Sambuc 		assert(0);
1164*433d6423SLionel Sambuc 	}
1165*433d6423SLionel Sambuc 
1166*433d6423SLionel Sambuc 	fp->fxp_read_s= packlen;
1167*433d6423SLionel Sambuc 	fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV;
1168*433d6423SLionel Sambuc 
1169*433d6423SLionel Sambuc 	/* Re-init the current buffer */
1170*433d6423SLionel Sambuc 	rfdp->rfd_status= 0;
1171*433d6423SLionel Sambuc 	rfdp->rfd_command= RFDC_EL;
1172*433d6423SLionel Sambuc 	rfdp->rfd_reserved= 0;
1173*433d6423SLionel Sambuc 	rfdp->rfd_res= 0;
1174*433d6423SLionel Sambuc 	rfdp->rfd_size= sizeof(rfdp->rfd_buf);
1175*433d6423SLionel Sambuc 
1176*433d6423SLionel Sambuc 	fxp_rx_nbuf= fp->fxp_rx_nbuf;
1177*433d6423SLionel Sambuc 	if (fxp_rx_head == 0)
1178*433d6423SLionel Sambuc 	{
1179*433d6423SLionel Sambuc 		prev_rfdp= &fp->fxp_rx_buf[fxp_rx_nbuf-1];
1180*433d6423SLionel Sambuc 	}
1181*433d6423SLionel Sambuc 	else
1182*433d6423SLionel Sambuc 		prev_rfdp= &rfdp[-1];
1183*433d6423SLionel Sambuc 
1184*433d6423SLionel Sambuc 	assert(prev_rfdp->rfd_command & RFDC_EL);
1185*433d6423SLionel Sambuc 	prev_rfdp->rfd_command &= ~RFDC_EL;
1186*433d6423SLionel Sambuc 
1187*433d6423SLionel Sambuc 	fxp_rx_head++;
1188*433d6423SLionel Sambuc 	if (fxp_rx_head == fxp_rx_nbuf)
1189*433d6423SLionel Sambuc 		fxp_rx_head= 0;
1190*433d6423SLionel Sambuc 	assert(fxp_rx_head < fxp_rx_nbuf);
1191*433d6423SLionel Sambuc 	fp->fxp_rx_head= fxp_rx_head;
1192*433d6423SLionel Sambuc 
1193*433d6423SLionel Sambuc 	if (!from_int)
1194*433d6423SLionel Sambuc 		reply(fp);
1195*433d6423SLionel Sambuc 
1196*433d6423SLionel Sambuc 	return;
1197*433d6423SLionel Sambuc 
1198*433d6423SLionel Sambuc suspend:
1199*433d6423SLionel Sambuc 	if (fp->fxp_rx_need_restart)
1200*433d6423SLionel Sambuc 	{
1201*433d6423SLionel Sambuc 		fp->fxp_rx_need_restart= 0;
1202*433d6423SLionel Sambuc 
1203*433d6423SLionel Sambuc 		/* Check the status of the RU */
1204*433d6423SLionel Sambuc 		scb_status= fxp_inb(port, SCB_STATUS);
1205*433d6423SLionel Sambuc 		if ((scb_status & SS_RUS_MASK) != SS_RU_NORES)
1206*433d6423SLionel Sambuc 		{
1207*433d6423SLionel Sambuc 			/* Race condition? */
1208*433d6423SLionel Sambuc 			printf("fxp_readv: restart race: 0x%x\n",
1209*433d6423SLionel Sambuc 				scb_status);
1210*433d6423SLionel Sambuc 			assert((scb_status & SS_RUS_MASK) == SS_RU_READY);
1211*433d6423SLionel Sambuc 		}
1212*433d6423SLionel Sambuc 		else
1213*433d6423SLionel Sambuc 		{
1214*433d6423SLionel Sambuc 			fxp_restart_ru(fp);
1215*433d6423SLionel Sambuc 		}
1216*433d6423SLionel Sambuc 	}
1217*433d6423SLionel Sambuc 	if (from_int)
1218*433d6423SLionel Sambuc 	{
1219*433d6423SLionel Sambuc 		assert(fp->fxp_flags & FF_READING);
1220*433d6423SLionel Sambuc 
1221*433d6423SLionel Sambuc 		/* No need to store any state */
1222*433d6423SLionel Sambuc 		return;
1223*433d6423SLionel Sambuc 	}
1224*433d6423SLionel Sambuc 
1225*433d6423SLionel Sambuc 	fp->fxp_rx_mess= *mp;
1226*433d6423SLionel Sambuc 	assert(!(fp->fxp_flags & FF_READING));
1227*433d6423SLionel Sambuc 	fp->fxp_flags |= FF_READING;
1228*433d6423SLionel Sambuc 
1229*433d6423SLionel Sambuc 	reply(fp);
1230*433d6423SLionel Sambuc }
1231*433d6423SLionel Sambuc 
1232*433d6423SLionel Sambuc /*===========================================================================*
1233*433d6423SLionel Sambuc  *				fxp_do_conf				     *
1234*433d6423SLionel Sambuc  *===========================================================================*/
1235*433d6423SLionel Sambuc static void fxp_do_conf(fp)
1236*433d6423SLionel Sambuc fxp_t *fp;
1237*433d6423SLionel Sambuc {
1238*433d6423SLionel Sambuc 	int r;
1239*433d6423SLionel Sambuc 	phys_bytes bus_addr;
1240*433d6423SLionel Sambuc 
1241*433d6423SLionel Sambuc 	/* Configure device */
1242*433d6423SLionel Sambuc 	tmpbufp->cc.cc_status= 0;
1243*433d6423SLionel Sambuc 	tmpbufp->cc.cc_command= CBL_C_EL | CBL_CONF;
1244*433d6423SLionel Sambuc 	tmpbufp->cc.cc_linkaddr= 0;
1245*433d6423SLionel Sambuc 	memcpy(tmpbufp->cc.cc_bytes, fp->fxp_conf_bytes,
1246*433d6423SLionel Sambuc 		sizeof(tmpbufp->cc.cc_bytes));
1247*433d6423SLionel Sambuc 
1248*433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->cc,
1249*433d6423SLionel Sambuc 		(phys_bytes)sizeof(tmpbufp->cc), &bus_addr);
1250*433d6423SLionel Sambuc 	if (r != OK)
1251*433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
1252*433d6423SLionel Sambuc 
1253*433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
1254*433d6423SLionel Sambuc 
1255*433d6423SLionel Sambuc 	/* Wait for CU command to complete */
1256*433d6423SLionel Sambuc 	SPIN_UNTIL(tmpbufp->cc.cc_status & CBL_F_C, 100000);
1257*433d6423SLionel Sambuc 
1258*433d6423SLionel Sambuc 	if (!(tmpbufp->cc.cc_status & CBL_F_C))
1259*433d6423SLionel Sambuc 		panic("fxp_do_conf: CU command failed to complete");
1260*433d6423SLionel Sambuc 	if (!(tmpbufp->cc.cc_status & CBL_F_OK))
1261*433d6423SLionel Sambuc 		panic("fxp_do_conf: CU command failed");
1262*433d6423SLionel Sambuc 
1263*433d6423SLionel Sambuc }
1264*433d6423SLionel Sambuc 
1265*433d6423SLionel Sambuc /*===========================================================================*
1266*433d6423SLionel Sambuc  *				fxp_cu_ptr_cmd				     *
1267*433d6423SLionel Sambuc  *===========================================================================*/
1268*433d6423SLionel Sambuc static void fxp_cu_ptr_cmd(fp, cmd, bus_addr, check_idle)
1269*433d6423SLionel Sambuc fxp_t *fp;
1270*433d6423SLionel Sambuc int cmd;
1271*433d6423SLionel Sambuc phys_bytes bus_addr;
1272*433d6423SLionel Sambuc int check_idle;
1273*433d6423SLionel Sambuc {
1274*433d6423SLionel Sambuc 	spin_t spin;
1275*433d6423SLionel Sambuc 	port_t port;
1276*433d6423SLionel Sambuc 	u8_t scb_cmd;
1277*433d6423SLionel Sambuc 
1278*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1279*433d6423SLionel Sambuc 
1280*433d6423SLionel Sambuc 	if (check_idle)
1281*433d6423SLionel Sambuc 	{
1282*433d6423SLionel Sambuc 		/* Consistency check. Make sure that CU is idle */
1283*433d6423SLionel Sambuc 		if ((fxp_inb(port, SCB_STATUS) & SS_CUS_MASK) != SS_CU_IDLE)
1284*433d6423SLionel Sambuc 			panic("fxp_cu_ptr_cmd: CU is not idle");
1285*433d6423SLionel Sambuc 	}
1286*433d6423SLionel Sambuc 
1287*433d6423SLionel Sambuc 	fxp_outl(port, SCB_POINTER, bus_addr);
1288*433d6423SLionel Sambuc 	fxp_outb(port, SCB_CMD, cmd);
1289*433d6423SLionel Sambuc 
1290*433d6423SLionel Sambuc 	/* What is a reasonable time-out? There is nothing in the
1291*433d6423SLionel Sambuc 	 * documentation. 1 ms should be enough. We use 100 ms.
1292*433d6423SLionel Sambuc 	 */
1293*433d6423SLionel Sambuc 	spin_init(&spin, 100000);
1294*433d6423SLionel Sambuc 	do {
1295*433d6423SLionel Sambuc 		/* Wait for CU command to be accepted */
1296*433d6423SLionel Sambuc 		scb_cmd= fxp_inb(port, SCB_CMD);
1297*433d6423SLionel Sambuc 		if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP)
1298*433d6423SLionel Sambuc 			break;
1299*433d6423SLionel Sambuc 	} while (spin_check(&spin));
1300*433d6423SLionel Sambuc 
1301*433d6423SLionel Sambuc 	if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP)
1302*433d6423SLionel Sambuc 		panic("fxp_cu_ptr_cmd: CU does not accept command");
1303*433d6423SLionel Sambuc }
1304*433d6423SLionel Sambuc 
1305*433d6423SLionel Sambuc /*===========================================================================*
1306*433d6423SLionel Sambuc  *				fxp_ru_ptr_cmd				     *
1307*433d6423SLionel Sambuc  *===========================================================================*/
1308*433d6423SLionel Sambuc static void fxp_ru_ptr_cmd(fp, cmd, bus_addr, check_idle)
1309*433d6423SLionel Sambuc fxp_t *fp;
1310*433d6423SLionel Sambuc int cmd;
1311*433d6423SLionel Sambuc phys_bytes bus_addr;
1312*433d6423SLionel Sambuc int check_idle;
1313*433d6423SLionel Sambuc {
1314*433d6423SLionel Sambuc 	spin_t spin;
1315*433d6423SLionel Sambuc 	port_t port;
1316*433d6423SLionel Sambuc 	u8_t scb_cmd;
1317*433d6423SLionel Sambuc 
1318*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1319*433d6423SLionel Sambuc 
1320*433d6423SLionel Sambuc 	if (check_idle)
1321*433d6423SLionel Sambuc 	{
1322*433d6423SLionel Sambuc 		/* Consistency check, make sure that RU is idle */
1323*433d6423SLionel Sambuc 		if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_IDLE)
1324*433d6423SLionel Sambuc 			panic("fxp_ru_ptr_cmd: RU is not idle");
1325*433d6423SLionel Sambuc 	}
1326*433d6423SLionel Sambuc 
1327*433d6423SLionel Sambuc 	fxp_outl(port, SCB_POINTER, bus_addr);
1328*433d6423SLionel Sambuc 	fxp_outb(port, SCB_CMD, cmd);
1329*433d6423SLionel Sambuc 
1330*433d6423SLionel Sambuc 	spin_init(&spin, 1000);
1331*433d6423SLionel Sambuc 	do {
1332*433d6423SLionel Sambuc 		/* Wait for RU command to be accepted */
1333*433d6423SLionel Sambuc 		scb_cmd= fxp_inb(port, SCB_CMD);
1334*433d6423SLionel Sambuc 		if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP)
1335*433d6423SLionel Sambuc 			break;
1336*433d6423SLionel Sambuc 	} while (spin_check(&spin));
1337*433d6423SLionel Sambuc 
1338*433d6423SLionel Sambuc 	if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP)
1339*433d6423SLionel Sambuc 		panic("fxp_ru_ptr_cmd: RU does not accept command");
1340*433d6423SLionel Sambuc }
1341*433d6423SLionel Sambuc 
1342*433d6423SLionel Sambuc /*===========================================================================*
1343*433d6423SLionel Sambuc  *				fxp_restart_ru				     *
1344*433d6423SLionel Sambuc  *===========================================================================*/
1345*433d6423SLionel Sambuc static void fxp_restart_ru(fp)
1346*433d6423SLionel Sambuc fxp_t *fp;
1347*433d6423SLionel Sambuc {
1348*433d6423SLionel Sambuc 	int i, fxp_rx_nbuf;
1349*433d6423SLionel Sambuc 	port_t port;
1350*433d6423SLionel Sambuc 	struct rfd *rfdp;
1351*433d6423SLionel Sambuc 
1352*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1353*433d6423SLionel Sambuc 
1354*433d6423SLionel Sambuc 	fxp_rx_nbuf= fp->fxp_rx_nbuf;
1355*433d6423SLionel Sambuc 	for (i= 0, rfdp= fp->fxp_rx_buf; i<fxp_rx_nbuf; i++, rfdp++)
1356*433d6423SLionel Sambuc 	{
1357*433d6423SLionel Sambuc 		rfdp->rfd_status= 0;
1358*433d6423SLionel Sambuc 		rfdp->rfd_command= 0;
1359*433d6423SLionel Sambuc 		if (i == fp->fxp_rx_nbuf-1)
1360*433d6423SLionel Sambuc 			rfdp->rfd_command= RFDC_EL;
1361*433d6423SLionel Sambuc 		rfdp->rfd_reserved= 0;
1362*433d6423SLionel Sambuc 		rfdp->rfd_res= 0;
1363*433d6423SLionel Sambuc 		rfdp->rfd_size= sizeof(rfdp->rfd_buf);
1364*433d6423SLionel Sambuc 	}
1365*433d6423SLionel Sambuc 	fp->fxp_rx_head= 0;
1366*433d6423SLionel Sambuc 
1367*433d6423SLionel Sambuc 	/* Make sure that RU is in the 'No resources' state */
1368*433d6423SLionel Sambuc 	if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_NORES)
1369*433d6423SLionel Sambuc 		panic("fxp_restart_ru: RU is in an unexpected state");
1370*433d6423SLionel Sambuc 
1371*433d6423SLionel Sambuc 	fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
1372*433d6423SLionel Sambuc 		FALSE /* do not check idle */);
1373*433d6423SLionel Sambuc }
1374*433d6423SLionel Sambuc 
1375*433d6423SLionel Sambuc /*===========================================================================*
1376*433d6423SLionel Sambuc  *				fxp_getstat_s				     *
1377*433d6423SLionel Sambuc  *===========================================================================*/
1378*433d6423SLionel Sambuc static void fxp_getstat_s(message *mp)
1379*433d6423SLionel Sambuc {
1380*433d6423SLionel Sambuc 	int r;
1381*433d6423SLionel Sambuc 	fxp_t *fp;
1382*433d6423SLionel Sambuc 	u32_t *p;
1383*433d6423SLionel Sambuc 	eth_stat_t stats;
1384*433d6423SLionel Sambuc 
1385*433d6423SLionel Sambuc 	fp= fxp_state;
1386*433d6423SLionel Sambuc 
1387*433d6423SLionel Sambuc 	assert(fp->fxp_mode == FM_ENABLED);
1388*433d6423SLionel Sambuc 	assert(fp->fxp_flags & FF_ENABLED);
1389*433d6423SLionel Sambuc 
1390*433d6423SLionel Sambuc 	p= &fp->fxp_stat.sc_tx_fcp;
1391*433d6423SLionel Sambuc 	*p= 0;
1392*433d6423SLionel Sambuc 
1393*433d6423SLionel Sambuc 	/* The dump commmand doesn't take a pointer. Setting a pointer
1394*433d6423SLionel Sambuc 	 * doesn't hurt though.
1395*433d6423SLionel Sambuc 	 */
1396*433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */);
1397*433d6423SLionel Sambuc 
1398*433d6423SLionel Sambuc 	/* Wait for CU command to complete */
1399*433d6423SLionel Sambuc 	SPIN_UNTIL(*p != 0, 1000);
1400*433d6423SLionel Sambuc 
1401*433d6423SLionel Sambuc 	if (*p == 0)
1402*433d6423SLionel Sambuc 		panic("fxp_getstat: CU command failed to complete");
1403*433d6423SLionel Sambuc 	if (*p != SCM_DSC)
1404*433d6423SLionel Sambuc 		panic("fxp_getstat: bad magic");
1405*433d6423SLionel Sambuc 
1406*433d6423SLionel Sambuc 	stats.ets_recvErr=
1407*433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_crc +
1408*433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_align +
1409*433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_resource +
1410*433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_overrun +
1411*433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_cd +
1412*433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_short;
1413*433d6423SLionel Sambuc 	stats.ets_sendErr=
1414*433d6423SLionel Sambuc 		fp->fxp_stat.sc_tx_maxcol +
1415*433d6423SLionel Sambuc 		fp->fxp_stat.sc_tx_latecol +
1416*433d6423SLionel Sambuc 		fp->fxp_stat.sc_tx_crs;
1417*433d6423SLionel Sambuc 	stats.ets_OVW= fp->fxp_stat.sc_rx_overrun;
1418*433d6423SLionel Sambuc 	stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc;
1419*433d6423SLionel Sambuc 	stats.ets_frameAll= fp->fxp_stat.sc_rx_align;
1420*433d6423SLionel Sambuc 	stats.ets_missedP= fp->fxp_stat.sc_rx_resource;
1421*433d6423SLionel Sambuc 	stats.ets_packetR= fp->fxp_stat.sc_rx_good;
1422*433d6423SLionel Sambuc 	stats.ets_packetT= fp->fxp_stat.sc_tx_good;
1423*433d6423SLionel Sambuc 	stats.ets_transDef= fp->fxp_stat.sc_tx_defered;
1424*433d6423SLionel Sambuc 	stats.ets_collision= fp->fxp_stat.sc_tx_totcol;
1425*433d6423SLionel Sambuc 	stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol;
1426*433d6423SLionel Sambuc 	stats.ets_carrSense= fp->fxp_stat.sc_tx_crs;
1427*433d6423SLionel Sambuc 	stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun;
1428*433d6423SLionel Sambuc 	stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun;
1429*433d6423SLionel Sambuc 	stats.ets_CDheartbeat= 0;
1430*433d6423SLionel Sambuc 	stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
1431*433d6423SLionel Sambuc 
1432*433d6423SLionel Sambuc 	r= sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0,
1433*433d6423SLionel Sambuc 		(vir_bytes)&stats, sizeof(stats));
1434*433d6423SLionel Sambuc 	if (r != OK)
1435*433d6423SLionel Sambuc 		panic("fxp_getstat_s: sys_safecopyto failed: %d", r);
1436*433d6423SLionel Sambuc 
1437*433d6423SLionel Sambuc 	mp->m_type= DL_STAT_REPLY;
1438*433d6423SLionel Sambuc 	r= ipc_send(mp->m_source, mp);
1439*433d6423SLionel Sambuc 	if (r != OK)
1440*433d6423SLionel Sambuc 		panic("fxp_getstat_s: ipc_send failed: %d", r);
1441*433d6423SLionel Sambuc }
1442*433d6423SLionel Sambuc 
1443*433d6423SLionel Sambuc /*===========================================================================*
1444*433d6423SLionel Sambuc  *				fxp_handler				     *
1445*433d6423SLionel Sambuc  *===========================================================================*/
1446*433d6423SLionel Sambuc static void fxp_handler(fxp_t *fp)
1447*433d6423SLionel Sambuc {
1448*433d6423SLionel Sambuc 	int port;
1449*433d6423SLionel Sambuc 	u16_t isr;
1450*433d6423SLionel Sambuc 
1451*433d6423SLionel Sambuc 	RAND_UPDATE
1452*433d6423SLionel Sambuc 
1453*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1454*433d6423SLionel Sambuc 
1455*433d6423SLionel Sambuc 	/* Ack interrupt */
1456*433d6423SLionel Sambuc 	isr= fxp_inb(port, SCB_INT_STAT);
1457*433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_STAT, isr);
1458*433d6423SLionel Sambuc 
1459*433d6423SLionel Sambuc 	if (isr & SIS_FR)
1460*433d6423SLionel Sambuc 	{
1461*433d6423SLionel Sambuc 		isr &= ~SIS_FR;
1462*433d6423SLionel Sambuc 
1463*433d6423SLionel Sambuc 		if (!fp->fxp_got_int && (fp->fxp_flags & FF_READING))
1464*433d6423SLionel Sambuc 		{
1465*433d6423SLionel Sambuc 			fp->fxp_got_int= TRUE;
1466*433d6423SLionel Sambuc 			interrupt(fxp_tasknr);
1467*433d6423SLionel Sambuc 		}
1468*433d6423SLionel Sambuc 	}
1469*433d6423SLionel Sambuc 	if (isr & SIS_CNA)
1470*433d6423SLionel Sambuc 	{
1471*433d6423SLionel Sambuc 		isr &= ~SIS_CNA;
1472*433d6423SLionel Sambuc 		if (!fp->fxp_tx_idle)
1473*433d6423SLionel Sambuc 		{
1474*433d6423SLionel Sambuc 			fp->fxp_send_int= TRUE;
1475*433d6423SLionel Sambuc 			if (!fp->fxp_got_int)
1476*433d6423SLionel Sambuc 			{
1477*433d6423SLionel Sambuc 				fp->fxp_got_int= TRUE;
1478*433d6423SLionel Sambuc 				interrupt(fxp_tasknr);
1479*433d6423SLionel Sambuc 			}
1480*433d6423SLionel Sambuc 		}
1481*433d6423SLionel Sambuc 	}
1482*433d6423SLionel Sambuc 	if (isr & SIS_RNR)
1483*433d6423SLionel Sambuc 	{
1484*433d6423SLionel Sambuc 		isr &= ~SIS_RNR;
1485*433d6423SLionel Sambuc 
1486*433d6423SLionel Sambuc 		/* Assume that receive buffer is full of packets. fxp_readv
1487*433d6423SLionel Sambuc 		 * will restart the RU.
1488*433d6423SLionel Sambuc 		 */
1489*433d6423SLionel Sambuc 		fp->fxp_rx_need_restart= 1;
1490*433d6423SLionel Sambuc 	}
1491*433d6423SLionel Sambuc 	if (isr)
1492*433d6423SLionel Sambuc 	{
1493*433d6423SLionel Sambuc 		printf("fxp_handler: unhandled interrupt: isr = 0x%02x\n",
1494*433d6423SLionel Sambuc 			isr);
1495*433d6423SLionel Sambuc 	}
1496*433d6423SLionel Sambuc }
1497*433d6423SLionel Sambuc 
1498*433d6423SLionel Sambuc /*===========================================================================*
1499*433d6423SLionel Sambuc  *				fxp_check_ints				     *
1500*433d6423SLionel Sambuc  *===========================================================================*/
1501*433d6423SLionel Sambuc static void fxp_check_ints(fxp_t *fp)
1502*433d6423SLionel Sambuc {
1503*433d6423SLionel Sambuc 	int n, fxp_flags, prev_tail;
1504*433d6423SLionel Sambuc 	int fxp_tx_tail, fxp_tx_nbuf, fxp_tx_threshold;
1505*433d6423SLionel Sambuc 	port_t port;
1506*433d6423SLionel Sambuc 	u32_t busaddr;
1507*433d6423SLionel Sambuc 	u16_t tx_status;
1508*433d6423SLionel Sambuc 	u8_t scb_status;
1509*433d6423SLionel Sambuc 	struct tx *txp;
1510*433d6423SLionel Sambuc 
1511*433d6423SLionel Sambuc 	fxp_flags= fp->fxp_flags;
1512*433d6423SLionel Sambuc 
1513*433d6423SLionel Sambuc 	if (fxp_flags & FF_READING)
1514*433d6423SLionel Sambuc 	{
1515*433d6423SLionel Sambuc 		if (!(fp->fxp_rx_buf[fp->fxp_rx_head].rfd_status & RFDS_C))
1516*433d6423SLionel Sambuc 			; /* Nothing */
1517*433d6423SLionel Sambuc 		else
1518*433d6423SLionel Sambuc 		{
1519*433d6423SLionel Sambuc 			fxp_readv_s(&fp->fxp_rx_mess, TRUE /* from int */);
1520*433d6423SLionel Sambuc 		}
1521*433d6423SLionel Sambuc 	}
1522*433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
1523*433d6423SLionel Sambuc 		;	/* Nothing to do */
1524*433d6423SLionel Sambuc 	else if (fp->fxp_send_int)
1525*433d6423SLionel Sambuc 	{
1526*433d6423SLionel Sambuc 		fp->fxp_send_int= FALSE;
1527*433d6423SLionel Sambuc 		fxp_tx_tail= fp->fxp_tx_tail;
1528*433d6423SLionel Sambuc 		fxp_tx_nbuf= fp->fxp_tx_nbuf;
1529*433d6423SLionel Sambuc 		n= 0;
1530*433d6423SLionel Sambuc 		for (;;)
1531*433d6423SLionel Sambuc 		{
1532*433d6423SLionel Sambuc 			txp= &fp->fxp_tx_buf[fxp_tx_tail];
1533*433d6423SLionel Sambuc 			tx_status= txp->tx_status;
1534*433d6423SLionel Sambuc 			if (!(tx_status & TXS_C))
1535*433d6423SLionel Sambuc 				break;
1536*433d6423SLionel Sambuc 
1537*433d6423SLionel Sambuc 			n++;
1538*433d6423SLionel Sambuc 
1539*433d6423SLionel Sambuc 			assert(tx_status & TXS_OK);
1540*433d6423SLionel Sambuc 			if (tx_status & TXS_U)
1541*433d6423SLionel Sambuc 			{
1542*433d6423SLionel Sambuc 				fxp_tx_threshold= fp->fxp_tx_threshold;
1543*433d6423SLionel Sambuc 				if (fxp_tx_threshold < TXTT_MAX)
1544*433d6423SLionel Sambuc 				{
1545*433d6423SLionel Sambuc 					fxp_tx_threshold++;
1546*433d6423SLionel Sambuc 					fp->fxp_tx_threshold= fxp_tx_threshold;
1547*433d6423SLionel Sambuc 				}
1548*433d6423SLionel Sambuc 				printf(
1549*433d6423SLionel Sambuc 			"fxp_check_ints: fxp_tx_threshold = 0x%x\n",
1550*433d6423SLionel Sambuc 					fxp_tx_threshold);
1551*433d6423SLionel Sambuc 			}
1552*433d6423SLionel Sambuc 
1553*433d6423SLionel Sambuc 			if (txp->tx_command & TXC_EL)
1554*433d6423SLionel Sambuc 			{
1555*433d6423SLionel Sambuc 				fp->fxp_tx_idle= 1;
1556*433d6423SLionel Sambuc 				break;
1557*433d6423SLionel Sambuc 			}
1558*433d6423SLionel Sambuc 
1559*433d6423SLionel Sambuc 			fxp_tx_tail++;
1560*433d6423SLionel Sambuc 			if (fxp_tx_tail == fxp_tx_nbuf)
1561*433d6423SLionel Sambuc 				fxp_tx_tail= 0;
1562*433d6423SLionel Sambuc 			assert(fxp_tx_tail < fxp_tx_nbuf);
1563*433d6423SLionel Sambuc 		}
1564*433d6423SLionel Sambuc 
1565*433d6423SLionel Sambuc 		if (fp->fxp_need_conf)
1566*433d6423SLionel Sambuc 		{
1567*433d6423SLionel Sambuc 			/* Check the status of the CU */
1568*433d6423SLionel Sambuc 			port= fp->fxp_base_port;
1569*433d6423SLionel Sambuc 			scb_status= fxp_inb(port, SCB_STATUS);
1570*433d6423SLionel Sambuc 			if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
1571*433d6423SLionel Sambuc 			{
1572*433d6423SLionel Sambuc 				/* Nothing to do */
1573*433d6423SLionel Sambuc 				printf("scb_status = 0x%x\n", scb_status);
1574*433d6423SLionel Sambuc 			}
1575*433d6423SLionel Sambuc 			else
1576*433d6423SLionel Sambuc 			{
1577*433d6423SLionel Sambuc 				printf("fxp_check_ints: fxp_need_conf\n");
1578*433d6423SLionel Sambuc 				fp->fxp_need_conf= FALSE;
1579*433d6423SLionel Sambuc 				fxp_do_conf(fp);
1580*433d6423SLionel Sambuc 			}
1581*433d6423SLionel Sambuc 		}
1582*433d6423SLionel Sambuc 
1583*433d6423SLionel Sambuc 		if (n)
1584*433d6423SLionel Sambuc 		{
1585*433d6423SLionel Sambuc 			if (!fp->fxp_tx_idle)
1586*433d6423SLionel Sambuc 			{
1587*433d6423SLionel Sambuc 				fp->fxp_tx_tail= fxp_tx_tail;
1588*433d6423SLionel Sambuc 
1589*433d6423SLionel Sambuc 				/* Check the status of the CU */
1590*433d6423SLionel Sambuc 				port= fp->fxp_base_port;
1591*433d6423SLionel Sambuc 				scb_status= fxp_inb(port, SCB_STATUS);
1592*433d6423SLionel Sambuc 				if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
1593*433d6423SLionel Sambuc 				{
1594*433d6423SLionel Sambuc 					/* Nothing to do */
1595*433d6423SLionel Sambuc 					printf("scb_status = 0x%x\n",
1596*433d6423SLionel Sambuc 						scb_status);
1597*433d6423SLionel Sambuc 
1598*433d6423SLionel Sambuc 				}
1599*433d6423SLionel Sambuc 				else
1600*433d6423SLionel Sambuc 				{
1601*433d6423SLionel Sambuc 					if (fxp_tx_tail == 0)
1602*433d6423SLionel Sambuc 						prev_tail= fxp_tx_nbuf-1;
1603*433d6423SLionel Sambuc 					else
1604*433d6423SLionel Sambuc 						prev_tail= fxp_tx_tail-1;
1605*433d6423SLionel Sambuc 					busaddr= fp->fxp_tx_buf[prev_tail].
1606*433d6423SLionel Sambuc 						tx_linkaddr;
1607*433d6423SLionel Sambuc 
1608*433d6423SLionel Sambuc 					fxp_cu_ptr_cmd(fp, SC_CU_START,
1609*433d6423SLionel Sambuc 						busaddr, 1 /* check idle */);
1610*433d6423SLionel Sambuc 				}
1611*433d6423SLionel Sambuc 			}
1612*433d6423SLionel Sambuc 
1613*433d6423SLionel Sambuc 			if (fp->fxp_flags & FF_SEND_AVAIL)
1614*433d6423SLionel Sambuc 			{
1615*433d6423SLionel Sambuc 				fxp_writev_s(&fp->fxp_tx_mess,
1616*433d6423SLionel Sambuc 					TRUE /* from int */);
1617*433d6423SLionel Sambuc 			}
1618*433d6423SLionel Sambuc 		}
1619*433d6423SLionel Sambuc 
1620*433d6423SLionel Sambuc 	}
1621*433d6423SLionel Sambuc 	if (fp->fxp_report_link)
1622*433d6423SLionel Sambuc 		fxp_report_link(fp);
1623*433d6423SLionel Sambuc 
1624*433d6423SLionel Sambuc 	if (fp->fxp_flags & (FF_PACK_SENT | FF_PACK_RECV))
1625*433d6423SLionel Sambuc 		reply(fp);
1626*433d6423SLionel Sambuc }
1627*433d6423SLionel Sambuc 
1628*433d6423SLionel Sambuc /*===========================================================================*
1629*433d6423SLionel Sambuc  *				fxp_watchdog_f				     *
1630*433d6423SLionel Sambuc  *===========================================================================*/
1631*433d6423SLionel Sambuc static void fxp_watchdog_f(tp)
1632*433d6423SLionel Sambuc minix_timer_t *tp;
1633*433d6423SLionel Sambuc {
1634*433d6423SLionel Sambuc 	fxp_t *fp;
1635*433d6423SLionel Sambuc 
1636*433d6423SLionel Sambuc 	set_timer(&fxp_watchdog, system_hz, fxp_watchdog_f, 0);
1637*433d6423SLionel Sambuc 
1638*433d6423SLionel Sambuc 	fp= fxp_state;
1639*433d6423SLionel Sambuc 	if (fp->fxp_mode != FM_ENABLED)
1640*433d6423SLionel Sambuc 		return;
1641*433d6423SLionel Sambuc 
1642*433d6423SLionel Sambuc 	/* Handle race condition, MII interface might be busy */
1643*433d6423SLionel Sambuc 	if(!fp->fxp_mii_busy)
1644*433d6423SLionel Sambuc 	{
1645*433d6423SLionel Sambuc 		/* Check the link status. */
1646*433d6423SLionel Sambuc 		if (fxp_link_changed(fp))
1647*433d6423SLionel Sambuc 		{
1648*433d6423SLionel Sambuc #if VERBOSE
1649*433d6423SLionel Sambuc 			printf("fxp_watchdog_f: link changed\n");
1650*433d6423SLionel Sambuc #endif
1651*433d6423SLionel Sambuc 			fp->fxp_report_link= TRUE;
1652*433d6423SLionel Sambuc 			fp->fxp_got_int= TRUE;
1653*433d6423SLionel Sambuc 			interrupt(fxp_tasknr);
1654*433d6423SLionel Sambuc 		}
1655*433d6423SLionel Sambuc 	}
1656*433d6423SLionel Sambuc 
1657*433d6423SLionel Sambuc 	if (!(fp->fxp_flags & FF_SEND_AVAIL))
1658*433d6423SLionel Sambuc 	{
1659*433d6423SLionel Sambuc 		/* Assume that an idle system is alive */
1660*433d6423SLionel Sambuc 		fp->fxp_tx_alive= TRUE;
1661*433d6423SLionel Sambuc 		return;
1662*433d6423SLionel Sambuc 	}
1663*433d6423SLionel Sambuc 	if (fp->fxp_tx_alive)
1664*433d6423SLionel Sambuc 	{
1665*433d6423SLionel Sambuc 		fp->fxp_tx_alive= FALSE;
1666*433d6423SLionel Sambuc 		return;
1667*433d6423SLionel Sambuc 	}
1668*433d6423SLionel Sambuc 
1669*433d6423SLionel Sambuc 	fp->fxp_need_reset= TRUE;
1670*433d6423SLionel Sambuc 	fp->fxp_got_int= TRUE;
1671*433d6423SLionel Sambuc 	interrupt(fxp_tasknr);
1672*433d6423SLionel Sambuc }
1673*433d6423SLionel Sambuc 
1674*433d6423SLionel Sambuc /*===========================================================================*
1675*433d6423SLionel Sambuc  *				fxp_link_changed			     *
1676*433d6423SLionel Sambuc  *===========================================================================*/
1677*433d6423SLionel Sambuc static int fxp_link_changed(fp)
1678*433d6423SLionel Sambuc fxp_t *fp;
1679*433d6423SLionel Sambuc {
1680*433d6423SLionel Sambuc 	u16_t scr;
1681*433d6423SLionel Sambuc 
1682*433d6423SLionel Sambuc 	scr= mii_read(fp, MII_SCR);
1683*433d6423SLionel Sambuc 	scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
1684*433d6423SLionel Sambuc 
1685*433d6423SLionel Sambuc 	return (fp->fxp_mii_scr != scr);
1686*433d6423SLionel Sambuc }
1687*433d6423SLionel Sambuc 
1688*433d6423SLionel Sambuc /*===========================================================================*
1689*433d6423SLionel Sambuc  *				fxp_report_link				     *
1690*433d6423SLionel Sambuc  *===========================================================================*/
1691*433d6423SLionel Sambuc static void fxp_report_link(fxp_t *fp)
1692*433d6423SLionel Sambuc {
1693*433d6423SLionel Sambuc 	u16_t mii_ctrl, mii_status, mii_id1, mii_id2,
1694*433d6423SLionel Sambuc 		mii_ana, mii_anlpa, mii_ane, mii_extstat,
1695*433d6423SLionel Sambuc 		mii_ms_ctrl, mii_ms_status, scr;
1696*433d6423SLionel Sambuc 	u32_t oui;
1697*433d6423SLionel Sambuc 	int model, rev;
1698*433d6423SLionel Sambuc 	int f, link_up;
1699*433d6423SLionel Sambuc 
1700*433d6423SLionel Sambuc 	fp->fxp_report_link= FALSE;
1701*433d6423SLionel Sambuc 
1702*433d6423SLionel Sambuc 	scr= mii_read(fp, MII_SCR);
1703*433d6423SLionel Sambuc 	scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
1704*433d6423SLionel Sambuc 	fp->fxp_mii_scr= scr;
1705*433d6423SLionel Sambuc 
1706*433d6423SLionel Sambuc 	mii_ctrl= mii_read(fp, MII_CTRL);
1707*433d6423SLionel Sambuc 	mii_read(fp, MII_STATUS); /* The status reg is latched, read twice */
1708*433d6423SLionel Sambuc 	mii_status= mii_read(fp, MII_STATUS);
1709*433d6423SLionel Sambuc 	mii_id1= mii_read(fp, MII_PHYID_H);
1710*433d6423SLionel Sambuc 	mii_id2= mii_read(fp, MII_PHYID_L);
1711*433d6423SLionel Sambuc 	mii_ana= mii_read(fp, MII_ANA);
1712*433d6423SLionel Sambuc 	mii_anlpa= mii_read(fp, MII_ANLPA);
1713*433d6423SLionel Sambuc 	mii_ane= mii_read(fp, MII_ANE);
1714*433d6423SLionel Sambuc 	if (mii_status & MII_STATUS_EXT_STAT)
1715*433d6423SLionel Sambuc 		mii_extstat= mii_read(fp, MII_EXT_STATUS);
1716*433d6423SLionel Sambuc 	else
1717*433d6423SLionel Sambuc 		mii_extstat= 0;
1718*433d6423SLionel Sambuc 	if (fp->fxp_ms_regs)
1719*433d6423SLionel Sambuc 	{
1720*433d6423SLionel Sambuc 		mii_ms_ctrl= mii_read(fp, MII_MS_CTRL);
1721*433d6423SLionel Sambuc 		mii_ms_status= mii_read(fp, MII_MS_STATUS);
1722*433d6423SLionel Sambuc 	}
1723*433d6423SLionel Sambuc 	else
1724*433d6423SLionel Sambuc 	{
1725*433d6423SLionel Sambuc 		mii_ms_ctrl= 0;
1726*433d6423SLionel Sambuc 		mii_ms_status= 0;
1727*433d6423SLionel Sambuc 	}
1728*433d6423SLionel Sambuc 
1729*433d6423SLionel Sambuc 	/* How do we know about the link status? */
1730*433d6423SLionel Sambuc 	link_up= !!(mii_status & MII_STATUS_LS);
1731*433d6423SLionel Sambuc 
1732*433d6423SLionel Sambuc 	fp->fxp_link_up= link_up;
1733*433d6423SLionel Sambuc 	if (!link_up)
1734*433d6423SLionel Sambuc 	{
1735*433d6423SLionel Sambuc #if VERBOSE
1736*433d6423SLionel Sambuc 		printf("%s: link down\n", fp->fxp_name);
1737*433d6423SLionel Sambuc #endif
1738*433d6423SLionel Sambuc 		return;
1739*433d6423SLionel Sambuc 	}
1740*433d6423SLionel Sambuc 
1741*433d6423SLionel Sambuc 	oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) |
1742*433d6423SLionel Sambuc 		((mii_id2 & MII_PL_OUI_L_MASK) >> MII_PL_OUI_L_SHIFT);
1743*433d6423SLionel Sambuc 	model= ((mii_id2 & MII_PL_MODEL_MASK) >> MII_PL_MODEL_SHIFT);
1744*433d6423SLionel Sambuc 	rev= (mii_id2 & MII_PL_REV_MASK);
1745*433d6423SLionel Sambuc 
1746*433d6423SLionel Sambuc #if VERBOSE
1747*433d6423SLionel Sambuc 	printf("OUI 0x%06lx, Model 0x%02x, Revision 0x%x\n", oui, model, rev);
1748*433d6423SLionel Sambuc #endif
1749*433d6423SLionel Sambuc 
1750*433d6423SLionel Sambuc 	if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1751*433d6423SLionel Sambuc 	{
1752*433d6423SLionel Sambuc 		printf("%s: PHY: ", fp->fxp_name);
1753*433d6423SLionel Sambuc 		f= 1;
1754*433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_LB)
1755*433d6423SLionel Sambuc 		{
1756*433d6423SLionel Sambuc 			printf("loopback mode");
1757*433d6423SLionel Sambuc 			f= 0;
1758*433d6423SLionel Sambuc 		}
1759*433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_PD)
1760*433d6423SLionel Sambuc 		{
1761*433d6423SLionel Sambuc 			if (!f) printf(", ");
1762*433d6423SLionel Sambuc 			f= 0;
1763*433d6423SLionel Sambuc 			printf("powered down");
1764*433d6423SLionel Sambuc 		}
1765*433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_ISO)
1766*433d6423SLionel Sambuc 		{
1767*433d6423SLionel Sambuc 			if (!f) printf(", ");
1768*433d6423SLionel Sambuc 			f= 0;
1769*433d6423SLionel Sambuc 			printf("isolated");
1770*433d6423SLionel Sambuc 		}
1771*433d6423SLionel Sambuc 		printf("\n");
1772*433d6423SLionel Sambuc 		return;
1773*433d6423SLionel Sambuc 	}
1774*433d6423SLionel Sambuc 	if (!(mii_ctrl & MII_CTRL_ANE))
1775*433d6423SLionel Sambuc 	{
1776*433d6423SLionel Sambuc 		printf("%s: manual config: ", fp->fxp_name);
1777*433d6423SLionel Sambuc 		switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1778*433d6423SLionel Sambuc 		{
1779*433d6423SLionel Sambuc 		case MII_CTRL_SP_10:	printf("10 Mbps"); break;
1780*433d6423SLionel Sambuc 		case MII_CTRL_SP_100:	printf("100 Mbps"); break;
1781*433d6423SLionel Sambuc 		case MII_CTRL_SP_1000:	printf("1000 Mbps"); break;
1782*433d6423SLionel Sambuc 		case MII_CTRL_SP_RES:	printf("reserved speed"); break;
1783*433d6423SLionel Sambuc 		}
1784*433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_DM)
1785*433d6423SLionel Sambuc 			printf(", full duplex");
1786*433d6423SLionel Sambuc 		else
1787*433d6423SLionel Sambuc 			printf(", half duplex");
1788*433d6423SLionel Sambuc 		printf("\n");
1789*433d6423SLionel Sambuc 		return;
1790*433d6423SLionel Sambuc 	}
1791*433d6423SLionel Sambuc 
1792*433d6423SLionel Sambuc 	if (!debug) goto resspeed;
1793*433d6423SLionel Sambuc 
1794*433d6423SLionel Sambuc 	printf("%s: ", fp->fxp_name);
1795*433d6423SLionel Sambuc 	mii_print_stat_speed(mii_status, mii_extstat);
1796*433d6423SLionel Sambuc 	printf("\n");
1797*433d6423SLionel Sambuc 
1798*433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_ANC))
1799*433d6423SLionel Sambuc 		printf("%s: auto-negotiation not complete\n", fp->fxp_name);
1800*433d6423SLionel Sambuc 	if (mii_status & MII_STATUS_RF)
1801*433d6423SLionel Sambuc 		printf("%s: remote fault detected\n", fp->fxp_name);
1802*433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_ANA))
1803*433d6423SLionel Sambuc 	{
1804*433d6423SLionel Sambuc 		printf("%s: local PHY has no auto-negotiation ability\n",
1805*433d6423SLionel Sambuc 			fp->fxp_name);
1806*433d6423SLionel Sambuc 	}
1807*433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_LS))
1808*433d6423SLionel Sambuc 		printf("%s: link down\n", fp->fxp_name);
1809*433d6423SLionel Sambuc 	if (mii_status & MII_STATUS_JD)
1810*433d6423SLionel Sambuc 		printf("%s: jabber condition detected\n", fp->fxp_name);
1811*433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_EC))
1812*433d6423SLionel Sambuc 	{
1813*433d6423SLionel Sambuc 		printf("%s: no extended register set\n", fp->fxp_name);
1814*433d6423SLionel Sambuc 		goto resspeed;
1815*433d6423SLionel Sambuc 	}
1816*433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_ANC))
1817*433d6423SLionel Sambuc 		goto resspeed;
1818*433d6423SLionel Sambuc 
1819*433d6423SLionel Sambuc 	printf("%s: local cap.: ", fp->fxp_name);
1820*433d6423SLionel Sambuc 	if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
1821*433d6423SLionel Sambuc 	{
1822*433d6423SLionel Sambuc 		printf("1000 Mbps: T-");
1823*433d6423SLionel Sambuc 		switch(mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
1824*433d6423SLionel Sambuc 		{
1825*433d6423SLionel Sambuc 		case MII_MSC_1000T_FD:	printf("FD"); break;
1826*433d6423SLionel Sambuc 		case MII_MSC_1000T_HD:	printf("HD"); break;
1827*433d6423SLionel Sambuc 		default:		printf("FD/HD"); break;
1828*433d6423SLionel Sambuc 		}
1829*433d6423SLionel Sambuc 		if (mii_ana)
1830*433d6423SLionel Sambuc 			printf(", ");
1831*433d6423SLionel Sambuc 	}
1832*433d6423SLionel Sambuc 	mii_print_techab(mii_ana);
1833*433d6423SLionel Sambuc 	printf("\n");
1834*433d6423SLionel Sambuc 
1835*433d6423SLionel Sambuc 	if (mii_ane & MII_ANE_PDF)
1836*433d6423SLionel Sambuc 		printf("%s: parallel detection fault\n", fp->fxp_name);
1837*433d6423SLionel Sambuc 	if (!(mii_ane & MII_ANE_LPANA))
1838*433d6423SLionel Sambuc 	{
1839*433d6423SLionel Sambuc 		printf("%s: link-partner does not support auto-negotiation\n",
1840*433d6423SLionel Sambuc 			fp->fxp_name);
1841*433d6423SLionel Sambuc 		goto resspeed;
1842*433d6423SLionel Sambuc 	}
1843*433d6423SLionel Sambuc 
1844*433d6423SLionel Sambuc 	printf("%s: remote cap.: ", fp->fxp_name);
1845*433d6423SLionel Sambuc 	if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
1846*433d6423SLionel Sambuc 	if (mii_ms_status & (MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
1847*433d6423SLionel Sambuc 	{
1848*433d6423SLionel Sambuc 		printf("1000 Mbps: T-");
1849*433d6423SLionel Sambuc 		switch(mii_ms_status &
1850*433d6423SLionel Sambuc 			(MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
1851*433d6423SLionel Sambuc 		{
1852*433d6423SLionel Sambuc 		case MII_MSS_LP1000T_FD:	printf("FD"); break;
1853*433d6423SLionel Sambuc 		case MII_MSS_LP1000T_HD:	printf("HD"); break;
1854*433d6423SLionel Sambuc 		default:			printf("FD/HD"); break;
1855*433d6423SLionel Sambuc 		}
1856*433d6423SLionel Sambuc 		if (mii_anlpa)
1857*433d6423SLionel Sambuc 			printf(", ");
1858*433d6423SLionel Sambuc 	}
1859*433d6423SLionel Sambuc 	mii_print_techab(mii_anlpa);
1860*433d6423SLionel Sambuc 	printf("\n");
1861*433d6423SLionel Sambuc 
1862*433d6423SLionel Sambuc 	if (fp->fxp_ms_regs)
1863*433d6423SLionel Sambuc 	{
1864*433d6423SLionel Sambuc 		printf("%s: ", fp->fxp_name);
1865*433d6423SLionel Sambuc 		if (mii_ms_ctrl & MII_MSC_MS_MANUAL)
1866*433d6423SLionel Sambuc 		{
1867*433d6423SLionel Sambuc 			printf("manual %s",
1868*433d6423SLionel Sambuc 				(mii_ms_ctrl & MII_MSC_MS_VAL) ?
1869*433d6423SLionel Sambuc 				"MASTER" : "SLAVE");
1870*433d6423SLionel Sambuc 		}
1871*433d6423SLionel Sambuc 		else
1872*433d6423SLionel Sambuc 		{
1873*433d6423SLionel Sambuc 			printf("%s device",
1874*433d6423SLionel Sambuc 				(mii_ms_ctrl & MII_MSC_MULTIPORT) ?
1875*433d6423SLionel Sambuc 				"multiport" : "single-port");
1876*433d6423SLionel Sambuc 		}
1877*433d6423SLionel Sambuc 		if (mii_ms_ctrl & MII_MSC_RES)
1878*433d6423SLionel Sambuc 			printf(" reserved<0x%x>", mii_ms_ctrl & MII_MSC_RES);
1879*433d6423SLionel Sambuc 		printf(": ");
1880*433d6423SLionel Sambuc 		if (mii_ms_status & MII_MSS_FAULT)
1881*433d6423SLionel Sambuc 			printf("M/S config fault");
1882*433d6423SLionel Sambuc 		else if (mii_ms_status & MII_MSS_MASTER)
1883*433d6423SLionel Sambuc 			printf("MASTER");
1884*433d6423SLionel Sambuc 		else
1885*433d6423SLionel Sambuc 			printf("SLAVE");
1886*433d6423SLionel Sambuc 		printf("\n");
1887*433d6423SLionel Sambuc 	}
1888*433d6423SLionel Sambuc 
1889*433d6423SLionel Sambuc 	if (mii_ms_status & (MII_MSS_LP1000T_FD|MII_MSS_LP1000T_HD))
1890*433d6423SLionel Sambuc 	{
1891*433d6423SLionel Sambuc 		if (!(mii_ms_status & MII_MSS_LOCREC))
1892*433d6423SLionel Sambuc 		{
1893*433d6423SLionel Sambuc 			printf("%s: local receiver not OK\n",
1894*433d6423SLionel Sambuc 				fp->fxp_name);
1895*433d6423SLionel Sambuc 		}
1896*433d6423SLionel Sambuc 		if (!(mii_ms_status & MII_MSS_REMREC))
1897*433d6423SLionel Sambuc 		{
1898*433d6423SLionel Sambuc 			printf("%s: remote receiver not OK\n",
1899*433d6423SLionel Sambuc 				fp->fxp_name);
1900*433d6423SLionel Sambuc 		}
1901*433d6423SLionel Sambuc 	}
1902*433d6423SLionel Sambuc 	if (mii_ms_status & (MII_MSS_RES|MII_MSS_IDLE_ERR))
1903*433d6423SLionel Sambuc 	{
1904*433d6423SLionel Sambuc 		printf("%s", fp->fxp_name);
1905*433d6423SLionel Sambuc 		if (mii_ms_status & MII_MSS_RES)
1906*433d6423SLionel Sambuc 			printf(" reserved<0x%x>", mii_ms_status & MII_MSS_RES);
1907*433d6423SLionel Sambuc 		if (mii_ms_status & MII_MSS_IDLE_ERR)
1908*433d6423SLionel Sambuc 		{
1909*433d6423SLionel Sambuc 			printf(" idle error %d",
1910*433d6423SLionel Sambuc 				mii_ms_status & MII_MSS_IDLE_ERR);
1911*433d6423SLionel Sambuc 		}
1912*433d6423SLionel Sambuc 		printf("\n");
1913*433d6423SLionel Sambuc 	}
1914*433d6423SLionel Sambuc 
1915*433d6423SLionel Sambuc resspeed:
1916*433d6423SLionel Sambuc #if VERBOSE
1917*433d6423SLionel Sambuc 	printf("%s: link up, %d Mbps, %s duplex\n",
1918*433d6423SLionel Sambuc 		fp->fxp_name, (scr & MII_SCR_100) ? 100 : 10,
1919*433d6423SLionel Sambuc 		(scr & MII_SCR_FD) ? "full" : "half");
1920*433d6423SLionel Sambuc #endif
1921*433d6423SLionel Sambuc 	;
1922*433d6423SLionel Sambuc }
1923*433d6423SLionel Sambuc 
1924*433d6423SLionel Sambuc /*===========================================================================*
1925*433d6423SLionel Sambuc  *				reply					     *
1926*433d6423SLionel Sambuc  *===========================================================================*/
1927*433d6423SLionel Sambuc static void reply(fp)
1928*433d6423SLionel Sambuc fxp_t *fp;
1929*433d6423SLionel Sambuc {
1930*433d6423SLionel Sambuc 	message reply;
1931*433d6423SLionel Sambuc 	int flags;
1932*433d6423SLionel Sambuc 	int r;
1933*433d6423SLionel Sambuc 
1934*433d6423SLionel Sambuc 	flags = DL_NOFLAGS;
1935*433d6423SLionel Sambuc 	if (fp->fxp_flags & FF_PACK_SENT)
1936*433d6423SLionel Sambuc 		flags |= DL_PACK_SEND;
1937*433d6423SLionel Sambuc 	if (fp->fxp_flags & FF_PACK_RECV)
1938*433d6423SLionel Sambuc 		flags |= DL_PACK_RECV;
1939*433d6423SLionel Sambuc 
1940*433d6423SLionel Sambuc 	reply.m_type = DL_TASK_REPLY;
1941*433d6423SLionel Sambuc 	reply.m_netdrv_net_dl_task.flags = flags;
1942*433d6423SLionel Sambuc 	reply.m_netdrv_net_dl_task.count = fp->fxp_read_s;
1943*433d6423SLionel Sambuc 
1944*433d6423SLionel Sambuc 	r= ipc_send(fp->fxp_client, &reply);
1945*433d6423SLionel Sambuc 
1946*433d6423SLionel Sambuc 	if (r < 0)
1947*433d6423SLionel Sambuc 		panic("fxp: ipc_send failed: %d", r);
1948*433d6423SLionel Sambuc 
1949*433d6423SLionel Sambuc 	fp->fxp_read_s = 0;
1950*433d6423SLionel Sambuc 	fp->fxp_flags &= ~(FF_PACK_SENT | FF_PACK_RECV);
1951*433d6423SLionel Sambuc }
1952*433d6423SLionel Sambuc 
1953*433d6423SLionel Sambuc /*===========================================================================*
1954*433d6423SLionel Sambuc  *				mess_reply				     *
1955*433d6423SLionel Sambuc  *===========================================================================*/
1956*433d6423SLionel Sambuc static void mess_reply(req, reply_mess)
1957*433d6423SLionel Sambuc message *req;
1958*433d6423SLionel Sambuc message *reply_mess;
1959*433d6423SLionel Sambuc {
1960*433d6423SLionel Sambuc 	if (ipc_send(req->m_source, reply_mess) != OK)
1961*433d6423SLionel Sambuc 		panic("fxp: unable to mess_reply");
1962*433d6423SLionel Sambuc }
1963*433d6423SLionel Sambuc 
1964*433d6423SLionel Sambuc /*===========================================================================*
1965*433d6423SLionel Sambuc  *				eeprom_read				     *
1966*433d6423SLionel Sambuc  *===========================================================================*/
1967*433d6423SLionel Sambuc static u16_t eeprom_read(fp, reg)
1968*433d6423SLionel Sambuc fxp_t *fp;
1969*433d6423SLionel Sambuc int reg;
1970*433d6423SLionel Sambuc {
1971*433d6423SLionel Sambuc 	port_t port;
1972*433d6423SLionel Sambuc 	u16_t v;
1973*433d6423SLionel Sambuc 	int b, i, alen;
1974*433d6423SLionel Sambuc 
1975*433d6423SLionel Sambuc 	alen= fp->fxp_ee_addrlen;
1976*433d6423SLionel Sambuc 	if (!alen)
1977*433d6423SLionel Sambuc 	{
1978*433d6423SLionel Sambuc 		eeprom_addrsize(fp);
1979*433d6423SLionel Sambuc 		alen= fp->fxp_ee_addrlen;
1980*433d6423SLionel Sambuc 		assert(alen == 6 || alen == 8);
1981*433d6423SLionel Sambuc 	}
1982*433d6423SLionel Sambuc 
1983*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1984*433d6423SLionel Sambuc 
1985*433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, CE_EECS);	/* Enable EEPROM */
1986*433d6423SLionel Sambuc 	v= EEPROM_READ_PREFIX;
1987*433d6423SLionel Sambuc 	for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
1988*433d6423SLionel Sambuc 	{
1989*433d6423SLionel Sambuc 		b= ((v & (1 << i)) ? CE_EEDI : 0);
1990*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
1991*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
1992*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1993*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
1994*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1995*433d6423SLionel Sambuc 	}
1996*433d6423SLionel Sambuc 
1997*433d6423SLionel Sambuc 	v= reg;
1998*433d6423SLionel Sambuc 	for (i= alen-1; i >= 0; i--)
1999*433d6423SLionel Sambuc 	{
2000*433d6423SLionel Sambuc 		b= ((v & (1 << i)) ? CE_EEDI : 0);
2001*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
2002*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
2003*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2004*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
2005*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2006*433d6423SLionel Sambuc 	}
2007*433d6423SLionel Sambuc 
2008*433d6423SLionel Sambuc 	v= 0;
2009*433d6423SLionel Sambuc 	for (i= 0; i<16; i++)
2010*433d6423SLionel Sambuc 	{
2011*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
2012*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2013*433d6423SLionel Sambuc 		b= !!(fxp_inb(port, CSR_EEPROM) & CE_EEDO);
2014*433d6423SLionel Sambuc 		v= (v << 1) | b;
2015*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS );
2016*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2017*433d6423SLionel Sambuc 	}
2018*433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, 0);	/* Disable EEPROM */
2019*433d6423SLionel Sambuc 	micro_delay(EECS_DELAY);
2020*433d6423SLionel Sambuc 
2021*433d6423SLionel Sambuc 	return v;
2022*433d6423SLionel Sambuc }
2023*433d6423SLionel Sambuc 
2024*433d6423SLionel Sambuc /*===========================================================================*
2025*433d6423SLionel Sambuc  *				eeprom_addrsize				     *
2026*433d6423SLionel Sambuc  *===========================================================================*/
2027*433d6423SLionel Sambuc static void eeprom_addrsize(fp)
2028*433d6423SLionel Sambuc fxp_t *fp;
2029*433d6423SLionel Sambuc {
2030*433d6423SLionel Sambuc 	port_t port;
2031*433d6423SLionel Sambuc 	u16_t v;
2032*433d6423SLionel Sambuc 	int b, i;
2033*433d6423SLionel Sambuc 
2034*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
2035*433d6423SLionel Sambuc 
2036*433d6423SLionel Sambuc 	/* Try to find out the size of the EEPROM */
2037*433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, CE_EECS);	/* Enable EEPROM */
2038*433d6423SLionel Sambuc 	v= EEPROM_READ_PREFIX;
2039*433d6423SLionel Sambuc 	for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
2040*433d6423SLionel Sambuc 	{
2041*433d6423SLionel Sambuc 		b= ((v & (1 << i)) ? CE_EEDI : 0);
2042*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
2043*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
2044*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2045*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
2046*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2047*433d6423SLionel Sambuc 	}
2048*433d6423SLionel Sambuc 
2049*433d6423SLionel Sambuc 	for (i= 0; i<32; i++)
2050*433d6423SLionel Sambuc 	{
2051*433d6423SLionel Sambuc 		b= 0;
2052*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
2053*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
2054*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2055*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
2056*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2057*433d6423SLionel Sambuc 		v= fxp_inb(port, CSR_EEPROM);
2058*433d6423SLionel Sambuc 		if (!(v & CE_EEDO))
2059*433d6423SLionel Sambuc 			break;
2060*433d6423SLionel Sambuc 	}
2061*433d6423SLionel Sambuc 	if (i >= 32)
2062*433d6423SLionel Sambuc 		panic("eeprom_addrsize: failed");
2063*433d6423SLionel Sambuc 	fp->fxp_ee_addrlen= i+1;
2064*433d6423SLionel Sambuc 
2065*433d6423SLionel Sambuc 	/* Discard 16 data bits */
2066*433d6423SLionel Sambuc 	for (i= 0; i<16; i++)
2067*433d6423SLionel Sambuc 	{
2068*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
2069*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2070*433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS );
2071*433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
2072*433d6423SLionel Sambuc 	}
2073*433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, 0);	/* Disable EEPROM */
2074*433d6423SLionel Sambuc 	micro_delay(EECS_DELAY);
2075*433d6423SLionel Sambuc 
2076*433d6423SLionel Sambuc #if VERBOSE
2077*433d6423SLionel Sambuc 	printf("%s EEPROM address length: %d\n",
2078*433d6423SLionel Sambuc 		fp->fxp_name, fp->fxp_ee_addrlen);
2079*433d6423SLionel Sambuc #endif
2080*433d6423SLionel Sambuc }
2081*433d6423SLionel Sambuc 
2082*433d6423SLionel Sambuc /*===========================================================================*
2083*433d6423SLionel Sambuc  *				mii_read				     *
2084*433d6423SLionel Sambuc  *===========================================================================*/
2085*433d6423SLionel Sambuc static u16_t mii_read(fp, reg)
2086*433d6423SLionel Sambuc fxp_t *fp;
2087*433d6423SLionel Sambuc int reg;
2088*433d6423SLionel Sambuc {
2089*433d6423SLionel Sambuc 	spin_t spin;
2090*433d6423SLionel Sambuc 	port_t port;
2091*433d6423SLionel Sambuc 	u32_t v;
2092*433d6423SLionel Sambuc 
2093*433d6423SLionel Sambuc 	port= fp->fxp_base_port;
2094*433d6423SLionel Sambuc 
2095*433d6423SLionel Sambuc 	assert(!fp->fxp_mii_busy);
2096*433d6423SLionel Sambuc 	fp->fxp_mii_busy++;
2097*433d6423SLionel Sambuc 
2098*433d6423SLionel Sambuc 	if (!(fxp_inl(port, CSR_MDI_CTL) & CM_READY))
2099*433d6423SLionel Sambuc 		panic("mii_read: MDI not ready");
2100*433d6423SLionel Sambuc 	fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) |
2101*433d6423SLionel Sambuc 		(reg << CM_REG_SHIFT));
2102*433d6423SLionel Sambuc 
2103*433d6423SLionel Sambuc 	spin_init(&spin, 100000);
2104*433d6423SLionel Sambuc 	do {
2105*433d6423SLionel Sambuc 		v= fxp_inl(port, CSR_MDI_CTL);
2106*433d6423SLionel Sambuc 		if (v & CM_READY)
2107*433d6423SLionel Sambuc 			break;
2108*433d6423SLionel Sambuc 	} while (spin_check(&spin));
2109*433d6423SLionel Sambuc 
2110*433d6423SLionel Sambuc 	if (!(v & CM_READY))
2111*433d6423SLionel Sambuc 		panic("mii_read: MDI not ready after command");
2112*433d6423SLionel Sambuc 
2113*433d6423SLionel Sambuc 	fp->fxp_mii_busy--;
2114*433d6423SLionel Sambuc 	assert(!fp->fxp_mii_busy);
2115*433d6423SLionel Sambuc 
2116*433d6423SLionel Sambuc 	return v & CM_DATA_MASK;
2117*433d6423SLionel Sambuc }
2118*433d6423SLionel Sambuc 
2119*433d6423SLionel Sambuc static u8_t do_inb(port_t port)
2120*433d6423SLionel Sambuc {
2121*433d6423SLionel Sambuc 	int r;
2122*433d6423SLionel Sambuc 	u32_t value;
2123*433d6423SLionel Sambuc 
2124*433d6423SLionel Sambuc 	r= sys_inb(port, &value);
2125*433d6423SLionel Sambuc 	if (r != OK)
2126*433d6423SLionel Sambuc 		panic("sys_inb failed: %d", r);
2127*433d6423SLionel Sambuc 	return value;
2128*433d6423SLionel Sambuc }
2129*433d6423SLionel Sambuc 
2130*433d6423SLionel Sambuc static u32_t do_inl(port_t port)
2131*433d6423SLionel Sambuc {
2132*433d6423SLionel Sambuc 	int r;
2133*433d6423SLionel Sambuc 	u32_t value;
2134*433d6423SLionel Sambuc 
2135*433d6423SLionel Sambuc 	r= sys_inl(port, &value);
2136*433d6423SLionel Sambuc 	if (r != OK)
2137*433d6423SLionel Sambuc 		panic("sys_inl failed: %d", r);
2138*433d6423SLionel Sambuc 	return value;
2139*433d6423SLionel Sambuc }
2140*433d6423SLionel Sambuc 
2141*433d6423SLionel Sambuc static void do_outb(port_t port, u8_t value)
2142*433d6423SLionel Sambuc {
2143*433d6423SLionel Sambuc 	int r;
2144*433d6423SLionel Sambuc 
2145*433d6423SLionel Sambuc 	r= sys_outb(port, value);
2146*433d6423SLionel Sambuc 	if (r != OK)
2147*433d6423SLionel Sambuc 		panic("sys_outb failed: %d", r);
2148*433d6423SLionel Sambuc }
2149*433d6423SLionel Sambuc 
2150*433d6423SLionel Sambuc static void do_outl(port_t port, u32_t value)
2151*433d6423SLionel Sambuc {
2152*433d6423SLionel Sambuc 	int r;
2153*433d6423SLionel Sambuc 
2154*433d6423SLionel Sambuc 	r= sys_outl(port, value);
2155*433d6423SLionel Sambuc 	if (r != OK)
2156*433d6423SLionel Sambuc 		panic("sys_outl failed: %d", r);
2157*433d6423SLionel Sambuc }
2158*433d6423SLionel Sambuc 
2159*433d6423SLionel Sambuc static void tell_dev(buf, size, pci_bus, pci_dev, pci_func)
2160*433d6423SLionel Sambuc vir_bytes buf;
2161*433d6423SLionel Sambuc size_t size;
2162*433d6423SLionel Sambuc int pci_bus;
2163*433d6423SLionel Sambuc int pci_dev;
2164*433d6423SLionel Sambuc int pci_func;
2165*433d6423SLionel Sambuc {
2166*433d6423SLionel Sambuc 	int r;
2167*433d6423SLionel Sambuc 	endpoint_t dev_e;
2168*433d6423SLionel Sambuc 	message m;
2169*433d6423SLionel Sambuc 
2170*433d6423SLionel Sambuc 	r= ds_retrieve_label_endpt("amddev", &dev_e);
2171*433d6423SLionel Sambuc 	if (r != OK)
2172*433d6423SLionel Sambuc 	{
2173*433d6423SLionel Sambuc #if 0
2174*433d6423SLionel Sambuc 		printf(
2175*433d6423SLionel Sambuc 		"fxp`tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
2176*433d6423SLionel Sambuc 			r);
2177*433d6423SLionel Sambuc #endif
2178*433d6423SLionel Sambuc 		return;
2179*433d6423SLionel Sambuc 	}
2180*433d6423SLionel Sambuc 
2181*433d6423SLionel Sambuc 	m.m_type= IOMMU_MAP;
2182*433d6423SLionel Sambuc 	m.m2_i1= pci_bus;
2183*433d6423SLionel Sambuc 	m.m2_i2= pci_dev;
2184*433d6423SLionel Sambuc 	m.m2_i3= pci_func;
2185*433d6423SLionel Sambuc 	m.m2_l1= buf;
2186*433d6423SLionel Sambuc 	m.m2_l2= size;
2187*433d6423SLionel Sambuc 
2188*433d6423SLionel Sambuc 	r= ipc_sendrec(dev_e, &m);
2189*433d6423SLionel Sambuc 	if (r != OK)
2190*433d6423SLionel Sambuc 	{
2191*433d6423SLionel Sambuc 		printf("fxp`tell_dev: ipc_sendrec to %d failed: %d\n",
2192*433d6423SLionel Sambuc 			dev_e, r);
2193*433d6423SLionel Sambuc 		return;
2194*433d6423SLionel Sambuc 	}
2195*433d6423SLionel Sambuc 	if (m.m_type != OK)
2196*433d6423SLionel Sambuc 	{
2197*433d6423SLionel Sambuc 		printf("fxp`tell_dev: dma map request failed: %d\n",
2198*433d6423SLionel Sambuc 			m.m_type);
2199*433d6423SLionel Sambuc 		return;
2200*433d6423SLionel Sambuc 	}
2201*433d6423SLionel Sambuc }
2202*433d6423SLionel Sambuc 
2203*433d6423SLionel Sambuc /*
2204*433d6423SLionel Sambuc  * $PchId: fxp.c,v 1.4 2005/01/31 22:10:37 philip Exp $
2205*433d6423SLionel Sambuc  */
2206*433d6423SLionel Sambuc 
2207