xref: /minix3/minix/drivers/net/fxp/fxp.c (revision d4dd6511b9dc029206ce2c925ed135e16555aae4)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * fxp.c
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * This file contains an ethernet device driver for Intel 82557, 82558,
5433d6423SLionel Sambuc  * 82559, 82550, and 82562 fast ethernet controllers.
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * Created:	Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
8433d6423SLionel Sambuc  */
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include <minix/drivers.h>
11433d6423SLionel Sambuc #include <minix/netdriver.h>
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include <machine/pci.h>
14433d6423SLionel Sambuc #include <minix/ds.h>
1596e62d65SDavid van Moolenbroek #include <assert.h>
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc #include "fxp.h"
18433d6423SLionel Sambuc #include "mii.h"
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc /* Number of receive buffers */
21433d6423SLionel Sambuc #define N_RX_BUF	40
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc /* Number of transmit buffers */
24433d6423SLionel Sambuc #define N_TX_BUF	4
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc /* Configuration */
27433d6423SLionel Sambuc #define FXP_ENVVAR	"FXPETH"
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc typedef int irq_hook_t;
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc static union tmpbuf
32433d6423SLionel Sambuc {
33433d6423SLionel Sambuc 	char pad[4096];
34433d6423SLionel Sambuc 	struct cbl_conf cc;
35433d6423SLionel Sambuc 	struct ias ias;
36433d6423SLionel Sambuc } *tmpbufp;
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc typedef struct fxp
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc 	port_t fxp_base_port;
41433d6423SLionel Sambuc 	int fxp_got_int;
42433d6423SLionel Sambuc 	int fxp_send_int;
43433d6423SLionel Sambuc 	int fxp_irq;
44433d6423SLionel Sambuc 	int fxp_type;			/* What kind of hardware */
45433d6423SLionel Sambuc 	int fxp_ms_regs;		/* Master/slave registers */
46433d6423SLionel Sambuc 	int fxp_ee_addrlen;		/* #EEPROM address bits */
47433d6423SLionel Sambuc 	int fxp_tx_alive;
48433d6423SLionel Sambuc 	int fxp_need_reset;
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc 	/* Rx */
51433d6423SLionel Sambuc 	int fxp_rx_nbuf;
52433d6423SLionel Sambuc 	int fxp_rx_bufsize;
53433d6423SLionel Sambuc 	struct rfd *fxp_rx_buf;
54433d6423SLionel Sambuc 	phys_bytes fxp_rx_busaddr;
55433d6423SLionel Sambuc 	int fxp_rx_head;
56433d6423SLionel Sambuc 	int fxp_rx_need_restart;
57433d6423SLionel Sambuc 	int fxp_need_conf;		/* Re-configure after draining send
58433d6423SLionel Sambuc 					 * queue
59433d6423SLionel Sambuc 					 */
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc 	/* Tx */
62433d6423SLionel Sambuc 	int fxp_tx_nbuf;
63433d6423SLionel Sambuc 	int fxp_tx_bufsize;
64433d6423SLionel Sambuc 	struct tx *fxp_tx_buf;
65433d6423SLionel Sambuc 	phys_bytes fxp_tx_busaddr;
66433d6423SLionel Sambuc 	int fxp_tx_idle;
67433d6423SLionel Sambuc 	int fxp_tx_head;
68433d6423SLionel Sambuc 	int fxp_tx_tail;
69433d6423SLionel Sambuc 	int fxp_tx_threshold;
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc 	/* Link status */
72433d6423SLionel Sambuc 	int fxp_report_link;
73433d6423SLionel Sambuc 	int fxp_link_up;
74433d6423SLionel Sambuc 	u16_t fxp_mii_scr;
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc 	irq_hook_t fxp_hook;
77433d6423SLionel Sambuc 	struct sc fxp_stat;
78433d6423SLionel Sambuc 	u8_t fxp_conf_bytes[CC_BYTES_NR];
7996e62d65SDavid van Moolenbroek } fxp_t;
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc /* fxp_type */
82433d6423SLionel Sambuc #define FT_UNKNOWN	0x0
83433d6423SLionel Sambuc #define FT_82557	0x1
84433d6423SLionel Sambuc #define FT_82558A	0x2
85433d6423SLionel Sambuc #define FT_82559	0x4
86433d6423SLionel Sambuc #define FT_82801	0x8
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc static fxp_t *fxp_state;
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc #define fxp_inb(port, offset)	(do_inb((port) + (offset)))
91433d6423SLionel Sambuc #define fxp_inl(port, offset)	(do_inl((port) + (offset)))
92433d6423SLionel Sambuc #define fxp_outb(port, offset, value)	(do_outb((port) + (offset), (value)))
93433d6423SLionel Sambuc #define fxp_outl(port, offset, value)	(do_outl((port) + (offset), (value)))
94433d6423SLionel Sambuc 
95f7df02e7SDavid van Moolenbroek static int fxp_init(unsigned int instance, netdriver_addr_t *addr,
96f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks);
9796e62d65SDavid van Moolenbroek static void fxp_intr(unsigned int __unused mask);
9896e62d65SDavid van Moolenbroek static void fxp_stop(void);
99433d6423SLionel Sambuc static int fxp_probe(fxp_t *fp, int skip);
100433d6423SLionel Sambuc static void fxp_conf_hw(fxp_t *fp);
101f7df02e7SDavid van Moolenbroek static void fxp_init_hw(fxp_t *fp, netdriver_addr_t *addr,
102f7df02e7SDavid van Moolenbroek 	unsigned int instance);
103433d6423SLionel Sambuc static void fxp_init_buf(fxp_t *fp);
104433d6423SLionel Sambuc static void fxp_reset_hw(fxp_t *fp);
105f7df02e7SDavid van Moolenbroek static void fxp_confaddr(fxp_t *fp, netdriver_addr_t *addr,
106f7df02e7SDavid van Moolenbroek 	unsigned int instance);
107f7df02e7SDavid van Moolenbroek static void fxp_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
108f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count);
10996e62d65SDavid van Moolenbroek static int fxp_send(struct netdriver_data *data, size_t size);
11096e62d65SDavid van Moolenbroek static ssize_t fxp_recv(struct netdriver_data *data, size_t max);
111433d6423SLionel Sambuc static void fxp_do_conf(fxp_t *fp);
112433d6423SLionel Sambuc static void fxp_cu_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int
113433d6423SLionel Sambuc 	check_idle);
114433d6423SLionel Sambuc static void fxp_ru_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int
115433d6423SLionel Sambuc 	check_idle);
116433d6423SLionel Sambuc static void fxp_restart_ru(fxp_t *fp);
117433d6423SLionel Sambuc static void fxp_handler(fxp_t *fp);
118433d6423SLionel Sambuc static void fxp_check_ints(fxp_t *fp);
119f7df02e7SDavid van Moolenbroek static void fxp_tick(void);
120433d6423SLionel Sambuc static int fxp_link_changed(fxp_t *fp);
121f7df02e7SDavid van Moolenbroek static unsigned int fxp_get_link(uint32_t *media);
122433d6423SLionel Sambuc static void fxp_report_link(fxp_t *fp);
123433d6423SLionel Sambuc static u16_t eeprom_read(fxp_t *fp, int reg);
124433d6423SLionel Sambuc static void eeprom_addrsize(fxp_t *fp);
125433d6423SLionel Sambuc static u16_t mii_read(fxp_t *fp, int reg);
126433d6423SLionel Sambuc static u8_t do_inb(port_t port);
127433d6423SLionel Sambuc static u32_t do_inl(port_t port);
128433d6423SLionel Sambuc static void do_outb(port_t port, u8_t v);
129433d6423SLionel Sambuc static void do_outl(port_t port, u32_t v);
13096e62d65SDavid van Moolenbroek static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int
131433d6423SLionel Sambuc 	pci_dev, int pci_func);
132433d6423SLionel Sambuc 
13396e62d65SDavid van Moolenbroek static const struct netdriver fxp_table = {
134f7df02e7SDavid van Moolenbroek 	.ndr_name	= "fxp",
13596e62d65SDavid van Moolenbroek 	.ndr_init	= fxp_init,
13696e62d65SDavid van Moolenbroek 	.ndr_stop	= fxp_stop,
137f7df02e7SDavid van Moolenbroek 	.ndr_set_mode	= fxp_set_mode,
13896e62d65SDavid van Moolenbroek 	.ndr_recv	= fxp_recv,
13996e62d65SDavid van Moolenbroek 	.ndr_send	= fxp_send,
140f7df02e7SDavid van Moolenbroek 	.ndr_get_link	= fxp_get_link,
14196e62d65SDavid van Moolenbroek 	.ndr_intr	= fxp_intr,
142f7df02e7SDavid van Moolenbroek 	.ndr_tick	= fxp_tick,
14396e62d65SDavid van Moolenbroek };
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc /*===========================================================================*
146433d6423SLionel Sambuc  *				main					     *
147433d6423SLionel Sambuc  *===========================================================================*/
main(int argc,char * argv[])148433d6423SLionel Sambuc int main(int argc, char *argv[])
149433d6423SLionel Sambuc {
150433d6423SLionel Sambuc 	env_setargs(argc, argv);
151433d6423SLionel Sambuc 
15296e62d65SDavid van Moolenbroek 	netdriver_task(&fxp_table);
153433d6423SLionel Sambuc 
15496e62d65SDavid van Moolenbroek 	return 0;
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc /*===========================================================================*
15896e62d65SDavid van Moolenbroek  *				fxp_intr				     *
159433d6423SLionel Sambuc  *===========================================================================*/
fxp_intr(unsigned int __unused mask)16096e62d65SDavid van Moolenbroek static void fxp_intr(unsigned int __unused mask)
161433d6423SLionel Sambuc {
162433d6423SLionel Sambuc 	int r;
16396e62d65SDavid van Moolenbroek 	fxp_t *fp;
164433d6423SLionel Sambuc 
16596e62d65SDavid van Moolenbroek 	fp= fxp_state;
166433d6423SLionel Sambuc 
16796e62d65SDavid van Moolenbroek 	fxp_handler(fp);
168433d6423SLionel Sambuc 
16996e62d65SDavid van Moolenbroek 	if ((r = sys_irqenable(&fp->fxp_hook)) != OK)
17096e62d65SDavid van Moolenbroek 		panic("unable to enable interrupts: %d", r);
171433d6423SLionel Sambuc 
17296e62d65SDavid van Moolenbroek 	if (!fp->fxp_got_int)
17396e62d65SDavid van Moolenbroek 		return;
17496e62d65SDavid van Moolenbroek 	fp->fxp_got_int= 0;
17596e62d65SDavid van Moolenbroek 	fxp_check_ints(fp);
176433d6423SLionel Sambuc }
177433d6423SLionel Sambuc 
178433d6423SLionel Sambuc /*===========================================================================*
17996e62d65SDavid van Moolenbroek  *				fxp_stop				     *
180433d6423SLionel Sambuc  *===========================================================================*/
fxp_stop(void)18196e62d65SDavid van Moolenbroek static void fxp_stop(void)
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc 	port_t port;
184433d6423SLionel Sambuc 	fxp_t *fp;
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc 	fp= fxp_state;
187433d6423SLionel Sambuc 
188433d6423SLionel Sambuc 	port= fp->fxp_base_port;
189433d6423SLionel Sambuc 
19096e62d65SDavid van Moolenbroek 	/* Stop device */
19196e62d65SDavid van Moolenbroek #if VERBOSE
192f7df02e7SDavid van Moolenbroek 	printf("%s: stopping device\n", netdriver_name());
19396e62d65SDavid van Moolenbroek #endif
194433d6423SLionel Sambuc 
19596e62d65SDavid van Moolenbroek 	fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
196433d6423SLionel Sambuc }
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc /*===========================================================================*
199433d6423SLionel Sambuc  *				fxp_init				     *
200433d6423SLionel Sambuc  *===========================================================================*/
fxp_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)201f7df02e7SDavid van Moolenbroek static int fxp_init(unsigned int instance, netdriver_addr_t *addr,
202f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks)
203433d6423SLionel Sambuc {
204433d6423SLionel Sambuc 	fxp_t *fp;
20596e62d65SDavid van Moolenbroek 	int r;
20696e62d65SDavid van Moolenbroek 
20796e62d65SDavid van Moolenbroek 	if (!(fxp_state = alloc_contig(sizeof(*fxp_state), 0, NULL)))
20896e62d65SDavid van Moolenbroek 		panic("couldn't allocate table");
209433d6423SLionel Sambuc 
210433d6423SLionel Sambuc 	fp= fxp_state;
211433d6423SLionel Sambuc 
21296e62d65SDavid van Moolenbroek 	memset(fp, 0, sizeof(*fp));
21396e62d65SDavid van Moolenbroek 
21496e62d65SDavid van Moolenbroek 	if ((r = tsc_calibrate()) != OK)
21596e62d65SDavid van Moolenbroek 		panic("tsc_calibrate failed: %d", r);
216433d6423SLionel Sambuc 
21796e62d65SDavid van Moolenbroek 	/* Configure PCI device. */
218f7df02e7SDavid van Moolenbroek 	if (!fxp_probe(fp, instance))
21996e62d65SDavid van Moolenbroek 		return ENXIO;
22096e62d65SDavid van Moolenbroek 
22196e62d65SDavid van Moolenbroek 	fxp_conf_hw(fp);
22296e62d65SDavid van Moolenbroek 
223f7df02e7SDavid van Moolenbroek 	fxp_init_hw(fp, addr, instance);
22496e62d65SDavid van Moolenbroek 	fxp_report_link(fp);
22596e62d65SDavid van Moolenbroek 
226f7df02e7SDavid van Moolenbroek 	*caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
227f7df02e7SDavid van Moolenbroek 	*ticks = sys_hz();
22896e62d65SDavid van Moolenbroek 	return OK;
229433d6423SLionel Sambuc }
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc /*===========================================================================*
232433d6423SLionel Sambuc  *				fxp_probe				     *
233433d6423SLionel Sambuc  *===========================================================================*/
fxp_probe(fxp_t * fp,int skip)234433d6423SLionel Sambuc static int fxp_probe(fxp_t *fp, int skip)
235433d6423SLionel Sambuc {
236433d6423SLionel Sambuc 	int r, devind;
2372e537462SDavid van Moolenbroek 	u16_t vid, did, cr;
238433d6423SLionel Sambuc 	u32_t bar;
239433d6423SLionel Sambuc 	u8_t ilr, rev;
240f7df02e7SDavid van Moolenbroek 	const char *str;
241433d6423SLionel Sambuc #if VERBOSE
242f7df02e7SDavid van Moolenbroek 	const char *dname;
243433d6423SLionel Sambuc #endif
244433d6423SLionel Sambuc 
24596e62d65SDavid van Moolenbroek 	pci_init();
24696e62d65SDavid van Moolenbroek 
247433d6423SLionel Sambuc 	r= pci_first_dev(&devind, &vid, &did);
248433d6423SLionel Sambuc 	if (r == 0)
249433d6423SLionel Sambuc 		return FALSE;
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 	while (skip--)
252433d6423SLionel Sambuc 	{
253433d6423SLionel Sambuc 		r= pci_next_dev(&devind, &vid, &did);
254433d6423SLionel Sambuc 		if (!r)
255433d6423SLionel Sambuc 			return FALSE;
256433d6423SLionel Sambuc 	}
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc #if VERBOSE
259433d6423SLionel Sambuc 	dname= pci_dev_name(vid, did);
260433d6423SLionel Sambuc 	if (!dname)
261433d6423SLionel Sambuc 		dname= "unknown device";
262433d6423SLionel Sambuc 	printf("%s: %s (%04x/%04x) at %s\n",
263f7df02e7SDavid van Moolenbroek 		netdriver_name(), dname, vid, did, pci_slot_name(devind));
264433d6423SLionel Sambuc #endif
265433d6423SLionel Sambuc 	pci_reserve(devind);
266433d6423SLionel Sambuc 
2672e537462SDavid van Moolenbroek 	/* Enable bus mastering if necessary. */
2682e537462SDavid van Moolenbroek 	cr = pci_attr_r16(devind, PCI_CR);
2692e537462SDavid van Moolenbroek 	if (!(cr & PCI_CR_MAST_EN))
2702e537462SDavid van Moolenbroek 		pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
2712e537462SDavid van Moolenbroek 
272433d6423SLionel Sambuc 	bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0;
273433d6423SLionel Sambuc 	if (bar < 0x400) {
274433d6423SLionel Sambuc 		panic("fxp_probe: base address is not properly configured");
275433d6423SLionel Sambuc 	}
276433d6423SLionel Sambuc 	fp->fxp_base_port= bar;
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc 	ilr= pci_attr_r8(devind, PCI_ILR);
279433d6423SLionel Sambuc 	fp->fxp_irq= ilr;
28096e62d65SDavid van Moolenbroek #if VERBOSE
281433d6423SLionel Sambuc 	printf("%s: using I/O address 0x%lx, IRQ %d\n",
282f7df02e7SDavid van Moolenbroek 		netdriver_name(), (unsigned long)bar, ilr);
28396e62d65SDavid van Moolenbroek #endif
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc 	rev= pci_attr_r8(devind, PCI_REV);
286433d6423SLionel Sambuc 	str= NULL;
287433d6423SLionel Sambuc 	fp->fxp_type= FT_UNKNOWN;
288433d6423SLionel Sambuc 	switch(rev)
289433d6423SLionel Sambuc 	{
290433d6423SLionel Sambuc 	case FXP_REV_82557A:	str= "82557A";			/* 0x01 */
291433d6423SLionel Sambuc 				fp->fxp_type= FT_82557;
292433d6423SLionel Sambuc 				break;
293433d6423SLionel Sambuc 	case FXP_REV_82557B:	str= "82557B"; break;		/* 0x02 */
294433d6423SLionel Sambuc 	case FXP_REV_82557C:	str= "82557C"; break;		/* 0x03 */
295433d6423SLionel Sambuc 	case FXP_REV_82558A:	str= "82558A"; 			/* 0x04 */
296433d6423SLionel Sambuc 				fp->fxp_type= FT_82558A;
297433d6423SLionel Sambuc 				break;
298433d6423SLionel Sambuc 	case FXP_REV_82558B:	str= "82558B"; 			/* 0x05 */
299433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
300433d6423SLionel Sambuc 				break;
301433d6423SLionel Sambuc 	case FXP_REV_82559A:	str= "82559A"; break;		/* 0x06 */
302433d6423SLionel Sambuc 	case FXP_REV_82559B:	str= "82559B"; break;		/* 0x07 */
303433d6423SLionel Sambuc 	case FXP_REV_82559C:	str= "82559C";			/* 0x08 */
304433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
305433d6423SLionel Sambuc 				break;
306433d6423SLionel Sambuc 	case FXP_REV_82559ERA:	str= "82559ER-A"; 		/* 0x09 */
307433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
308433d6423SLionel Sambuc 				break;
309433d6423SLionel Sambuc 	case FXP_REV_82550_1:	str= "82550(1)"; 		/* 0x0C */
310433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
311433d6423SLionel Sambuc 				break;
312433d6423SLionel Sambuc 	case FXP_REV_82550_2:	str= "82550(2)"; 		/* 0x0D */
313433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
314433d6423SLionel Sambuc 				break;
315433d6423SLionel Sambuc 	case FXP_REV_82550_3:	str= "82550(3)"; 		/* 0x0E */
316433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
317433d6423SLionel Sambuc 				break;
318433d6423SLionel Sambuc 	case FXP_REV_82551_1:	str= "82551(1)"; 		/* 0x0F */
319433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
320433d6423SLionel Sambuc 				break;
321433d6423SLionel Sambuc 	case FXP_REV_82551_2:	str= "82551(2)"; 		/* 0x10 */
322433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
323433d6423SLionel Sambuc 				break;
324433d6423SLionel Sambuc 	case FXP_REV_82801CAM:	str= "82801CAM"; 		/* 0x42 */
325433d6423SLionel Sambuc 				fp->fxp_type= FT_82801;
326433d6423SLionel Sambuc 				break;
327433d6423SLionel Sambuc 	case FXP_REV_82801DB:	str= "82801DB"; 		/* 0x81 */
328433d6423SLionel Sambuc 				fp->fxp_type= FT_82801;
329433d6423SLionel Sambuc 				break;
330433d6423SLionel Sambuc 	case FXP_REV_82550_4:	str= "82550(4)"; 		/* 0x83 */
331433d6423SLionel Sambuc 				fp->fxp_type= FT_82559;
332433d6423SLionel Sambuc 				break;
333433d6423SLionel Sambuc 	}
334433d6423SLionel Sambuc 
335433d6423SLionel Sambuc #if VERBOSE
336433d6423SLionel Sambuc 	if (str)
337f7df02e7SDavid van Moolenbroek 		printf("%s: device revision: %s\n", netdriver_name(), str);
338433d6423SLionel Sambuc 	else
339f7df02e7SDavid van Moolenbroek 		printf("%s: unknown revision: 0x%x\n", netdriver_name(),
340f7df02e7SDavid van Moolenbroek 		    rev);
341433d6423SLionel Sambuc #endif
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc 	if (fp->fxp_type == FT_UNKNOWN)
344433d6423SLionel Sambuc 	{
345433d6423SLionel Sambuc 		printf("fxp_probe: device is not supported by this driver\n");
346433d6423SLionel Sambuc 		return FALSE;
347433d6423SLionel Sambuc 	}
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc 	return TRUE;
350433d6423SLionel Sambuc }
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc /*===========================================================================*
353433d6423SLionel Sambuc  *				fxp_conf_hw				     *
354433d6423SLionel Sambuc  *===========================================================================*/
fxp_conf_hw(fxp_t * fp)355433d6423SLionel Sambuc static void fxp_conf_hw(fxp_t *fp)
356433d6423SLionel Sambuc {
357433d6423SLionel Sambuc #if VERBOSE
358433d6423SLionel Sambuc 	int i;
359433d6423SLionel Sambuc #endif
360433d6423SLionel Sambuc 
361433d6423SLionel Sambuc 	fp->fxp_got_int= 0;
362433d6423SLionel Sambuc 	fp->fxp_send_int= 0;
363433d6423SLionel Sambuc 	fp->fxp_ee_addrlen= 0;	/* Unknown */
364433d6423SLionel Sambuc 	fp->fxp_need_reset= 0;
365433d6423SLionel Sambuc 	fp->fxp_report_link= 0;
366433d6423SLionel Sambuc 	fp->fxp_link_up= -1;	/* Unknown */
367433d6423SLionel Sambuc 	fp->fxp_rx_need_restart= 0;
368433d6423SLionel Sambuc 	fp->fxp_need_conf= 0;
369433d6423SLionel Sambuc 	fp->fxp_tx_head= 0;
370433d6423SLionel Sambuc 	fp->fxp_tx_tail= 0;
371433d6423SLionel Sambuc 	fp->fxp_tx_alive= 0;
372433d6423SLionel Sambuc 	fp->fxp_tx_threshold= TXTT_MIN;
373433d6423SLionel Sambuc 
374433d6423SLionel Sambuc 	/* Try to come up with a sensible configuration for the current
375433d6423SLionel Sambuc 	 * device. Unfortunately every device is different, defaults are
376433d6423SLionel Sambuc 	 * not always zero, and some fields are re-used with a completely
377433d6423SLionel Sambuc 	 * different interpretation. We start out with a sensible default
378433d6423SLionel Sambuc 	 * for all devices and then add device specific changes.
379433d6423SLionel Sambuc 	 */
380433d6423SLionel Sambuc 	fp->fxp_conf_bytes[0]= CC_BYTES_NR;
381433d6423SLionel Sambuc 	fp->fxp_conf_bytes[1]= CTL_DEFAULT | CRL_DEFAULT;
382433d6423SLionel Sambuc 	fp->fxp_conf_bytes[2]= CAI_DEFAULT;
383433d6423SLionel Sambuc 	fp->fxp_conf_bytes[3]= 0;
384433d6423SLionel Sambuc 	fp->fxp_conf_bytes[4]= 0;
385433d6423SLionel Sambuc 	fp->fxp_conf_bytes[5]= 0;
386433d6423SLionel Sambuc 	fp->fxp_conf_bytes[6]= CCB6_ESC | CCB6_ETCB | CCB6_RES;
387433d6423SLionel Sambuc 	fp->fxp_conf_bytes[7]= CUR_1;
388433d6423SLionel Sambuc 	fp->fxp_conf_bytes[8]= CCB8_503_MII;
389433d6423SLionel Sambuc 	fp->fxp_conf_bytes[9]= 0;
390433d6423SLionel Sambuc 	fp->fxp_conf_bytes[10]= CLB_NORMAL | CPAL_DEFAULT | CCB10_NSAI |
391433d6423SLionel Sambuc 				CCB10_RES1;
392433d6423SLionel Sambuc 	fp->fxp_conf_bytes[11]= 0;
393433d6423SLionel Sambuc 	fp->fxp_conf_bytes[12]= CIS_DEFAULT;
394433d6423SLionel Sambuc 	fp->fxp_conf_bytes[13]= CCB13_DEFAULT;
395433d6423SLionel Sambuc 	fp->fxp_conf_bytes[14]= CCB14_DEFAULT;
396433d6423SLionel Sambuc 	fp->fxp_conf_bytes[15]= CCB15_RES1 | CCB15_RES2;
397433d6423SLionel Sambuc 	fp->fxp_conf_bytes[16]= CCB16_DEFAULT;
398433d6423SLionel Sambuc 	fp->fxp_conf_bytes[17]= CCB17_DEFAULT;
399433d6423SLionel Sambuc 	fp->fxp_conf_bytes[18]= CCB18_RES1 | CCB18_PFCT | CCB18_PE;
400433d6423SLionel Sambuc 	fp->fxp_conf_bytes[19]= CCB19_FDPE;
401433d6423SLionel Sambuc 	fp->fxp_conf_bytes[20]= CCB20_PFCL | CCB20_RES1;
402433d6423SLionel Sambuc 	fp->fxp_conf_bytes[21]= CCB21_RES21;
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc #if VERBOSE
405433d6423SLionel Sambuc 	for (i= 0; i<CC_BYTES_NR; i++)
406433d6423SLionel Sambuc 		printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
407433d6423SLionel Sambuc 	printf("\n");
408433d6423SLionel Sambuc #endif
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc 	switch(fp->fxp_type)
411433d6423SLionel Sambuc 	{
412433d6423SLionel Sambuc 	case FT_82557:
413433d6423SLionel Sambuc 		break;
414433d6423SLionel Sambuc 	case FT_82558A:
415433d6423SLionel Sambuc 	case FT_82559:
416433d6423SLionel Sambuc 	case FT_82801:
417433d6423SLionel Sambuc 		fp->fxp_conf_bytes[18] |= CCB18_LROK;
418433d6423SLionel Sambuc 
419433d6423SLionel Sambuc 		if (fp->fxp_type == FT_82801)
420433d6423SLionel Sambuc 		{
421433d6423SLionel Sambuc 			fp->fxp_conf_bytes[6] = 0xba; /* ctrl 1 */
422433d6423SLionel Sambuc 			fp->fxp_conf_bytes[15] = 0x48; /* promiscuous */
423433d6423SLionel Sambuc 			fp->fxp_conf_bytes[21] = 0x05; /* mc_all */
424433d6423SLionel Sambuc 		}
425433d6423SLionel Sambuc 		break;
426433d6423SLionel Sambuc 	default:
427433d6423SLionel Sambuc 		panic("fxp_conf_hw: bad device type: %d", fp->fxp_type);
428433d6423SLionel Sambuc 	}
429433d6423SLionel Sambuc 
430433d6423SLionel Sambuc 	/* Assume an 82555 (compatible) PHY. The should be changed for
431433d6423SLionel Sambuc 	 * 82557 NICs with different PHYs
432433d6423SLionel Sambuc 	 */
433433d6423SLionel Sambuc 	fp->fxp_ms_regs = 0;	/* No master/slave registers. */
434433d6423SLionel Sambuc 
435433d6423SLionel Sambuc #if VERBOSE
436433d6423SLionel Sambuc 	for (i= 0; i<CC_BYTES_NR; i++)
437433d6423SLionel Sambuc 		printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
438433d6423SLionel Sambuc 	printf("\n");
439433d6423SLionel Sambuc #endif
440433d6423SLionel Sambuc }
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc /*===========================================================================*
443433d6423SLionel Sambuc  *				fxp_init_hw				     *
444433d6423SLionel Sambuc  *===========================================================================*/
fxp_init_hw(fxp_t * fp,netdriver_addr_t * addr,unsigned int instance)445f7df02e7SDavid van Moolenbroek static void fxp_init_hw(fxp_t *fp, netdriver_addr_t *addr,
446f7df02e7SDavid van Moolenbroek 	unsigned int instance)
447433d6423SLionel Sambuc {
44896e62d65SDavid van Moolenbroek 	int r, isr;
449433d6423SLionel Sambuc 	port_t port;
450433d6423SLionel Sambuc 	phys_bytes bus_addr;
451433d6423SLionel Sambuc 
452433d6423SLionel Sambuc 	port= fp->fxp_base_port;
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc 	fxp_init_buf(fp);
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc 	/* Set the interrupt handler and policy. Do not automatically
457433d6423SLionel Sambuc 	 * reenable interrupts. Return the IRQ line number on interrupts.
458433d6423SLionel Sambuc  	 */
459433d6423SLionel Sambuc  	fp->fxp_hook = fp->fxp_irq;
460433d6423SLionel Sambuc 	r= sys_irqsetpolicy(fp->fxp_irq, 0, &fp->fxp_hook);
461433d6423SLionel Sambuc 	if (r != OK)
462433d6423SLionel Sambuc 		panic("sys_irqsetpolicy failed: %d", r);
463433d6423SLionel Sambuc 
464433d6423SLionel Sambuc 	fxp_reset_hw(fp);
465433d6423SLionel Sambuc 
466433d6423SLionel Sambuc 	r= sys_irqenable(&fp->fxp_hook);
467433d6423SLionel Sambuc 	if (r != OK)
468433d6423SLionel Sambuc 		panic("sys_irqenable failed: %d", r);
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 	/* Reset PHY? */
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc 	fxp_do_conf(fp);
473433d6423SLionel Sambuc 
474433d6423SLionel Sambuc 	/* Set pointer to statistical counters */
475433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat),
476433d6423SLionel Sambuc 		&bus_addr);
477433d6423SLionel Sambuc 	if (r != OK)
478433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
479433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_LOAD_DCA, bus_addr, TRUE /* check idle */);
480433d6423SLionel Sambuc 
481433d6423SLionel Sambuc 	/* Ack previous interrupts */
482433d6423SLionel Sambuc 	isr= fxp_inb(port, SCB_INT_STAT);
483433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_STAT, isr);
484433d6423SLionel Sambuc 
485433d6423SLionel Sambuc 	/* Enable interrupts */
486433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_MASK, 0);
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc 	fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
489433d6423SLionel Sambuc 		TRUE /* check idle */);
490433d6423SLionel Sambuc 
491f7df02e7SDavid van Moolenbroek 	fxp_confaddr(fp, addr, instance);
492433d6423SLionel Sambuc }
493433d6423SLionel Sambuc 
494433d6423SLionel Sambuc /*===========================================================================*
495433d6423SLionel Sambuc  *				fxp_init_buf				     *
496433d6423SLionel Sambuc  *===========================================================================*/
fxp_init_buf(fp)497433d6423SLionel Sambuc static void fxp_init_buf(fp)
498433d6423SLionel Sambuc fxp_t *fp;
499433d6423SLionel Sambuc {
500433d6423SLionel Sambuc 	size_t rx_totbufsize, tx_totbufsize, tot_bufsize, alloc_bufsize;
501433d6423SLionel Sambuc 	char *alloc_buf;
502433d6423SLionel Sambuc 	phys_bytes buf, bus_addr;
503433d6423SLionel Sambuc 	int i, r;
504433d6423SLionel Sambuc 	struct rfd *rfdp;
505433d6423SLionel Sambuc 	struct tx *txp;
506433d6423SLionel Sambuc 	phys_bytes ph;
507433d6423SLionel Sambuc 
508433d6423SLionel Sambuc 	fp->fxp_rx_nbuf= N_RX_BUF;
509433d6423SLionel Sambuc 	rx_totbufsize= fp->fxp_rx_nbuf * sizeof(struct rfd);
510433d6423SLionel Sambuc 	fp->fxp_rx_bufsize= rx_totbufsize;
511433d6423SLionel Sambuc 
512433d6423SLionel Sambuc 	fp->fxp_tx_nbuf= N_TX_BUF;
513433d6423SLionel Sambuc 	tx_totbufsize= fp->fxp_tx_nbuf * sizeof(struct tx);
514433d6423SLionel Sambuc 	fp->fxp_tx_bufsize= tx_totbufsize;
515433d6423SLionel Sambuc 
516433d6423SLionel Sambuc 	tot_bufsize= sizeof(*tmpbufp) + tx_totbufsize + rx_totbufsize;
517433d6423SLionel Sambuc 	if (tot_bufsize % 4096)
518433d6423SLionel Sambuc 		tot_bufsize += 4096 - (tot_bufsize % 4096);
519433d6423SLionel Sambuc 	alloc_bufsize= tot_bufsize;
520433d6423SLionel Sambuc 	alloc_buf= alloc_contig(alloc_bufsize, AC_ALIGN4K, &ph);
52196e62d65SDavid van Moolenbroek 	if (alloc_buf == NULL)
52296e62d65SDavid van Moolenbroek 		panic("fxp_init_buf: unable to alloc_contig size: %d",
52396e62d65SDavid van Moolenbroek 			alloc_bufsize);
524433d6423SLionel Sambuc 
525433d6423SLionel Sambuc 	buf= (phys_bytes)alloc_buf;
526433d6423SLionel Sambuc 
52796e62d65SDavid van Moolenbroek 	tell_iommu((vir_bytes)buf, tot_bufsize, 0, 0, 0);
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc 	tmpbufp= (union tmpbuf *)buf;
530433d6423SLionel Sambuc 
531433d6423SLionel Sambuc 	fp->fxp_rx_buf= (struct rfd *)&tmpbufp[1];
532433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)fp->fxp_rx_buf, rx_totbufsize,
533433d6423SLionel Sambuc 		&bus_addr);
534433d6423SLionel Sambuc 	if (r != OK)
535433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
536433d6423SLionel Sambuc 	fp->fxp_rx_busaddr= bus_addr;
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc #if 0
539433d6423SLionel Sambuc 	printf("fxp_init_buf: got phys 0x%x for vir 0x%x\n",
540433d6423SLionel Sambuc 		fp->fxp_rx_busaddr, fp->fxp_rx_buf);
541433d6423SLionel Sambuc #endif
542433d6423SLionel Sambuc 
543433d6423SLionel Sambuc 	for (i= 0, rfdp= fp->fxp_rx_buf; i<fp->fxp_rx_nbuf; i++, rfdp++)
544433d6423SLionel Sambuc 	{
545433d6423SLionel Sambuc 		rfdp->rfd_status= 0;
546433d6423SLionel Sambuc 		rfdp->rfd_command= 0;
547433d6423SLionel Sambuc 		if (i != fp->fxp_rx_nbuf-1)
548433d6423SLionel Sambuc 		{
549433d6423SLionel Sambuc 			r= sys_umap(SELF, VM_D, (vir_bytes)&rfdp[1],
550433d6423SLionel Sambuc 				sizeof(rfdp[1]), &bus_addr);
551433d6423SLionel Sambuc 			if (r != OK)
552433d6423SLionel Sambuc 				panic("sys_umap failed: %d", r);
553433d6423SLionel Sambuc 			rfdp->rfd_linkaddr= bus_addr;
554433d6423SLionel Sambuc 		}
555433d6423SLionel Sambuc 		else
556433d6423SLionel Sambuc 		{
557433d6423SLionel Sambuc 			rfdp->rfd_linkaddr= fp->fxp_rx_busaddr;
558433d6423SLionel Sambuc 			rfdp->rfd_command |= RFDC_EL;
559433d6423SLionel Sambuc 		}
560433d6423SLionel Sambuc 		rfdp->rfd_reserved= 0;
561433d6423SLionel Sambuc 		rfdp->rfd_res= 0;
562433d6423SLionel Sambuc 		rfdp->rfd_size= sizeof(rfdp->rfd_buf);
563433d6423SLionel Sambuc 
564433d6423SLionel Sambuc 	}
565433d6423SLionel Sambuc 	fp->fxp_rx_head= 0;
566433d6423SLionel Sambuc 
567433d6423SLionel Sambuc 	fp->fxp_tx_buf= (struct tx *)((char *)fp->fxp_rx_buf+rx_totbufsize);
568433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)fp->fxp_tx_buf,
569433d6423SLionel Sambuc 		(phys_bytes)tx_totbufsize, &fp->fxp_tx_busaddr);
570433d6423SLionel Sambuc 	if (r != OK)
571433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
572433d6423SLionel Sambuc 
573433d6423SLionel Sambuc 	for (i= 0, txp= fp->fxp_tx_buf; i<fp->fxp_tx_nbuf; i++, txp++)
574433d6423SLionel Sambuc 	{
575433d6423SLionel Sambuc 		txp->tx_status= 0;
576433d6423SLionel Sambuc 		txp->tx_command= TXC_EL | CBL_NOP;	/* Just in case */
577433d6423SLionel Sambuc 		if (i != fp->fxp_tx_nbuf-1)
578433d6423SLionel Sambuc 		{
579433d6423SLionel Sambuc 			r= sys_umap(SELF, VM_D, (vir_bytes)&txp[1],
580433d6423SLionel Sambuc 				(phys_bytes)sizeof(txp[1]), &bus_addr);
581433d6423SLionel Sambuc 			if (r != OK)
582433d6423SLionel Sambuc 				panic("sys_umap failed: %d", r);
583433d6423SLionel Sambuc 			txp->tx_linkaddr= bus_addr;
584433d6423SLionel Sambuc 		}
585433d6423SLionel Sambuc 		else
586433d6423SLionel Sambuc 		{
587433d6423SLionel Sambuc 			txp->tx_linkaddr= fp->fxp_tx_busaddr;
588433d6423SLionel Sambuc 		}
589433d6423SLionel Sambuc 		txp->tx_tbda= TX_TBDA_NIL;
590433d6423SLionel Sambuc 		txp->tx_size= 0;
591433d6423SLionel Sambuc 		txp->tx_tthresh= fp->fxp_tx_threshold;
592433d6423SLionel Sambuc 		txp->tx_ntbd= 0;
593433d6423SLionel Sambuc 	}
59496e62d65SDavid van Moolenbroek 	fp->fxp_tx_idle= TRUE;
595433d6423SLionel Sambuc }
596433d6423SLionel Sambuc 
597433d6423SLionel Sambuc /*===========================================================================*
598433d6423SLionel Sambuc  *				fxp_reset_hw				     *
599433d6423SLionel Sambuc  *===========================================================================*/
fxp_reset_hw(fp)600433d6423SLionel Sambuc static void fxp_reset_hw(fp)
601433d6423SLionel Sambuc fxp_t *fp;
602433d6423SLionel Sambuc {
603433d6423SLionel Sambuc /* Inline the function in init? */
604433d6423SLionel Sambuc 	port_t port;
605433d6423SLionel Sambuc 
606433d6423SLionel Sambuc 	port= fp->fxp_base_port;
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc 	/* Reset device */
609433d6423SLionel Sambuc 	fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
610*d4dd6511Srlfnb 	micro_delay(CSR_PORT_RESET_DELAY);
611433d6423SLionel Sambuc 
612433d6423SLionel Sambuc 	/* Disable interrupts */
613433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_MASK, SIM_M);
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc 	/* Set CU base to zero */
616433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_LOAD_BASE, 0, TRUE /* check idle */);
617433d6423SLionel Sambuc 
618433d6423SLionel Sambuc 	/* Set RU base to zero */
619433d6423SLionel Sambuc 	fxp_ru_ptr_cmd(fp, SC_RU_LOAD_BASE, 0, TRUE /* check idle */);
620433d6423SLionel Sambuc }
621433d6423SLionel Sambuc 
622433d6423SLionel Sambuc /*===========================================================================*
623433d6423SLionel Sambuc  *				fxp_confaddr				     *
624433d6423SLionel Sambuc  *===========================================================================*/
fxp_confaddr(fxp_t * fp,netdriver_addr_t * addr,unsigned int instance)625f7df02e7SDavid van Moolenbroek static void fxp_confaddr(fxp_t *fp, netdriver_addr_t *addr,
626f7df02e7SDavid van Moolenbroek 	unsigned int instance)
627433d6423SLionel Sambuc {
628433d6423SLionel Sambuc 	static char eakey[]= FXP_ENVVAR "#_EA";
629433d6423SLionel Sambuc 	static char eafmt[]= "x:x:x:x:x:x";
630433d6423SLionel Sambuc 	int i, r;
631433d6423SLionel Sambuc 	phys_bytes bus_addr;
632433d6423SLionel Sambuc 	long v;
633433d6423SLionel Sambuc 
634433d6423SLionel Sambuc 	/* User defined ethernet address? */
635f7df02e7SDavid van Moolenbroek 	eakey[sizeof(FXP_ENVVAR)-1]= '0' + instance;
636433d6423SLionel Sambuc 
637433d6423SLionel Sambuc 	for (i= 0; i < 6; i++)
638433d6423SLionel Sambuc 	{
639433d6423SLionel Sambuc 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
640433d6423SLionel Sambuc 			break;
641f7df02e7SDavid van Moolenbroek 		addr->na_addr[i]= v;
642433d6423SLionel Sambuc 	}
643433d6423SLionel Sambuc 
644433d6423SLionel Sambuc 	if (i != 0 && i != 6) env_panic(eakey);	/* It's all or nothing */
645433d6423SLionel Sambuc 
646433d6423SLionel Sambuc 	if (i == 0)
647433d6423SLionel Sambuc 	{
648433d6423SLionel Sambuc 		/* Get ethernet address from EEPROM */
649433d6423SLionel Sambuc 		for (i= 0; i<3; i++)
650433d6423SLionel Sambuc 		{
651433d6423SLionel Sambuc 			v= eeprom_read(fp, i);
652f7df02e7SDavid van Moolenbroek 			addr->na_addr[i*2]= (v & 0xff);
653f7df02e7SDavid van Moolenbroek 			addr->na_addr[i*2+1]= ((v >> 8) & 0xff);
654433d6423SLionel Sambuc 		}
655433d6423SLionel Sambuc 	}
656433d6423SLionel Sambuc 
657433d6423SLionel Sambuc 	/* Tell NIC about ethernet address */
658433d6423SLionel Sambuc 	tmpbufp->ias.ias_status= 0;
659433d6423SLionel Sambuc 	tmpbufp->ias.ias_command= CBL_C_EL | CBL_AIS;
660433d6423SLionel Sambuc 	tmpbufp->ias.ias_linkaddr= 0;
661f7df02e7SDavid van Moolenbroek 	memcpy(tmpbufp->ias.ias_ethaddr, addr->na_addr,
662433d6423SLionel Sambuc 		sizeof(tmpbufp->ias.ias_ethaddr));
663433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->ias,
664433d6423SLionel Sambuc 		(phys_bytes)sizeof(tmpbufp->ias), &bus_addr);
665433d6423SLionel Sambuc 	if (r != OK)
666433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
667433d6423SLionel Sambuc 
668433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
669433d6423SLionel Sambuc 
670433d6423SLionel Sambuc 	/* Wait for CU command to complete */
671433d6423SLionel Sambuc 	SPIN_UNTIL(tmpbufp->ias.ias_status & CBL_F_C, 1000);
672433d6423SLionel Sambuc 
673433d6423SLionel Sambuc 	if (!(tmpbufp->ias.ias_status & CBL_F_C))
674433d6423SLionel Sambuc 		panic("fxp_confaddr: CU command failed to complete");
675433d6423SLionel Sambuc 	if (!(tmpbufp->ias.ias_status & CBL_F_OK))
676433d6423SLionel Sambuc 		panic("fxp_confaddr: CU command failed");
677433d6423SLionel Sambuc 
678433d6423SLionel Sambuc #if VERBOSE
679f7df02e7SDavid van Moolenbroek 	printf("%s: hardware ethernet address: ", netdriver_name());
680433d6423SLionel Sambuc 	for (i= 0; i<6; i++)
681f7df02e7SDavid van Moolenbroek 		printf("%02x%s", addr->na_addr[i], i < 5 ? ":" : "");
682433d6423SLionel Sambuc 	printf("\n");
683433d6423SLionel Sambuc #endif
684433d6423SLionel Sambuc }
685433d6423SLionel Sambuc 
686433d6423SLionel Sambuc /*===========================================================================*
687f7df02e7SDavid van Moolenbroek  *				fxp_set_mode				     *
688433d6423SLionel Sambuc  *===========================================================================*/
fxp_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)689f7df02e7SDavid van Moolenbroek static void fxp_set_mode(unsigned int mode,
690f7df02e7SDavid van Moolenbroek 	const netdriver_addr_t * mcast_list __unused,
691f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count __unused)
692433d6423SLionel Sambuc {
69396e62d65SDavid van Moolenbroek 	fxp_t *fp;
69496e62d65SDavid van Moolenbroek 
69596e62d65SDavid van Moolenbroek 	fp = fxp_state;
69696e62d65SDavid van Moolenbroek 
697433d6423SLionel Sambuc 	fp->fxp_conf_bytes[0]= CC_BYTES_NR;	/* Just to be sure */
698433d6423SLionel Sambuc 	fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM);
699433d6423SLionel Sambuc 	fp->fxp_conf_bytes[21] &= ~CCB21_MA;
700433d6423SLionel Sambuc 
701f7df02e7SDavid van Moolenbroek 	if (mode & NDEV_MODE_PROMISC)
702433d6423SLionel Sambuc 		fp->fxp_conf_bytes[15] |= CCB15_PM;
703f7df02e7SDavid van Moolenbroek 	if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
704433d6423SLionel Sambuc 		fp->fxp_conf_bytes[21] |= CCB21_MA;
705433d6423SLionel Sambuc 
706f7df02e7SDavid van Moolenbroek 	if (!(mode & (NDEV_MODE_BCAST | NDEV_MODE_MCAST_LIST |
707f7df02e7SDavid van Moolenbroek 	    NDEV_MODE_MCAST_ALL | NDEV_MODE_PROMISC)))
708433d6423SLionel Sambuc 		fp->fxp_conf_bytes[15] |= CCB15_BD;
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc 	/* Queue request if not idle */
711433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
712433d6423SLionel Sambuc 	{
713433d6423SLionel Sambuc 		fxp_do_conf(fp);
714433d6423SLionel Sambuc 	}
715433d6423SLionel Sambuc 	else
716433d6423SLionel Sambuc 	{
717433d6423SLionel Sambuc 		printf("fxp_rec_mode: setting fxp_need_conf\n");
718433d6423SLionel Sambuc 		fp->fxp_need_conf= TRUE;
719433d6423SLionel Sambuc 	}
720433d6423SLionel Sambuc }
721433d6423SLionel Sambuc 
722433d6423SLionel Sambuc /*===========================================================================*
72396e62d65SDavid van Moolenbroek  *				fxp_send				     *
724433d6423SLionel Sambuc  *===========================================================================*/
fxp_send(struct netdriver_data * data,size_t size)72596e62d65SDavid van Moolenbroek static int fxp_send(struct netdriver_data *data, size_t size)
726433d6423SLionel Sambuc {
72796e62d65SDavid van Moolenbroek 	int prev_head;
728433d6423SLionel Sambuc 	int fxp_tx_nbuf, fxp_tx_head;
729433d6423SLionel Sambuc 	u16_t tx_command;
730433d6423SLionel Sambuc 	fxp_t *fp;
731433d6423SLionel Sambuc 	struct tx *txp, *prev_txp;
732433d6423SLionel Sambuc 
733433d6423SLionel Sambuc 	fp= fxp_state;
734433d6423SLionel Sambuc 
735433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
736433d6423SLionel Sambuc 	{
737433d6423SLionel Sambuc 		txp= fp->fxp_tx_buf;
738433d6423SLionel Sambuc 		fxp_tx_head= 0;	/* lint */
739433d6423SLionel Sambuc 		prev_txp= NULL;	/* lint */
740433d6423SLionel Sambuc 	}
741433d6423SLionel Sambuc 	else
742433d6423SLionel Sambuc 	{
743433d6423SLionel Sambuc 		fxp_tx_nbuf= fp->fxp_tx_nbuf;
744433d6423SLionel Sambuc 		prev_head= fp->fxp_tx_head;
745433d6423SLionel Sambuc 		fxp_tx_head= prev_head+1;
746433d6423SLionel Sambuc 		if (fxp_tx_head == fxp_tx_nbuf)
747433d6423SLionel Sambuc 			fxp_tx_head= 0;
748433d6423SLionel Sambuc 		assert(fxp_tx_head < fxp_tx_nbuf);
749433d6423SLionel Sambuc 
750433d6423SLionel Sambuc 		if (fxp_tx_head == fp->fxp_tx_tail)
751433d6423SLionel Sambuc 		{
752433d6423SLionel Sambuc 			/* Send queue is full */
75396e62d65SDavid van Moolenbroek 			return SUSPEND;
754433d6423SLionel Sambuc 		}
755433d6423SLionel Sambuc 
756433d6423SLionel Sambuc 		prev_txp= &fp->fxp_tx_buf[prev_head];
757433d6423SLionel Sambuc 		txp= &fp->fxp_tx_buf[fxp_tx_head];
758433d6423SLionel Sambuc 	}
759433d6423SLionel Sambuc 
76096e62d65SDavid van Moolenbroek 	/* Copy in the packet data */
76196e62d65SDavid van Moolenbroek 	netdriver_copyin(data, 0, txp->tx_buf, size);
762433d6423SLionel Sambuc 
763433d6423SLionel Sambuc 	txp->tx_status= 0;
764433d6423SLionel Sambuc 	txp->tx_command= TXC_EL | CBL_XMIT;
765433d6423SLionel Sambuc 	txp->tx_tbda= TX_TBDA_NIL;
766433d6423SLionel Sambuc 	txp->tx_size= TXSZ_EOF | size;
767433d6423SLionel Sambuc 	txp->tx_tthresh= fp->fxp_tx_threshold;
768433d6423SLionel Sambuc 	txp->tx_ntbd= 0;
769433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
770433d6423SLionel Sambuc 	{
77196e62d65SDavid van Moolenbroek 		fp->fxp_tx_idle= FALSE;
772433d6423SLionel Sambuc 		fp->fxp_tx_head= fp->fxp_tx_tail= 0;
773433d6423SLionel Sambuc 
774433d6423SLionel Sambuc 		fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr,
775433d6423SLionel Sambuc 			TRUE /* check idle */);
776433d6423SLionel Sambuc 	}
777433d6423SLionel Sambuc 	else
778433d6423SLionel Sambuc 	{
779433d6423SLionel Sambuc 		/* Link new request in transmit list */
780433d6423SLionel Sambuc 		tx_command= prev_txp->tx_command;
781433d6423SLionel Sambuc 		assert(tx_command == (TXC_EL | CBL_XMIT));
782433d6423SLionel Sambuc 		prev_txp->tx_command= CBL_XMIT;
783433d6423SLionel Sambuc 		fp->fxp_tx_head= fxp_tx_head;
784433d6423SLionel Sambuc 	}
785433d6423SLionel Sambuc 
78696e62d65SDavid van Moolenbroek 	return OK;
787433d6423SLionel Sambuc }
788433d6423SLionel Sambuc 
789433d6423SLionel Sambuc /*===========================================================================*
79096e62d65SDavid van Moolenbroek  *				fxp_check_restart			     *
791433d6423SLionel Sambuc  *===========================================================================*/
fxp_check_restart(fxp_t * fp)79296e62d65SDavid van Moolenbroek static void fxp_check_restart(fxp_t *fp)
793433d6423SLionel Sambuc {
79496e62d65SDavid van Moolenbroek 	port_t port;
79596e62d65SDavid van Moolenbroek 	u8_t scb_status;
79696e62d65SDavid van Moolenbroek 
79796e62d65SDavid van Moolenbroek 	if (!fp->fxp_rx_need_restart)
79896e62d65SDavid van Moolenbroek 		return;
79996e62d65SDavid van Moolenbroek 
80096e62d65SDavid van Moolenbroek 	fp->fxp_rx_need_restart= 0;
80196e62d65SDavid van Moolenbroek 
80296e62d65SDavid van Moolenbroek 	/* Check the status of the RU */
80396e62d65SDavid van Moolenbroek 	port= fp->fxp_base_port;
80496e62d65SDavid van Moolenbroek 	scb_status= fxp_inb(port, SCB_STATUS);
80596e62d65SDavid van Moolenbroek 	if ((scb_status & SS_RUS_MASK) != SS_RU_NORES)
80696e62d65SDavid van Moolenbroek 	{
80796e62d65SDavid van Moolenbroek 		/* Race condition? */
80896e62d65SDavid van Moolenbroek 		printf("fxp_check_restart: restart race: 0x%x\n", scb_status);
80996e62d65SDavid van Moolenbroek 		assert((scb_status & SS_RUS_MASK) == SS_RU_READY);
81096e62d65SDavid van Moolenbroek 	}
81196e62d65SDavid van Moolenbroek 	else
81296e62d65SDavid van Moolenbroek 	{
81396e62d65SDavid van Moolenbroek 		fxp_restart_ru(fp);
81496e62d65SDavid van Moolenbroek 	}
81596e62d65SDavid van Moolenbroek }
81696e62d65SDavid van Moolenbroek 
81796e62d65SDavid van Moolenbroek /*===========================================================================*
81896e62d65SDavid van Moolenbroek  *				fxp_recv				     *
81996e62d65SDavid van Moolenbroek  *===========================================================================*/
fxp_recv(struct netdriver_data * data,size_t max)82096e62d65SDavid van Moolenbroek static ssize_t fxp_recv(struct netdriver_data *data, size_t max)
82196e62d65SDavid van Moolenbroek {
82296e62d65SDavid van Moolenbroek 	int fxp_rx_head, fxp_rx_nbuf;
823433d6423SLionel Sambuc 	port_t port;
824433d6423SLionel Sambuc 	unsigned packlen;
825433d6423SLionel Sambuc 	u16_t rfd_status;
826433d6423SLionel Sambuc 	u16_t rfd_res;
827433d6423SLionel Sambuc 	fxp_t *fp;
828433d6423SLionel Sambuc 	struct rfd *rfdp, *prev_rfdp;
829433d6423SLionel Sambuc 
830433d6423SLionel Sambuc 	fp= fxp_state;
831433d6423SLionel Sambuc 
832433d6423SLionel Sambuc 	port= fp->fxp_base_port;
833433d6423SLionel Sambuc 
834433d6423SLionel Sambuc 	fxp_rx_head= fp->fxp_rx_head;
835433d6423SLionel Sambuc 	rfdp= &fp->fxp_rx_buf[fxp_rx_head];
836433d6423SLionel Sambuc 
837433d6423SLionel Sambuc 	rfd_status= rfdp->rfd_status;
83896e62d65SDavid van Moolenbroek 	if (!(rfd_status & RFDS_C)) {
839433d6423SLionel Sambuc 		/* Receive buffer is empty, suspend */
84096e62d65SDavid van Moolenbroek 		fxp_check_restart(fp);
84196e62d65SDavid van Moolenbroek 
84296e62d65SDavid van Moolenbroek 		return SUSPEND;
843433d6423SLionel Sambuc 	}
844433d6423SLionel Sambuc 
845433d6423SLionel Sambuc 	if (!(rfd_status & RFDS_OK))
846433d6423SLionel Sambuc 	{
847433d6423SLionel Sambuc 		/* Not OK? What happened? */
848433d6423SLionel Sambuc 		assert(0);
849433d6423SLionel Sambuc 	}
850433d6423SLionel Sambuc 	else
851433d6423SLionel Sambuc 	{
852433d6423SLionel Sambuc 		assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR |
853433d6423SLionel Sambuc 			RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT |
854433d6423SLionel Sambuc 			RFDS_RXERR)));
855433d6423SLionel Sambuc 	}
856433d6423SLionel Sambuc 	rfd_res= rfdp->rfd_res;
857433d6423SLionel Sambuc 	assert(rfd_res & RFDR_EOF);
858433d6423SLionel Sambuc 	assert(rfd_res & RFDR_F);
859433d6423SLionel Sambuc 
860433d6423SLionel Sambuc 	packlen= rfd_res & RFDSZ_SIZE;
861433d6423SLionel Sambuc 
86296e62d65SDavid van Moolenbroek 	/* Copy out the packet data */
86396e62d65SDavid van Moolenbroek 	if (packlen > max)
86496e62d65SDavid van Moolenbroek 		packlen = max;
865433d6423SLionel Sambuc 
86696e62d65SDavid van Moolenbroek 	netdriver_copyout(data, 0, rfdp->rfd_buf, packlen);
867433d6423SLionel Sambuc 
868433d6423SLionel Sambuc 	/* Re-init the current buffer */
869433d6423SLionel Sambuc 	rfdp->rfd_status= 0;
870433d6423SLionel Sambuc 	rfdp->rfd_command= RFDC_EL;
871433d6423SLionel Sambuc 	rfdp->rfd_reserved= 0;
872433d6423SLionel Sambuc 	rfdp->rfd_res= 0;
873433d6423SLionel Sambuc 	rfdp->rfd_size= sizeof(rfdp->rfd_buf);
874433d6423SLionel Sambuc 
875433d6423SLionel Sambuc 	fxp_rx_nbuf= fp->fxp_rx_nbuf;
876433d6423SLionel Sambuc 	if (fxp_rx_head == 0)
877433d6423SLionel Sambuc 	{
878433d6423SLionel Sambuc 		prev_rfdp= &fp->fxp_rx_buf[fxp_rx_nbuf-1];
879433d6423SLionel Sambuc 	}
880433d6423SLionel Sambuc 	else
881433d6423SLionel Sambuc 		prev_rfdp= &rfdp[-1];
882433d6423SLionel Sambuc 
883433d6423SLionel Sambuc 	assert(prev_rfdp->rfd_command & RFDC_EL);
884433d6423SLionel Sambuc 	prev_rfdp->rfd_command &= ~RFDC_EL;
885433d6423SLionel Sambuc 
886433d6423SLionel Sambuc 	fxp_rx_head++;
887433d6423SLionel Sambuc 	if (fxp_rx_head == fxp_rx_nbuf)
888433d6423SLionel Sambuc 		fxp_rx_head= 0;
889433d6423SLionel Sambuc 	assert(fxp_rx_head < fxp_rx_nbuf);
890433d6423SLionel Sambuc 	fp->fxp_rx_head= fxp_rx_head;
891433d6423SLionel Sambuc 
89296e62d65SDavid van Moolenbroek 	return packlen;
893433d6423SLionel Sambuc }
894433d6423SLionel Sambuc 
895433d6423SLionel Sambuc /*===========================================================================*
896433d6423SLionel Sambuc  *				fxp_do_conf				     *
897433d6423SLionel Sambuc  *===========================================================================*/
fxp_do_conf(fp)898433d6423SLionel Sambuc static void fxp_do_conf(fp)
899433d6423SLionel Sambuc fxp_t *fp;
900433d6423SLionel Sambuc {
901433d6423SLionel Sambuc 	int r;
902433d6423SLionel Sambuc 	phys_bytes bus_addr;
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc 	/* Configure device */
905433d6423SLionel Sambuc 	tmpbufp->cc.cc_status= 0;
906433d6423SLionel Sambuc 	tmpbufp->cc.cc_command= CBL_C_EL | CBL_CONF;
907433d6423SLionel Sambuc 	tmpbufp->cc.cc_linkaddr= 0;
908433d6423SLionel Sambuc 	memcpy(tmpbufp->cc.cc_bytes, fp->fxp_conf_bytes,
909433d6423SLionel Sambuc 		sizeof(tmpbufp->cc.cc_bytes));
910433d6423SLionel Sambuc 
911433d6423SLionel Sambuc 	r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->cc,
912433d6423SLionel Sambuc 		(phys_bytes)sizeof(tmpbufp->cc), &bus_addr);
913433d6423SLionel Sambuc 	if (r != OK)
914433d6423SLionel Sambuc 		panic("sys_umap failed: %d", r);
915433d6423SLionel Sambuc 
916433d6423SLionel Sambuc 	fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
917433d6423SLionel Sambuc 
918433d6423SLionel Sambuc 	/* Wait for CU command to complete */
919433d6423SLionel Sambuc 	SPIN_UNTIL(tmpbufp->cc.cc_status & CBL_F_C, 100000);
920433d6423SLionel Sambuc 
921433d6423SLionel Sambuc 	if (!(tmpbufp->cc.cc_status & CBL_F_C))
922433d6423SLionel Sambuc 		panic("fxp_do_conf: CU command failed to complete");
923433d6423SLionel Sambuc 	if (!(tmpbufp->cc.cc_status & CBL_F_OK))
924433d6423SLionel Sambuc 		panic("fxp_do_conf: CU command failed");
925433d6423SLionel Sambuc 
926433d6423SLionel Sambuc }
927433d6423SLionel Sambuc 
928433d6423SLionel Sambuc /*===========================================================================*
929433d6423SLionel Sambuc  *				fxp_cu_ptr_cmd				     *
930433d6423SLionel Sambuc  *===========================================================================*/
fxp_cu_ptr_cmd(fp,cmd,bus_addr,check_idle)931433d6423SLionel Sambuc static void fxp_cu_ptr_cmd(fp, cmd, bus_addr, check_idle)
932433d6423SLionel Sambuc fxp_t *fp;
933433d6423SLionel Sambuc int cmd;
934433d6423SLionel Sambuc phys_bytes bus_addr;
935433d6423SLionel Sambuc int check_idle;
936433d6423SLionel Sambuc {
937433d6423SLionel Sambuc 	spin_t spin;
938433d6423SLionel Sambuc 	port_t port;
939433d6423SLionel Sambuc 	u8_t scb_cmd;
940433d6423SLionel Sambuc 
941433d6423SLionel Sambuc 	port= fp->fxp_base_port;
942433d6423SLionel Sambuc 
943433d6423SLionel Sambuc 	if (check_idle)
944433d6423SLionel Sambuc 	{
945433d6423SLionel Sambuc 		/* Consistency check. Make sure that CU is idle */
946433d6423SLionel Sambuc 		if ((fxp_inb(port, SCB_STATUS) & SS_CUS_MASK) != SS_CU_IDLE)
947433d6423SLionel Sambuc 			panic("fxp_cu_ptr_cmd: CU is not idle");
948433d6423SLionel Sambuc 	}
949433d6423SLionel Sambuc 
950433d6423SLionel Sambuc 	fxp_outl(port, SCB_POINTER, bus_addr);
951433d6423SLionel Sambuc 	fxp_outb(port, SCB_CMD, cmd);
952433d6423SLionel Sambuc 
953433d6423SLionel Sambuc 	/* What is a reasonable time-out? There is nothing in the
954433d6423SLionel Sambuc 	 * documentation. 1 ms should be enough. We use 100 ms.
955433d6423SLionel Sambuc 	 */
956433d6423SLionel Sambuc 	spin_init(&spin, 100000);
957433d6423SLionel Sambuc 	do {
958433d6423SLionel Sambuc 		/* Wait for CU command to be accepted */
959433d6423SLionel Sambuc 		scb_cmd= fxp_inb(port, SCB_CMD);
960433d6423SLionel Sambuc 		if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP)
961433d6423SLionel Sambuc 			break;
962433d6423SLionel Sambuc 	} while (spin_check(&spin));
963433d6423SLionel Sambuc 
964433d6423SLionel Sambuc 	if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP)
965433d6423SLionel Sambuc 		panic("fxp_cu_ptr_cmd: CU does not accept command");
966433d6423SLionel Sambuc }
967433d6423SLionel Sambuc 
968433d6423SLionel Sambuc /*===========================================================================*
969433d6423SLionel Sambuc  *				fxp_ru_ptr_cmd				     *
970433d6423SLionel Sambuc  *===========================================================================*/
fxp_ru_ptr_cmd(fp,cmd,bus_addr,check_idle)971433d6423SLionel Sambuc static void fxp_ru_ptr_cmd(fp, cmd, bus_addr, check_idle)
972433d6423SLionel Sambuc fxp_t *fp;
973433d6423SLionel Sambuc int cmd;
974433d6423SLionel Sambuc phys_bytes bus_addr;
975433d6423SLionel Sambuc int check_idle;
976433d6423SLionel Sambuc {
977433d6423SLionel Sambuc 	spin_t spin;
978433d6423SLionel Sambuc 	port_t port;
979433d6423SLionel Sambuc 	u8_t scb_cmd;
980433d6423SLionel Sambuc 
981433d6423SLionel Sambuc 	port= fp->fxp_base_port;
982433d6423SLionel Sambuc 
983433d6423SLionel Sambuc 	if (check_idle)
984433d6423SLionel Sambuc 	{
985433d6423SLionel Sambuc 		/* Consistency check, make sure that RU is idle */
986433d6423SLionel Sambuc 		if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_IDLE)
987433d6423SLionel Sambuc 			panic("fxp_ru_ptr_cmd: RU is not idle");
988433d6423SLionel Sambuc 	}
989433d6423SLionel Sambuc 
990433d6423SLionel Sambuc 	fxp_outl(port, SCB_POINTER, bus_addr);
991433d6423SLionel Sambuc 	fxp_outb(port, SCB_CMD, cmd);
992433d6423SLionel Sambuc 
993433d6423SLionel Sambuc 	spin_init(&spin, 1000);
994433d6423SLionel Sambuc 	do {
995433d6423SLionel Sambuc 		/* Wait for RU command to be accepted */
996433d6423SLionel Sambuc 		scb_cmd= fxp_inb(port, SCB_CMD);
997433d6423SLionel Sambuc 		if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP)
998433d6423SLionel Sambuc 			break;
999433d6423SLionel Sambuc 	} while (spin_check(&spin));
1000433d6423SLionel Sambuc 
1001433d6423SLionel Sambuc 	if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP)
1002433d6423SLionel Sambuc 		panic("fxp_ru_ptr_cmd: RU does not accept command");
1003433d6423SLionel Sambuc }
1004433d6423SLionel Sambuc 
1005433d6423SLionel Sambuc /*===========================================================================*
1006433d6423SLionel Sambuc  *				fxp_restart_ru				     *
1007433d6423SLionel Sambuc  *===========================================================================*/
fxp_restart_ru(fp)1008433d6423SLionel Sambuc static void fxp_restart_ru(fp)
1009433d6423SLionel Sambuc fxp_t *fp;
1010433d6423SLionel Sambuc {
1011433d6423SLionel Sambuc 	int i, fxp_rx_nbuf;
1012433d6423SLionel Sambuc 	port_t port;
1013433d6423SLionel Sambuc 	struct rfd *rfdp;
1014433d6423SLionel Sambuc 
1015433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1016433d6423SLionel Sambuc 
1017433d6423SLionel Sambuc 	fxp_rx_nbuf= fp->fxp_rx_nbuf;
1018433d6423SLionel Sambuc 	for (i= 0, rfdp= fp->fxp_rx_buf; i<fxp_rx_nbuf; i++, rfdp++)
1019433d6423SLionel Sambuc 	{
1020433d6423SLionel Sambuc 		rfdp->rfd_status= 0;
1021433d6423SLionel Sambuc 		rfdp->rfd_command= 0;
1022433d6423SLionel Sambuc 		if (i == fp->fxp_rx_nbuf-1)
1023433d6423SLionel Sambuc 			rfdp->rfd_command= RFDC_EL;
1024433d6423SLionel Sambuc 		rfdp->rfd_reserved= 0;
1025433d6423SLionel Sambuc 		rfdp->rfd_res= 0;
1026433d6423SLionel Sambuc 		rfdp->rfd_size= sizeof(rfdp->rfd_buf);
1027433d6423SLionel Sambuc 	}
1028433d6423SLionel Sambuc 	fp->fxp_rx_head= 0;
1029433d6423SLionel Sambuc 
1030433d6423SLionel Sambuc 	/* Make sure that RU is in the 'No resources' state */
1031433d6423SLionel Sambuc 	if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_NORES)
1032433d6423SLionel Sambuc 		panic("fxp_restart_ru: RU is in an unexpected state");
1033433d6423SLionel Sambuc 
1034433d6423SLionel Sambuc 	fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
1035433d6423SLionel Sambuc 		FALSE /* do not check idle */);
1036433d6423SLionel Sambuc }
1037433d6423SLionel Sambuc 
1038433d6423SLionel Sambuc /*===========================================================================*
1039f7df02e7SDavid van Moolenbroek  *				fxp_update_stats			     *
1040433d6423SLionel Sambuc  *===========================================================================*/
fxp_update_stats(void)1041f7df02e7SDavid van Moolenbroek static void fxp_update_stats(void)
1042433d6423SLionel Sambuc {
1043433d6423SLionel Sambuc 	fxp_t *fp;
1044433d6423SLionel Sambuc 	u32_t *p;
1045433d6423SLionel Sambuc 
1046433d6423SLionel Sambuc 	fp= fxp_state;
1047433d6423SLionel Sambuc 
1048433d6423SLionel Sambuc 	p= &fp->fxp_stat.sc_tx_fcp;
1049433d6423SLionel Sambuc 	*p= 0;
1050433d6423SLionel Sambuc 
1051433d6423SLionel Sambuc 	/* The dump commmand doesn't take a pointer. Setting a pointer
1052433d6423SLionel Sambuc 	 * doesn't hurt though.
1053433d6423SLionel Sambuc 	 */
1054f7df02e7SDavid van Moolenbroek 	fxp_cu_ptr_cmd(fp, SC_CU_DUMP_RSET_SC, 0,
1055f7df02e7SDavid van Moolenbroek 	    FALSE /* do not check idle */);
1056433d6423SLionel Sambuc 
1057433d6423SLionel Sambuc 	/* Wait for CU command to complete */
1058f7df02e7SDavid van Moolenbroek 	SPIN_UNTIL(*p != 0, 2500);
1059433d6423SLionel Sambuc 
1060433d6423SLionel Sambuc 	if (*p == 0)
106196e62d65SDavid van Moolenbroek 		panic("fxp_stat: CU command failed to complete");
1062f7df02e7SDavid van Moolenbroek 	if (*p != SCM_DRSC)
106396e62d65SDavid van Moolenbroek 		panic("fxp_stat: bad magic");
1064433d6423SLionel Sambuc 
1065f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(fp->fxp_stat.sc_rx_crc +
1066433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_align +
1067433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_resource +
1068433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_overrun +
1069433d6423SLionel Sambuc 		fp->fxp_stat.sc_rx_cd +
1070f7df02e7SDavid van Moolenbroek 		fp->fxp_stat.sc_rx_short);
1071f7df02e7SDavid van Moolenbroek 	netdriver_stat_coll(fp->fxp_stat.sc_tx_maxcol +
1072f7df02e7SDavid van Moolenbroek 		fp->fxp_stat.sc_tx_latecol);
1073f7df02e7SDavid van Moolenbroek 	netdriver_stat_oerror(fp->fxp_stat.sc_tx_crs);
1074433d6423SLionel Sambuc }
1075433d6423SLionel Sambuc 
1076433d6423SLionel Sambuc /*===========================================================================*
1077433d6423SLionel Sambuc  *				fxp_handler				     *
1078433d6423SLionel Sambuc  *===========================================================================*/
fxp_handler(fxp_t * fp)1079433d6423SLionel Sambuc static void fxp_handler(fxp_t *fp)
1080433d6423SLionel Sambuc {
1081433d6423SLionel Sambuc 	int port;
1082433d6423SLionel Sambuc 	u16_t isr;
1083433d6423SLionel Sambuc 
1084433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1085433d6423SLionel Sambuc 
1086433d6423SLionel Sambuc 	/* Ack interrupt */
1087433d6423SLionel Sambuc 	isr= fxp_inb(port, SCB_INT_STAT);
1088433d6423SLionel Sambuc 	fxp_outb(port, SCB_INT_STAT, isr);
1089433d6423SLionel Sambuc 
1090433d6423SLionel Sambuc 	if (isr & SIS_FR)
1091433d6423SLionel Sambuc 	{
1092433d6423SLionel Sambuc 		isr &= ~SIS_FR;
1093433d6423SLionel Sambuc 
1094433d6423SLionel Sambuc 		fp->fxp_got_int= TRUE;
1095433d6423SLionel Sambuc 	}
1096433d6423SLionel Sambuc 	if (isr & SIS_CNA)
1097433d6423SLionel Sambuc 	{
1098433d6423SLionel Sambuc 		isr &= ~SIS_CNA;
1099433d6423SLionel Sambuc 		if (!fp->fxp_tx_idle)
1100433d6423SLionel Sambuc 		{
1101433d6423SLionel Sambuc 			fp->fxp_send_int= TRUE;
1102433d6423SLionel Sambuc 			fp->fxp_got_int= TRUE;
1103433d6423SLionel Sambuc 		}
1104433d6423SLionel Sambuc 	}
1105433d6423SLionel Sambuc 	if (isr & SIS_RNR)
1106433d6423SLionel Sambuc 	{
1107433d6423SLionel Sambuc 		isr &= ~SIS_RNR;
1108433d6423SLionel Sambuc 
110996e62d65SDavid van Moolenbroek 		/* Assume that receive buffer is full of packets. fxp_recv
1110433d6423SLionel Sambuc 		 * will restart the RU.
1111433d6423SLionel Sambuc 		 */
1112433d6423SLionel Sambuc 		fp->fxp_rx_need_restart= 1;
1113433d6423SLionel Sambuc 	}
1114433d6423SLionel Sambuc 	if (isr)
1115433d6423SLionel Sambuc 	{
1116433d6423SLionel Sambuc 		printf("fxp_handler: unhandled interrupt: isr = 0x%02x\n",
1117433d6423SLionel Sambuc 			isr);
1118433d6423SLionel Sambuc 	}
1119433d6423SLionel Sambuc }
1120433d6423SLionel Sambuc 
1121433d6423SLionel Sambuc /*===========================================================================*
1122433d6423SLionel Sambuc  *				fxp_check_ints				     *
1123433d6423SLionel Sambuc  *===========================================================================*/
fxp_check_ints(fxp_t * fp)1124433d6423SLionel Sambuc static void fxp_check_ints(fxp_t *fp)
1125433d6423SLionel Sambuc {
112696e62d65SDavid van Moolenbroek 	int n, prev_tail;
1127433d6423SLionel Sambuc 	int fxp_tx_tail, fxp_tx_nbuf, fxp_tx_threshold;
1128433d6423SLionel Sambuc 	port_t port;
1129433d6423SLionel Sambuc 	u32_t busaddr;
1130433d6423SLionel Sambuc 	u16_t tx_status;
1131433d6423SLionel Sambuc 	u8_t scb_status;
1132433d6423SLionel Sambuc 	struct tx *txp;
1133433d6423SLionel Sambuc 
113496e62d65SDavid van Moolenbroek 	netdriver_recv();
1135433d6423SLionel Sambuc 
1136433d6423SLionel Sambuc 	if (fp->fxp_tx_idle)
1137433d6423SLionel Sambuc 		;	/* Nothing to do */
1138433d6423SLionel Sambuc 	else if (fp->fxp_send_int)
1139433d6423SLionel Sambuc 	{
1140433d6423SLionel Sambuc 		fp->fxp_send_int= FALSE;
1141433d6423SLionel Sambuc 		fxp_tx_tail= fp->fxp_tx_tail;
1142433d6423SLionel Sambuc 		fxp_tx_nbuf= fp->fxp_tx_nbuf;
1143433d6423SLionel Sambuc 		n= 0;
1144433d6423SLionel Sambuc 		for (;;)
1145433d6423SLionel Sambuc 		{
1146433d6423SLionel Sambuc 			txp= &fp->fxp_tx_buf[fxp_tx_tail];
1147433d6423SLionel Sambuc 			tx_status= txp->tx_status;
1148433d6423SLionel Sambuc 			if (!(tx_status & TXS_C))
1149433d6423SLionel Sambuc 				break;
1150433d6423SLionel Sambuc 
1151433d6423SLionel Sambuc 			n++;
1152433d6423SLionel Sambuc 
1153433d6423SLionel Sambuc 			assert(tx_status & TXS_OK);
1154433d6423SLionel Sambuc 			if (tx_status & TXS_U)
1155433d6423SLionel Sambuc 			{
1156433d6423SLionel Sambuc 				fxp_tx_threshold= fp->fxp_tx_threshold;
1157433d6423SLionel Sambuc 				if (fxp_tx_threshold < TXTT_MAX)
1158433d6423SLionel Sambuc 				{
1159433d6423SLionel Sambuc 					fxp_tx_threshold++;
1160433d6423SLionel Sambuc 					fp->fxp_tx_threshold= fxp_tx_threshold;
1161433d6423SLionel Sambuc 				}
1162433d6423SLionel Sambuc 				printf(
1163433d6423SLionel Sambuc 			"fxp_check_ints: fxp_tx_threshold = 0x%x\n",
1164433d6423SLionel Sambuc 					fxp_tx_threshold);
1165433d6423SLionel Sambuc 			}
1166433d6423SLionel Sambuc 
1167433d6423SLionel Sambuc 			if (txp->tx_command & TXC_EL)
1168433d6423SLionel Sambuc 			{
116996e62d65SDavid van Moolenbroek 				fp->fxp_tx_idle= TRUE;
1170433d6423SLionel Sambuc 				break;
1171433d6423SLionel Sambuc 			}
1172433d6423SLionel Sambuc 
1173433d6423SLionel Sambuc 			fxp_tx_tail++;
1174433d6423SLionel Sambuc 			if (fxp_tx_tail == fxp_tx_nbuf)
1175433d6423SLionel Sambuc 				fxp_tx_tail= 0;
1176433d6423SLionel Sambuc 			assert(fxp_tx_tail < fxp_tx_nbuf);
1177433d6423SLionel Sambuc 		}
1178433d6423SLionel Sambuc 
1179433d6423SLionel Sambuc 		if (fp->fxp_need_conf)
1180433d6423SLionel Sambuc 		{
1181433d6423SLionel Sambuc 			/* Check the status of the CU */
1182433d6423SLionel Sambuc 			port= fp->fxp_base_port;
1183433d6423SLionel Sambuc 			scb_status= fxp_inb(port, SCB_STATUS);
1184433d6423SLionel Sambuc 			if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
1185433d6423SLionel Sambuc 			{
1186433d6423SLionel Sambuc 				/* Nothing to do */
1187433d6423SLionel Sambuc 				printf("scb_status = 0x%x\n", scb_status);
1188433d6423SLionel Sambuc 			}
1189433d6423SLionel Sambuc 			else
1190433d6423SLionel Sambuc 			{
1191433d6423SLionel Sambuc 				printf("fxp_check_ints: fxp_need_conf\n");
1192433d6423SLionel Sambuc 				fp->fxp_need_conf= FALSE;
1193433d6423SLionel Sambuc 				fxp_do_conf(fp);
1194433d6423SLionel Sambuc 			}
1195433d6423SLionel Sambuc 		}
1196433d6423SLionel Sambuc 
1197433d6423SLionel Sambuc 		if (n)
1198433d6423SLionel Sambuc 		{
1199433d6423SLionel Sambuc 			if (!fp->fxp_tx_idle)
1200433d6423SLionel Sambuc 			{
1201433d6423SLionel Sambuc 				fp->fxp_tx_tail= fxp_tx_tail;
1202433d6423SLionel Sambuc 
1203433d6423SLionel Sambuc 				/* Check the status of the CU */
1204433d6423SLionel Sambuc 				port= fp->fxp_base_port;
1205433d6423SLionel Sambuc 				scb_status= fxp_inb(port, SCB_STATUS);
1206433d6423SLionel Sambuc 				if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
1207433d6423SLionel Sambuc 				{
1208433d6423SLionel Sambuc 					/* Nothing to do */
1209433d6423SLionel Sambuc 					printf("scb_status = 0x%x\n",
1210433d6423SLionel Sambuc 						scb_status);
1211433d6423SLionel Sambuc 
1212433d6423SLionel Sambuc 				}
1213433d6423SLionel Sambuc 				else
1214433d6423SLionel Sambuc 				{
1215433d6423SLionel Sambuc 					if (fxp_tx_tail == 0)
1216433d6423SLionel Sambuc 						prev_tail= fxp_tx_nbuf-1;
1217433d6423SLionel Sambuc 					else
1218433d6423SLionel Sambuc 						prev_tail= fxp_tx_tail-1;
1219433d6423SLionel Sambuc 					busaddr= fp->fxp_tx_buf[prev_tail].
1220433d6423SLionel Sambuc 						tx_linkaddr;
1221433d6423SLionel Sambuc 
1222433d6423SLionel Sambuc 					fxp_cu_ptr_cmd(fp, SC_CU_START,
1223433d6423SLionel Sambuc 						busaddr, 1 /* check idle */);
1224433d6423SLionel Sambuc 				}
1225433d6423SLionel Sambuc 			}
1226433d6423SLionel Sambuc 
122796e62d65SDavid van Moolenbroek 			fp->fxp_tx_alive = TRUE;
122896e62d65SDavid van Moolenbroek 
122996e62d65SDavid van Moolenbroek 			netdriver_send();
1230433d6423SLionel Sambuc 		}
1231433d6423SLionel Sambuc 
1232433d6423SLionel Sambuc 	}
1233f7df02e7SDavid van Moolenbroek 	if (fp->fxp_report_link) {
1234f7df02e7SDavid van Moolenbroek 		netdriver_link();
1235f7df02e7SDavid van Moolenbroek 
1236433d6423SLionel Sambuc 		fxp_report_link(fp);
1237433d6423SLionel Sambuc 	}
1238f7df02e7SDavid van Moolenbroek }
1239433d6423SLionel Sambuc 
1240433d6423SLionel Sambuc /*===========================================================================*
1241f7df02e7SDavid van Moolenbroek  *				fxp_tick				     *
1242433d6423SLionel Sambuc  *===========================================================================*/
fxp_tick(void)1243f7df02e7SDavid van Moolenbroek static void fxp_tick(void)
1244433d6423SLionel Sambuc {
1245433d6423SLionel Sambuc 	fxp_t *fp;
1246433d6423SLionel Sambuc 
1247f7df02e7SDavid van Moolenbroek 	fxp_update_stats();
1248433d6423SLionel Sambuc 
1249433d6423SLionel Sambuc 	fp= fxp_state;
1250433d6423SLionel Sambuc 
1251433d6423SLionel Sambuc 	/* Check the link status. */
125296e62d65SDavid van Moolenbroek 	if (fxp_link_changed(fp)) {
1253433d6423SLionel Sambuc #if VERBOSE
1254f7df02e7SDavid van Moolenbroek 		printf("fxp_tick: link changed\n");
1255433d6423SLionel Sambuc #endif
1256433d6423SLionel Sambuc 		fp->fxp_report_link= TRUE;
125796e62d65SDavid van Moolenbroek 		fxp_check_ints(fp);
1258433d6423SLionel Sambuc 	}
1259433d6423SLionel Sambuc 
126096e62d65SDavid van Moolenbroek 	if (fp->fxp_tx_idle)
1261433d6423SLionel Sambuc 	{
1262433d6423SLionel Sambuc 		/* Assume that an idle system is alive */
1263433d6423SLionel Sambuc 		fp->fxp_tx_alive= TRUE;
1264433d6423SLionel Sambuc 		return;
1265433d6423SLionel Sambuc 	}
1266433d6423SLionel Sambuc 	if (fp->fxp_tx_alive)
1267433d6423SLionel Sambuc 	{
1268433d6423SLionel Sambuc 		fp->fxp_tx_alive= FALSE;
1269433d6423SLionel Sambuc 		return;
1270433d6423SLionel Sambuc 	}
1271433d6423SLionel Sambuc 
127296e62d65SDavid van Moolenbroek 	/* XXX this flag is never actually checked! */
1273433d6423SLionel Sambuc 	fp->fxp_need_reset= TRUE;
127496e62d65SDavid van Moolenbroek 	fxp_check_ints(fp);
1275433d6423SLionel Sambuc }
1276433d6423SLionel Sambuc 
1277433d6423SLionel Sambuc /*===========================================================================*
1278433d6423SLionel Sambuc  *				fxp_link_changed			     *
1279433d6423SLionel Sambuc  *===========================================================================*/
fxp_link_changed(fxp_t * fp)128096e62d65SDavid van Moolenbroek static int fxp_link_changed(fxp_t *fp)
1281433d6423SLionel Sambuc {
1282433d6423SLionel Sambuc 	u16_t scr;
1283433d6423SLionel Sambuc 
1284433d6423SLionel Sambuc 	scr= mii_read(fp, MII_SCR);
1285433d6423SLionel Sambuc 	scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
1286433d6423SLionel Sambuc 
1287433d6423SLionel Sambuc 	return (fp->fxp_mii_scr != scr);
1288433d6423SLionel Sambuc }
1289433d6423SLionel Sambuc 
1290433d6423SLionel Sambuc /*===========================================================================*
1291f7df02e7SDavid van Moolenbroek  *				fxp_get_link				     *
1292f7df02e7SDavid van Moolenbroek  *===========================================================================*/
fxp_get_link(uint32_t * media)1293f7df02e7SDavid van Moolenbroek static unsigned int fxp_get_link(uint32_t *media)
1294f7df02e7SDavid van Moolenbroek {
1295f7df02e7SDavid van Moolenbroek 	fxp_t *fp;
1296f7df02e7SDavid van Moolenbroek 	u16_t mii_status, scr;
1297f7df02e7SDavid van Moolenbroek 
1298f7df02e7SDavid van Moolenbroek 	fp = fxp_state;
1299f7df02e7SDavid van Moolenbroek 
1300f7df02e7SDavid van Moolenbroek 	scr= mii_read(fp, MII_SCR);
1301f7df02e7SDavid van Moolenbroek 
1302f7df02e7SDavid van Moolenbroek 	mii_read(fp, MII_STATUS); /* The status reg is latched, read twice */
1303f7df02e7SDavid van Moolenbroek 	mii_status= mii_read(fp, MII_STATUS);
1304f7df02e7SDavid van Moolenbroek 
1305f7df02e7SDavid van Moolenbroek 	if (!(mii_status & MII_STATUS_LS))
1306f7df02e7SDavid van Moolenbroek 		return NDEV_LINK_DOWN;
1307f7df02e7SDavid van Moolenbroek 
1308f7df02e7SDavid van Moolenbroek 	if (scr & MII_SCR_100)
1309f7df02e7SDavid van Moolenbroek 		*media = IFM_ETHER | IFM_100_TX;
1310f7df02e7SDavid van Moolenbroek 	else
1311f7df02e7SDavid van Moolenbroek 		*media = IFM_ETHER | IFM_10_T;
1312f7df02e7SDavid van Moolenbroek 
1313f7df02e7SDavid van Moolenbroek 	if (scr & MII_SCR_FD)
1314f7df02e7SDavid van Moolenbroek 		*media |= IFM_FDX;
1315f7df02e7SDavid van Moolenbroek 	else
1316f7df02e7SDavid van Moolenbroek 		*media |= IFM_HDX;
1317f7df02e7SDavid van Moolenbroek 
1318f7df02e7SDavid van Moolenbroek 	return NDEV_LINK_UP;
1319f7df02e7SDavid van Moolenbroek }
1320f7df02e7SDavid van Moolenbroek 
1321f7df02e7SDavid van Moolenbroek /*===========================================================================*
1322433d6423SLionel Sambuc  *				fxp_report_link				     *
1323433d6423SLionel Sambuc  *===========================================================================*/
fxp_report_link(fxp_t * fp)1324433d6423SLionel Sambuc static void fxp_report_link(fxp_t *fp)
1325433d6423SLionel Sambuc {
1326433d6423SLionel Sambuc 	u16_t mii_ctrl, mii_status, mii_id1, mii_id2,
1327433d6423SLionel Sambuc 		mii_ana, mii_anlpa, mii_ane, mii_extstat,
1328433d6423SLionel Sambuc 		mii_ms_ctrl, mii_ms_status, scr;
1329433d6423SLionel Sambuc 	u32_t oui;
1330433d6423SLionel Sambuc 	int model, rev;
1331433d6423SLionel Sambuc 	int f, link_up;
1332433d6423SLionel Sambuc 
1333433d6423SLionel Sambuc 	fp->fxp_report_link= FALSE;
1334433d6423SLionel Sambuc 
1335433d6423SLionel Sambuc 	scr= mii_read(fp, MII_SCR);
1336433d6423SLionel Sambuc 	scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
1337433d6423SLionel Sambuc 	fp->fxp_mii_scr= scr;
1338433d6423SLionel Sambuc 
1339433d6423SLionel Sambuc 	mii_ctrl= mii_read(fp, MII_CTRL);
1340433d6423SLionel Sambuc 	mii_read(fp, MII_STATUS); /* The status reg is latched, read twice */
1341433d6423SLionel Sambuc 	mii_status= mii_read(fp, MII_STATUS);
1342433d6423SLionel Sambuc 	mii_id1= mii_read(fp, MII_PHYID_H);
1343433d6423SLionel Sambuc 	mii_id2= mii_read(fp, MII_PHYID_L);
1344433d6423SLionel Sambuc 	mii_ana= mii_read(fp, MII_ANA);
1345433d6423SLionel Sambuc 	mii_anlpa= mii_read(fp, MII_ANLPA);
1346433d6423SLionel Sambuc 	mii_ane= mii_read(fp, MII_ANE);
1347433d6423SLionel Sambuc 	if (mii_status & MII_STATUS_EXT_STAT)
1348433d6423SLionel Sambuc 		mii_extstat= mii_read(fp, MII_EXT_STATUS);
1349433d6423SLionel Sambuc 	else
1350433d6423SLionel Sambuc 		mii_extstat= 0;
1351433d6423SLionel Sambuc 	if (fp->fxp_ms_regs)
1352433d6423SLionel Sambuc 	{
1353433d6423SLionel Sambuc 		mii_ms_ctrl= mii_read(fp, MII_MS_CTRL);
1354433d6423SLionel Sambuc 		mii_ms_status= mii_read(fp, MII_MS_STATUS);
1355433d6423SLionel Sambuc 	}
1356433d6423SLionel Sambuc 	else
1357433d6423SLionel Sambuc 	{
1358433d6423SLionel Sambuc 		mii_ms_ctrl= 0;
1359433d6423SLionel Sambuc 		mii_ms_status= 0;
1360433d6423SLionel Sambuc 	}
1361433d6423SLionel Sambuc 
1362433d6423SLionel Sambuc 	/* How do we know about the link status? */
1363433d6423SLionel Sambuc 	link_up= !!(mii_status & MII_STATUS_LS);
1364433d6423SLionel Sambuc 
1365433d6423SLionel Sambuc 	fp->fxp_link_up= link_up;
1366433d6423SLionel Sambuc 	if (!link_up)
1367433d6423SLionel Sambuc 	{
1368433d6423SLionel Sambuc #if VERBOSE
1369f7df02e7SDavid van Moolenbroek 		printf("%s: link down\n", netdriver_name());
1370433d6423SLionel Sambuc #endif
1371433d6423SLionel Sambuc 		return;
1372433d6423SLionel Sambuc 	}
1373433d6423SLionel Sambuc 
1374433d6423SLionel Sambuc 	oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) |
1375433d6423SLionel Sambuc 		((mii_id2 & MII_PL_OUI_L_MASK) >> MII_PL_OUI_L_SHIFT);
1376433d6423SLionel Sambuc 	model= ((mii_id2 & MII_PL_MODEL_MASK) >> MII_PL_MODEL_SHIFT);
1377433d6423SLionel Sambuc 	rev= (mii_id2 & MII_PL_REV_MASK);
1378433d6423SLionel Sambuc 
1379433d6423SLionel Sambuc #if VERBOSE
138096e62d65SDavid van Moolenbroek 	printf("OUI 0x%06x, Model 0x%02x, Revision 0x%x\n", oui, model, rev);
1381433d6423SLionel Sambuc #endif
1382433d6423SLionel Sambuc 
1383433d6423SLionel Sambuc 	if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1384433d6423SLionel Sambuc 	{
1385433d6423SLionel Sambuc 		f= 1;
1386f7df02e7SDavid van Moolenbroek #if VERBOSE
1387f7df02e7SDavid van Moolenbroek 		printf("%s: PHY: ", netdriver_name());
1388433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_LB)
1389433d6423SLionel Sambuc 		{
1390433d6423SLionel Sambuc 			printf("loopback mode");
1391433d6423SLionel Sambuc 			f= 0;
1392433d6423SLionel Sambuc 		}
1393433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_PD)
1394433d6423SLionel Sambuc 		{
1395433d6423SLionel Sambuc 			if (!f) printf(", ");
1396433d6423SLionel Sambuc 			f= 0;
1397433d6423SLionel Sambuc 			printf("powered down");
1398433d6423SLionel Sambuc 		}
1399433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_ISO)
1400433d6423SLionel Sambuc 		{
1401433d6423SLionel Sambuc 			if (!f) printf(", ");
1402433d6423SLionel Sambuc 			f= 0;
1403433d6423SLionel Sambuc 			printf("isolated");
1404433d6423SLionel Sambuc 		}
1405433d6423SLionel Sambuc 		printf("\n");
1406f7df02e7SDavid van Moolenbroek #endif
1407433d6423SLionel Sambuc 		return;
1408433d6423SLionel Sambuc 	}
1409433d6423SLionel Sambuc 	if (!(mii_ctrl & MII_CTRL_ANE))
1410433d6423SLionel Sambuc 	{
1411f7df02e7SDavid van Moolenbroek #if VERBOSE
1412f7df02e7SDavid van Moolenbroek 		printf("%s: manual config: ", netdriver_name());
1413433d6423SLionel Sambuc 		switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1414433d6423SLionel Sambuc 		{
1415433d6423SLionel Sambuc 		case MII_CTRL_SP_10:	printf("10 Mbps"); break;
1416433d6423SLionel Sambuc 		case MII_CTRL_SP_100:	printf("100 Mbps"); break;
1417433d6423SLionel Sambuc 		case MII_CTRL_SP_1000:	printf("1000 Mbps"); break;
1418433d6423SLionel Sambuc 		case MII_CTRL_SP_RES:	printf("reserved speed"); break;
1419433d6423SLionel Sambuc 		}
1420433d6423SLionel Sambuc 		if (mii_ctrl & MII_CTRL_DM)
1421433d6423SLionel Sambuc 			printf(", full duplex");
1422433d6423SLionel Sambuc 		else
1423433d6423SLionel Sambuc 			printf(", half duplex");
1424433d6423SLionel Sambuc 		printf("\n");
1425f7df02e7SDavid van Moolenbroek #endif
1426433d6423SLionel Sambuc 		return;
1427433d6423SLionel Sambuc 	}
1428433d6423SLionel Sambuc 
142996e62d65SDavid van Moolenbroek #if VERBOSE
1430f7df02e7SDavid van Moolenbroek 	printf("%s: ", netdriver_name());
1431433d6423SLionel Sambuc 	mii_print_stat_speed(mii_status, mii_extstat);
1432433d6423SLionel Sambuc 	printf("\n");
1433433d6423SLionel Sambuc 
1434433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_ANC))
1435f7df02e7SDavid van Moolenbroek 		printf("%s: auto-negotiation not complete\n",
1436f7df02e7SDavid van Moolenbroek 		    netdriver_name());
1437433d6423SLionel Sambuc 	if (mii_status & MII_STATUS_RF)
1438f7df02e7SDavid van Moolenbroek 		printf("%s: remote fault detected\n", netdriver_name());
1439433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_ANA))
1440433d6423SLionel Sambuc 	{
1441433d6423SLionel Sambuc 		printf("%s: local PHY has no auto-negotiation ability\n",
1442f7df02e7SDavid van Moolenbroek 			netdriver_name());
1443433d6423SLionel Sambuc 	}
1444433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_LS))
1445f7df02e7SDavid van Moolenbroek 		printf("%s: link down\n", netdriver_name());
1446433d6423SLionel Sambuc 	if (mii_status & MII_STATUS_JD)
1447f7df02e7SDavid van Moolenbroek 		printf("%s: jabber condition detected\n", netdriver_name());
1448433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_EC))
1449433d6423SLionel Sambuc 	{
1450f7df02e7SDavid van Moolenbroek 		printf("%s: no extended register set\n", netdriver_name());
1451433d6423SLionel Sambuc 		goto resspeed;
1452433d6423SLionel Sambuc 	}
1453433d6423SLionel Sambuc 	if (!(mii_status & MII_STATUS_ANC))
1454433d6423SLionel Sambuc 		goto resspeed;
1455433d6423SLionel Sambuc 
1456f7df02e7SDavid van Moolenbroek 	printf("%s: local cap.: ", netdriver_name());
1457433d6423SLionel Sambuc 	if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
1458433d6423SLionel Sambuc 	{
1459433d6423SLionel Sambuc 		printf("1000 Mbps: T-");
1460433d6423SLionel Sambuc 		switch(mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
1461433d6423SLionel Sambuc 		{
1462433d6423SLionel Sambuc 		case MII_MSC_1000T_FD:	printf("FD"); break;
1463433d6423SLionel Sambuc 		case MII_MSC_1000T_HD:	printf("HD"); break;
1464433d6423SLionel Sambuc 		default:		printf("FD/HD"); break;
1465433d6423SLionel Sambuc 		}
1466433d6423SLionel Sambuc 		if (mii_ana)
1467433d6423SLionel Sambuc 			printf(", ");
1468433d6423SLionel Sambuc 	}
1469433d6423SLionel Sambuc 	mii_print_techab(mii_ana);
1470433d6423SLionel Sambuc 	printf("\n");
1471433d6423SLionel Sambuc 
1472433d6423SLionel Sambuc 	if (mii_ane & MII_ANE_PDF)
1473f7df02e7SDavid van Moolenbroek 		printf("%s: parallel detection fault\n", netdriver_name());
1474433d6423SLionel Sambuc 	if (!(mii_ane & MII_ANE_LPANA))
1475433d6423SLionel Sambuc 	{
1476433d6423SLionel Sambuc 		printf("%s: link-partner does not support auto-negotiation\n",
1477f7df02e7SDavid van Moolenbroek 			netdriver_name());
1478433d6423SLionel Sambuc 		goto resspeed;
1479433d6423SLionel Sambuc 	}
1480433d6423SLionel Sambuc 
1481f7df02e7SDavid van Moolenbroek 	printf("%s: remote cap.: ", netdriver_name());
1482433d6423SLionel Sambuc 	if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
1483433d6423SLionel Sambuc 	if (mii_ms_status & (MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
1484433d6423SLionel Sambuc 	{
1485433d6423SLionel Sambuc 		printf("1000 Mbps: T-");
1486433d6423SLionel Sambuc 		switch(mii_ms_status &
1487433d6423SLionel Sambuc 			(MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
1488433d6423SLionel Sambuc 		{
1489433d6423SLionel Sambuc 		case MII_MSS_LP1000T_FD:	printf("FD"); break;
1490433d6423SLionel Sambuc 		case MII_MSS_LP1000T_HD:	printf("HD"); break;
1491433d6423SLionel Sambuc 		default:			printf("FD/HD"); break;
1492433d6423SLionel Sambuc 		}
1493433d6423SLionel Sambuc 		if (mii_anlpa)
1494433d6423SLionel Sambuc 			printf(", ");
1495433d6423SLionel Sambuc 	}
1496433d6423SLionel Sambuc 	mii_print_techab(mii_anlpa);
1497433d6423SLionel Sambuc 	printf("\n");
1498433d6423SLionel Sambuc 
1499433d6423SLionel Sambuc 	if (fp->fxp_ms_regs)
1500433d6423SLionel Sambuc 	{
1501f7df02e7SDavid van Moolenbroek 		printf("%s: ", netdriver_name());
1502433d6423SLionel Sambuc 		if (mii_ms_ctrl & MII_MSC_MS_MANUAL)
1503433d6423SLionel Sambuc 		{
1504433d6423SLionel Sambuc 			printf("manual %s",
1505433d6423SLionel Sambuc 				(mii_ms_ctrl & MII_MSC_MS_VAL) ?
1506433d6423SLionel Sambuc 				"MASTER" : "SLAVE");
1507433d6423SLionel Sambuc 		}
1508433d6423SLionel Sambuc 		else
1509433d6423SLionel Sambuc 		{
1510433d6423SLionel Sambuc 			printf("%s device",
1511433d6423SLionel Sambuc 				(mii_ms_ctrl & MII_MSC_MULTIPORT) ?
1512433d6423SLionel Sambuc 				"multiport" : "single-port");
1513433d6423SLionel Sambuc 		}
1514433d6423SLionel Sambuc 		if (mii_ms_ctrl & MII_MSC_RES)
1515433d6423SLionel Sambuc 			printf(" reserved<0x%x>", mii_ms_ctrl & MII_MSC_RES);
1516433d6423SLionel Sambuc 		printf(": ");
1517433d6423SLionel Sambuc 		if (mii_ms_status & MII_MSS_FAULT)
1518433d6423SLionel Sambuc 			printf("M/S config fault");
1519433d6423SLionel Sambuc 		else if (mii_ms_status & MII_MSS_MASTER)
1520433d6423SLionel Sambuc 			printf("MASTER");
1521433d6423SLionel Sambuc 		else
1522433d6423SLionel Sambuc 			printf("SLAVE");
1523433d6423SLionel Sambuc 		printf("\n");
1524433d6423SLionel Sambuc 	}
1525433d6423SLionel Sambuc 
1526433d6423SLionel Sambuc 	if (mii_ms_status & (MII_MSS_LP1000T_FD|MII_MSS_LP1000T_HD))
1527433d6423SLionel Sambuc 	{
1528433d6423SLionel Sambuc 		if (!(mii_ms_status & MII_MSS_LOCREC))
1529433d6423SLionel Sambuc 		{
1530433d6423SLionel Sambuc 			printf("%s: local receiver not OK\n",
1531f7df02e7SDavid van Moolenbroek 				netdriver_name());
1532433d6423SLionel Sambuc 		}
1533433d6423SLionel Sambuc 		if (!(mii_ms_status & MII_MSS_REMREC))
1534433d6423SLionel Sambuc 		{
1535433d6423SLionel Sambuc 			printf("%s: remote receiver not OK\n",
1536f7df02e7SDavid van Moolenbroek 				netdriver_name());
1537433d6423SLionel Sambuc 		}
1538433d6423SLionel Sambuc 	}
1539433d6423SLionel Sambuc 	if (mii_ms_status & (MII_MSS_RES|MII_MSS_IDLE_ERR))
1540433d6423SLionel Sambuc 	{
1541f7df02e7SDavid van Moolenbroek 		printf("%s", netdriver_name());
1542433d6423SLionel Sambuc 		if (mii_ms_status & MII_MSS_RES)
1543433d6423SLionel Sambuc 			printf(" reserved<0x%x>", mii_ms_status & MII_MSS_RES);
1544433d6423SLionel Sambuc 		if (mii_ms_status & MII_MSS_IDLE_ERR)
1545433d6423SLionel Sambuc 		{
1546433d6423SLionel Sambuc 			printf(" idle error %d",
1547433d6423SLionel Sambuc 				mii_ms_status & MII_MSS_IDLE_ERR);
1548433d6423SLionel Sambuc 		}
1549433d6423SLionel Sambuc 		printf("\n");
1550433d6423SLionel Sambuc 	}
1551433d6423SLionel Sambuc resspeed:
155296e62d65SDavid van Moolenbroek #endif
155396e62d65SDavid van Moolenbroek 
1554433d6423SLionel Sambuc #if VERBOSE
1555433d6423SLionel Sambuc 	printf("%s: link up, %d Mbps, %s duplex\n",
1556f7df02e7SDavid van Moolenbroek 		netdriver_name(), (scr & MII_SCR_100) ? 100 : 10,
1557433d6423SLionel Sambuc 		(scr & MII_SCR_FD) ? "full" : "half");
1558433d6423SLionel Sambuc #endif
1559433d6423SLionel Sambuc }
1560433d6423SLionel Sambuc 
1561433d6423SLionel Sambuc /*===========================================================================*
1562433d6423SLionel Sambuc  *				eeprom_read				     *
1563433d6423SLionel Sambuc  *===========================================================================*/
eeprom_read(fxp_t * fp,int reg)156496e62d65SDavid van Moolenbroek static u16_t eeprom_read(fxp_t *fp, int reg)
1565433d6423SLionel Sambuc {
1566433d6423SLionel Sambuc 	port_t port;
1567433d6423SLionel Sambuc 	u16_t v;
1568433d6423SLionel Sambuc 	int b, i, alen;
1569433d6423SLionel Sambuc 
1570433d6423SLionel Sambuc 	alen= fp->fxp_ee_addrlen;
1571433d6423SLionel Sambuc 	if (!alen)
1572433d6423SLionel Sambuc 	{
1573433d6423SLionel Sambuc 		eeprom_addrsize(fp);
1574433d6423SLionel Sambuc 		alen= fp->fxp_ee_addrlen;
1575433d6423SLionel Sambuc 		assert(alen == 6 || alen == 8);
1576433d6423SLionel Sambuc 	}
1577433d6423SLionel Sambuc 
1578433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1579433d6423SLionel Sambuc 
1580433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, CE_EECS);	/* Enable EEPROM */
1581433d6423SLionel Sambuc 	v= EEPROM_READ_PREFIX;
1582433d6423SLionel Sambuc 	for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
1583433d6423SLionel Sambuc 	{
1584433d6423SLionel Sambuc 		b= ((v & (1 << i)) ? CE_EEDI : 0);
1585433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
1586433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
1587433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1588433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
1589433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1590433d6423SLionel Sambuc 	}
1591433d6423SLionel Sambuc 
1592433d6423SLionel Sambuc 	v= reg;
1593433d6423SLionel Sambuc 	for (i= alen-1; i >= 0; i--)
1594433d6423SLionel Sambuc 	{
1595433d6423SLionel Sambuc 		b= ((v & (1 << i)) ? CE_EEDI : 0);
1596433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
1597433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
1598433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1599433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
1600433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1601433d6423SLionel Sambuc 	}
1602433d6423SLionel Sambuc 
1603433d6423SLionel Sambuc 	v= 0;
1604433d6423SLionel Sambuc 	for (i= 0; i<16; i++)
1605433d6423SLionel Sambuc 	{
1606433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
1607433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1608433d6423SLionel Sambuc 		b= !!(fxp_inb(port, CSR_EEPROM) & CE_EEDO);
1609433d6423SLionel Sambuc 		v= (v << 1) | b;
1610433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS );
1611433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1612433d6423SLionel Sambuc 	}
1613433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, 0);	/* Disable EEPROM */
1614433d6423SLionel Sambuc 	micro_delay(EECS_DELAY);
1615433d6423SLionel Sambuc 
1616433d6423SLionel Sambuc 	return v;
1617433d6423SLionel Sambuc }
1618433d6423SLionel Sambuc 
1619433d6423SLionel Sambuc /*===========================================================================*
1620433d6423SLionel Sambuc  *				eeprom_addrsize				     *
1621433d6423SLionel Sambuc  *===========================================================================*/
eeprom_addrsize(fxp_t * fp)162296e62d65SDavid van Moolenbroek static void eeprom_addrsize(fxp_t *fp)
1623433d6423SLionel Sambuc {
1624433d6423SLionel Sambuc 	port_t port;
1625433d6423SLionel Sambuc 	u16_t v;
1626433d6423SLionel Sambuc 	int b, i;
1627433d6423SLionel Sambuc 
1628433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1629433d6423SLionel Sambuc 
1630433d6423SLionel Sambuc 	/* Try to find out the size of the EEPROM */
1631433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, CE_EECS);	/* Enable EEPROM */
1632433d6423SLionel Sambuc 	v= EEPROM_READ_PREFIX;
1633433d6423SLionel Sambuc 	for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
1634433d6423SLionel Sambuc 	{
1635433d6423SLionel Sambuc 		b= ((v & (1 << i)) ? CE_EEDI : 0);
1636433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
1637433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
1638433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1639433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
1640433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1641433d6423SLionel Sambuc 	}
1642433d6423SLionel Sambuc 
1643433d6423SLionel Sambuc 	for (i= 0; i<32; i++)
1644433d6423SLionel Sambuc 	{
1645433d6423SLionel Sambuc 		b= 0;
1646433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);	/* bit */
1647433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
1648433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1649433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | b);
1650433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1651433d6423SLionel Sambuc 		v= fxp_inb(port, CSR_EEPROM);
1652433d6423SLionel Sambuc 		if (!(v & CE_EEDO))
1653433d6423SLionel Sambuc 			break;
1654433d6423SLionel Sambuc 	}
1655433d6423SLionel Sambuc 	if (i >= 32)
1656433d6423SLionel Sambuc 		panic("eeprom_addrsize: failed");
1657433d6423SLionel Sambuc 	fp->fxp_ee_addrlen= i+1;
1658433d6423SLionel Sambuc 
1659433d6423SLionel Sambuc 	/* Discard 16 data bits */
1660433d6423SLionel Sambuc 	for (i= 0; i<16; i++)
1661433d6423SLionel Sambuc 	{
1662433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
1663433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1664433d6423SLionel Sambuc 		fxp_outb(port, CSR_EEPROM, CE_EECS );
1665433d6423SLionel Sambuc 		micro_delay(EESK_PERIOD/2+1);
1666433d6423SLionel Sambuc 	}
1667433d6423SLionel Sambuc 	fxp_outb(port, CSR_EEPROM, 0);	/* Disable EEPROM */
1668433d6423SLionel Sambuc 	micro_delay(EECS_DELAY);
1669433d6423SLionel Sambuc 
1670433d6423SLionel Sambuc #if VERBOSE
1671433d6423SLionel Sambuc 	printf("%s EEPROM address length: %d\n",
1672f7df02e7SDavid van Moolenbroek 		netdriver_name(), fp->fxp_ee_addrlen);
1673433d6423SLionel Sambuc #endif
1674433d6423SLionel Sambuc }
1675433d6423SLionel Sambuc 
1676433d6423SLionel Sambuc /*===========================================================================*
1677433d6423SLionel Sambuc  *				mii_read				     *
1678433d6423SLionel Sambuc  *===========================================================================*/
mii_read(fxp_t * fp,int reg)167996e62d65SDavid van Moolenbroek static u16_t mii_read(fxp_t *fp, int reg)
1680433d6423SLionel Sambuc {
1681433d6423SLionel Sambuc 	spin_t spin;
1682433d6423SLionel Sambuc 	port_t port;
1683433d6423SLionel Sambuc 	u32_t v;
1684433d6423SLionel Sambuc 
1685433d6423SLionel Sambuc 	port= fp->fxp_base_port;
1686433d6423SLionel Sambuc 
1687433d6423SLionel Sambuc 	if (!(fxp_inl(port, CSR_MDI_CTL) & CM_READY))
1688433d6423SLionel Sambuc 		panic("mii_read: MDI not ready");
1689433d6423SLionel Sambuc 	fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) |
1690433d6423SLionel Sambuc 		(reg << CM_REG_SHIFT));
1691433d6423SLionel Sambuc 
1692433d6423SLionel Sambuc 	spin_init(&spin, 100000);
1693433d6423SLionel Sambuc 	do {
1694433d6423SLionel Sambuc 		v= fxp_inl(port, CSR_MDI_CTL);
1695433d6423SLionel Sambuc 		if (v & CM_READY)
1696433d6423SLionel Sambuc 			break;
1697433d6423SLionel Sambuc 	} while (spin_check(&spin));
1698433d6423SLionel Sambuc 
1699433d6423SLionel Sambuc 	if (!(v & CM_READY))
1700433d6423SLionel Sambuc 		panic("mii_read: MDI not ready after command");
1701433d6423SLionel Sambuc 
1702433d6423SLionel Sambuc 	return v & CM_DATA_MASK;
1703433d6423SLionel Sambuc }
1704433d6423SLionel Sambuc 
do_inb(port_t port)1705433d6423SLionel Sambuc static u8_t do_inb(port_t port)
1706433d6423SLionel Sambuc {
1707433d6423SLionel Sambuc 	int r;
1708433d6423SLionel Sambuc 	u32_t value;
1709433d6423SLionel Sambuc 
1710433d6423SLionel Sambuc 	r= sys_inb(port, &value);
1711433d6423SLionel Sambuc 	if (r != OK)
1712433d6423SLionel Sambuc 		panic("sys_inb failed: %d", r);
1713433d6423SLionel Sambuc 	return value;
1714433d6423SLionel Sambuc }
1715433d6423SLionel Sambuc 
do_inl(port_t port)1716433d6423SLionel Sambuc static u32_t do_inl(port_t port)
1717433d6423SLionel Sambuc {
1718433d6423SLionel Sambuc 	int r;
1719433d6423SLionel Sambuc 	u32_t value;
1720433d6423SLionel Sambuc 
1721433d6423SLionel Sambuc 	r= sys_inl(port, &value);
1722433d6423SLionel Sambuc 	if (r != OK)
1723433d6423SLionel Sambuc 		panic("sys_inl failed: %d", r);
1724433d6423SLionel Sambuc 	return value;
1725433d6423SLionel Sambuc }
1726433d6423SLionel Sambuc 
do_outb(port_t port,u8_t value)1727433d6423SLionel Sambuc static void do_outb(port_t port, u8_t value)
1728433d6423SLionel Sambuc {
1729433d6423SLionel Sambuc 	int r;
1730433d6423SLionel Sambuc 
1731433d6423SLionel Sambuc 	r= sys_outb(port, value);
1732433d6423SLionel Sambuc 	if (r != OK)
1733433d6423SLionel Sambuc 		panic("sys_outb failed: %d", r);
1734433d6423SLionel Sambuc }
1735433d6423SLionel Sambuc 
do_outl(port_t port,u32_t value)1736433d6423SLionel Sambuc static void do_outl(port_t port, u32_t value)
1737433d6423SLionel Sambuc {
1738433d6423SLionel Sambuc 	int r;
1739433d6423SLionel Sambuc 
1740433d6423SLionel Sambuc 	r= sys_outl(port, value);
1741433d6423SLionel Sambuc 	if (r != OK)
1742433d6423SLionel Sambuc 		panic("sys_outl failed: %d", r);
1743433d6423SLionel Sambuc }
1744433d6423SLionel Sambuc 
174596e62d65SDavid van Moolenbroek /* TODO: obviously this needs a lot of work. */
tell_iommu(vir_bytes buf,size_t size,int pci_bus,int pci_dev,int pci_func)174696e62d65SDavid van Moolenbroek static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev,
174796e62d65SDavid van Moolenbroek 	int pci_func)
1748433d6423SLionel Sambuc {
1749433d6423SLionel Sambuc 	int r;
1750433d6423SLionel Sambuc 	endpoint_t dev_e;
1751433d6423SLionel Sambuc 	message m;
1752433d6423SLionel Sambuc 
1753433d6423SLionel Sambuc 	r= ds_retrieve_label_endpt("amddev", &dev_e);
1754433d6423SLionel Sambuc 	if (r != OK)
1755433d6423SLionel Sambuc 	{
1756433d6423SLionel Sambuc #if 0
175796e62d65SDavid van Moolenbroek 		printf("fxp`tell_iommu: ds_retrieve_label_endpt failed "
175896e62d65SDavid van Moolenbroek 		    "for 'amddev': %d\n", r);
1759433d6423SLionel Sambuc #endif
1760433d6423SLionel Sambuc 		return;
1761433d6423SLionel Sambuc 	}
1762433d6423SLionel Sambuc 
1763433d6423SLionel Sambuc 	m.m_type= IOMMU_MAP;
1764433d6423SLionel Sambuc 	m.m2_i1= pci_bus;
1765433d6423SLionel Sambuc 	m.m2_i2= pci_dev;
1766433d6423SLionel Sambuc 	m.m2_i3= pci_func;
1767433d6423SLionel Sambuc 	m.m2_l1= buf;
1768433d6423SLionel Sambuc 	m.m2_l2= size;
1769433d6423SLionel Sambuc 
1770433d6423SLionel Sambuc 	r= ipc_sendrec(dev_e, &m);
1771433d6423SLionel Sambuc 	if (r != OK)
1772433d6423SLionel Sambuc 	{
177396e62d65SDavid van Moolenbroek 		printf("fxp`tell_iommu: ipc_sendrec to %d failed: %d\n",
1774433d6423SLionel Sambuc 			dev_e, r);
1775433d6423SLionel Sambuc 		return;
1776433d6423SLionel Sambuc 	}
1777433d6423SLionel Sambuc 	if (m.m_type != OK)
1778433d6423SLionel Sambuc 	{
177996e62d65SDavid van Moolenbroek 		printf("fxp`tell_iommu: dma map request failed: %d\n",
1780433d6423SLionel Sambuc 			m.m_type);
1781433d6423SLionel Sambuc 		return;
1782433d6423SLionel Sambuc 	}
1783433d6423SLionel Sambuc }
1784433d6423SLionel Sambuc 
1785433d6423SLionel Sambuc /*
1786433d6423SLionel Sambuc  * $PchId: fxp.c,v 1.4 2005/01/31 22:10:37 philip Exp $
1787433d6423SLionel Sambuc  */
1788