1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc * dp8390.c
3433d6423SLionel Sambuc *
4433d6423SLionel Sambuc * This file contains a ethernet device driver for NS dp8390 based ethernet
5433d6423SLionel Sambuc * cards.
6433d6423SLionel Sambuc *
7433d6423SLionel Sambuc * Created: before Dec 28, 1992 by Philip Homburg <philip@f-mnx.phicoh.com>
8433d6423SLionel Sambuc *
9433d6423SLionel Sambuc * Modified Mar 10 1994 by Philip Homburg
10433d6423SLionel Sambuc * Become a generic dp8390 driver.
11433d6423SLionel Sambuc *
12433d6423SLionel Sambuc * Modified Dec 20 1996 by G. Falzoni <falzoni@marina.scn.de>
13433d6423SLionel Sambuc * Added support for 3c503 boards.
14433d6423SLionel Sambuc */
15433d6423SLionel Sambuc
16433d6423SLionel Sambuc #include <minix/drivers.h>
17433d6423SLionel Sambuc #include <minix/netdriver.h>
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc #include <sys/mman.h>
20433d6423SLionel Sambuc #include "assert.h"
21433d6423SLionel Sambuc
22433d6423SLionel Sambuc #include "local.h"
23433d6423SLionel Sambuc #include "dp8390.h"
24433d6423SLionel Sambuc
25433d6423SLionel Sambuc static dpeth_t de_state;
26433d6423SLionel Sambuc
27433d6423SLionel Sambuc u32_t system_hz;
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc /* Configuration */
30433d6423SLionel Sambuc typedef struct dp_conf
31433d6423SLionel Sambuc {
32433d6423SLionel Sambuc port_t dpc_port;
33433d6423SLionel Sambuc int dpc_irq;
34433d6423SLionel Sambuc phys_bytes dpc_mem;
35433d6423SLionel Sambuc } dp_conf_t;
36433d6423SLionel Sambuc
37433d6423SLionel Sambuc #define DP_CONF_NR 4
38433d6423SLionel Sambuc static dp_conf_t dp_conf[DP_CONF_NR]= /* Card addresses */
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc /* I/O port, IRQ, Buffer address. */
41433d6423SLionel Sambuc { 0x280, 3, 0xD0000, },
42433d6423SLionel Sambuc { 0x300, 5, 0xC8000, },
43433d6423SLionel Sambuc { 0x380, 10, 0xD8000, },
44433d6423SLionel Sambuc { 0x000, 0, 0x00000, },
45433d6423SLionel Sambuc };
46433d6423SLionel Sambuc
47433d6423SLionel Sambuc /* Card inits configured out? */
48433d6423SLionel Sambuc #if !ENABLE_WDETH
49433d6423SLionel Sambuc #define wdeth_probe(dep) (0)
50433d6423SLionel Sambuc #endif
51433d6423SLionel Sambuc #if !ENABLE_NE2000
52433d6423SLionel Sambuc #define ne_probe(dep) (0)
53433d6423SLionel Sambuc #endif
54433d6423SLionel Sambuc #if !ENABLE_3C503
55433d6423SLionel Sambuc #define el2_probe(dep) (0)
56433d6423SLionel Sambuc #endif
57433d6423SLionel Sambuc
58433d6423SLionel Sambuc /* Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
59433d6423SLionel Sambuc * on writes to the CR register. Additional CR_STAs do not appear to hurt
60433d6423SLionel Sambuc * genuine dp8390s
61433d6423SLionel Sambuc */
62433d6423SLionel Sambuc #define CR_EXTRA CR_STA
63433d6423SLionel Sambuc
64*f7df02e7SDavid van Moolenbroek static int do_init(unsigned int instance, netdriver_addr_t *addr,
65*f7df02e7SDavid van Moolenbroek uint32_t *caps, unsigned int *ticks);
66*f7df02e7SDavid van Moolenbroek static void pci_conf(unsigned int instance);
673913e490SDavid van Moolenbroek static int do_send(struct netdriver_data *data, size_t size);
683913e490SDavid van Moolenbroek static ssize_t do_recv(struct netdriver_data *data, size_t max);
69*f7df02e7SDavid van Moolenbroek static void do_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
70*f7df02e7SDavid van Moolenbroek unsigned int mcast_count);
713913e490SDavid van Moolenbroek static void do_stop(void);
72*f7df02e7SDavid van Moolenbroek static void dp_init(dpeth_t *dep, unsigned int instance);
73*f7df02e7SDavid van Moolenbroek static void dp_confaddr(dpeth_t *dep, unsigned int instance);
74433d6423SLionel Sambuc static void dp_reset(dpeth_t *dep);
753913e490SDavid van Moolenbroek static void do_intr(unsigned int mask);
76*f7df02e7SDavid van Moolenbroek static void do_tick(void);
77433d6423SLionel Sambuc static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t
78433d6423SLionel Sambuc size, void *dst);
79433d6423SLionel Sambuc static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset,
80433d6423SLionel Sambuc size_t size, void *dst);
81433d6423SLionel Sambuc static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset,
82433d6423SLionel Sambuc size_t size, void *dst);
833913e490SDavid van Moolenbroek static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page,
843913e490SDavid van Moolenbroek size_t length);
853913e490SDavid van Moolenbroek static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
863913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count);
873913e490SDavid van Moolenbroek static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
883913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count);
893913e490SDavid van Moolenbroek static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
903913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count);
913913e490SDavid van Moolenbroek static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
923913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count);
933913e490SDavid van Moolenbroek static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
943913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count);
953913e490SDavid van Moolenbroek static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
963913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count);
97*f7df02e7SDavid van Moolenbroek static void conf_hw(dpeth_t *dep, unsigned int instance);
98*f7df02e7SDavid van Moolenbroek static void update_conf(dpeth_t *dep, dp_conf_t *dcp, unsigned int instance);
99433d6423SLionel Sambuc static void map_hw_buffer(dpeth_t *dep);
100433d6423SLionel Sambuc static void insb(port_t port, void *buf, size_t size);
101433d6423SLionel Sambuc static void insw(port_t port, void *buf, size_t size);
102433d6423SLionel Sambuc
1033913e490SDavid van Moolenbroek static const struct netdriver dp_table = {
104*f7df02e7SDavid van Moolenbroek .ndr_name = "dp",
1053913e490SDavid van Moolenbroek .ndr_init = do_init,
1063913e490SDavid van Moolenbroek .ndr_stop = do_stop,
107*f7df02e7SDavid van Moolenbroek .ndr_set_mode = do_set_mode,
1083913e490SDavid van Moolenbroek .ndr_recv = do_recv,
1093913e490SDavid van Moolenbroek .ndr_send = do_send,
110*f7df02e7SDavid van Moolenbroek .ndr_intr = do_intr,
111*f7df02e7SDavid van Moolenbroek .ndr_tick = do_tick
1123913e490SDavid van Moolenbroek };
113433d6423SLionel Sambuc
114433d6423SLionel Sambuc /*===========================================================================*
1153913e490SDavid van Moolenbroek * main *
116433d6423SLionel Sambuc *===========================================================================*/
main(int argc,char * argv[])117433d6423SLionel Sambuc int main(int argc, char *argv[])
118433d6423SLionel Sambuc {
119433d6423SLionel Sambuc env_setargs(argc, argv);
120433d6423SLionel Sambuc
1213913e490SDavid van Moolenbroek netdriver_task(&dp_table);
122433d6423SLionel Sambuc
1233913e490SDavid van Moolenbroek return 0;
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc
126433d6423SLionel Sambuc /*===========================================================================*
1273913e490SDavid van Moolenbroek * do_init *
128433d6423SLionel Sambuc *===========================================================================*/
do_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)129*f7df02e7SDavid van Moolenbroek static int do_init(unsigned int instance, netdriver_addr_t *addr,
130*f7df02e7SDavid van Moolenbroek uint32_t *caps, unsigned int *ticks)
131433d6423SLionel Sambuc {
132433d6423SLionel Sambuc /* Initialize the dp8390 driver. */
133433d6423SLionel Sambuc dpeth_t *dep;
134433d6423SLionel Sambuc
135433d6423SLionel Sambuc system_hz = sys_hz();
136433d6423SLionel Sambuc
137433d6423SLionel Sambuc dep = &de_state;
1383913e490SDavid van Moolenbroek memset(dep, 0, sizeof(*dep));
139433d6423SLionel Sambuc
140*f7df02e7SDavid van Moolenbroek pci_conf(instance); /* Configure PCI devices. */
141433d6423SLionel Sambuc
1423913e490SDavid van Moolenbroek /* This is the default, try to (re)locate the device. */
143*f7df02e7SDavid van Moolenbroek conf_hw(dep, instance);
144433d6423SLionel Sambuc
145*f7df02e7SDavid van Moolenbroek dp_init(dep, instance);
146433d6423SLionel Sambuc
147*f7df02e7SDavid van Moolenbroek memcpy(addr, dep->de_address.na_addr, sizeof(*addr));
148*f7df02e7SDavid van Moolenbroek *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
149*f7df02e7SDavid van Moolenbroek *ticks = sys_hz(); /* update statistics once a second */
1503913e490SDavid van Moolenbroek return OK;
151433d6423SLionel Sambuc }
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc #if 0
154433d6423SLionel Sambuc /*===========================================================================*
155433d6423SLionel Sambuc * dp8390_dump *
156433d6423SLionel Sambuc *===========================================================================*/
1573913e490SDavid van Moolenbroek void dp8390_dump(void)
158433d6423SLionel Sambuc {
159433d6423SLionel Sambuc dpeth_t *dep;
160433d6423SLionel Sambuc int isr;
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc dep = &de_state;
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc printf("\n");
165*f7df02e7SDavid van Moolenbroek printf("dp8390 statistics of %s:\n", netdriver_name());
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc isr= inb_reg0(dep, DP_ISR);
168433d6423SLionel Sambuc printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr,
169433d6423SLionel Sambuc inb_reg0(dep, DP_ISR), dep->de_flags);
170433d6423SLionel Sambuc }
171433d6423SLionel Sambuc #endif
172433d6423SLionel Sambuc
173433d6423SLionel Sambuc /*===========================================================================*
174*f7df02e7SDavid van Moolenbroek * pci_env *
175*f7df02e7SDavid van Moolenbroek *===========================================================================*/
pci_env(unsigned int instance)176*f7df02e7SDavid van Moolenbroek static int pci_env(unsigned int instance)
177*f7df02e7SDavid van Moolenbroek {
178*f7df02e7SDavid van Moolenbroek char envvar[16], value[EP_BUF_SIZE];
179*f7df02e7SDavid van Moolenbroek const char punct[] = ":,;.";
180*f7df02e7SDavid van Moolenbroek
181*f7df02e7SDavid van Moolenbroek strlcpy(envvar, "DPETH0", sizeof(envvar));
182*f7df02e7SDavid van Moolenbroek envvar[5] += instance;
183*f7df02e7SDavid van Moolenbroek
184*f7df02e7SDavid van Moolenbroek /* If no setting with this name is present, default to PCI. */
185*f7df02e7SDavid van Moolenbroek if (env_get_param(envvar, value, sizeof(value)) != 0)
186*f7df02e7SDavid van Moolenbroek return TRUE;
187*f7df02e7SDavid van Moolenbroek
188*f7df02e7SDavid van Moolenbroek /* Legacy support: check for a "pci" prefix. */
189*f7df02e7SDavid van Moolenbroek return (strncmp(value, "pci", 3) == 0 &&
190*f7df02e7SDavid van Moolenbroek strchr(punct, value[3]) != NULL);
191*f7df02e7SDavid van Moolenbroek }
192*f7df02e7SDavid van Moolenbroek
193*f7df02e7SDavid van Moolenbroek /*===========================================================================*
194433d6423SLionel Sambuc * pci_conf *
195433d6423SLionel Sambuc *===========================================================================*/
pci_conf(unsigned int instance)196*f7df02e7SDavid van Moolenbroek static void pci_conf(unsigned int instance)
197433d6423SLionel Sambuc {
198433d6423SLionel Sambuc struct dpeth *dep;
199*f7df02e7SDavid van Moolenbroek unsigned int i, pci_instance;
200433d6423SLionel Sambuc
201433d6423SLionel Sambuc dep= &de_state;
202433d6423SLionel Sambuc
203*f7df02e7SDavid van Moolenbroek if (!(dep->de_pci= pci_env(instance)))
204433d6423SLionel Sambuc return; /* no PCI config */
205433d6423SLionel Sambuc
206433d6423SLionel Sambuc /* Count the number of dp instances before this one that are configured
207433d6423SLionel Sambuc * for PCI, so that we can skip that many when enumerating PCI devices.
208433d6423SLionel Sambuc */
209433d6423SLionel Sambuc pci_instance= 0;
210*f7df02e7SDavid van Moolenbroek for (i= 0; i < instance; i++) {
211*f7df02e7SDavid van Moolenbroek if (pci_env(i))
212433d6423SLionel Sambuc pci_instance++;
213433d6423SLionel Sambuc }
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc if (!rtl_probe(dep, pci_instance))
2163913e490SDavid van Moolenbroek panic("no matching PCI device found");
217433d6423SLionel Sambuc }
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc /*===========================================================================*
2203913e490SDavid van Moolenbroek * do_send *
221433d6423SLionel Sambuc *===========================================================================*/
do_send(struct netdriver_data * data,size_t size)2223913e490SDavid van Moolenbroek static int do_send(struct netdriver_data *data, size_t size)
223433d6423SLionel Sambuc {
224433d6423SLionel Sambuc int sendq_head;
225433d6423SLionel Sambuc dpeth_t *dep;
226433d6423SLionel Sambuc
227433d6423SLionel Sambuc dep= &de_state;
228433d6423SLionel Sambuc
229433d6423SLionel Sambuc sendq_head= dep->de_sendq_head;
230433d6423SLionel Sambuc if (dep->de_sendq[sendq_head].sq_filled)
2313913e490SDavid van Moolenbroek return SUSPEND;
232433d6423SLionel Sambuc
2333913e490SDavid van Moolenbroek (dep->de_user2nicf_s)(dep, data,
2343913e490SDavid van Moolenbroek dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE, 0, size);
235433d6423SLionel Sambuc
236433d6423SLionel Sambuc dep->de_sendq[sendq_head].sq_filled= TRUE;
237433d6423SLionel Sambuc if (dep->de_sendq_tail == sendq_head)
238433d6423SLionel Sambuc {
239433d6423SLionel Sambuc outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
240433d6423SLionel Sambuc outb_reg0(dep, DP_TBCR1, size >> 8);
241433d6423SLionel Sambuc outb_reg0(dep, DP_TBCR0, size & 0xff);
242433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);/* there it goes.. */
243433d6423SLionel Sambuc }
244433d6423SLionel Sambuc else
245433d6423SLionel Sambuc dep->de_sendq[sendq_head].sq_size= size;
246433d6423SLionel Sambuc
247433d6423SLionel Sambuc if (++sendq_head == dep->de_sendq_nr)
248433d6423SLionel Sambuc sendq_head= 0;
249433d6423SLionel Sambuc assert(sendq_head < SENDQ_NR);
250433d6423SLionel Sambuc dep->de_sendq_head= sendq_head;
251433d6423SLionel Sambuc
2523913e490SDavid van Moolenbroek return OK;
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc
255433d6423SLionel Sambuc /*===========================================================================*
256*f7df02e7SDavid van Moolenbroek * do_set_mode *
257433d6423SLionel Sambuc *===========================================================================*/
do_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)258*f7df02e7SDavid van Moolenbroek static void do_set_mode(unsigned int mode,
259*f7df02e7SDavid van Moolenbroek const netdriver_addr_t * mcast_list __unused,
260*f7df02e7SDavid van Moolenbroek unsigned int mcast_count __unused)
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc dpeth_t *dep;
2633913e490SDavid van Moolenbroek int dp_rcr_reg;
264433d6423SLionel Sambuc
265433d6423SLionel Sambuc dep = &de_state;
266433d6423SLionel Sambuc
2673913e490SDavid van Moolenbroek outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
268433d6423SLionel Sambuc
2693913e490SDavid van Moolenbroek dp_rcr_reg = 0;
270*f7df02e7SDavid van Moolenbroek if (mode & NDEV_MODE_PROMISC)
2713913e490SDavid van Moolenbroek dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
272*f7df02e7SDavid van Moolenbroek if (mode & NDEV_MODE_BCAST)
2733913e490SDavid van Moolenbroek dp_rcr_reg |= RCR_AB;
274*f7df02e7SDavid van Moolenbroek if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
2753913e490SDavid van Moolenbroek dp_rcr_reg |= RCR_AM;
2763913e490SDavid van Moolenbroek outb_reg0(dep, DP_RCR, dp_rcr_reg);
277433d6423SLionel Sambuc }
278433d6423SLionel Sambuc
279433d6423SLionel Sambuc /*===========================================================================*
280*f7df02e7SDavid van Moolenbroek * dp_update_stats *
281433d6423SLionel Sambuc *===========================================================================*/
dp_update_stats(dpeth_t * dep)282*f7df02e7SDavid van Moolenbroek static void dp_update_stats(dpeth_t * dep)
283433d6423SLionel Sambuc {
284433d6423SLionel Sambuc
285*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(inb_reg0(dep, DP_CNTR0));
286*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(inb_reg0(dep, DP_CNTR1));
287*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(inb_reg0(dep, DP_CNTR2));
288*f7df02e7SDavid van Moolenbroek }
289433d6423SLionel Sambuc
290*f7df02e7SDavid van Moolenbroek /*===========================================================================*
291*f7df02e7SDavid van Moolenbroek * do_tick *
292*f7df02e7SDavid van Moolenbroek *===========================================================================*/
do_tick(void)293*f7df02e7SDavid van Moolenbroek static void do_tick(void)
294*f7df02e7SDavid van Moolenbroek {
295433d6423SLionel Sambuc
296*f7df02e7SDavid van Moolenbroek dp_update_stats(&de_state);
297433d6423SLionel Sambuc }
298433d6423SLionel Sambuc
299433d6423SLionel Sambuc /*===========================================================================*
3003913e490SDavid van Moolenbroek * do_stop *
301433d6423SLionel Sambuc *===========================================================================*/
do_stop(void)3023913e490SDavid van Moolenbroek static void do_stop(void)
303433d6423SLionel Sambuc {
3043913e490SDavid van Moolenbroek dpeth_t *dep;
305433d6423SLionel Sambuc
3063913e490SDavid van Moolenbroek dep = &de_state;
307433d6423SLionel Sambuc
308433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
309433d6423SLionel Sambuc (dep->de_stopf)(dep);
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc /*===========================================================================*
313433d6423SLionel Sambuc * dp_init *
314433d6423SLionel Sambuc *===========================================================================*/
dp_init(dpeth_t * dep,unsigned int instance)315*f7df02e7SDavid van Moolenbroek static void dp_init(dpeth_t *dep, unsigned int instance)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc int i, r;
318433d6423SLionel Sambuc
319433d6423SLionel Sambuc /* General initialization */
320433d6423SLionel Sambuc dep->de_flags = DEF_EMPTY;
321433d6423SLionel Sambuc (*dep->de_initf)(dep);
322433d6423SLionel Sambuc
323*f7df02e7SDavid van Moolenbroek dp_confaddr(dep, instance);
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc if (debug)
326433d6423SLionel Sambuc {
327*f7df02e7SDavid van Moolenbroek printf("%s: Ethernet address ", netdriver_name());
328433d6423SLionel Sambuc for (i= 0; i < 6; i++)
329*f7df02e7SDavid van Moolenbroek printf("%x%c", dep->de_address.na_addr[i],
330433d6423SLionel Sambuc i < 5 ? ':' : '\n');
331433d6423SLionel Sambuc }
332433d6423SLionel Sambuc
333433d6423SLionel Sambuc /* Map buffer */
334433d6423SLionel Sambuc map_hw_buffer(dep);
335433d6423SLionel Sambuc
336433d6423SLionel Sambuc /* Initialization of the dp8390 following the mandatory procedure
337433d6423SLionel Sambuc * in reference manual ("DP8390D/NS32490D NIC Network Interface
338433d6423SLionel Sambuc * Controller", National Semiconductor, July 1995, Page 29).
339433d6423SLionel Sambuc */
340433d6423SLionel Sambuc /* Step 1: */
341433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
342433d6423SLionel Sambuc /* Step 2: */
343433d6423SLionel Sambuc if (dep->de_16bit)
344433d6423SLionel Sambuc outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
345433d6423SLionel Sambuc else
346433d6423SLionel Sambuc outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS);
347433d6423SLionel Sambuc /* Step 3: */
348433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, 0);
349433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, 0);
350433d6423SLionel Sambuc /* Step 4: */
3513913e490SDavid van Moolenbroek outb_reg0(dep, DP_RCR, 0);
352433d6423SLionel Sambuc /* Step 5: */
353433d6423SLionel Sambuc outb_reg0(dep, DP_TCR, TCR_INTERNAL);
354433d6423SLionel Sambuc /* Step 6: */
355433d6423SLionel Sambuc outb_reg0(dep, DP_BNRY, dep->de_startpage);
356433d6423SLionel Sambuc outb_reg0(dep, DP_PSTART, dep->de_startpage);
357433d6423SLionel Sambuc outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
358433d6423SLionel Sambuc /* Step 7: */
359433d6423SLionel Sambuc outb_reg0(dep, DP_ISR, 0xFF);
360433d6423SLionel Sambuc /* Step 8: */
361433d6423SLionel Sambuc outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE |
362433d6423SLionel Sambuc IMR_OVWE | IMR_CNTE);
363433d6423SLionel Sambuc /* Step 9: */
364433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
365433d6423SLionel Sambuc
366*f7df02e7SDavid van Moolenbroek outb_reg1(dep, DP_PAR0, dep->de_address.na_addr[0]);
367*f7df02e7SDavid van Moolenbroek outb_reg1(dep, DP_PAR1, dep->de_address.na_addr[1]);
368*f7df02e7SDavid van Moolenbroek outb_reg1(dep, DP_PAR2, dep->de_address.na_addr[2]);
369*f7df02e7SDavid van Moolenbroek outb_reg1(dep, DP_PAR3, dep->de_address.na_addr[3]);
370*f7df02e7SDavid van Moolenbroek outb_reg1(dep, DP_PAR4, dep->de_address.na_addr[4]);
371*f7df02e7SDavid van Moolenbroek outb_reg1(dep, DP_PAR5, dep->de_address.na_addr[5]);
372433d6423SLionel Sambuc
373433d6423SLionel Sambuc outb_reg1(dep, DP_MAR0, 0xff);
374433d6423SLionel Sambuc outb_reg1(dep, DP_MAR1, 0xff);
375433d6423SLionel Sambuc outb_reg1(dep, DP_MAR2, 0xff);
376433d6423SLionel Sambuc outb_reg1(dep, DP_MAR3, 0xff);
377433d6423SLionel Sambuc outb_reg1(dep, DP_MAR4, 0xff);
378433d6423SLionel Sambuc outb_reg1(dep, DP_MAR5, 0xff);
379433d6423SLionel Sambuc outb_reg1(dep, DP_MAR6, 0xff);
380433d6423SLionel Sambuc outb_reg1(dep, DP_MAR7, 0xff);
381433d6423SLionel Sambuc
382433d6423SLionel Sambuc outb_reg1(dep, DP_CURR, dep->de_startpage + 1);
383433d6423SLionel Sambuc /* Step 10: */
384433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA);
385433d6423SLionel Sambuc /* Step 11: */
386433d6423SLionel Sambuc outb_reg0(dep, DP_TCR, TCR_NORMAL);
387433d6423SLionel Sambuc
388433d6423SLionel Sambuc inb_reg0(dep, DP_CNTR0); /* reset counters by reading */
389433d6423SLionel Sambuc inb_reg0(dep, DP_CNTR1);
390433d6423SLionel Sambuc inb_reg0(dep, DP_CNTR2);
391433d6423SLionel Sambuc
392433d6423SLionel Sambuc /* Finish the initialization. */
393433d6423SLionel Sambuc for (i= 0; i<dep->de_sendq_nr; i++)
394433d6423SLionel Sambuc dep->de_sendq[i].sq_filled= 0;
395433d6423SLionel Sambuc dep->de_sendq_head= 0;
396433d6423SLionel Sambuc dep->de_sendq_tail= 0;
397433d6423SLionel Sambuc if (!dep->de_prog_IO)
398433d6423SLionel Sambuc {
399433d6423SLionel Sambuc dep->de_user2nicf_s= dp_user2nic_s;
400433d6423SLionel Sambuc dep->de_nic2userf_s= dp_nic2user_s;
401433d6423SLionel Sambuc dep->de_getblockf= dp_getblock;
402433d6423SLionel Sambuc }
403433d6423SLionel Sambuc else if (dep->de_16bit)
404433d6423SLionel Sambuc {
405433d6423SLionel Sambuc dep->de_user2nicf_s= dp_pio16_user2nic_s;
406433d6423SLionel Sambuc dep->de_nic2userf_s= dp_pio16_nic2user_s;
407433d6423SLionel Sambuc dep->de_getblockf= dp_pio16_getblock;
408433d6423SLionel Sambuc }
409433d6423SLionel Sambuc else
410433d6423SLionel Sambuc {
411433d6423SLionel Sambuc dep->de_user2nicf_s= dp_pio8_user2nic_s;
412433d6423SLionel Sambuc dep->de_nic2userf_s= dp_pio8_nic2user_s;
413433d6423SLionel Sambuc dep->de_getblockf= dp_pio8_getblock;
414433d6423SLionel Sambuc }
415433d6423SLionel Sambuc
416433d6423SLionel Sambuc /* Set the interrupt handler and policy. Do not automatically
417433d6423SLionel Sambuc * reenable interrupts. Return the IRQ line number on interrupts.
418433d6423SLionel Sambuc */
419433d6423SLionel Sambuc dep->de_hook = dep->de_irq;
420433d6423SLionel Sambuc r= sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
421433d6423SLionel Sambuc if (r != OK)
422433d6423SLionel Sambuc panic("sys_irqsetpolicy failed: %d", r);
423433d6423SLionel Sambuc
424433d6423SLionel Sambuc r= sys_irqenable(&dep->de_hook);
425433d6423SLionel Sambuc if (r != OK)
4263913e490SDavid van Moolenbroek panic("unable to enable interrupts: %d", r);
427433d6423SLionel Sambuc }
428433d6423SLionel Sambuc
429433d6423SLionel Sambuc /*===========================================================================*
430433d6423SLionel Sambuc * dp_confaddr *
431433d6423SLionel Sambuc *===========================================================================*/
dp_confaddr(dpeth_t * dep,unsigned int instance)432*f7df02e7SDavid van Moolenbroek static void dp_confaddr(dpeth_t *dep, unsigned int instance)
433433d6423SLionel Sambuc {
434433d6423SLionel Sambuc int i;
435433d6423SLionel Sambuc char eakey[16];
436433d6423SLionel Sambuc static char eafmt[]= "x:x:x:x:x:x";
437433d6423SLionel Sambuc long v;
438433d6423SLionel Sambuc
439433d6423SLionel Sambuc /* User defined ethernet address? */
440433d6423SLionel Sambuc strlcpy(eakey, "DPETH0_EA", sizeof(eakey));
441*f7df02e7SDavid van Moolenbroek eakey[5] += instance;
442433d6423SLionel Sambuc
443433d6423SLionel Sambuc for (i= 0; i < 6; i++)
444433d6423SLionel Sambuc {
445*f7df02e7SDavid van Moolenbroek v= dep->de_address.na_addr[i];
446433d6423SLionel Sambuc if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
447433d6423SLionel Sambuc {
448433d6423SLionel Sambuc break;
449433d6423SLionel Sambuc }
450*f7df02e7SDavid van Moolenbroek dep->de_address.na_addr[i]= v;
451433d6423SLionel Sambuc }
452433d6423SLionel Sambuc
453433d6423SLionel Sambuc if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
454433d6423SLionel Sambuc }
455433d6423SLionel Sambuc
456433d6423SLionel Sambuc /*===========================================================================*
457433d6423SLionel Sambuc * dp_reset *
458433d6423SLionel Sambuc *===========================================================================*/
dp_reset(dpeth_t * dep)4593913e490SDavid van Moolenbroek static void dp_reset(dpeth_t *dep)
460433d6423SLionel Sambuc {
461433d6423SLionel Sambuc int i;
462433d6423SLionel Sambuc
463433d6423SLionel Sambuc /* Stop chip */
464433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
465433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, 0);
466433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, 0);
467433d6423SLionel Sambuc for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
468433d6423SLionel Sambuc ; /* Do nothing */
469433d6423SLionel Sambuc outb_reg0(dep, DP_TCR, TCR_1EXTERNAL|TCR_OFST);
470433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_STA|CR_DM_ABORT);
471433d6423SLionel Sambuc outb_reg0(dep, DP_TCR, TCR_NORMAL);
472433d6423SLionel Sambuc
473433d6423SLionel Sambuc /* Acknowledge the ISR_RDC (remote dma) interrupt. */
474433d6423SLionel Sambuc for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); i++)
475433d6423SLionel Sambuc ; /* Do nothing */
476433d6423SLionel Sambuc outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~ISR_RDC);
477433d6423SLionel Sambuc
478433d6423SLionel Sambuc /* Reset the transmit ring. If we were transmitting a packet, we
479433d6423SLionel Sambuc * pretend that the packet is processed. Higher layers will
480433d6423SLionel Sambuc * retransmit if the packet wasn't actually sent.
481433d6423SLionel Sambuc */
482433d6423SLionel Sambuc dep->de_sendq_head= dep->de_sendq_tail= 0;
483433d6423SLionel Sambuc for (i= 0; i<dep->de_sendq_nr; i++)
484433d6423SLionel Sambuc dep->de_sendq[i].sq_filled= 0;
4853913e490SDavid van Moolenbroek netdriver_send();
486433d6423SLionel Sambuc dep->de_flags &= ~DEF_STOPPED;
487433d6423SLionel Sambuc }
488433d6423SLionel Sambuc
489433d6423SLionel Sambuc /*===========================================================================*
4903913e490SDavid van Moolenbroek * do_intr *
491433d6423SLionel Sambuc *===========================================================================*/
do_intr(unsigned int __unused mask)4923913e490SDavid van Moolenbroek static void do_intr(unsigned int __unused mask)
493433d6423SLionel Sambuc {
4943913e490SDavid van Moolenbroek dpeth_t *dep;
495433d6423SLionel Sambuc int isr, tsr;
4963913e490SDavid van Moolenbroek int r, size, sendq_tail;
497433d6423SLionel Sambuc
4983913e490SDavid van Moolenbroek dep = &de_state;
499433d6423SLionel Sambuc
500433d6423SLionel Sambuc for(;;)
501433d6423SLionel Sambuc {
502433d6423SLionel Sambuc isr = inb_reg0(dep, DP_ISR);
503433d6423SLionel Sambuc if (!isr)
504433d6423SLionel Sambuc break;
505433d6423SLionel Sambuc outb_reg0(dep, DP_ISR, isr);
506433d6423SLionel Sambuc if (isr & (ISR_PTX|ISR_TXE))
507433d6423SLionel Sambuc {
508433d6423SLionel Sambuc if (isr & ISR_TXE)
509433d6423SLionel Sambuc {
510433d6423SLionel Sambuc #if DEBUG
511*f7df02e7SDavid van Moolenbroek printf("%s: got send error\n",
512*f7df02e7SDavid van Moolenbroek netdriver_name());
513433d6423SLionel Sambuc #endif
514*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(1);
515433d6423SLionel Sambuc }
516433d6423SLionel Sambuc else
517433d6423SLionel Sambuc {
518433d6423SLionel Sambuc tsr = inb_reg0(dep, DP_TSR);
519433d6423SLionel Sambuc
520*f7df02e7SDavid van Moolenbroek if (tsr & TSR_PTX) {
521*f7df02e7SDavid van Moolenbroek /* Transmission was successful. */
522*f7df02e7SDavid van Moolenbroek }
523433d6423SLionel Sambuc #if 0 /* Reserved in later manuals, should be ignored */
524433d6423SLionel Sambuc if (!(tsr & TSR_DFR))
525433d6423SLionel Sambuc {
526433d6423SLionel Sambuc /* In most (all?) implementations of
527433d6423SLionel Sambuc * the dp8390, this bit is set
528433d6423SLionel Sambuc * when the packet is not deferred
529433d6423SLionel Sambuc */
530433d6423SLionel Sambuc }
531433d6423SLionel Sambuc #endif
532*f7df02e7SDavid van Moolenbroek if (tsr & TSR_COL) netdriver_stat_coll(1);
533433d6423SLionel Sambuc }
534433d6423SLionel Sambuc sendq_tail= dep->de_sendq_tail;
535433d6423SLionel Sambuc
536433d6423SLionel Sambuc if (!(dep->de_sendq[sendq_tail].sq_filled))
537433d6423SLionel Sambuc {
538433d6423SLionel Sambuc /* Software bug? */
539433d6423SLionel Sambuc assert(!debug);
540433d6423SLionel Sambuc
541433d6423SLionel Sambuc /* Or hardware bug? */
542433d6423SLionel Sambuc printf(
543433d6423SLionel Sambuc "%s: transmit interrupt, but not sending\n",
544*f7df02e7SDavid van Moolenbroek netdriver_name());
545433d6423SLionel Sambuc continue;
546433d6423SLionel Sambuc }
547433d6423SLionel Sambuc dep->de_sendq[sendq_tail].sq_filled= 0;
548433d6423SLionel Sambuc if (++sendq_tail == dep->de_sendq_nr)
549433d6423SLionel Sambuc sendq_tail= 0;
550433d6423SLionel Sambuc dep->de_sendq_tail= sendq_tail;
551433d6423SLionel Sambuc if (dep->de_sendq[sendq_tail].sq_filled)
552433d6423SLionel Sambuc {
553433d6423SLionel Sambuc size= dep->de_sendq[sendq_tail].sq_size;
554433d6423SLionel Sambuc outb_reg0(dep, DP_TPSR,
555433d6423SLionel Sambuc dep->de_sendq[sendq_tail].sq_sendpage);
556433d6423SLionel Sambuc outb_reg0(dep, DP_TBCR1, size >> 8);
557433d6423SLionel Sambuc outb_reg0(dep, DP_TBCR0, size & 0xff);
558433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);
559433d6423SLionel Sambuc }
5603913e490SDavid van Moolenbroek netdriver_send();
561433d6423SLionel Sambuc }
562433d6423SLionel Sambuc
563433d6423SLionel Sambuc if (isr & ISR_PRX)
5643913e490SDavid van Moolenbroek netdriver_recv();
565433d6423SLionel Sambuc
566*f7df02e7SDavid van Moolenbroek if (isr & ISR_RXE)
567*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(1);
568433d6423SLionel Sambuc if (isr & ISR_CNT)
569*f7df02e7SDavid van Moolenbroek dp_update_stats(dep);
570433d6423SLionel Sambuc if (isr & ISR_RDC)
571433d6423SLionel Sambuc {
572433d6423SLionel Sambuc /* Nothing to do */
573433d6423SLionel Sambuc }
574433d6423SLionel Sambuc if (isr & ISR_RST)
575433d6423SLionel Sambuc {
576433d6423SLionel Sambuc /* this means we got an interrupt but the ethernet
577433d6423SLionel Sambuc * chip is shutdown. We set the flag DEF_STOPPED,
578433d6423SLionel Sambuc * and continue processing arrived packets. When the
579433d6423SLionel Sambuc * receive buffer is empty, we reset the dp8390.
580433d6423SLionel Sambuc */
581433d6423SLionel Sambuc #if 0
582433d6423SLionel Sambuc { printW(); printf(
583*f7df02e7SDavid van Moolenbroek "%s: NIC stopped\n", netdriver_name()); }
584433d6423SLionel Sambuc #endif
585433d6423SLionel Sambuc dep->de_flags |= DEF_STOPPED;
5863913e490SDavid van Moolenbroek netdriver_recv(); /* see if we can reset right now */
587433d6423SLionel Sambuc break;
588433d6423SLionel Sambuc }
589433d6423SLionel Sambuc }
5903913e490SDavid van Moolenbroek
5913913e490SDavid van Moolenbroek if ((r = sys_irqenable(&dep->de_hook)) != OK)
5923913e490SDavid van Moolenbroek panic("unable enable interrupts: %d", r);
593433d6423SLionel Sambuc }
594433d6423SLionel Sambuc
595433d6423SLionel Sambuc /*===========================================================================*
5963913e490SDavid van Moolenbroek * do_recv *
597433d6423SLionel Sambuc *===========================================================================*/
do_recv(struct netdriver_data * data,size_t max)5983913e490SDavid van Moolenbroek static ssize_t do_recv(struct netdriver_data *data, size_t max)
599433d6423SLionel Sambuc {
6003913e490SDavid van Moolenbroek dpeth_t *dep;
601433d6423SLionel Sambuc dp_rcvhdr_t header;
602433d6423SLionel Sambuc unsigned pageno, curr, next;
6033913e490SDavid van Moolenbroek size_t length;
6043913e490SDavid van Moolenbroek int packet_processed;
605433d6423SLionel Sambuc u16_t eth_type;
606433d6423SLionel Sambuc
6073913e490SDavid van Moolenbroek dep = &de_state;
6083913e490SDavid van Moolenbroek
609433d6423SLionel Sambuc packet_processed = FALSE;
610433d6423SLionel Sambuc pageno = inb_reg0(dep, DP_BNRY) + 1;
611433d6423SLionel Sambuc if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
612433d6423SLionel Sambuc
613433d6423SLionel Sambuc do
614433d6423SLionel Sambuc {
615433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P1 | CR_EXTRA);
616433d6423SLionel Sambuc curr = inb_reg1(dep, DP_CURR);
617433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
618433d6423SLionel Sambuc
6193913e490SDavid van Moolenbroek if (curr == pageno) {
6203913e490SDavid van Moolenbroek if (dep->de_flags & DEF_STOPPED) {
6213913e490SDavid van Moolenbroek /* The chip is stopped, and all arrived packets
6223913e490SDavid van Moolenbroek * are delivered.
6233913e490SDavid van Moolenbroek */
6243913e490SDavid van Moolenbroek dp_reset(dep);
6253913e490SDavid van Moolenbroek }
6263913e490SDavid van Moolenbroek
6273913e490SDavid van Moolenbroek return SUSPEND;
6283913e490SDavid van Moolenbroek }
629433d6423SLionel Sambuc
630433d6423SLionel Sambuc (dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header),
631433d6423SLionel Sambuc &header);
632433d6423SLionel Sambuc (dep->de_getblockf)(dep, pageno, sizeof(header) +
633*f7df02e7SDavid van Moolenbroek 2*sizeof(netdriver_addr_t), sizeof(eth_type),
634*f7df02e7SDavid van Moolenbroek ð_type);
635433d6423SLionel Sambuc
636433d6423SLionel Sambuc length = (header.dr_rbcl | (header.dr_rbch << 8)) -
637433d6423SLionel Sambuc sizeof(dp_rcvhdr_t);
638433d6423SLionel Sambuc next = header.dr_next;
639*f7df02e7SDavid van Moolenbroek if (length < NDEV_ETH_PACKET_MIN || length > max)
640433d6423SLionel Sambuc {
641433d6423SLionel Sambuc printf("%s: packet with strange length arrived: %d\n",
642*f7df02e7SDavid van Moolenbroek netdriver_name(), (int) length);
643433d6423SLionel Sambuc next= curr;
644433d6423SLionel Sambuc }
645433d6423SLionel Sambuc else if (next < dep->de_startpage || next >= dep->de_stoppage)
646433d6423SLionel Sambuc {
647*f7df02e7SDavid van Moolenbroek printf("%s: strange next page\n", netdriver_name());
648433d6423SLionel Sambuc next= curr;
649433d6423SLionel Sambuc }
650433d6423SLionel Sambuc else if (header.dr_status & RSR_FO)
651433d6423SLionel Sambuc {
652433d6423SLionel Sambuc /* This is very serious, so we issue a warning and
653433d6423SLionel Sambuc * reset the buffers */
654433d6423SLionel Sambuc printf("%s: fifo overrun, resetting receive buffer\n",
655*f7df02e7SDavid van Moolenbroek netdriver_name());
656*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(1);
657433d6423SLionel Sambuc next = curr;
658433d6423SLionel Sambuc }
6593913e490SDavid van Moolenbroek else if (header.dr_status & RSR_PRX)
660433d6423SLionel Sambuc {
6613913e490SDavid van Moolenbroek dp_pkt2user_s(dep, data, pageno, length);
662433d6423SLionel Sambuc
663433d6423SLionel Sambuc packet_processed = TRUE;
664433d6423SLionel Sambuc }
665433d6423SLionel Sambuc if (next == dep->de_startpage)
666433d6423SLionel Sambuc outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
667433d6423SLionel Sambuc else
668433d6423SLionel Sambuc outb_reg0(dep, DP_BNRY, next - 1);
669433d6423SLionel Sambuc
670433d6423SLionel Sambuc pageno = next;
6713913e490SDavid van Moolenbroek } while (!packet_processed);
672433d6423SLionel Sambuc
6733913e490SDavid van Moolenbroek return length;
674433d6423SLionel Sambuc }
675433d6423SLionel Sambuc
676433d6423SLionel Sambuc /*===========================================================================*
677433d6423SLionel Sambuc * dp_getblock *
678433d6423SLionel Sambuc *===========================================================================*/
dp_getblock(dpeth_t * dep,int page,size_t offset,size_t size,void * dst)6793913e490SDavid van Moolenbroek static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size,
6803913e490SDavid van Moolenbroek void *dst)
681433d6423SLionel Sambuc {
682433d6423SLionel Sambuc offset = page * DP_PAGESIZE + offset;
683433d6423SLionel Sambuc
684433d6423SLionel Sambuc memcpy(dst, dep->de_locmem + offset, size);
685433d6423SLionel Sambuc }
686433d6423SLionel Sambuc
687433d6423SLionel Sambuc /*===========================================================================*
688433d6423SLionel Sambuc * dp_pio8_getblock *
689433d6423SLionel Sambuc *===========================================================================*/
dp_pio8_getblock(dpeth_t * dep,int page,size_t offset,size_t size,void * dst)6903913e490SDavid van Moolenbroek static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset,
6913913e490SDavid van Moolenbroek size_t size, void *dst)
692433d6423SLionel Sambuc {
693433d6423SLionel Sambuc offset = page * DP_PAGESIZE + offset;
694433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, size & 0xFF);
695433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, size >> 8);
696433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR0, offset & 0xFF);
697433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR1, offset >> 8);
698433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
699433d6423SLionel Sambuc
700433d6423SLionel Sambuc insb(dep->de_data_port, dst, size);
701433d6423SLionel Sambuc }
702433d6423SLionel Sambuc
703433d6423SLionel Sambuc /*===========================================================================*
704433d6423SLionel Sambuc * dp_pio16_getblock *
705433d6423SLionel Sambuc *===========================================================================*/
dp_pio16_getblock(dpeth_t * dep,int page,size_t offset,size_t size,void * dst)7063913e490SDavid van Moolenbroek static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset,
7073913e490SDavid van Moolenbroek size_t size, void *dst)
708433d6423SLionel Sambuc {
709433d6423SLionel Sambuc offset = page * DP_PAGESIZE + offset;
710433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, size & 0xFF);
711433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, size >> 8);
712433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR0, offset & 0xFF);
713433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR1, offset >> 8);
714433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
715433d6423SLionel Sambuc
716433d6423SLionel Sambuc assert (!(size & 1));
717433d6423SLionel Sambuc insw(dep->de_data_port, dst, size);
718433d6423SLionel Sambuc }
719433d6423SLionel Sambuc
720433d6423SLionel Sambuc /*===========================================================================*
721433d6423SLionel Sambuc * dp_pkt2user_s *
722433d6423SLionel Sambuc *===========================================================================*/
dp_pkt2user_s(dpeth_t * dep,struct netdriver_data * data,int page,size_t length)7233913e490SDavid van Moolenbroek static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page,
7243913e490SDavid van Moolenbroek size_t length)
725433d6423SLionel Sambuc {
726*f7df02e7SDavid van Moolenbroek unsigned int last, count;
727433d6423SLionel Sambuc
728433d6423SLionel Sambuc last = page + (length - 1) / DP_PAGESIZE;
729433d6423SLionel Sambuc if (last >= dep->de_stoppage)
730433d6423SLionel Sambuc {
731433d6423SLionel Sambuc count = (dep->de_stoppage - page) * DP_PAGESIZE -
732433d6423SLionel Sambuc sizeof(dp_rcvhdr_t);
733433d6423SLionel Sambuc
7343913e490SDavid van Moolenbroek (dep->de_nic2userf_s)(dep, data,
7353913e490SDavid van Moolenbroek page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, count);
7363913e490SDavid van Moolenbroek (dep->de_nic2userf_s)(dep, data,
7373913e490SDavid van Moolenbroek dep->de_startpage * DP_PAGESIZE, count, length - count);
738433d6423SLionel Sambuc }
739433d6423SLionel Sambuc else
740433d6423SLionel Sambuc {
7413913e490SDavid van Moolenbroek (dep->de_nic2userf_s)(dep, data,
7423913e490SDavid van Moolenbroek page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, length);
743433d6423SLionel Sambuc }
744433d6423SLionel Sambuc }
745433d6423SLionel Sambuc
746433d6423SLionel Sambuc /*===========================================================================*
747433d6423SLionel Sambuc * dp_user2nic_s *
748433d6423SLionel Sambuc *===========================================================================*/
dp_user2nic_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)7493913e490SDavid van Moolenbroek static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
7503913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count)
751433d6423SLionel Sambuc {
7523913e490SDavid van Moolenbroek netdriver_copyin(data, offset, dep->de_locmem + nic_addr, count);
753433d6423SLionel Sambuc }
754433d6423SLionel Sambuc
755433d6423SLionel Sambuc /*===========================================================================*
756433d6423SLionel Sambuc * dp_pio8_user2nic_s *
757433d6423SLionel Sambuc *===========================================================================*/
dp_pio8_user2nic_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)7583913e490SDavid van Moolenbroek static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
7593913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count)
760433d6423SLionel Sambuc {
7613913e490SDavid van Moolenbroek int i;
762433d6423SLionel Sambuc
763433d6423SLionel Sambuc outb_reg0(dep, DP_ISR, ISR_RDC);
764433d6423SLionel Sambuc
765433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, count & 0xFF);
766433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, count >> 8);
767433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
768433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
769433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
770433d6423SLionel Sambuc
7713913e490SDavid van Moolenbroek netdriver_portoutb(data, offset, dep->de_data_port, count);
772433d6423SLionel Sambuc
773433d6423SLionel Sambuc for (i= 0; i<100; i++)
774433d6423SLionel Sambuc {
775433d6423SLionel Sambuc if (inb_reg0(dep, DP_ISR) & ISR_RDC)
776433d6423SLionel Sambuc break;
777433d6423SLionel Sambuc }
778433d6423SLionel Sambuc if (i == 100)
779433d6423SLionel Sambuc {
780433d6423SLionel Sambuc panic("dp8390: remote dma failed to complete");
781433d6423SLionel Sambuc }
782433d6423SLionel Sambuc }
783433d6423SLionel Sambuc
784433d6423SLionel Sambuc /*===========================================================================*
785433d6423SLionel Sambuc * dp_pio16_user2nic_s *
786433d6423SLionel Sambuc *===========================================================================*/
dp_pio16_user2nic_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)7873913e490SDavid van Moolenbroek static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
7883913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count)
789433d6423SLionel Sambuc {
7903913e490SDavid van Moolenbroek size_t ecount;
7913913e490SDavid van Moolenbroek int i;
792433d6423SLionel Sambuc
793433d6423SLionel Sambuc ecount= (count+1) & ~1;
794433d6423SLionel Sambuc
795433d6423SLionel Sambuc outb_reg0(dep, DP_ISR, ISR_RDC);
796433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
797433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, ecount >> 8);
798433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
799433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
800433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
801433d6423SLionel Sambuc
8023913e490SDavid van Moolenbroek netdriver_portoutw(data, offset, dep->de_data_port, count);
803433d6423SLionel Sambuc
804433d6423SLionel Sambuc for (i= 0; i<100; i++)
805433d6423SLionel Sambuc {
806433d6423SLionel Sambuc if (inb_reg0(dep, DP_ISR) & ISR_RDC)
807433d6423SLionel Sambuc break;
808433d6423SLionel Sambuc }
809433d6423SLionel Sambuc if (i == 100)
810433d6423SLionel Sambuc {
811433d6423SLionel Sambuc panic("dp8390: remote dma failed to complete");
812433d6423SLionel Sambuc }
813433d6423SLionel Sambuc }
814433d6423SLionel Sambuc
815433d6423SLionel Sambuc /*===========================================================================*
816433d6423SLionel Sambuc * dp_nic2user_s *
817433d6423SLionel Sambuc *===========================================================================*/
dp_nic2user_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)8183913e490SDavid van Moolenbroek static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
8193913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count)
820433d6423SLionel Sambuc {
8213913e490SDavid van Moolenbroek netdriver_copyout(data, offset, dep->de_locmem + nic_addr, count);
822433d6423SLionel Sambuc }
823433d6423SLionel Sambuc
824433d6423SLionel Sambuc /*===========================================================================*
825433d6423SLionel Sambuc * dp_pio8_nic2user_s *
826433d6423SLionel Sambuc *===========================================================================*/
dp_pio8_nic2user_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)8273913e490SDavid van Moolenbroek static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
8283913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count)
829433d6423SLionel Sambuc {
830433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, count & 0xFF);
831433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, count >> 8);
832433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
833433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
834433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
835433d6423SLionel Sambuc
8363913e490SDavid van Moolenbroek netdriver_portinb(data, offset, dep->de_data_port, count);
837433d6423SLionel Sambuc }
838433d6423SLionel Sambuc
839433d6423SLionel Sambuc /*===========================================================================*
840433d6423SLionel Sambuc * dp_pio16_nic2user_s *
841433d6423SLionel Sambuc *===========================================================================*/
dp_pio16_nic2user_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)8423913e490SDavid van Moolenbroek static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
8433913e490SDavid van Moolenbroek int nic_addr, size_t offset, size_t count)
844433d6423SLionel Sambuc {
8453913e490SDavid van Moolenbroek size_t ecount;
846433d6423SLionel Sambuc
847433d6423SLionel Sambuc ecount= (count+1) & ~1;
848433d6423SLionel Sambuc
849433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
850433d6423SLionel Sambuc outb_reg0(dep, DP_RBCR1, ecount >> 8);
851433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
852433d6423SLionel Sambuc outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
853433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
854433d6423SLionel Sambuc
8553913e490SDavid van Moolenbroek netdriver_portinw(data, offset, dep->de_data_port, count);
856433d6423SLionel Sambuc }
857433d6423SLionel Sambuc
858433d6423SLionel Sambuc /*===========================================================================*
859433d6423SLionel Sambuc * conf_hw *
860433d6423SLionel Sambuc *===========================================================================*/
conf_hw(dpeth_t * dep,unsigned int instance)861*f7df02e7SDavid van Moolenbroek static void conf_hw(dpeth_t *dep, unsigned int instance)
862433d6423SLionel Sambuc {
863433d6423SLionel Sambuc int confnr;
864433d6423SLionel Sambuc dp_conf_t *dcp;
865433d6423SLionel Sambuc
866433d6423SLionel Sambuc /* Pick a default configuration for this instance. */
867*f7df02e7SDavid van Moolenbroek confnr= MIN(instance, DP_CONF_NR-1);
868433d6423SLionel Sambuc
869433d6423SLionel Sambuc dcp= &dp_conf[confnr];
870*f7df02e7SDavid van Moolenbroek update_conf(dep, dcp, instance);
871433d6423SLionel Sambuc if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep))
8723913e490SDavid van Moolenbroek panic("no ethernet card found at 0x%x\n", dep->de_base_port);
873433d6423SLionel Sambuc
874433d6423SLionel Sambuc /* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000;
875433d6423SLionel Sambuc }
876433d6423SLionel Sambuc
877433d6423SLionel Sambuc /*===========================================================================*
878433d6423SLionel Sambuc * update_conf *
879433d6423SLionel Sambuc *===========================================================================*/
update_conf(dpeth_t * dep,dp_conf_t * dcp,unsigned int instance)880*f7df02e7SDavid van Moolenbroek static void update_conf(dpeth_t *dep, dp_conf_t *dcp, unsigned int instance)
881433d6423SLionel Sambuc {
882433d6423SLionel Sambuc long v;
883433d6423SLionel Sambuc static char dpc_fmt[] = "x:d:x:x";
884433d6423SLionel Sambuc char eckey[16];
885433d6423SLionel Sambuc
886433d6423SLionel Sambuc if (dep->de_pci)
887433d6423SLionel Sambuc {
888433d6423SLionel Sambuc /* PCI device is present */
889433d6423SLionel Sambuc return; /* Already configured */
890433d6423SLionel Sambuc }
891433d6423SLionel Sambuc
892433d6423SLionel Sambuc strlcpy(eckey, "DPETH0", sizeof(eckey));
893*f7df02e7SDavid van Moolenbroek eckey[5] += instance;
894433d6423SLionel Sambuc
895433d6423SLionel Sambuc /* Get the default settings and modify them from the environment. */
896433d6423SLionel Sambuc v= dcp->dpc_port;
8973913e490SDavid van Moolenbroek (void) env_parse(eckey, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL);
898433d6423SLionel Sambuc dep->de_base_port= v;
899433d6423SLionel Sambuc
900433d6423SLionel Sambuc v= dcp->dpc_irq | DEI_DEFAULT;
901433d6423SLionel Sambuc (void) env_parse(eckey, dpc_fmt, 1, &v, 0L, (long) NR_IRQ_VECTORS - 1);
902433d6423SLionel Sambuc dep->de_irq= v;
903433d6423SLionel Sambuc
904433d6423SLionel Sambuc v= dcp->dpc_mem;
905433d6423SLionel Sambuc (void) env_parse(eckey, dpc_fmt, 2, &v, 0L, 0xFFFFFL);
906433d6423SLionel Sambuc dep->de_linmem= v;
907433d6423SLionel Sambuc
908433d6423SLionel Sambuc v= 0;
909433d6423SLionel Sambuc (void) env_parse(eckey, dpc_fmt, 3, &v, 0x2000L, 0x8000L);
910433d6423SLionel Sambuc dep->de_ramsize= v;
911433d6423SLionel Sambuc }
912433d6423SLionel Sambuc
913433d6423SLionel Sambuc /*===========================================================================*
914433d6423SLionel Sambuc * map_hw_buffer *
915433d6423SLionel Sambuc *===========================================================================*/
map_hw_buffer(dpeth_t * dep)9163913e490SDavid van Moolenbroek static void map_hw_buffer(dpeth_t *dep)
917433d6423SLionel Sambuc {
918433d6423SLionel Sambuc
919433d6423SLionel Sambuc if (dep->de_prog_IO)
920433d6423SLionel Sambuc {
921433d6423SLionel Sambuc #if 0
922433d6423SLionel Sambuc printf(
923433d6423SLionel Sambuc "map_hw_buffer: programmed I/O, no need to map buffer\n");
924433d6423SLionel Sambuc #endif
925433d6423SLionel Sambuc dep->de_locmem = (char *)-dep->de_ramsize; /* trap errors */
926433d6423SLionel Sambuc return;
927433d6423SLionel Sambuc }
928433d6423SLionel Sambuc
929433d6423SLionel Sambuc dep->de_locmem=
930433d6423SLionel Sambuc vm_map_phys(SELF, (void *) dep->de_linmem, dep->de_ramsize);
931433d6423SLionel Sambuc if (dep->de_locmem == MAP_FAILED)
932433d6423SLionel Sambuc panic("map_hw_buffer: vm_map_phys failed");
933433d6423SLionel Sambuc }
934433d6423SLionel Sambuc
inb(port_t port)935433d6423SLionel Sambuc u8_t inb(port_t port)
936433d6423SLionel Sambuc {
937433d6423SLionel Sambuc int r;
938433d6423SLionel Sambuc u32_t value;
939433d6423SLionel Sambuc
940433d6423SLionel Sambuc r= sys_inb(port, &value);
941433d6423SLionel Sambuc if (r != OK)
942433d6423SLionel Sambuc {
943433d6423SLionel Sambuc printf("inb failed for port 0x%x\n", port);
944433d6423SLionel Sambuc panic("sys_inb failed: %d", r);
945433d6423SLionel Sambuc }
946433d6423SLionel Sambuc return value;
947433d6423SLionel Sambuc }
948433d6423SLionel Sambuc
inw(port_t port)949433d6423SLionel Sambuc u16_t inw(port_t port)
950433d6423SLionel Sambuc {
951433d6423SLionel Sambuc int r;
952433d6423SLionel Sambuc u32_t value;
953433d6423SLionel Sambuc
954433d6423SLionel Sambuc r= sys_inw(port, &value);
955433d6423SLionel Sambuc if (r != OK)
956433d6423SLionel Sambuc panic("sys_inw failed: %d", r);
957433d6423SLionel Sambuc return (u16_t) value;
958433d6423SLionel Sambuc }
959433d6423SLionel Sambuc
outb(port_t port,u8_t value)960433d6423SLionel Sambuc void outb(port_t port, u8_t value)
961433d6423SLionel Sambuc {
962433d6423SLionel Sambuc int r;
963433d6423SLionel Sambuc
964433d6423SLionel Sambuc r= sys_outb(port, value);
965433d6423SLionel Sambuc if (r != OK)
966433d6423SLionel Sambuc panic("sys_outb failed: %d", r);
967433d6423SLionel Sambuc }
968433d6423SLionel Sambuc
outw(port_t port,u16_t value)969433d6423SLionel Sambuc void outw(port_t port, u16_t value)
970433d6423SLionel Sambuc {
971433d6423SLionel Sambuc int r;
972433d6423SLionel Sambuc
973433d6423SLionel Sambuc r= sys_outw(port, value);
974433d6423SLionel Sambuc if (r != OK)
975433d6423SLionel Sambuc panic("sys_outw failed: %d", r);
976433d6423SLionel Sambuc }
977433d6423SLionel Sambuc
insb(port_t port,void * buf,size_t size)978433d6423SLionel Sambuc static void insb(port_t port, void *buf, size_t size)
979433d6423SLionel Sambuc {
980433d6423SLionel Sambuc int r;
981433d6423SLionel Sambuc
9823913e490SDavid van Moolenbroek r= sys_insb(port, SELF, buf, size);
983433d6423SLionel Sambuc if (r != OK)
984433d6423SLionel Sambuc panic("sys_sdevio failed: %d", r);
985433d6423SLionel Sambuc }
986433d6423SLionel Sambuc
insw(port_t port,void * buf,size_t size)9873913e490SDavid van Moolenbroek static void insw(port_t port, void *buf, size_t size)
988433d6423SLionel Sambuc {
989433d6423SLionel Sambuc int r;
990433d6423SLionel Sambuc
9913913e490SDavid van Moolenbroek r= sys_insw(port, SELF, buf, size);
992433d6423SLionel Sambuc if (r != OK)
993433d6423SLionel Sambuc panic("sys_sdevio failed: %d", r);
994433d6423SLionel Sambuc }
995433d6423SLionel Sambuc
996433d6423SLionel Sambuc /*
997433d6423SLionel Sambuc * $PchId: dp8390.c,v 1.25 2005/02/10 17:32:07 philip Exp $
998433d6423SLionel Sambuc */
999