xref: /minix3/minix/drivers/net/e1000/e1000.c (revision 107df7c8fabf2d51ba8e0606ed44abc6d487523f)
1*107df7c8SDavid van Moolenbroek /* A device driver for Intel Pro/1000 Gigabit Ethernet Controllers. */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include <minix/drivers.h>
4433d6423SLionel Sambuc #include <minix/netdriver.h>
5433d6423SLionel Sambuc #include <stdlib.h>
6433d6423SLionel Sambuc #include <net/gen/ether.h>
7433d6423SLionel Sambuc #include <net/gen/eth_io.h>
8433d6423SLionel Sambuc #include <machine/pci.h>
9433d6423SLionel Sambuc #include <minix/ds.h>
10433d6423SLionel Sambuc #include <minix/vm.h>
11433d6423SLionel Sambuc #include <minix/timers.h>
12433d6423SLionel Sambuc #include <sys/mman.h>
13433d6423SLionel Sambuc #include "assert.h"
14433d6423SLionel Sambuc #include "e1000.h"
15433d6423SLionel Sambuc #include "e1000_hw.h"
16433d6423SLionel Sambuc #include "e1000_reg.h"
17433d6423SLionel Sambuc #include "e1000_pci.h"
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc static int e1000_instance;
20433d6423SLionel Sambuc static e1000_t e1000_state;
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc static void e1000_init(message *mp);
23433d6423SLionel Sambuc static void e1000_init_pci(void);
24433d6423SLionel Sambuc static int e1000_probe(e1000_t *e, int skip);
25433d6423SLionel Sambuc static int e1000_init_hw(e1000_t *e);
26433d6423SLionel Sambuc static void e1000_init_addr(e1000_t *e);
27433d6423SLionel Sambuc static void e1000_init_buf(e1000_t *e);
28433d6423SLionel Sambuc static void e1000_reset_hw(e1000_t *e);
29433d6423SLionel Sambuc static void e1000_writev_s(message *mp, int from_int);
30433d6423SLionel Sambuc static void e1000_readv_s(message *mp, int from_int);
31433d6423SLionel Sambuc static void e1000_getstat_s(message *mp);
32433d6423SLionel Sambuc static void e1000_interrupt(message *mp);
33433d6423SLionel Sambuc static int e1000_link_changed(e1000_t *e);
34433d6423SLionel Sambuc static void e1000_stop(e1000_t *e);
35433d6423SLionel Sambuc static uint32_t e1000_reg_read(e1000_t *e, uint32_t reg);
36433d6423SLionel Sambuc static void e1000_reg_write(e1000_t *e, uint32_t reg, uint32_t value);
37433d6423SLionel Sambuc static void e1000_reg_set(e1000_t *e, uint32_t reg, uint32_t value);
38433d6423SLionel Sambuc static void e1000_reg_unset(e1000_t *e, uint32_t reg, uint32_t value);
39433d6423SLionel Sambuc static u16_t eeprom_eerd(void *e, int reg);
40433d6423SLionel Sambuc static u16_t eeprom_ich(void *e, int reg);
41433d6423SLionel Sambuc static int eeprom_ich_init(e1000_t *e);
42*107df7c8SDavid van Moolenbroek static int eeprom_ich_cycle(e1000_t *e, u32_t timeout);
43433d6423SLionel Sambuc static void reply(e1000_t *e);
44433d6423SLionel Sambuc static void mess_reply(message *req, message *reply);
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc /* SEF functions and variables. */
47433d6423SLionel Sambuc static void sef_local_startup(void);
48433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info);
49433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo);
50433d6423SLionel Sambuc 
51*107df7c8SDavid van Moolenbroek /*
52*107df7c8SDavid van Moolenbroek  * The e1000 driver.
53*107df7c8SDavid van Moolenbroek  */
54*107df7c8SDavid van Moolenbroek int
55*107df7c8SDavid van Moolenbroek main(int argc, char * argv[])
56433d6423SLionel Sambuc {
57433d6423SLionel Sambuc 	message m;
58433d6423SLionel Sambuc 	int ipc_status;
59433d6423SLionel Sambuc 	int r;
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc 	/* SEF local startup. */
62433d6423SLionel Sambuc 	env_setargs(argc, argv);
63433d6423SLionel Sambuc 	sef_local_startup();
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc 	/*
66433d6423SLionel Sambuc 	 * Enter the main driver loop.
67433d6423SLionel Sambuc 	 */
68*107df7c8SDavid van Moolenbroek 	while (TRUE) {
69433d6423SLionel Sambuc 		if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK)
70433d6423SLionel Sambuc 			panic("netdriver_receive failed: %d", r);
71433d6423SLionel Sambuc 
72*107df7c8SDavid van Moolenbroek 		if (is_ipc_notify(ipc_status)) {
73*107df7c8SDavid van Moolenbroek 			switch (_ENDPOINT_P(m.m_source)) {
74433d6423SLionel Sambuc 			case HARDWARE:
75433d6423SLionel Sambuc 				e1000_interrupt(&m);
76433d6423SLionel Sambuc 				break;
77433d6423SLionel Sambuc 			}
78*107df7c8SDavid van Moolenbroek 
79433d6423SLionel Sambuc 			continue;
80433d6423SLionel Sambuc 		}
81*107df7c8SDavid van Moolenbroek 
82*107df7c8SDavid van Moolenbroek 		switch (m.m_type) {
83433d6423SLionel Sambuc 		case DL_WRITEV_S:	e1000_writev_s(&m, FALSE);	break;
84433d6423SLionel Sambuc 		case DL_READV_S:	e1000_readv_s(&m, FALSE);	break;
85433d6423SLionel Sambuc 		case DL_CONF:		e1000_init(&m);			break;
86433d6423SLionel Sambuc 		case DL_GETSTAT_S:	e1000_getstat_s(&m);		break;
87*107df7c8SDavid van Moolenbroek 		default:		panic("illegal message: %d", m.m_type);
88433d6423SLionel Sambuc 		}
89433d6423SLionel Sambuc 	}
90433d6423SLionel Sambuc }
91433d6423SLionel Sambuc 
92*107df7c8SDavid van Moolenbroek /*
93*107df7c8SDavid van Moolenbroek  * Perform SEF initialization.
94*107df7c8SDavid van Moolenbroek  */
95*107df7c8SDavid van Moolenbroek static void
96*107df7c8SDavid van Moolenbroek sef_local_startup(void)
97433d6423SLionel Sambuc {
98*107df7c8SDavid van Moolenbroek 
99433d6423SLionel Sambuc 	/* Register init callbacks. */
100433d6423SLionel Sambuc 	sef_setcb_init_fresh(sef_cb_init_fresh);
101433d6423SLionel Sambuc 	sef_setcb_init_lu(sef_cb_init_fresh);
102433d6423SLionel Sambuc 	sef_setcb_init_restart(sef_cb_init_fresh);
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc 	/* Register live update callbacks. */
105433d6423SLionel Sambuc 	sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
106433d6423SLionel Sambuc 	sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 	/* Register signal callbacks. */
109433d6423SLionel Sambuc 	sef_setcb_signal_handler(sef_cb_signal_handler);
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc 	/* Let SEF perform startup. */
112433d6423SLionel Sambuc 	sef_startup();
113433d6423SLionel Sambuc }
114433d6423SLionel Sambuc 
115*107df7c8SDavid van Moolenbroek /*
116*107df7c8SDavid van Moolenbroek  * Initialize the e1000 driver.
117*107df7c8SDavid van Moolenbroek  */
118*107df7c8SDavid van Moolenbroek static int
119*107df7c8SDavid van Moolenbroek sef_cb_init_fresh(int __unused type, sef_init_info_t * __unused info)
120433d6423SLionel Sambuc {
121433d6423SLionel Sambuc 	long v;
122433d6423SLionel Sambuc 	int r;
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 	v = 0;
125433d6423SLionel Sambuc 	(void)env_parse("instance", "d", 0, &v, 0, 255);
126433d6423SLionel Sambuc 	e1000_instance = (int) v;
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 	/* Clear state. */
129433d6423SLionel Sambuc 	memset(&e1000_state, 0, sizeof(e1000_state));
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 	/* Perform calibration. */
132433d6423SLionel Sambuc 	if ((r = tsc_calibrate()) != OK)
133433d6423SLionel Sambuc 		panic("tsc_calibrate failed: %d", r);
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc 	/* Announce we are up! */
136433d6423SLionel Sambuc 	netdriver_announce();
137433d6423SLionel Sambuc 
138*107df7c8SDavid van Moolenbroek 	return OK;
139433d6423SLionel Sambuc }
140433d6423SLionel Sambuc 
141*107df7c8SDavid van Moolenbroek /*
142*107df7c8SDavid van Moolenbroek  * Process a signal.
143*107df7c8SDavid van Moolenbroek  */
144*107df7c8SDavid van Moolenbroek static void
145*107df7c8SDavid van Moolenbroek sef_cb_signal_handler(int signo)
146433d6423SLionel Sambuc {
147433d6423SLionel Sambuc 	e1000_t *e;
148*107df7c8SDavid van Moolenbroek 
149433d6423SLionel Sambuc 	e = &e1000_state;
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc 	E1000_DEBUG(3, ("%s: got signal\n", e->name));
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc 	/* Only check for termination signal, ignore anything else. */
154433d6423SLionel Sambuc 	if (signo != SIGTERM) return;
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc 	e1000_stop(e);
157433d6423SLionel Sambuc }
158433d6423SLionel Sambuc 
159*107df7c8SDavid van Moolenbroek /*
160*107df7c8SDavid van Moolenbroek  * Process a configuration message from Inet.
161*107df7c8SDavid van Moolenbroek  */
162*107df7c8SDavid van Moolenbroek static void
163*107df7c8SDavid van Moolenbroek e1000_init(message * mp)
164433d6423SLionel Sambuc {
165433d6423SLionel Sambuc 	static int first_time = 1;
166433d6423SLionel Sambuc 	message reply_mess;
167433d6423SLionel Sambuc 	e1000_t *e;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000: init()\n"));
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc 	/* Configure PCI devices, if needed. */
172*107df7c8SDavid van Moolenbroek 	if (first_time) {
173433d6423SLionel Sambuc 		first_time = 0;
174433d6423SLionel Sambuc 		e1000_init_pci();
175433d6423SLionel Sambuc 	}
176*107df7c8SDavid van Moolenbroek 
177433d6423SLionel Sambuc 	e = &e1000_state;
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc 	/* Initialize hardware, if needed. */
180*107df7c8SDavid van Moolenbroek 	if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e))) {
181433d6423SLionel Sambuc 		reply_mess.m_type = DL_CONF_REPLY;
182433d6423SLionel Sambuc 		reply_mess.m_netdrv_net_dl_conf.stat = ENXIO;
183433d6423SLionel Sambuc 		mess_reply(mp, &reply_mess);
184433d6423SLionel Sambuc 		return;
185433d6423SLionel Sambuc 	}
186*107df7c8SDavid van Moolenbroek 
187433d6423SLionel Sambuc 	/* Reply back to INET. */
188433d6423SLionel Sambuc 	reply_mess.m_type = DL_CONF_REPLY;
189433d6423SLionel Sambuc 	reply_mess.m_netdrv_net_dl_conf.stat = OK;
190433d6423SLionel Sambuc 	memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, e->address.ea_addr,
191433d6423SLionel Sambuc 	    sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr));
192433d6423SLionel Sambuc 	mess_reply(mp, &reply_mess);
193433d6423SLionel Sambuc }
194433d6423SLionel Sambuc 
195*107df7c8SDavid van Moolenbroek /*
196*107df7c8SDavid van Moolenbroek  * Find a matching PCI device.
197*107df7c8SDavid van Moolenbroek  */
198*107df7c8SDavid van Moolenbroek static void
199*107df7c8SDavid van Moolenbroek e1000_init_pci(void)
200433d6423SLionel Sambuc {
201433d6423SLionel Sambuc 	e1000_t *e;
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc 	/* Initialize the PCI bus. */
204433d6423SLionel Sambuc 	pci_init();
205433d6423SLionel Sambuc 
206*107df7c8SDavid van Moolenbroek 	/* Try to detect e1000 cards. */
207433d6423SLionel Sambuc 	e = &e1000_state;
208433d6423SLionel Sambuc 	strlcpy(e->name, "e1000#0", sizeof(e->name));
209433d6423SLionel Sambuc 	e->name[6] += e1000_instance;
210*107df7c8SDavid van Moolenbroek 
211433d6423SLionel Sambuc 	e1000_probe(e, e1000_instance);
212433d6423SLionel Sambuc }
213433d6423SLionel Sambuc 
214*107df7c8SDavid van Moolenbroek /*
215*107df7c8SDavid van Moolenbroek  * Find a matching device.  Return TRUE on success.
216*107df7c8SDavid van Moolenbroek  */
217*107df7c8SDavid van Moolenbroek static int
218*107df7c8SDavid van Moolenbroek e1000_probe(e1000_t * e, int skip)
219433d6423SLionel Sambuc {
220433d6423SLionel Sambuc 	int r, devind, ioflag;
221433d6423SLionel Sambuc 	u16_t vid, did, cr;
222433d6423SLionel Sambuc 	u32_t status[2];
223433d6423SLionel Sambuc 	u32_t base, size;
224*107df7c8SDavid van Moolenbroek 	size_t flash_size;
225433d6423SLionel Sambuc 	u32_t gfpreg, sector_base_addr;
226433d6423SLionel Sambuc 	char *dname;
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc 	E1000_DEBUG(3, ("%s: probe()\n", e->name));
229433d6423SLionel Sambuc 
230*107df7c8SDavid van Moolenbroek 	/* Attempt to iterate the PCI bus. Start at the beginning. */
231433d6423SLionel Sambuc 	if ((r = pci_first_dev(&devind, &vid, &did)) == 0)
232433d6423SLionel Sambuc 		return FALSE;
233*107df7c8SDavid van Moolenbroek 
234433d6423SLionel Sambuc 	/* Loop devices on the PCI bus. */
235*107df7c8SDavid van Moolenbroek 	while (skip--) {
236433d6423SLionel Sambuc 		E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n",
237433d6423SLionel Sambuc 		    e->name, devind, vid, did));
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc 		if (!(r = pci_next_dev(&devind, &vid, &did)))
240433d6423SLionel Sambuc 			return FALSE;
241433d6423SLionel Sambuc 	}
242*107df7c8SDavid van Moolenbroek 
243*107df7c8SDavid van Moolenbroek 	/* We found a matching card.  Set card-specific properties. */
244433d6423SLionel Sambuc 	e->status |= E1000_DETECTED;
245433d6423SLionel Sambuc 	e->eeprom_read = eeprom_eerd;
246433d6423SLionel Sambuc 
247*107df7c8SDavid van Moolenbroek 	switch (did) {
248433d6423SLionel Sambuc 	case E1000_DEV_ID_ICH10_D_BM_LM:
249433d6423SLionel Sambuc 	case E1000_DEV_ID_ICH10_R_BM_LF:
250433d6423SLionel Sambuc 		e->eeprom_read = eeprom_ich;
251433d6423SLionel Sambuc 		break;
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc 	case E1000_DEV_ID_82540EM:
254433d6423SLionel Sambuc 	case E1000_DEV_ID_82545EM:
255433d6423SLionel Sambuc 		e->eeprom_done_bit = (1 << 4);
256433d6423SLionel Sambuc 		e->eeprom_addr_off = 8;
257433d6423SLionel Sambuc 		break;
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 	default:
260433d6423SLionel Sambuc 		e->eeprom_done_bit = (1 << 1);
261433d6423SLionel Sambuc 		e->eeprom_addr_off = 2;
262433d6423SLionel Sambuc 		break;
263433d6423SLionel Sambuc 	}
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 	/* Inform the user about the new card. */
266433d6423SLionel Sambuc 	if (!(dname = pci_dev_name(vid, did)))
267433d6423SLionel Sambuc 		dname = "Intel Pro/1000 Gigabit Ethernet Card";
268433d6423SLionel Sambuc 	E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n",
269*107df7c8SDavid van Moolenbroek 	    e->name, dname, vid, did, e->revision, pci_slot_name(devind)));
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 	/* Reserve PCI resources found. */
272433d6423SLionel Sambuc 	if ((r = pci_reserve_ok(devind)) != OK)
273433d6423SLionel Sambuc 		panic("failed to reserve PCI device: %d", r);
274*107df7c8SDavid van Moolenbroek 
275433d6423SLionel Sambuc 	/* Read PCI configuration. */
276433d6423SLionel Sambuc 	e->irq = pci_attr_r8(devind, PCI_ILR);
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc 	if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK)
279*107df7c8SDavid van Moolenbroek 		panic("failed to get PCI BAR: %d", r);
280*107df7c8SDavid van Moolenbroek 	if (ioflag)
281*107df7c8SDavid van Moolenbroek 		panic("PCI BAR is not for memory");
282433d6423SLionel Sambuc 
283*107df7c8SDavid van Moolenbroek 	if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED)
284433d6423SLionel Sambuc 		panic("failed to map hardware registers from PCI");
285433d6423SLionel Sambuc 
286*107df7c8SDavid van Moolenbroek 	/* Enable DMA bus mastering if necessary. */
287433d6423SLionel Sambuc 	cr = pci_attr_r16(devind, PCI_CR);
288433d6423SLionel Sambuc 	if (!(cr & PCI_CR_MAST_EN))
289433d6423SLionel Sambuc 		pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc 	/* Optionally map flash memory. */
292*107df7c8SDavid van Moolenbroek 	if (did != E1000_DEV_ID_82540EM && did != E1000_DEV_ID_82545EM &&
293*107df7c8SDavid van Moolenbroek 	    did != E1000_DEV_ID_82540EP && pci_attr_r32(devind, PCI_BAR_2)) {
294*107df7c8SDavid van Moolenbroek 		/*
295*107df7c8SDavid van Moolenbroek 		 * 82566/82567/82562V series support mapping 4kB of flash
296*107df7c8SDavid van Moolenbroek 		 * memory.
297*107df7c8SDavid van Moolenbroek 		 */
298*107df7c8SDavid van Moolenbroek 		switch (did) {
299433d6423SLionel Sambuc 		case E1000_DEV_ID_ICH10_D_BM_LM:
300433d6423SLionel Sambuc 		case E1000_DEV_ID_ICH10_R_BM_LF:
301433d6423SLionel Sambuc 			flash_size = 0x1000;
302433d6423SLionel Sambuc 			break;
303433d6423SLionel Sambuc 		default:
304433d6423SLionel Sambuc 			flash_size = 0x10000;
305433d6423SLionel Sambuc 		}
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc 		if ((e->flash = vm_map_phys(SELF,
308433d6423SLionel Sambuc 		    (void *)pci_attr_r32(devind, PCI_BAR_2),
309*107df7c8SDavid van Moolenbroek 		    flash_size)) == MAP_FAILED)
310*107df7c8SDavid van Moolenbroek 			panic("e1000: couldn't map in flash");
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc 		/*
313433d6423SLionel Sambuc 		 * sector_base_addr is a "sector"-aligned address (4096 bytes)
314433d6423SLionel Sambuc 		 */
315*107df7c8SDavid van Moolenbroek 		gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG);
316433d6423SLionel Sambuc 		sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc 		/* flash_base_addr is byte-aligned */
319*107df7c8SDavid van Moolenbroek 		e->flash_base_addr =
320*107df7c8SDavid van Moolenbroek 		    sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
321433d6423SLionel Sambuc 	}
322*107df7c8SDavid van Moolenbroek 
323*107df7c8SDavid van Moolenbroek 	/* Output debug information. */
324433d6423SLionel Sambuc 	status[0] = e1000_reg_read(e, E1000_REG_STATUS);
325*107df7c8SDavid van Moolenbroek 	E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq));
326*107df7c8SDavid van Moolenbroek 	E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name,
327*107df7c8SDavid van Moolenbroek 	    status[0] & 3 ? "up"   : "down", status[0] & 1 ? "full" : "half"));
328*107df7c8SDavid van Moolenbroek 
329433d6423SLionel Sambuc 	return TRUE;
330433d6423SLionel Sambuc }
331433d6423SLionel Sambuc 
332*107df7c8SDavid van Moolenbroek /*
333*107df7c8SDavid van Moolenbroek  * Initialize the hardware.
334*107df7c8SDavid van Moolenbroek  */
335*107df7c8SDavid van Moolenbroek static int
336*107df7c8SDavid van Moolenbroek e1000_init_hw(e1000_t * e)
337433d6423SLionel Sambuc {
338433d6423SLionel Sambuc 	int r, i;
339433d6423SLionel Sambuc 
340433d6423SLionel Sambuc 	e->status |= E1000_ENABLED;
341433d6423SLionel Sambuc 	e->irq_hook = e->irq;
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc 	/*
344433d6423SLionel Sambuc 	 * Set the interrupt handler and policy.  Do not automatically
345*107df7c8SDavid van Moolenbroek 	 * reenable interrupts.  Return the IRQ line number on interrupts.
346433d6423SLionel Sambuc 	 */
347433d6423SLionel Sambuc 	if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK)
348433d6423SLionel Sambuc 		panic("sys_irqsetpolicy failed: %d", r);
349433d6423SLionel Sambuc 	if ((r = sys_irqenable(&e->irq_hook)) != OK)
350433d6423SLionel Sambuc 		panic("sys_irqenable failed: %d", r);
351*107df7c8SDavid van Moolenbroek 
352433d6423SLionel Sambuc 	/* Reset hardware. */
353433d6423SLionel Sambuc 	e1000_reset_hw(e);
354433d6423SLionel Sambuc 
355433d6423SLionel Sambuc 	/*
356*107df7c8SDavid van Moolenbroek 	 * Initialize appropriately, according to section 14.3 General
357*107df7c8SDavid van Moolenbroek 	 * Configuration of Intel's Gigabit Ethernet Controllers Software
358*107df7c8SDavid van Moolenbroek 	 * Developer's Manual.
359433d6423SLionel Sambuc 	 */
360*107df7c8SDavid van Moolenbroek 	e1000_reg_set(e, E1000_REG_CTRL,
361*107df7c8SDavid van Moolenbroek 	    E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU);
362433d6423SLionel Sambuc 	e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST);
363433d6423SLionel Sambuc 	e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST);
364433d6423SLionel Sambuc 	e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS);
365433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_FCAL, 0);
366433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_FCAH, 0);
367433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_FCT, 0);
368433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_FCTTV, 0);
369433d6423SLionel Sambuc 	e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME);
370433d6423SLionel Sambuc 
371433d6423SLionel Sambuc 	/* Clear Multicast Table Array (MTA). */
372433d6423SLionel Sambuc 	for (i = 0; i < 128; i++)
373*107df7c8SDavid van Moolenbroek 		e1000_reg_write(e, E1000_REG_MTA + i, 0);
374*107df7c8SDavid van Moolenbroek 
375433d6423SLionel Sambuc 	/* Initialize statistics registers. */
376433d6423SLionel Sambuc 	for (i = 0; i < 64; i++)
377433d6423SLionel Sambuc 		e1000_reg_write(e, E1000_REG_CRCERRS + (i * 4), 0);
378*107df7c8SDavid van Moolenbroek 
379*107df7c8SDavid van Moolenbroek 	/* Acquire MAC address and set up RX/TX buffers. */
380433d6423SLionel Sambuc 	e1000_init_addr(e);
381433d6423SLionel Sambuc 	e1000_init_buf(e);
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc 	/* Enable interrupts. */
384*107df7c8SDavid van Moolenbroek 	e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | E1000_REG_IMS_RXO |
385*107df7c8SDavid van Moolenbroek 	    E1000_REG_IMS_RXT | E1000_REG_IMS_TXQE | E1000_REG_IMS_TXDW);
386433d6423SLionel Sambuc 	return TRUE;
387433d6423SLionel Sambuc }
388433d6423SLionel Sambuc 
389*107df7c8SDavid van Moolenbroek /*
390*107df7c8SDavid van Moolenbroek  * Initialize the card's ethernet address.
391*107df7c8SDavid van Moolenbroek  */
392*107df7c8SDavid van Moolenbroek static void
393*107df7c8SDavid van Moolenbroek e1000_init_addr(e1000_t * e)
394433d6423SLionel Sambuc {
395433d6423SLionel Sambuc 	static char eakey[] = E1000_ENVVAR "#_EA";
396433d6423SLionel Sambuc 	static char eafmt[] = "x:x:x:x:x:x";
397433d6423SLionel Sambuc 	u16_t word;
398433d6423SLionel Sambuc 	int i;
399433d6423SLionel Sambuc 	long v;
400433d6423SLionel Sambuc 
401*107df7c8SDavid van Moolenbroek 	/* Do we have a user defined ethernet address? */
402433d6423SLionel Sambuc 	eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance;
403433d6423SLionel Sambuc 
404*107df7c8SDavid van Moolenbroek 	for (i = 0; i < 6; i++) {
405433d6423SLionel Sambuc 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
406433d6423SLionel Sambuc 			break;
407433d6423SLionel Sambuc 		else
408433d6423SLionel Sambuc 			e->address.ea_addr[i] = v;
409433d6423SLionel Sambuc 	}
410*107df7c8SDavid van Moolenbroek 
411*107df7c8SDavid van Moolenbroek 	/* If that fails, read Ethernet Address from EEPROM. */
412*107df7c8SDavid van Moolenbroek 	if (i != 6) {
413*107df7c8SDavid van Moolenbroek 		for (i = 0; i < 3; i++) {
414433d6423SLionel Sambuc 			word = e->eeprom_read(e, i);
415*107df7c8SDavid van Moolenbroek 			e->address.ea_addr[(i * 2)]     = (word & 0x00ff);
416433d6423SLionel Sambuc 			e->address.ea_addr[(i * 2) + 1] = (word & 0xff00) >> 8;
417433d6423SLionel Sambuc 		}
418433d6423SLionel Sambuc 	}
419*107df7c8SDavid van Moolenbroek 
420*107df7c8SDavid van Moolenbroek 	/* Set Receive Address. */
421433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&e->address.ea_addr[0]));
422433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&e->address.ea_addr[4]));
423433d6423SLionel Sambuc 	e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV);
424433d6423SLionel Sambuc 	e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE);
425433d6423SLionel Sambuc 
426433d6423SLionel Sambuc 	E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name,
427433d6423SLionel Sambuc 	    e->address.ea_addr[0], e->address.ea_addr[1],
428433d6423SLionel Sambuc 	    e->address.ea_addr[2], e->address.ea_addr[3],
429433d6423SLionel Sambuc 	    e->address.ea_addr[4], e->address.ea_addr[5]));
430433d6423SLionel Sambuc }
431433d6423SLionel Sambuc 
432*107df7c8SDavid van Moolenbroek /*
433*107df7c8SDavid van Moolenbroek  * Initialize receive and transmit buffers.
434*107df7c8SDavid van Moolenbroek  */
435*107df7c8SDavid van Moolenbroek static void
436*107df7c8SDavid van Moolenbroek e1000_init_buf(e1000_t * e)
437433d6423SLionel Sambuc {
438433d6423SLionel Sambuc 	phys_bytes rx_buff_p;
439433d6423SLionel Sambuc 	phys_bytes tx_buff_p;
440433d6423SLionel Sambuc 	int i;
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc 	/* Number of descriptors. */
443433d6423SLionel Sambuc 	e->rx_desc_count = E1000_RXDESC_NR;
444433d6423SLionel Sambuc 	e->tx_desc_count = E1000_TXDESC_NR;
445433d6423SLionel Sambuc 
446*107df7c8SDavid van Moolenbroek 	/* Allocate the receive descriptors. */
447*107df7c8SDavid van Moolenbroek 	if (!e->rx_desc) {
448433d6423SLionel Sambuc 		if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) *
449*107df7c8SDavid van Moolenbroek 		    e->rx_desc_count, AC_ALIGN4K, &e->rx_desc_p)) == NULL)
450433d6423SLionel Sambuc 			panic("failed to allocate RX descriptors");
451433d6423SLionel Sambuc 
452*107df7c8SDavid van Moolenbroek 		memset(e->rx_desc, 0,
453*107df7c8SDavid van Moolenbroek 		    sizeof(e1000_rx_desc_t) * e->rx_desc_count);
454*107df7c8SDavid van Moolenbroek 
455433d6423SLionel Sambuc 		e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE;
456433d6423SLionel Sambuc 
457*107df7c8SDavid van Moolenbroek 		/* Allocate receive buffers. */
458*107df7c8SDavid van Moolenbroek 		if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, AC_ALIGN4K,
459*107df7c8SDavid van Moolenbroek 		    &rx_buff_p)) == NULL)
460433d6423SLionel Sambuc 			panic("failed to allocate RX buffers");
461*107df7c8SDavid van Moolenbroek 
462433d6423SLionel Sambuc 		/* Set up receive descriptors. */
463433d6423SLionel Sambuc 		for (i = 0; i < E1000_RXDESC_NR; i++)
464*107df7c8SDavid van Moolenbroek 			e->rx_desc[i].buffer = rx_buff_p +
465*107df7c8SDavid van Moolenbroek 			    (i * E1000_IOBUF_SIZE);
466433d6423SLionel Sambuc 	}
467433d6423SLionel Sambuc 
468*107df7c8SDavid van Moolenbroek 	/* Allocate transmit descriptors. */
469*107df7c8SDavid van Moolenbroek 	if (!e->tx_desc) {
470*107df7c8SDavid van Moolenbroek 		if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) *
471*107df7c8SDavid van Moolenbroek 		    e->tx_desc_count, AC_ALIGN4K, &e->tx_desc_p)) == NULL)
472*107df7c8SDavid van Moolenbroek 				panic("failed to allocate TX descriptors");
473*107df7c8SDavid van Moolenbroek 
474*107df7c8SDavid van Moolenbroek 		memset(e->tx_desc, 0,
475*107df7c8SDavid van Moolenbroek 		    sizeof(e1000_tx_desc_t) * e->tx_desc_count);
476*107df7c8SDavid van Moolenbroek 
477*107df7c8SDavid van Moolenbroek 		/* Allocate transmit buffers. */
478433d6423SLionel Sambuc 		e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE;
479433d6423SLionel Sambuc 
480433d6423SLionel Sambuc 		/* Attempt to allocate. */
481*107df7c8SDavid van Moolenbroek 		if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, AC_ALIGN4K,
482*107df7c8SDavid van Moolenbroek 		    &tx_buff_p)) == NULL)
483433d6423SLionel Sambuc 			panic("failed to allocate TX buffers");
484*107df7c8SDavid van Moolenbroek 
485433d6423SLionel Sambuc 		/* Set up transmit descriptors. */
486433d6423SLionel Sambuc 		for (i = 0; i < E1000_TXDESC_NR; i++)
487*107df7c8SDavid van Moolenbroek 			e->tx_desc[i].buffer = tx_buff_p +
488*107df7c8SDavid van Moolenbroek 			    (i * E1000_IOBUF_SIZE);
489433d6423SLionel Sambuc 	}
490*107df7c8SDavid van Moolenbroek 
491*107df7c8SDavid van Moolenbroek 	/* Set up the receive ring registers. */
492433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_RDBAL, e->rx_desc_p);
493433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_RDBAH, 0);
494*107df7c8SDavid van Moolenbroek 	e1000_reg_write(e, E1000_REG_RDLEN,
495*107df7c8SDavid van Moolenbroek 	    e->rx_desc_count * sizeof(e1000_rx_desc_t));
496433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_RDH, 0);
497433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1);
498433d6423SLionel Sambuc 	e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE);
499433d6423SLionel Sambuc 	e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN);
500433d6423SLionel Sambuc 
501*107df7c8SDavid van Moolenbroek 	/* Set up the transmit ring registers. */
502433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_TDBAL, e->tx_desc_p);
503433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_TDBAH, 0);
504*107df7c8SDavid van Moolenbroek 	e1000_reg_write(e, E1000_REG_TDLEN,
505*107df7c8SDavid van Moolenbroek 	    e->tx_desc_count * sizeof(e1000_tx_desc_t));
506433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_TDH, 0);
507433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_TDT, 0);
508*107df7c8SDavid van Moolenbroek 	e1000_reg_set(e, E1000_REG_TCTL,
509*107df7c8SDavid van Moolenbroek 	    E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP);
510433d6423SLionel Sambuc }
511433d6423SLionel Sambuc 
512*107df7c8SDavid van Moolenbroek /*
513*107df7c8SDavid van Moolenbroek  * Reset the card.
514*107df7c8SDavid van Moolenbroek  */
515*107df7c8SDavid van Moolenbroek static void
516*107df7c8SDavid van Moolenbroek e1000_reset_hw(e1000_t * e)
517433d6423SLionel Sambuc {
518*107df7c8SDavid van Moolenbroek 
519433d6423SLionel Sambuc 	/* Assert a Device Reset signal. */
520433d6423SLionel Sambuc 	e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST);
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc 	/* Wait one microsecond. */
523433d6423SLionel Sambuc 	tickdelay(1);
524433d6423SLionel Sambuc }
525433d6423SLionel Sambuc 
526*107df7c8SDavid van Moolenbroek /*
527*107df7c8SDavid van Moolenbroek  * Try to send a packet.
528*107df7c8SDavid van Moolenbroek  */
529*107df7c8SDavid van Moolenbroek static void
530*107df7c8SDavid van Moolenbroek e1000_writev_s(message * mp, int from_int)
531433d6423SLionel Sambuc {
532433d6423SLionel Sambuc 	e1000_t *e = &e1000_state;
533433d6423SLionel Sambuc 	e1000_tx_desc_t *desc;
534433d6423SLionel Sambuc 	iovec_s_t iovec[E1000_IOVEC_NR];
535433d6423SLionel Sambuc 	int r, head, tail, i, bytes = 0, size;
536433d6423SLionel Sambuc 
537433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000: writev_s(%p,%d)\n", mp, from_int));
538433d6423SLionel Sambuc 
539433d6423SLionel Sambuc 	/* Are we called from the interrupt handler? */
540*107df7c8SDavid van Moolenbroek 	if (!from_int) {
541433d6423SLionel Sambuc 		/* We cannot write twice simultaneously.
542433d6423SLionel Sambuc 		assert(!(e->status & E1000_WRITING)); */
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc 		/* Copy write message. */
545433d6423SLionel Sambuc 		e->tx_message = *mp;
546433d6423SLionel Sambuc 		e->client = mp->m_source;
547433d6423SLionel Sambuc 		e->status |= E1000_WRITING;
548433d6423SLionel Sambuc 
549433d6423SLionel Sambuc 		/* Must be a sane vector count. */
550433d6423SLionel Sambuc 		assert(e->tx_message.m_net_netdrv_dl_writev_s.count > 0);
551*107df7c8SDavid van Moolenbroek 		assert(e->tx_message.m_net_netdrv_dl_writev_s.count <
552*107df7c8SDavid van Moolenbroek 		    E1000_IOVEC_NR);
553433d6423SLionel Sambuc 
554433d6423SLionel Sambuc 		/*
555433d6423SLionel Sambuc 		 * Copy the I/O vector table.
556433d6423SLionel Sambuc 		 */
557433d6423SLionel Sambuc 		if ((r = sys_safecopyfrom(e->tx_message.m_source,
558433d6423SLionel Sambuc 		    e->tx_message.m_net_netdrv_dl_writev_s.grant, 0,
559433d6423SLionel Sambuc 		    (vir_bytes)iovec,
560433d6423SLionel Sambuc 		    e->tx_message.m_net_netdrv_dl_writev_s.count *
561433d6423SLionel Sambuc 		    sizeof(iovec_s_t))) != OK)
562433d6423SLionel Sambuc 			panic("sys_safecopyfrom() failed: %d", r);
563*107df7c8SDavid van Moolenbroek 
564433d6423SLionel Sambuc 		/* Find the head, tail and current descriptors. */
565433d6423SLionel Sambuc 		head =  e1000_reg_read(e, E1000_REG_TDH);
566433d6423SLionel Sambuc 		tail =  e1000_reg_read(e, E1000_REG_TDT);
567433d6423SLionel Sambuc 		desc = &e->tx_desc[tail];
568433d6423SLionel Sambuc 
569433d6423SLionel Sambuc 		E1000_DEBUG(4, ("%s: head=%d, tail=%d\n",
570433d6423SLionel Sambuc 		    e->name, head, tail));
571433d6423SLionel Sambuc 
572433d6423SLionel Sambuc 		/* Loop vector elements. */
573*107df7c8SDavid van Moolenbroek 		for (i = 0; i < e->tx_message.m_net_netdrv_dl_writev_s.count;
574*107df7c8SDavid van Moolenbroek 		    i++)
575433d6423SLionel Sambuc 		{
576433d6423SLionel Sambuc 			size = iovec[i].iov_size < (E1000_IOBUF_SIZE - bytes) ?
577433d6423SLionel Sambuc 			    iovec[i].iov_size : (E1000_IOBUF_SIZE - bytes);
578433d6423SLionel Sambuc 
579433d6423SLionel Sambuc 			E1000_DEBUG(4, ("iovec[%d] = %d\n", i, size));
580433d6423SLionel Sambuc 
581433d6423SLionel Sambuc 			/* Copy bytes to TX queue buffers. */
582433d6423SLionel Sambuc 			if ((r = sys_safecopyfrom(e->tx_message.m_source,
583*107df7c8SDavid van Moolenbroek 			    iovec[i].iov_grant, 0, (vir_bytes) e->tx_buffer +
584*107df7c8SDavid van Moolenbroek 			    (tail * E1000_IOBUF_SIZE), size)) != OK)
585433d6423SLionel Sambuc 				panic("sys_safecopyfrom() failed: %d", r);
586*107df7c8SDavid van Moolenbroek 
587433d6423SLionel Sambuc 			/* Mark this descriptor ready. */
588433d6423SLionel Sambuc 			desc->status  = 0;
589433d6423SLionel Sambuc 			desc->command = 0;
590433d6423SLionel Sambuc 			desc->length  = size;
591433d6423SLionel Sambuc 
592433d6423SLionel Sambuc 			/* Marks End-of-Packet. */
593*107df7c8SDavid van Moolenbroek 			if (i ==
594*107df7c8SDavid van Moolenbroek 			    e->tx_message.m_net_netdrv_dl_writev_s.count - 1) {
595433d6423SLionel Sambuc 				desc->command = E1000_TX_CMD_EOP |
596*107df7c8SDavid van Moolenbroek 				    E1000_TX_CMD_FCS | E1000_TX_CMD_RS;
597433d6423SLionel Sambuc 			}
598433d6423SLionel Sambuc 			/* Move to next descriptor. */
599433d6423SLionel Sambuc 			tail = (tail + 1) % e->tx_desc_count;
600433d6423SLionel Sambuc 			bytes +=  size;
601433d6423SLionel Sambuc 			desc = &e->tx_desc[tail];
602433d6423SLionel Sambuc 		}
603*107df7c8SDavid van Moolenbroek 
604433d6423SLionel Sambuc 		/* Increment tail.  Start transmission. */
605433d6423SLionel Sambuc 		e1000_reg_write(e, E1000_REG_TDT,  tail);
606433d6423SLionel Sambuc 
607433d6423SLionel Sambuc 		E1000_DEBUG(2, ("e1000: wrote %d byte packet\n", bytes));
608*107df7c8SDavid van Moolenbroek 	} else
609433d6423SLionel Sambuc 		e->status |= E1000_TRANSMIT;
610433d6423SLionel Sambuc 	reply(e);
611433d6423SLionel Sambuc }
612433d6423SLionel Sambuc 
613*107df7c8SDavid van Moolenbroek /*
614*107df7c8SDavid van Moolenbroek  * Try to receive a packet.
615*107df7c8SDavid van Moolenbroek  */
616*107df7c8SDavid van Moolenbroek static void
617*107df7c8SDavid van Moolenbroek e1000_readv_s(message * mp, int from_int)
618433d6423SLionel Sambuc {
619433d6423SLionel Sambuc 	e1000_t *e = &e1000_state;
620433d6423SLionel Sambuc 	e1000_rx_desc_t *desc;
621433d6423SLionel Sambuc 	iovec_s_t iovec[E1000_IOVEC_NR];
622433d6423SLionel Sambuc 	int i, r, head, tail, cur, bytes = 0, size;
623433d6423SLionel Sambuc 
624433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000: readv_s(%p,%d)\n", mp, from_int));
625433d6423SLionel Sambuc 
626433d6423SLionel Sambuc 	/* Are we called from the interrupt handler? */
627*107df7c8SDavid van Moolenbroek 	if (!from_int) {
628433d6423SLionel Sambuc 		e->rx_message = *mp;
629433d6423SLionel Sambuc 		e->client = mp->m_source;
630433d6423SLionel Sambuc 		e->status |= E1000_READING;
631433d6423SLionel Sambuc 		e->rx_size = 0;
632433d6423SLionel Sambuc 
633433d6423SLionel Sambuc 		assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0);
634*107df7c8SDavid van Moolenbroek 		assert(e->rx_message.m_net_netdrv_dl_readv_s.count <
635*107df7c8SDavid van Moolenbroek 		    E1000_IOVEC_NR);
636433d6423SLionel Sambuc 	}
637*107df7c8SDavid van Moolenbroek 
638*107df7c8SDavid van Moolenbroek 	if (e->status & E1000_READING) {
639433d6423SLionel Sambuc 		/*
640433d6423SLionel Sambuc 		 * Copy the I/O vector table first.
641433d6423SLionel Sambuc 		 */
642433d6423SLionel Sambuc 		if ((r = sys_safecopyfrom(e->rx_message.m_source,
643433d6423SLionel Sambuc 		    e->rx_message.m_net_netdrv_dl_readv_s.grant, 0,
644433d6423SLionel Sambuc 		    (vir_bytes)iovec,
645433d6423SLionel Sambuc 		    e->rx_message.m_net_netdrv_dl_readv_s.count *
646433d6423SLionel Sambuc 		    sizeof(iovec_s_t))) != OK)
647433d6423SLionel Sambuc 			panic("sys_safecopyfrom() failed: %d", r);
648*107df7c8SDavid van Moolenbroek 
649433d6423SLionel Sambuc 		/* Find the head, tail and current descriptors. */
650433d6423SLionel Sambuc 		head = e1000_reg_read(e, E1000_REG_RDH);
651433d6423SLionel Sambuc 		tail = e1000_reg_read(e, E1000_REG_RDT);
652433d6423SLionel Sambuc 		cur  = (tail + 1) % e->rx_desc_count;
653433d6423SLionel Sambuc 		desc = &e->rx_desc[cur];
654433d6423SLionel Sambuc 
655433d6423SLionel Sambuc 		/*
656433d6423SLionel Sambuc 		 * Only handle one packet at a time.
657433d6423SLionel Sambuc 		 */
658*107df7c8SDavid van Moolenbroek 		if (!(desc->status & E1000_RX_STATUS_EOP)) {
659433d6423SLionel Sambuc 			reply(e);
660433d6423SLionel Sambuc 			return;
661433d6423SLionel Sambuc 		}
662433d6423SLionel Sambuc 		E1000_DEBUG(4, ("%s: head=%x, tail=%d\n",
663433d6423SLionel Sambuc 		    e->name, head, tail));
664433d6423SLionel Sambuc 
665433d6423SLionel Sambuc 		/*
666433d6423SLionel Sambuc 		 * Copy to vector elements.
667433d6423SLionel Sambuc 		 */
668433d6423SLionel Sambuc 		for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count &&
669*107df7c8SDavid van Moolenbroek 		    bytes < desc->length; i++) {
670433d6423SLionel Sambuc 			size = iovec[i].iov_size < (desc->length - bytes) ?
671433d6423SLionel Sambuc 			    iovec[i].iov_size : (desc->length - bytes);
672433d6423SLionel Sambuc 
673433d6423SLionel Sambuc 			E1000_DEBUG(4, ("iovec[%d] = %lu[%d]\n",
674433d6423SLionel Sambuc 			    i, iovec[i].iov_size, size));
675433d6423SLionel Sambuc 
676*107df7c8SDavid van Moolenbroek 			if ((r = sys_safecopyto(e->rx_message.m_source,
677*107df7c8SDavid van Moolenbroek 			    iovec[i].iov_grant, 0, (vir_bytes)e->rx_buffer +
678*107df7c8SDavid van Moolenbroek 			    bytes + (cur * E1000_IOBUF_SIZE), size)) != OK)
679433d6423SLionel Sambuc 				panic("sys_safecopyto() failed: %d", r);
680433d6423SLionel Sambuc 			bytes += size;
681433d6423SLionel Sambuc 		}
682433d6423SLionel Sambuc 		desc->status = 0;
683433d6423SLionel Sambuc 
684433d6423SLionel Sambuc 		/*
685433d6423SLionel Sambuc 		 * Update state.
686433d6423SLionel Sambuc 		 */
687433d6423SLionel Sambuc 		e->rx_size = bytes;
688433d6423SLionel Sambuc 		e->status |= E1000_RECEIVED;
689433d6423SLionel Sambuc 		E1000_DEBUG(2, ("e1000: got %d byte packet\n", e->rx_size));
690433d6423SLionel Sambuc 
691433d6423SLionel Sambuc 		/* Increment tail. */
692*107df7c8SDavid van Moolenbroek 		e1000_reg_write(e, E1000_REG_RDT,
693*107df7c8SDavid van Moolenbroek 		    (tail + 1) % e->rx_desc_count);
694433d6423SLionel Sambuc 	}
695433d6423SLionel Sambuc 	reply(e);
696433d6423SLionel Sambuc }
697433d6423SLionel Sambuc 
698*107df7c8SDavid van Moolenbroek /*
699*107df7c8SDavid van Moolenbroek  * Return statistics.
700*107df7c8SDavid van Moolenbroek  */
701*107df7c8SDavid van Moolenbroek static void
702*107df7c8SDavid van Moolenbroek e1000_getstat_s(message * mp)
703433d6423SLionel Sambuc {
704433d6423SLionel Sambuc 	int r;
705433d6423SLionel Sambuc 	eth_stat_t stats;
706433d6423SLionel Sambuc 	e1000_t *e = &e1000_state;
707433d6423SLionel Sambuc 
708433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000: getstat_s()\n"));
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc 	stats.ets_recvErr	= e1000_reg_read(e, E1000_REG_RXERRC);
711433d6423SLionel Sambuc 	stats.ets_sendErr	= 0;
712433d6423SLionel Sambuc 	stats.ets_OVW		= 0;
713433d6423SLionel Sambuc 	stats.ets_CRCerr	= e1000_reg_read(e, E1000_REG_CRCERRS);
714433d6423SLionel Sambuc 	stats.ets_frameAll	= 0;
715433d6423SLionel Sambuc 	stats.ets_missedP	= e1000_reg_read(e, E1000_REG_MPC);
716433d6423SLionel Sambuc 	stats.ets_packetR	= e1000_reg_read(e, E1000_REG_TPR);
717433d6423SLionel Sambuc 	stats.ets_packetT	= e1000_reg_read(e, E1000_REG_TPT);
718433d6423SLionel Sambuc 	stats.ets_collision	= e1000_reg_read(e, E1000_REG_COLC);
719433d6423SLionel Sambuc 	stats.ets_transAb	= 0;
720433d6423SLionel Sambuc 	stats.ets_carrSense	= 0;
721433d6423SLionel Sambuc 	stats.ets_fifoUnder	= 0;
722433d6423SLionel Sambuc 	stats.ets_fifoOver	= 0;
723433d6423SLionel Sambuc 	stats.ets_CDheartbeat	= 0;
724433d6423SLionel Sambuc 	stats.ets_OWC		= 0;
725433d6423SLionel Sambuc 
726433d6423SLionel Sambuc 	sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0,
727433d6423SLionel Sambuc 	    (vir_bytes)&stats, sizeof(stats));
728433d6423SLionel Sambuc 	mp->m_type = DL_STAT_REPLY;
729433d6423SLionel Sambuc 	if ((r = ipc_send(mp->m_source, mp)) != OK)
730433d6423SLionel Sambuc 		panic("e1000_getstat: ipc_send() failed: %d", r);
731433d6423SLionel Sambuc }
732433d6423SLionel Sambuc 
733*107df7c8SDavid van Moolenbroek /*
734*107df7c8SDavid van Moolenbroek  * Handle an interrupt.
735*107df7c8SDavid van Moolenbroek  */
736*107df7c8SDavid van Moolenbroek static void
737*107df7c8SDavid van Moolenbroek e1000_interrupt(message * mp)
738433d6423SLionel Sambuc {
739433d6423SLionel Sambuc 	e1000_t *e;
740433d6423SLionel Sambuc 	u32_t cause;
741433d6423SLionel Sambuc 
742433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000: interrupt\n"));
743433d6423SLionel Sambuc 
744433d6423SLionel Sambuc 	e = &e1000_state;
745433d6423SLionel Sambuc 
746*107df7c8SDavid van Moolenbroek 	/* Reenable interrupts. */
747433d6423SLionel Sambuc 	if (sys_irqenable(&e->irq_hook) != OK)
748433d6423SLionel Sambuc 		panic("failed to re-enable IRQ");
749433d6423SLionel Sambuc 
750433d6423SLionel Sambuc 	/* Read the Interrupt Cause Read register. */
751*107df7c8SDavid van Moolenbroek 	if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) {
752433d6423SLionel Sambuc 		if (cause & E1000_REG_ICR_LSC)
753433d6423SLionel Sambuc 			e1000_link_changed(e);
754433d6423SLionel Sambuc 
755433d6423SLionel Sambuc 		if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT))
756433d6423SLionel Sambuc 			e1000_readv_s(&e->rx_message, TRUE);
757433d6423SLionel Sambuc 
758*107df7c8SDavid van Moolenbroek 		if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW))
759433d6423SLionel Sambuc 			e1000_writev_s(&e->tx_message, TRUE);
760433d6423SLionel Sambuc 	}
761433d6423SLionel Sambuc }
762433d6423SLionel Sambuc 
763*107df7c8SDavid van Moolenbroek /*
764*107df7c8SDavid van Moolenbroek  * Link status has changed.  Nothing to do for now.
765*107df7c8SDavid van Moolenbroek  */
766*107df7c8SDavid van Moolenbroek static int
767*107df7c8SDavid van Moolenbroek e1000_link_changed(e1000_t * e)
768433d6423SLionel Sambuc {
769*107df7c8SDavid van Moolenbroek 
770433d6423SLionel Sambuc 	E1000_DEBUG(4, ("%s: link_changed()\n", e->name));
771433d6423SLionel Sambuc 	return FALSE;
772433d6423SLionel Sambuc }
773433d6423SLionel Sambuc 
774*107df7c8SDavid van Moolenbroek /*
775*107df7c8SDavid van Moolenbroek  * Stop the card.
776*107df7c8SDavid van Moolenbroek  */
777*107df7c8SDavid van Moolenbroek static void
778*107df7c8SDavid van Moolenbroek e1000_stop(e1000_t *e)
779433d6423SLionel Sambuc {
780*107df7c8SDavid van Moolenbroek 
781433d6423SLionel Sambuc 	E1000_DEBUG(3, ("%s: stop()\n", e->name));
782433d6423SLionel Sambuc 
783433d6423SLionel Sambuc 	e1000_reset_hw(e);
784433d6423SLionel Sambuc 
785433d6423SLionel Sambuc 	exit(EXIT_SUCCESS);
786433d6423SLionel Sambuc }
787433d6423SLionel Sambuc 
788*107df7c8SDavid van Moolenbroek /*
789*107df7c8SDavid van Moolenbroek  * Read from a register.
790*107df7c8SDavid van Moolenbroek  */
791*107df7c8SDavid van Moolenbroek static uint32_t
792*107df7c8SDavid van Moolenbroek e1000_reg_read(e1000_t * e, uint32_t reg)
793433d6423SLionel Sambuc {
794433d6423SLionel Sambuc 	uint32_t value;
795433d6423SLionel Sambuc 
796433d6423SLionel Sambuc 	/* Assume a sane register. */
797433d6423SLionel Sambuc 	assert(reg < 0x1ffff);
798433d6423SLionel Sambuc 
799433d6423SLionel Sambuc 	/* Read from memory mapped register. */
800*107df7c8SDavid van Moolenbroek 	value = *(volatile uint32_t *)(e->regs + reg);
801433d6423SLionel Sambuc 
802433d6423SLionel Sambuc 	/* Return the result. */
803433d6423SLionel Sambuc 	return value;
804433d6423SLionel Sambuc }
805433d6423SLionel Sambuc 
806*107df7c8SDavid van Moolenbroek /*
807*107df7c8SDavid van Moolenbroek  * Write to a register.
808*107df7c8SDavid van Moolenbroek  */
809*107df7c8SDavid van Moolenbroek static void
810*107df7c8SDavid van Moolenbroek e1000_reg_write(e1000_t * e, uint32_t reg, uint32_t value)
811433d6423SLionel Sambuc {
812*107df7c8SDavid van Moolenbroek 
813433d6423SLionel Sambuc 	/* Assume a sane register. */
814433d6423SLionel Sambuc 	assert(reg < 0x1ffff);
815433d6423SLionel Sambuc 
816433d6423SLionel Sambuc 	/* Write to memory mapped register. */
817433d6423SLionel Sambuc 	*(volatile u32_t *)(e->regs + reg) = value;
818433d6423SLionel Sambuc }
819433d6423SLionel Sambuc 
820*107df7c8SDavid van Moolenbroek /*
821*107df7c8SDavid van Moolenbroek  * Set bits in a register.
822*107df7c8SDavid van Moolenbroek  */
823*107df7c8SDavid van Moolenbroek static void
824*107df7c8SDavid van Moolenbroek e1000_reg_set(e1000_t * e, uint32_t reg, uint32_t value)
825433d6423SLionel Sambuc {
826433d6423SLionel Sambuc 	uint32_t data;
827433d6423SLionel Sambuc 
828433d6423SLionel Sambuc 	/* First read the current value. */
829433d6423SLionel Sambuc 	data = e1000_reg_read(e, reg);
830433d6423SLionel Sambuc 
831*107df7c8SDavid van Moolenbroek 	/* Set bits, and write back. */
832433d6423SLionel Sambuc 	e1000_reg_write(e, reg, data | value);
833433d6423SLionel Sambuc }
834433d6423SLionel Sambuc 
835*107df7c8SDavid van Moolenbroek /*
836*107df7c8SDavid van Moolenbroek  * Clear bits in a register.
837*107df7c8SDavid van Moolenbroek  */
838*107df7c8SDavid van Moolenbroek static void
839*107df7c8SDavid van Moolenbroek e1000_reg_unset(e1000_t * e, uint32_t reg, uint32_t value)
840433d6423SLionel Sambuc {
841433d6423SLionel Sambuc 	uint32_t data;
842433d6423SLionel Sambuc 
843433d6423SLionel Sambuc 	/* First read the current value. */
844433d6423SLionel Sambuc 	data = e1000_reg_read(e, reg);
845433d6423SLionel Sambuc 
846*107df7c8SDavid van Moolenbroek 	/* Unset bits, and write back. */
847433d6423SLionel Sambuc 	e1000_reg_write(e, reg, data & ~value);
848433d6423SLionel Sambuc }
849433d6423SLionel Sambuc 
850*107df7c8SDavid van Moolenbroek /*
851*107df7c8SDavid van Moolenbroek  * Read from EEPROM.
852*107df7c8SDavid van Moolenbroek  */
853*107df7c8SDavid van Moolenbroek static u16_t
854*107df7c8SDavid van Moolenbroek eeprom_eerd(void * v, int reg)
855433d6423SLionel Sambuc {
856433d6423SLionel Sambuc 	e1000_t *e = (e1000_t *)v;
857433d6423SLionel Sambuc 	u32_t data;
858433d6423SLionel Sambuc 
859433d6423SLionel Sambuc 	/* Request EEPROM read. */
860433d6423SLionel Sambuc 	e1000_reg_write(e, E1000_REG_EERD,
861433d6423SLionel Sambuc 	    (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START));
862433d6423SLionel Sambuc 
863433d6423SLionel Sambuc 	/* Wait until ready. */
864*107df7c8SDavid van Moolenbroek 	while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) &
865*107df7c8SDavid van Moolenbroek 	    e->eeprom_done_bit));
866433d6423SLionel Sambuc 
867433d6423SLionel Sambuc 	return data >> 16;
868433d6423SLionel Sambuc }
869433d6423SLionel Sambuc 
870*107df7c8SDavid van Moolenbroek /*
871*107df7c8SDavid van Moolenbroek  * Initialize ICH8 flash.
872*107df7c8SDavid van Moolenbroek  */
873*107df7c8SDavid van Moolenbroek static int
874*107df7c8SDavid van Moolenbroek eeprom_ich_init(e1000_t * e)
875433d6423SLionel Sambuc {
876433d6423SLionel Sambuc 	union ich8_hws_flash_status hsfsts;
877433d6423SLionel Sambuc 	int ret_val = -1;
878433d6423SLionel Sambuc 	int i = 0;
879433d6423SLionel Sambuc 
880433d6423SLionel Sambuc 	hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS);
881433d6423SLionel Sambuc 
882433d6423SLionel Sambuc 	/* Check if the flash descriptor is valid */
883*107df7c8SDavid van Moolenbroek 	if (hsfsts.hsf_status.fldesvalid == 0) {
884433d6423SLionel Sambuc 		E1000_DEBUG(3, ("Flash descriptor invalid. "
885433d6423SLionel Sambuc 		    "SW Sequencing must be used."));
886433d6423SLionel Sambuc 		goto out;
887433d6423SLionel Sambuc 	}
888*107df7c8SDavid van Moolenbroek 
889433d6423SLionel Sambuc 	/* Clear FCERR and DAEL in hw status by writing 1 */
890433d6423SLionel Sambuc 	hsfsts.hsf_status.flcerr = 1;
891433d6423SLionel Sambuc 	hsfsts.hsf_status.dael = 1;
892433d6423SLionel Sambuc 
893433d6423SLionel Sambuc 	E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval);
894433d6423SLionel Sambuc 
895433d6423SLionel Sambuc 	/*
896*107df7c8SDavid van Moolenbroek 	 * Either we should have a hardware SPI cycle in progress bit to check
897*107df7c8SDavid van Moolenbroek 	 * against, in order to start a new cycle or FDONE bit should be
898*107df7c8SDavid van Moolenbroek 	 * changed in the hardware so that it is 1 after hardware reset, which
899*107df7c8SDavid van Moolenbroek 	 * can then be used as an indication whether a cycle is in progress or
900*107df7c8SDavid van Moolenbroek 	 * has been completed.
901433d6423SLionel Sambuc 	 */
902*107df7c8SDavid van Moolenbroek 	if (hsfsts.hsf_status.flcinprog == 0) {
903433d6423SLionel Sambuc 		/*
904*107df7c8SDavid van Moolenbroek 		 * There is no cycle running at present, so we can start a
905*107df7c8SDavid van Moolenbroek 		 * cycle.  Begin by setting Flash Cycle Done.
906433d6423SLionel Sambuc 		 */
907433d6423SLionel Sambuc 		hsfsts.hsf_status.flcdone = 1;
908433d6423SLionel Sambuc 		E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval);
909433d6423SLionel Sambuc 		ret_val = 0;
910*107df7c8SDavid van Moolenbroek 	} else {
911433d6423SLionel Sambuc 		/*
912*107df7c8SDavid van Moolenbroek 		 * Otherwise poll for sometime so the current cycle has a
913*107df7c8SDavid van Moolenbroek 		 * chance to end before giving up.
914433d6423SLionel Sambuc 		 */
915*107df7c8SDavid van Moolenbroek 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
916*107df7c8SDavid van Moolenbroek 			hsfsts.regval = E1000_READ_FLASH_REG16(e,
917*107df7c8SDavid van Moolenbroek 			    ICH_FLASH_HSFSTS);
918433d6423SLionel Sambuc 
919*107df7c8SDavid van Moolenbroek 			if (hsfsts.hsf_status.flcinprog == 0) {
920433d6423SLionel Sambuc 				ret_val = 0;
921433d6423SLionel Sambuc 				break;
922433d6423SLionel Sambuc 			}
923433d6423SLionel Sambuc 			tickdelay(1);
924433d6423SLionel Sambuc 		}
925*107df7c8SDavid van Moolenbroek 		if (ret_val == 0) {
926433d6423SLionel Sambuc 			/*
927433d6423SLionel Sambuc 			 * Successful in waiting for previous cycle to timeout,
928433d6423SLionel Sambuc 			 * now set the Flash Cycle Done.
929433d6423SLionel Sambuc 			 */
930433d6423SLionel Sambuc 			hsfsts.hsf_status.flcdone = 1;
931433d6423SLionel Sambuc 			E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS,
932433d6423SLionel Sambuc 			    hsfsts.regval);
933*107df7c8SDavid van Moolenbroek 		} else {
934*107df7c8SDavid van Moolenbroek 			E1000_DEBUG(3,
935*107df7c8SDavid van Moolenbroek 			    ("Flash controller busy, cannot get access"));
936433d6423SLionel Sambuc 		}
937433d6423SLionel Sambuc 	}
938433d6423SLionel Sambuc out:
939433d6423SLionel Sambuc 	return ret_val;
940433d6423SLionel Sambuc }
941433d6423SLionel Sambuc 
942*107df7c8SDavid van Moolenbroek /*
943*107df7c8SDavid van Moolenbroek  * Start ICH8 flash cycle.
944*107df7c8SDavid van Moolenbroek  */
945*107df7c8SDavid van Moolenbroek static int
946*107df7c8SDavid van Moolenbroek eeprom_ich_cycle(e1000_t * e, u32_t timeout)
947433d6423SLionel Sambuc {
948433d6423SLionel Sambuc 	union ich8_hws_flash_ctrl hsflctl;
949433d6423SLionel Sambuc 	union ich8_hws_flash_status hsfsts;
950433d6423SLionel Sambuc 	int ret_val = -1;
951433d6423SLionel Sambuc 	u32_t i = 0;
952433d6423SLionel Sambuc 
953433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan"));
954433d6423SLionel Sambuc 
955433d6423SLionel Sambuc 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
956433d6423SLionel Sambuc 	hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL);
957433d6423SLionel Sambuc 	hsflctl.hsf_ctrl.flcgo = 1;
958433d6423SLionel Sambuc 	E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval);
959433d6423SLionel Sambuc 
960*107df7c8SDavid van Moolenbroek 	/* Wait till the FDONE bit is set to 1 */
961*107df7c8SDavid van Moolenbroek 	do {
962433d6423SLionel Sambuc 		hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS);
963433d6423SLionel Sambuc 		if (hsfsts.hsf_status.flcdone == 1)
964433d6423SLionel Sambuc 			break;
965433d6423SLionel Sambuc 		tickdelay(1);
966*107df7c8SDavid van Moolenbroek 	} while (i++ < timeout);
967433d6423SLionel Sambuc 
968433d6423SLionel Sambuc 	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
969433d6423SLionel Sambuc 		ret_val = 0;
970433d6423SLionel Sambuc 
971433d6423SLionel Sambuc 	return ret_val;
972433d6423SLionel Sambuc }
973433d6423SLionel Sambuc 
974*107df7c8SDavid van Moolenbroek /*
975*107df7c8SDavid van Moolenbroek  * Read from ICH8 flash.
976*107df7c8SDavid van Moolenbroek  */
977*107df7c8SDavid van Moolenbroek static u16_t
978*107df7c8SDavid van Moolenbroek eeprom_ich(void * v, int reg)
979433d6423SLionel Sambuc {
980433d6423SLionel Sambuc 	union ich8_hws_flash_status hsfsts;
981433d6423SLionel Sambuc 	union ich8_hws_flash_ctrl hsflctl;
982433d6423SLionel Sambuc 	u32_t flash_linear_addr;
983433d6423SLionel Sambuc 	u32_t flash_data = 0;
984433d6423SLionel Sambuc 	int ret_val = -1;
985433d6423SLionel Sambuc 	u8_t count = 0;
986433d6423SLionel Sambuc 	e1000_t *e = (e1000_t *)v;
987433d6423SLionel Sambuc 	u16_t data = 0;
988433d6423SLionel Sambuc 
989433d6423SLionel Sambuc 	E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan"));
990433d6423SLionel Sambuc 
991433d6423SLionel Sambuc 	if (reg > ICH_FLASH_LINEAR_ADDR_MASK)
992433d6423SLionel Sambuc 		goto out;
993433d6423SLionel Sambuc 
994433d6423SLionel Sambuc 	reg *= sizeof(u16_t);
995433d6423SLionel Sambuc 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) +
996433d6423SLionel Sambuc 	    e->flash_base_addr;
997433d6423SLionel Sambuc 
998433d6423SLionel Sambuc 	do {
999433d6423SLionel Sambuc 		tickdelay(1);
1000433d6423SLionel Sambuc 
1001433d6423SLionel Sambuc 		/* Steps */
1002433d6423SLionel Sambuc 		ret_val = eeprom_ich_init(e);
1003433d6423SLionel Sambuc 		if (ret_val != 0)
1004433d6423SLionel Sambuc 			break;
1005433d6423SLionel Sambuc 
1006433d6423SLionel Sambuc 		hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL);
1007433d6423SLionel Sambuc 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
1008433d6423SLionel Sambuc 		hsflctl.hsf_ctrl.fldbcount = 1;
1009433d6423SLionel Sambuc 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
1010433d6423SLionel Sambuc 		E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval);
1011433d6423SLionel Sambuc 		E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr);
1012433d6423SLionel Sambuc 
1013433d6423SLionel Sambuc 		ret_val = eeprom_ich_cycle(v, ICH_FLASH_READ_COMMAND_TIMEOUT);
1014433d6423SLionel Sambuc 
1015433d6423SLionel Sambuc 		/*
1016*107df7c8SDavid van Moolenbroek 		 * Check if FCERR is set to 1, if set to 1, clear it and try
1017*107df7c8SDavid van Moolenbroek 		 * the whole sequence a few more times, else read in (shift in)
1018*107df7c8SDavid van Moolenbroek 		 * the Flash Data0, the order is least significant byte first
1019*107df7c8SDavid van Moolenbroek 		 * msb to lsb.
1020433d6423SLionel Sambuc 		 */
1021*107df7c8SDavid van Moolenbroek 		if (ret_val == 0) {
1022433d6423SLionel Sambuc 			flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0);
1023433d6423SLionel Sambuc 			data = (u16_t)(flash_data & 0x0000FFFF);
1024433d6423SLionel Sambuc 			break;
1025*107df7c8SDavid van Moolenbroek 		} else {
1026433d6423SLionel Sambuc 			/*
1027433d6423SLionel Sambuc 			 * If we've gotten here, then things are probably
1028433d6423SLionel Sambuc 			 * completely hosed, but if the error condition is
1029433d6423SLionel Sambuc 			 * detected, it won't hurt to give it another try...
1030433d6423SLionel Sambuc 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
1031433d6423SLionel Sambuc 			 */
1032*107df7c8SDavid van Moolenbroek 			hsfsts.regval = E1000_READ_FLASH_REG16(e,
1033*107df7c8SDavid van Moolenbroek 			    ICH_FLASH_HSFSTS);
1034433d6423SLionel Sambuc 
1035*107df7c8SDavid van Moolenbroek 			if (hsfsts.hsf_status.flcerr == 1) {
1036433d6423SLionel Sambuc 				/* Repeat for some time before giving up. */
1037433d6423SLionel Sambuc 				continue;
1038*107df7c8SDavid van Moolenbroek 			} else if (hsfsts.hsf_status.flcdone == 0) {
1039433d6423SLionel Sambuc 				E1000_DEBUG(3, ("Timeout error - flash cycle "
1040433d6423SLionel Sambuc 				    "did not complete."));
1041433d6423SLionel Sambuc 				break;
1042433d6423SLionel Sambuc 			}
1043433d6423SLionel Sambuc 		}
1044433d6423SLionel Sambuc 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
1045433d6423SLionel Sambuc 
1046433d6423SLionel Sambuc out:
1047433d6423SLionel Sambuc 	return data;
1048433d6423SLionel Sambuc }
1049433d6423SLionel Sambuc 
1050*107df7c8SDavid van Moolenbroek /*
1051*107df7c8SDavid van Moolenbroek  * Reply to a task request from Inet.
1052*107df7c8SDavid van Moolenbroek  */
1053*107df7c8SDavid van Moolenbroek static void
1054*107df7c8SDavid van Moolenbroek reply(e1000_t *e)
1055433d6423SLionel Sambuc {
1056433d6423SLionel Sambuc 	message msg;
1057433d6423SLionel Sambuc 	int r;
1058433d6423SLionel Sambuc 
1059433d6423SLionel Sambuc 	/* Only reply to client for read/write request. */
1060*107df7c8SDavid van Moolenbroek 	if (!(e->status & E1000_READING || e->status & E1000_WRITING))
1061433d6423SLionel Sambuc 		return;
1062*107df7c8SDavid van Moolenbroek 
1063433d6423SLionel Sambuc 	/* Construct reply message. */
1064433d6423SLionel Sambuc 	msg.m_type = DL_TASK_REPLY;
1065433d6423SLionel Sambuc 	msg.m_netdrv_net_dl_task.flags = DL_NOFLAGS;
1066433d6423SLionel Sambuc 	msg.m_netdrv_net_dl_task.count = 0;
1067433d6423SLionel Sambuc 
1068433d6423SLionel Sambuc 	/* Did we successfully receive packet(s)? */
1069*107df7c8SDavid van Moolenbroek 	if (e->status & E1000_READING && e->status & E1000_RECEIVED) {
1070433d6423SLionel Sambuc 		msg.m_netdrv_net_dl_task.flags |= DL_PACK_RECV;
1071433d6423SLionel Sambuc 		msg.m_netdrv_net_dl_task.count =
1072433d6423SLionel Sambuc 		    e->rx_size >= ETH_MIN_PACK_SIZE ?
1073433d6423SLionel Sambuc 		    e->rx_size : ETH_MIN_PACK_SIZE;
1074433d6423SLionel Sambuc 
1075433d6423SLionel Sambuc 		/* Clear flags. */
1076433d6423SLionel Sambuc 		e->status &= ~(E1000_READING | E1000_RECEIVED);
1077433d6423SLionel Sambuc 	}
1078*107df7c8SDavid van Moolenbroek 
1079433d6423SLionel Sambuc 	/* Did we successfully transmit packet(s)? */
1080*107df7c8SDavid van Moolenbroek 	if (e->status & E1000_TRANSMIT && e->status & E1000_WRITING) {
1081433d6423SLionel Sambuc 		msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND;
1082433d6423SLionel Sambuc 
1083433d6423SLionel Sambuc 		/* Clear flags. */
1084433d6423SLionel Sambuc 		e->status &= ~(E1000_WRITING | E1000_TRANSMIT);
1085433d6423SLionel Sambuc 	}
1086433d6423SLionel Sambuc 
1087433d6423SLionel Sambuc 	/* Acknowledge to INET. */
1088433d6423SLionel Sambuc 	if ((r = ipc_send(e->client, &msg)) != OK)
1089433d6423SLionel Sambuc 		panic("ipc_send() failed: %d", r);
1090433d6423SLionel Sambuc }
1091433d6423SLionel Sambuc 
1092*107df7c8SDavid van Moolenbroek /*
1093*107df7c8SDavid van Moolenbroek  * Send a reply to Inet.
1094*107df7c8SDavid van Moolenbroek  */
1095*107df7c8SDavid van Moolenbroek static void
1096*107df7c8SDavid van Moolenbroek mess_reply(message *req, message *reply_mess)
1097433d6423SLionel Sambuc {
1098*107df7c8SDavid van Moolenbroek 
1099433d6423SLionel Sambuc 	if (ipc_send(req->m_source, reply_mess) != OK)
1100433d6423SLionel Sambuc 		panic("unable to send reply message");
1101433d6423SLionel Sambuc }
1102