1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc * rtl8139.c
3433d6423SLionel Sambuc *
4433d6423SLionel Sambuc * This file contains a ethernet device driver for Realtek rtl8139 based
5433d6423SLionel Sambuc * ethernet cards.
6433d6423SLionel Sambuc *
7433d6423SLionel Sambuc * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
8433d6423SLionel Sambuc * Changes:
9433d6423SLionel Sambuc * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder)
10433d6423SLionel Sambuc * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder)
11433d6423SLionel Sambuc *
12433d6423SLionel Sambuc */
13433d6423SLionel Sambuc
14433d6423SLionel Sambuc #define VERBOSE 0 /* Verbose debugging output */
15433d6423SLionel Sambuc #define RTL8139_FKEY 0 /* Use function key to dump RTL8139 status */
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc #include "rtl8139.h"
18433d6423SLionel Sambuc
194081bff6SDavid van Moolenbroek static re_t re_state;
20433d6423SLionel Sambuc
my_inb(u16_t port)21433d6423SLionel Sambuc static unsigned my_inb(u16_t port) {
22433d6423SLionel Sambuc u32_t value;
23433d6423SLionel Sambuc int s;
24433d6423SLionel Sambuc if ((s=sys_inb(port, &value)) !=OK)
25433d6423SLionel Sambuc printf("RTL8139: warning, sys_inb failed: %d\n", s);
26433d6423SLionel Sambuc return value;
27433d6423SLionel Sambuc }
my_inw(u16_t port)28433d6423SLionel Sambuc static unsigned my_inw(u16_t port) {
29433d6423SLionel Sambuc u32_t value;
30433d6423SLionel Sambuc int s;
31433d6423SLionel Sambuc if ((s=sys_inw(port, &value)) !=OK)
32433d6423SLionel Sambuc printf("RTL8139: warning, sys_inw failed: %d\n", s);
33433d6423SLionel Sambuc return value;
34433d6423SLionel Sambuc }
my_inl(u16_t port)35433d6423SLionel Sambuc static unsigned my_inl(u16_t port) {
36433d6423SLionel Sambuc u32_t value;
37433d6423SLionel Sambuc int s;
38433d6423SLionel Sambuc if ((s=sys_inl(port, &value)) !=OK)
39433d6423SLionel Sambuc printf("RTL8139: warning, sys_inl failed: %d\n", s);
40433d6423SLionel Sambuc return value;
41433d6423SLionel Sambuc }
42433d6423SLionel Sambuc #define rl_inb(port, offset) (my_inb((port) + (offset)))
43433d6423SLionel Sambuc #define rl_inw(port, offset) (my_inw((port) + (offset)))
44433d6423SLionel Sambuc #define rl_inl(port, offset) (my_inl((port) + (offset)))
45433d6423SLionel Sambuc
my_outb(u16_t port,u8_t value)46433d6423SLionel Sambuc static void my_outb(u16_t port, u8_t value) {
47433d6423SLionel Sambuc int s;
48433d6423SLionel Sambuc if ((s=sys_outb(port, value)) !=OK)
49433d6423SLionel Sambuc printf("RTL8139: warning, sys_outb failed: %d\n", s);
50433d6423SLionel Sambuc }
my_outw(u16_t port,u16_t value)51433d6423SLionel Sambuc static void my_outw(u16_t port, u16_t value) {
52433d6423SLionel Sambuc int s;
53433d6423SLionel Sambuc if ((s=sys_outw(port, value)) !=OK)
54433d6423SLionel Sambuc printf("RTL8139: warning, sys_outw failed: %d\n", s);
55433d6423SLionel Sambuc }
my_outl(u16_t port,u32_t value)56433d6423SLionel Sambuc static void my_outl(u16_t port, u32_t value) {
57433d6423SLionel Sambuc int s;
58433d6423SLionel Sambuc if ((s=sys_outl(port, value)) !=OK)
59433d6423SLionel Sambuc printf("RTL8139: warning, sys_outl failed: %d\n", s);
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc #define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
62433d6423SLionel Sambuc #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
63433d6423SLionel Sambuc #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
64433d6423SLionel Sambuc
65*f7df02e7SDavid van Moolenbroek static int rl_init(unsigned int instance, netdriver_addr_t *addr,
66*f7df02e7SDavid van Moolenbroek uint32_t *caps, unsigned int *ticks);
674081bff6SDavid van Moolenbroek static int rl_probe(re_t *rep, unsigned int skip);
68433d6423SLionel Sambuc static void rl_init_buf(re_t *rep);
69*f7df02e7SDavid van Moolenbroek static void rl_init_hw(re_t *rep, netdriver_addr_t *addr,
70*f7df02e7SDavid van Moolenbroek unsigned int instance);
71433d6423SLionel Sambuc static void rl_reset_hw(re_t *rep);
72*f7df02e7SDavid van Moolenbroek static void rl_set_hwaddr(const netdriver_addr_t *addr);
73*f7df02e7SDavid van Moolenbroek static void rl_confaddr(re_t *rep, netdriver_addr_t *addr,
74*f7df02e7SDavid van Moolenbroek unsigned int instance);
754081bff6SDavid van Moolenbroek static void rl_stop(void);
76433d6423SLionel Sambuc static void rl_rec_mode(re_t *rep);
77*f7df02e7SDavid van Moolenbroek static void rl_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
78*f7df02e7SDavid van Moolenbroek unsigned int mcast_count);
794081bff6SDavid van Moolenbroek static ssize_t rl_recv(struct netdriver_data *data, size_t max);
804081bff6SDavid van Moolenbroek static int rl_send(struct netdriver_data *data, size_t size);
81*f7df02e7SDavid van Moolenbroek static unsigned int rl_get_link(uint32_t *media);
824081bff6SDavid van Moolenbroek static void rl_intr(unsigned int mask);
83433d6423SLionel Sambuc static void rl_check_ints(re_t *rep);
844081bff6SDavid van Moolenbroek #if VERBOSE
85*f7df02e7SDavid van Moolenbroek static void rl_report_link(re_t *rep);
86433d6423SLionel Sambuc static void mii_print_techab(u16_t techab);
87433d6423SLionel Sambuc static void mii_print_stat_speed(u16_t stat, u16_t extstat);
884081bff6SDavid van Moolenbroek #endif
89433d6423SLionel Sambuc static void rl_clear_rx(re_t *rep);
90433d6423SLionel Sambuc static void rl_do_reset(re_t *rep);
914081bff6SDavid van Moolenbroek static void rl_other(const message *m_ptr, int ipc_status);
924081bff6SDavid van Moolenbroek static void rl_dump(void);
93433d6423SLionel Sambuc #if 0
94433d6423SLionel Sambuc static void dump_phy(re_t *rep);
95433d6423SLionel Sambuc #endif
96433d6423SLionel Sambuc static int rl_handler(re_t *rep);
97*f7df02e7SDavid van Moolenbroek static void rl_tick(void);
984081bff6SDavid van Moolenbroek static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int
99433d6423SLionel Sambuc pci_dev, int pci_func);
100433d6423SLionel Sambuc
1014081bff6SDavid van Moolenbroek static const struct netdriver rl_table = {
102*f7df02e7SDavid van Moolenbroek .ndr_name = "rl",
1034081bff6SDavid van Moolenbroek .ndr_init = rl_init,
1044081bff6SDavid van Moolenbroek .ndr_stop = rl_stop,
105*f7df02e7SDavid van Moolenbroek .ndr_set_mode = rl_set_mode,
106*f7df02e7SDavid van Moolenbroek .ndr_set_hwaddr = rl_set_hwaddr,
1074081bff6SDavid van Moolenbroek .ndr_recv = rl_recv,
1084081bff6SDavid van Moolenbroek .ndr_send = rl_send,
109*f7df02e7SDavid van Moolenbroek .ndr_get_link = rl_get_link,
1104081bff6SDavid van Moolenbroek .ndr_intr = rl_intr,
111*f7df02e7SDavid van Moolenbroek .ndr_tick = rl_tick,
1124081bff6SDavid van Moolenbroek .ndr_other = rl_other,
1134081bff6SDavid van Moolenbroek };
114433d6423SLionel Sambuc
115433d6423SLionel Sambuc /*===========================================================================*
116433d6423SLionel Sambuc * main *
117433d6423SLionel Sambuc *===========================================================================*/
main(int argc,char * argv[])118433d6423SLionel Sambuc int main(int argc, char *argv[])
119433d6423SLionel Sambuc {
120433d6423SLionel Sambuc
121433d6423SLionel Sambuc env_setargs(argc, argv);
122433d6423SLionel Sambuc
1234081bff6SDavid van Moolenbroek netdriver_task(&rl_table);
124433d6423SLionel Sambuc
1254081bff6SDavid van Moolenbroek return 0;
126433d6423SLionel Sambuc }
127433d6423SLionel Sambuc
128433d6423SLionel Sambuc /*===========================================================================*
1294081bff6SDavid van Moolenbroek * rl_intr *
130433d6423SLionel Sambuc *===========================================================================*/
rl_intr(unsigned int __unused mask)1314081bff6SDavid van Moolenbroek static void rl_intr(unsigned int __unused mask)
132433d6423SLionel Sambuc {
133433d6423SLionel Sambuc re_t *rep;
1344081bff6SDavid van Moolenbroek int s;
135433d6423SLionel Sambuc
136433d6423SLionel Sambuc rep = &re_state;
137433d6423SLionel Sambuc
1384081bff6SDavid van Moolenbroek /* Run interrupt handler at driver level. */
1394081bff6SDavid van Moolenbroek rl_handler(rep);
1404081bff6SDavid van Moolenbroek
1414081bff6SDavid van Moolenbroek /* Reenable interrupts for this hook. */
1424081bff6SDavid van Moolenbroek if ((s = sys_irqenable(&rep->re_hook_id)) != OK)
1434081bff6SDavid van Moolenbroek printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
1444081bff6SDavid van Moolenbroek
1454081bff6SDavid van Moolenbroek /* Perform tasks based on the flagged conditions. */
146433d6423SLionel Sambuc rl_check_ints(rep);
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc /*===========================================================================*
1504081bff6SDavid van Moolenbroek * rl_other *
151433d6423SLionel Sambuc *===========================================================================*/
rl_other(const message * m_ptr,int ipc_status)1524081bff6SDavid van Moolenbroek static void rl_other(const message *m_ptr, int ipc_status)
1534081bff6SDavid van Moolenbroek {
1544081bff6SDavid van Moolenbroek if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
1554081bff6SDavid van Moolenbroek rl_dump();
1564081bff6SDavid van Moolenbroek }
1574081bff6SDavid van Moolenbroek
1584081bff6SDavid van Moolenbroek /*===========================================================================*
1594081bff6SDavid van Moolenbroek * rl_stop *
1604081bff6SDavid van Moolenbroek *===========================================================================*/
rl_stop(void)1614081bff6SDavid van Moolenbroek static void rl_stop(void)
1624081bff6SDavid van Moolenbroek {
1634081bff6SDavid van Moolenbroek re_t *rep;
1644081bff6SDavid van Moolenbroek
1654081bff6SDavid van Moolenbroek rep = &re_state;
1664081bff6SDavid van Moolenbroek
1674081bff6SDavid van Moolenbroek rl_outb(rep->re_base_port, RL_CR, 0);
1684081bff6SDavid van Moolenbroek }
1694081bff6SDavid van Moolenbroek
1704081bff6SDavid van Moolenbroek /*===========================================================================*
1714081bff6SDavid van Moolenbroek * rl_dump *
1724081bff6SDavid van Moolenbroek *===========================================================================*/
rl_dump(void)1734081bff6SDavid van Moolenbroek static void rl_dump(void)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc re_t *rep;
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc rep= &re_state;
178433d6423SLionel Sambuc
179433d6423SLionel Sambuc printf("\n");
180*f7df02e7SDavid van Moolenbroek printf("Realtek RTL 8139 device %s:\n", netdriver_name());
181433d6423SLionel Sambuc
182433d6423SLionel Sambuc printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
183433d6423SLionel Sambuc rl_inw(rep->re_base_port, RL_TSAD),
184433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+0*4),
185433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+1*4),
186433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+2*4),
187433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+3*4));
188433d6423SLionel Sambuc printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
189433d6423SLionel Sambuc rep->re_tx_head, rep->re_tx_tail,
190433d6423SLionel Sambuc rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
191433d6423SLionel Sambuc rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc
194433d6423SLionel Sambuc /*===========================================================================*
195*f7df02e7SDavid van Moolenbroek * rl_set_mode *
196433d6423SLionel Sambuc *===========================================================================*/
rl_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list,unsigned int mcast_count)197*f7df02e7SDavid van Moolenbroek static void rl_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
198*f7df02e7SDavid van Moolenbroek unsigned int mcast_count)
199433d6423SLionel Sambuc {
200433d6423SLionel Sambuc re_t *rep;
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc rep= &re_state;
203433d6423SLionel Sambuc
2044081bff6SDavid van Moolenbroek rep->re_mode = mode;
205433d6423SLionel Sambuc
206433d6423SLionel Sambuc rl_rec_mode(rep);
207433d6423SLionel Sambuc }
208433d6423SLionel Sambuc
209433d6423SLionel Sambuc /*===========================================================================*
2104081bff6SDavid van Moolenbroek * rl_init *
211433d6423SLionel Sambuc *===========================================================================*/
rl_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)212*f7df02e7SDavid van Moolenbroek static int rl_init(unsigned int instance, netdriver_addr_t *addr,
213*f7df02e7SDavid van Moolenbroek uint32_t *caps, unsigned int *ticks)
214433d6423SLionel Sambuc {
2154081bff6SDavid van Moolenbroek /* Initialize the rtl8139 driver. */
216433d6423SLionel Sambuc re_t *rep;
2174081bff6SDavid van Moolenbroek #if RTL8139_FKEY
2184081bff6SDavid van Moolenbroek int r, fkeys, sfkeys;
2194081bff6SDavid van Moolenbroek #endif
220433d6423SLionel Sambuc
2214081bff6SDavid van Moolenbroek /* Initialize driver state. */
222433d6423SLionel Sambuc rep= &re_state;
2234081bff6SDavid van Moolenbroek memset(rep, 0, sizeof(*rep));
224433d6423SLionel Sambuc
2254081bff6SDavid van Moolenbroek rep->re_link_up= -1; /* Unknown */
2264081bff6SDavid van Moolenbroek rep->re_ertxth= RL_TSD_ERTXTH_8;
227433d6423SLionel Sambuc
2284081bff6SDavid van Moolenbroek /* Try to find a matching device. */
2294081bff6SDavid van Moolenbroek if (!rl_probe(rep, instance))
2304081bff6SDavid van Moolenbroek return ENXIO;
2314081bff6SDavid van Moolenbroek
2324081bff6SDavid van Moolenbroek /* Claim buffer memory. */
2334081bff6SDavid van Moolenbroek rl_init_buf(rep);
2344081bff6SDavid van Moolenbroek
2354081bff6SDavid van Moolenbroek /* Initialize the device we found. */
236*f7df02e7SDavid van Moolenbroek rl_init_hw(rep, addr, instance);
2374081bff6SDavid van Moolenbroek
2384081bff6SDavid van Moolenbroek #if VERBOSE
2394081bff6SDavid van Moolenbroek /* Report initial link status. */
2404081bff6SDavid van Moolenbroek rl_report_link(rep);
2414081bff6SDavid van Moolenbroek #endif
2424081bff6SDavid van Moolenbroek
2434081bff6SDavid van Moolenbroek #if RTL8139_FKEY
2444081bff6SDavid van Moolenbroek /* Observe some function key for debug dumps. */
2454081bff6SDavid van Moolenbroek fkeys = sfkeys = 0; bit_set(sfkeys, 9);
2464081bff6SDavid van Moolenbroek if ((r = fkey_map(&fkeys, &sfkeys)) != OK)
2474081bff6SDavid van Moolenbroek printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
2484081bff6SDavid van Moolenbroek #endif
2494081bff6SDavid van Moolenbroek
250*f7df02e7SDavid van Moolenbroek *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST | NDEV_CAP_HWADDR;
251*f7df02e7SDavid van Moolenbroek *ticks = sys_hz();
2524081bff6SDavid van Moolenbroek return OK;
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc
255433d6423SLionel Sambuc /*===========================================================================*
256433d6423SLionel Sambuc * rl_probe *
257433d6423SLionel Sambuc *===========================================================================*/
rl_probe(re_t * rep,unsigned int skip)2584081bff6SDavid van Moolenbroek static int rl_probe(re_t *rep, unsigned int skip)
259433d6423SLionel Sambuc {
260433d6423SLionel Sambuc int r, devind;
261b49f4cacSDavid van Moolenbroek u16_t cr, vid, did;
262433d6423SLionel Sambuc u32_t bar;
263433d6423SLionel Sambuc u8_t ilr;
264433d6423SLionel Sambuc #if VERBOSE
265*f7df02e7SDavid van Moolenbroek const char *dname;
266433d6423SLionel Sambuc #endif
267433d6423SLionel Sambuc
2684081bff6SDavid van Moolenbroek pci_init();
2694081bff6SDavid van Moolenbroek
270433d6423SLionel Sambuc r= pci_first_dev(&devind, &vid, &did);
271433d6423SLionel Sambuc if (r == 0)
272433d6423SLionel Sambuc return 0;
273433d6423SLionel Sambuc
274433d6423SLionel Sambuc while (skip--)
275433d6423SLionel Sambuc {
276433d6423SLionel Sambuc r= pci_next_dev(&devind, &vid, &did);
277433d6423SLionel Sambuc if (!r)
278433d6423SLionel Sambuc return 0;
279433d6423SLionel Sambuc }
280433d6423SLionel Sambuc
281433d6423SLionel Sambuc #if VERBOSE /* stay silent at startup, can always get status later */
282433d6423SLionel Sambuc dname= pci_dev_name(vid, did);
283433d6423SLionel Sambuc if (!dname)
284433d6423SLionel Sambuc dname= "unknown device";
285*f7df02e7SDavid van Moolenbroek printf("%s: ", netdriver_name());
286433d6423SLionel Sambuc printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
287433d6423SLionel Sambuc #endif
288433d6423SLionel Sambuc pci_reserve(devind);
289b49f4cacSDavid van Moolenbroek
290b49f4cacSDavid van Moolenbroek /* Enable bus mastering if necessary. */
291b49f4cacSDavid van Moolenbroek cr = pci_attr_r16(devind, PCI_CR);
292b49f4cacSDavid van Moolenbroek /* printf("cr = 0x%x\n", cr); */
293b49f4cacSDavid van Moolenbroek if (!(cr & PCI_CR_MAST_EN))
294b49f4cacSDavid van Moolenbroek pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
295b49f4cacSDavid van Moolenbroek
296433d6423SLionel Sambuc bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
297433d6423SLionel Sambuc if (bar < 0x400) {
298433d6423SLionel Sambuc panic("base address is not properly configured");
299433d6423SLionel Sambuc }
300433d6423SLionel Sambuc rep->re_base_port= bar;
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc ilr= pci_attr_r8(devind, PCI_ILR);
303433d6423SLionel Sambuc rep->re_irq= ilr;
3044081bff6SDavid van Moolenbroek #if VERBOSE
305433d6423SLionel Sambuc printf("%s: using I/O address 0x%lx, IRQ %d\n",
306*f7df02e7SDavid van Moolenbroek netdriver_name(), (unsigned long)bar, ilr);
3074081bff6SDavid van Moolenbroek #endif
308433d6423SLionel Sambuc
309433d6423SLionel Sambuc return TRUE;
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc /*===========================================================================*
313433d6423SLionel Sambuc * rl_init_buf *
314433d6423SLionel Sambuc *===========================================================================*/
rl_init_buf(re_t * rep)3154081bff6SDavid van Moolenbroek static void rl_init_buf(re_t *rep)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc size_t rx_bufsize, tx_bufsize, tot_bufsize;
318433d6423SLionel Sambuc phys_bytes buf;
319433d6423SLionel Sambuc char *mallocbuf;
320433d6423SLionel Sambuc int i, off;
321433d6423SLionel Sambuc
322433d6423SLionel Sambuc /* Allocate receive and transmit buffers */
323*f7df02e7SDavid van Moolenbroek tx_bufsize= NDEV_ETH_PACKET_MAX_TAGGED;
324433d6423SLionel Sambuc if (tx_bufsize % 4)
325433d6423SLionel Sambuc tx_bufsize += 4-(tx_bufsize % 4); /* Align */
326433d6423SLionel Sambuc rx_bufsize= RX_BUFSIZE;
327433d6423SLionel Sambuc tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
328433d6423SLionel Sambuc
329433d6423SLionel Sambuc if (tot_bufsize % 4096)
330433d6423SLionel Sambuc tot_bufsize += 4096-(tot_bufsize % 4096);
331433d6423SLionel Sambuc
332433d6423SLionel Sambuc #define BUF_ALIGNMENT (64*1024)
333433d6423SLionel Sambuc
3344081bff6SDavid van Moolenbroek if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf)))
335433d6423SLionel Sambuc panic("Couldn't allocate kernel buffer");
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc /* click-align mallocced buffer. this is what we used to get
338433d6423SLionel Sambuc * from kmalloc() too.
339433d6423SLionel Sambuc */
340433d6423SLionel Sambuc if((off = buf % BUF_ALIGNMENT)) {
341433d6423SLionel Sambuc mallocbuf += BUF_ALIGNMENT - off;
342433d6423SLionel Sambuc buf += BUF_ALIGNMENT - off;
343433d6423SLionel Sambuc }
344433d6423SLionel Sambuc
3454081bff6SDavid van Moolenbroek tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0);
346433d6423SLionel Sambuc
347433d6423SLionel Sambuc for (i= 0; i<N_TX_BUF; i++)
348433d6423SLionel Sambuc {
349433d6423SLionel Sambuc rep->re_tx[i].ret_buf= buf;
350433d6423SLionel Sambuc rep->re_tx[i].v_ret_buf= mallocbuf;
351433d6423SLionel Sambuc buf += tx_bufsize;
352433d6423SLionel Sambuc mallocbuf += tx_bufsize;
353433d6423SLionel Sambuc }
354433d6423SLionel Sambuc rep->re_rx_buf= buf;
355433d6423SLionel Sambuc rep->v_re_rx_buf= mallocbuf;
356433d6423SLionel Sambuc }
357433d6423SLionel Sambuc
358433d6423SLionel Sambuc /*===========================================================================*
359433d6423SLionel Sambuc * rl_init_hw *
360433d6423SLionel Sambuc *===========================================================================*/
rl_init_hw(re_t * rep,netdriver_addr_t * addr,unsigned int instance)361*f7df02e7SDavid van Moolenbroek static void rl_init_hw(re_t *rep, netdriver_addr_t *addr,
362*f7df02e7SDavid van Moolenbroek unsigned int instance)
363433d6423SLionel Sambuc {
3644081bff6SDavid van Moolenbroek #if VERBOSE
3654081bff6SDavid van Moolenbroek int i;
3664081bff6SDavid van Moolenbroek #endif
3674081bff6SDavid van Moolenbroek int s;
368433d6423SLionel Sambuc
369433d6423SLionel Sambuc /* Set the interrupt handler. The policy is to only send HARD_INT
370433d6423SLionel Sambuc * notifications. Don't reenable interrupts automatically. The id
371433d6423SLionel Sambuc * that is passed back is the interrupt line number.
372433d6423SLionel Sambuc */
373433d6423SLionel Sambuc rep->re_hook_id = rep->re_irq;
374433d6423SLionel Sambuc if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
375433d6423SLionel Sambuc printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
376433d6423SLionel Sambuc
377433d6423SLionel Sambuc rl_reset_hw(rep);
378433d6423SLionel Sambuc
379433d6423SLionel Sambuc if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
380433d6423SLionel Sambuc printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
381433d6423SLionel Sambuc
382433d6423SLionel Sambuc #if VERBOSE /* stay silent during startup, can always get status later */
383433d6423SLionel Sambuc if (rep->re_model) {
384*f7df02e7SDavid van Moolenbroek printf("%s: model %s\n", netdriver_name(), rep->re_model);
385433d6423SLionel Sambuc } else
386433d6423SLionel Sambuc {
387433d6423SLionel Sambuc printf("%s: unknown model 0x%08x\n",
388*f7df02e7SDavid van Moolenbroek netdriver_name(),
389433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TCR) &
390433d6423SLionel Sambuc (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
391433d6423SLionel Sambuc }
392433d6423SLionel Sambuc #endif
393433d6423SLionel Sambuc
394*f7df02e7SDavid van Moolenbroek rl_confaddr(rep, addr, instance);
3954081bff6SDavid van Moolenbroek
3964081bff6SDavid van Moolenbroek #if VERBOSE
397*f7df02e7SDavid van Moolenbroek printf("%s: Ethernet address ", netdriver_name());
398433d6423SLionel Sambuc for (i= 0; i < 6; i++)
399*f7df02e7SDavid van Moolenbroek printf("%x%c", addr->na_addr[i], i < 5 ? ':' : '\n');
4004081bff6SDavid van Moolenbroek #endif
401433d6423SLionel Sambuc }
402433d6423SLionel Sambuc
403433d6423SLionel Sambuc /*===========================================================================*
404433d6423SLionel Sambuc * rl_reset_hw *
405433d6423SLionel Sambuc *===========================================================================*/
rl_reset_hw(re_t * rep)4064081bff6SDavid van Moolenbroek static void rl_reset_hw(re_t *rep)
407433d6423SLionel Sambuc {
408433d6423SLionel Sambuc port_t port;
409433d6423SLionel Sambuc u32_t t;
410433d6423SLionel Sambuc phys_bytes bus_buf;
411433d6423SLionel Sambuc int i;
412433d6423SLionel Sambuc
413433d6423SLionel Sambuc port= rep->re_base_port;
414433d6423SLionel Sambuc
415433d6423SLionel Sambuc #if 0
416433d6423SLionel Sambuc /* Reset the PHY */
417433d6423SLionel Sambuc rl_outb(port, RL_BMCR, MII_CTRL_RST);
418433d6423SLionel Sambuc SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000);
419433d6423SLionel Sambuc if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
420433d6423SLionel Sambuc panic("reset PHY failed to complete");
421433d6423SLionel Sambuc #endif
422433d6423SLionel Sambuc
423433d6423SLionel Sambuc /* Reset the device */
424433d6423SLionel Sambuc #if VERBOSE
425433d6423SLionel Sambuc printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
426433d6423SLionel Sambuc port, rl_inb(port, RL_CR));
427433d6423SLionel Sambuc #endif
428433d6423SLionel Sambuc rl_outb(port, RL_CR, RL_CR_RST);
429433d6423SLionel Sambuc SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
430433d6423SLionel Sambuc #if VERBOSE
431433d6423SLionel Sambuc printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
432433d6423SLionel Sambuc port, rl_inb(port, RL_CR));
433433d6423SLionel Sambuc #endif
434433d6423SLionel Sambuc if (rl_inb(port, RL_CR) & RL_CR_RST)
435433d6423SLionel Sambuc printf("rtl8139: reset failed to complete");
436433d6423SLionel Sambuc
437433d6423SLionel Sambuc t= rl_inl(port, RL_TCR);
438433d6423SLionel Sambuc switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
439433d6423SLionel Sambuc {
440433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
441433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
442433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8139AG:
443433d6423SLionel Sambuc rep->re_model= "RTL8139A-G / RTL8139C";
444433d6423SLionel Sambuc break;
445433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8139B:
446433d6423SLionel Sambuc rep->re_model= "RTL8139B / RTL8130";
447433d6423SLionel Sambuc break;
448433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
449433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8100B:
450433d6423SLionel Sambuc rep->re_model= "RTL8100B/RTL8139D";
451433d6423SLionel Sambuc break;
452433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
453433d6423SLionel Sambuc case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
454433d6423SLionel Sambuc default:
455433d6423SLionel Sambuc rep->re_model= NULL;
456433d6423SLionel Sambuc break;
457433d6423SLionel Sambuc }
458433d6423SLionel Sambuc
459433d6423SLionel Sambuc #if 0
460433d6423SLionel Sambuc printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
461433d6423SLionel Sambuc #endif
462433d6423SLionel Sambuc
463433d6423SLionel Sambuc /* Intialize Rx */
464433d6423SLionel Sambuc
465433d6423SLionel Sambuc /* Should init multicast mask */
466433d6423SLionel Sambuc #if 0
467433d6423SLionel Sambuc 08-0f R/W MAR[0-7] multicast
468433d6423SLionel Sambuc #endif
469433d6423SLionel Sambuc bus_buf= vm_1phys2bus(rep->re_rx_buf);
470433d6423SLionel Sambuc rl_outl(port, RL_RBSTART, bus_buf);
471433d6423SLionel Sambuc
472433d6423SLionel Sambuc /* Initialize Tx */
473433d6423SLionel Sambuc for (i= 0; i<N_TX_BUF; i++)
474433d6423SLionel Sambuc {
475433d6423SLionel Sambuc rep->re_tx[i].ret_busy= FALSE;
476433d6423SLionel Sambuc bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
477433d6423SLionel Sambuc rl_outl(port, RL_TSAD0+i*4, bus_buf);
478433d6423SLionel Sambuc t= rl_inl(port, RL_TSD0+i*4);
479433d6423SLionel Sambuc assert(t & RL_TSD_OWN);
480433d6423SLionel Sambuc }
481433d6423SLionel Sambuc
4824081bff6SDavid van Moolenbroek rep->re_tx_busy = 0;
4834081bff6SDavid van Moolenbroek
484433d6423SLionel Sambuc #if 0
485433d6423SLionel Sambuc dump_phy(rep);
486433d6423SLionel Sambuc #endif
487433d6423SLionel Sambuc
488433d6423SLionel Sambuc t= rl_inw(port, RL_IMR);
489433d6423SLionel Sambuc rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
490433d6423SLionel Sambuc RL_IMR_LENCHG));
491433d6423SLionel Sambuc
492433d6423SLionel Sambuc t= rl_inw(port, RL_IMR);
493433d6423SLionel Sambuc rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
494433d6423SLionel Sambuc RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
495433d6423SLionel Sambuc
496433d6423SLionel Sambuc t= rl_inw(port, RL_IMR);
497433d6423SLionel Sambuc rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
498433d6423SLionel Sambuc
499433d6423SLionel Sambuc t= rl_inb(port, RL_CR);
500433d6423SLionel Sambuc rl_outb(port, RL_CR, t | RL_CR_RE);
501433d6423SLionel Sambuc
502433d6423SLionel Sambuc t= rl_inb(port, RL_CR);
503433d6423SLionel Sambuc rl_outb(port, RL_CR, t | RL_CR_TE);
504433d6423SLionel Sambuc
505433d6423SLionel Sambuc rl_outl(port, RL_RCR, RX_BUFBITS);
506433d6423SLionel Sambuc
507433d6423SLionel Sambuc t= rl_inl(port, RL_TCR);
508433d6423SLionel Sambuc rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
509433d6423SLionel Sambuc }
510433d6423SLionel Sambuc
511433d6423SLionel Sambuc /*===========================================================================*
512*f7df02e7SDavid van Moolenbroek * rl_set_hwaddr *
513*f7df02e7SDavid van Moolenbroek *===========================================================================*/
rl_set_hwaddr(const netdriver_addr_t * addr)514*f7df02e7SDavid van Moolenbroek static void rl_set_hwaddr(const netdriver_addr_t *addr)
515*f7df02e7SDavid van Moolenbroek {
516*f7df02e7SDavid van Moolenbroek re_t *rep;
517*f7df02e7SDavid van Moolenbroek port_t port;
518*f7df02e7SDavid van Moolenbroek u32_t w;
519*f7df02e7SDavid van Moolenbroek int i;
520*f7df02e7SDavid van Moolenbroek
521*f7df02e7SDavid van Moolenbroek rep = &re_state;
522*f7df02e7SDavid van Moolenbroek
523*f7df02e7SDavid van Moolenbroek port= rep->re_base_port;
524*f7df02e7SDavid van Moolenbroek rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
525*f7df02e7SDavid van Moolenbroek w= 0;
526*f7df02e7SDavid van Moolenbroek for (i= 0; i<4; i++)
527*f7df02e7SDavid van Moolenbroek w |= (addr->na_addr[i] << (i*8));
528*f7df02e7SDavid van Moolenbroek rl_outl(port, RL_IDR, w);
529*f7df02e7SDavid van Moolenbroek w= 0;
530*f7df02e7SDavid van Moolenbroek for (i= 4; i<6; i++)
531*f7df02e7SDavid van Moolenbroek w |= (addr->na_addr[i] << ((i-4)*8));
532*f7df02e7SDavid van Moolenbroek rl_outl(port, RL_IDR+4, w);
533*f7df02e7SDavid van Moolenbroek rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
534*f7df02e7SDavid van Moolenbroek }
535*f7df02e7SDavid van Moolenbroek
536*f7df02e7SDavid van Moolenbroek /*===========================================================================*
537433d6423SLionel Sambuc * rl_confaddr *
538433d6423SLionel Sambuc *===========================================================================*/
rl_confaddr(re_t * rep,netdriver_addr_t * addr,unsigned int instance)539*f7df02e7SDavid van Moolenbroek static void rl_confaddr(re_t *rep, netdriver_addr_t *addr,
540*f7df02e7SDavid van Moolenbroek unsigned int instance)
541433d6423SLionel Sambuc {
542433d6423SLionel Sambuc static char eakey[]= RL_ENVVAR "#_EA";
543433d6423SLionel Sambuc static char eafmt[]= "x:x:x:x:x:x";
544433d6423SLionel Sambuc port_t port;
545*f7df02e7SDavid van Moolenbroek int i;
546433d6423SLionel Sambuc long v;
547433d6423SLionel Sambuc
548433d6423SLionel Sambuc /* User defined ethernet address? */
549*f7df02e7SDavid van Moolenbroek eakey[sizeof(RL_ENVVAR)-1]= '0' + instance;
550433d6423SLionel Sambuc
551433d6423SLionel Sambuc for (i= 0; i < 6; i++)
552433d6423SLionel Sambuc {
553433d6423SLionel Sambuc if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
554433d6423SLionel Sambuc break;
555*f7df02e7SDavid van Moolenbroek addr->na_addr[i]= v;
556433d6423SLionel Sambuc }
557433d6423SLionel Sambuc
558433d6423SLionel Sambuc if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
559433d6423SLionel Sambuc
560433d6423SLionel Sambuc /* Should update ethernet address in hardware */
561433d6423SLionel Sambuc if (i == 6)
562*f7df02e7SDavid van Moolenbroek rl_set_hwaddr(addr);
563433d6423SLionel Sambuc
564433d6423SLionel Sambuc /* Get ethernet address */
565*f7df02e7SDavid van Moolenbroek port= rep->re_base_port;
566*f7df02e7SDavid van Moolenbroek
567433d6423SLionel Sambuc for (i= 0; i<6; i++)
568*f7df02e7SDavid van Moolenbroek addr->na_addr[i]= rl_inb(port, RL_IDR+i);
569433d6423SLionel Sambuc }
570433d6423SLionel Sambuc
571433d6423SLionel Sambuc /*===========================================================================*
572433d6423SLionel Sambuc * rl_rec_mode *
573433d6423SLionel Sambuc *===========================================================================*/
rl_rec_mode(re_t * rep)5744081bff6SDavid van Moolenbroek static void rl_rec_mode(re_t *rep)
575433d6423SLionel Sambuc {
576433d6423SLionel Sambuc port_t port;
577433d6423SLionel Sambuc u32_t rcr;
578433d6423SLionel Sambuc
579433d6423SLionel Sambuc port= rep->re_base_port;
580433d6423SLionel Sambuc rcr= rl_inl(port, RL_RCR);
581433d6423SLionel Sambuc rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
582*f7df02e7SDavid van Moolenbroek if (rep->re_mode & NDEV_MODE_PROMISC)
583433d6423SLionel Sambuc rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
584*f7df02e7SDavid van Moolenbroek if (rep->re_mode & NDEV_MODE_BCAST)
585433d6423SLionel Sambuc rcr |= RL_RCR_AB;
586*f7df02e7SDavid van Moolenbroek if (rep->re_mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
587433d6423SLionel Sambuc rcr |= RL_RCR_AM;
588433d6423SLionel Sambuc rcr |= RL_RCR_APM;
589433d6423SLionel Sambuc
590433d6423SLionel Sambuc rl_outl(port, RL_RCR, rcr);
591433d6423SLionel Sambuc }
592433d6423SLionel Sambuc
593433d6423SLionel Sambuc /*===========================================================================*
5944081bff6SDavid van Moolenbroek * rl_recv *
595433d6423SLionel Sambuc *===========================================================================*/
rl_recv(struct netdriver_data * data,size_t max)5964081bff6SDavid van Moolenbroek static ssize_t rl_recv(struct netdriver_data *data, size_t max)
597433d6423SLionel Sambuc {
5984081bff6SDavid van Moolenbroek int o, s;
599433d6423SLionel Sambuc port_t port;
600433d6423SLionel Sambuc unsigned amount, totlen, packlen;
601433d6423SLionel Sambuc u16_t d_start, d_end;
6024081bff6SDavid van Moolenbroek u32_t l, rxstat;
603433d6423SLionel Sambuc re_t *rep;
604433d6423SLionel Sambuc
605433d6423SLionel Sambuc rep= &re_state;
606433d6423SLionel Sambuc
607433d6423SLionel Sambuc if (rep->re_clear_rx)
6084081bff6SDavid van Moolenbroek return SUSPEND; /* Buffer overflow */
609433d6423SLionel Sambuc
610433d6423SLionel Sambuc port= rep->re_base_port;
611433d6423SLionel Sambuc
6124081bff6SDavid van Moolenbroek if (rl_inb(port, RL_CR) & RL_CR_BUFE)
613433d6423SLionel Sambuc {
614433d6423SLionel Sambuc /* Receive buffer is empty, suspend */
6154081bff6SDavid van Moolenbroek return SUSPEND;
616433d6423SLionel Sambuc }
617433d6423SLionel Sambuc
618433d6423SLionel Sambuc d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
619433d6423SLionel Sambuc d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
620433d6423SLionel Sambuc
621433d6423SLionel Sambuc #if RX_BUFSIZE <= USHRT_MAX
622433d6423SLionel Sambuc if (d_start >= RX_BUFSIZE)
623433d6423SLionel Sambuc {
6244081bff6SDavid van Moolenbroek printf("rl_recv: strange value in RL_CAPR: 0x%x\n",
625433d6423SLionel Sambuc rl_inw(port, RL_CAPR));
626433d6423SLionel Sambuc d_start %= RX_BUFSIZE;
627433d6423SLionel Sambuc }
628433d6423SLionel Sambuc #endif
629433d6423SLionel Sambuc
630433d6423SLionel Sambuc if (d_end > d_start)
631433d6423SLionel Sambuc amount= d_end-d_start;
632433d6423SLionel Sambuc else
633433d6423SLionel Sambuc amount= d_end+RX_BUFSIZE - d_start;
634433d6423SLionel Sambuc
635433d6423SLionel Sambuc rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
636433d6423SLionel Sambuc
637433d6423SLionel Sambuc /* Should convert from little endian to host byte order */
638433d6423SLionel Sambuc
639433d6423SLionel Sambuc if (!(rxstat & RL_RXS_ROK))
640433d6423SLionel Sambuc {
641433d6423SLionel Sambuc printf("rxstat = 0x%08x\n", rxstat);
642433d6423SLionel Sambuc printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
643433d6423SLionel Sambuc d_start, d_end, rxstat);
644433d6423SLionel Sambuc panic("received packet not OK");
645433d6423SLionel Sambuc }
646433d6423SLionel Sambuc totlen= (rxstat >> RL_RXS_LEN_S);
647*f7df02e7SDavid van Moolenbroek if (totlen < 8 || totlen > 2*NDEV_ETH_PACKET_MAX)
648433d6423SLionel Sambuc {
649433d6423SLionel Sambuc /* Someting went wrong */
650433d6423SLionel Sambuc printf(
6514081bff6SDavid van Moolenbroek "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n",
652433d6423SLionel Sambuc totlen, rxstat, d_start);
653433d6423SLionel Sambuc printf(
654433d6423SLionel Sambuc "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
655433d6423SLionel Sambuc d_start, d_end, totlen, rxstat);
656433d6423SLionel Sambuc panic(NULL);
657433d6423SLionel Sambuc }
658433d6423SLionel Sambuc
659433d6423SLionel Sambuc #if 0
660433d6423SLionel Sambuc printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
661433d6423SLionel Sambuc d_start, d_end, totlen, rxstat);
662433d6423SLionel Sambuc #endif
663433d6423SLionel Sambuc
664433d6423SLionel Sambuc if (totlen+4 > amount)
665433d6423SLionel Sambuc {
6664081bff6SDavid van Moolenbroek printf("rl_recv: packet not yet ready\n");
6674081bff6SDavid van Moolenbroek return SUSPEND;
668433d6423SLionel Sambuc }
669433d6423SLionel Sambuc
670433d6423SLionel Sambuc /* Should subtract the CRC */
671*f7df02e7SDavid van Moolenbroek packlen = MIN(totlen - NDEV_ETH_PACKET_CRC, max);
672433d6423SLionel Sambuc
6734081bff6SDavid van Moolenbroek /* Copy out the data. The packet may wrap in the receive buffer. */
6744081bff6SDavid van Moolenbroek o = (d_start+4) % RX_BUFSIZE;
675*f7df02e7SDavid van Moolenbroek s = MIN(RX_BUFSIZE - o, (int)packlen);
676433d6423SLionel Sambuc
6774081bff6SDavid van Moolenbroek netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s);
678*f7df02e7SDavid van Moolenbroek if (s < (int)packlen)
6794081bff6SDavid van Moolenbroek netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s);
680433d6423SLionel Sambuc
681433d6423SLionel Sambuc /* Avoid overflow in 16-bit computations */
682433d6423SLionel Sambuc l= d_start;
683433d6423SLionel Sambuc l += totlen+4;
684433d6423SLionel Sambuc l= (l+3) & ~3; /* align */
685433d6423SLionel Sambuc if (l >= RX_BUFSIZE)
686433d6423SLionel Sambuc {
687433d6423SLionel Sambuc l -= RX_BUFSIZE;
688433d6423SLionel Sambuc assert(l < RX_BUFSIZE);
689433d6423SLionel Sambuc }
690433d6423SLionel Sambuc rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
691433d6423SLionel Sambuc
6924081bff6SDavid van Moolenbroek return packlen;
693433d6423SLionel Sambuc }
694433d6423SLionel Sambuc
695433d6423SLionel Sambuc /*===========================================================================*
6964081bff6SDavid van Moolenbroek * rl_send *
697433d6423SLionel Sambuc *===========================================================================*/
rl_send(struct netdriver_data * data,size_t size)6984081bff6SDavid van Moolenbroek static int rl_send(struct netdriver_data *data, size_t size)
699433d6423SLionel Sambuc {
700433d6423SLionel Sambuc int tx_head;
701433d6423SLionel Sambuc re_t *rep;
702433d6423SLionel Sambuc
703433d6423SLionel Sambuc rep= &re_state;
704433d6423SLionel Sambuc
705433d6423SLionel Sambuc tx_head= rep->re_tx_head;
706433d6423SLionel Sambuc if (rep->re_tx[tx_head].ret_busy)
7074081bff6SDavid van Moolenbroek return SUSPEND;
708433d6423SLionel Sambuc
7094081bff6SDavid van Moolenbroek netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size);
710433d6423SLionel Sambuc
7114081bff6SDavid van Moolenbroek rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size);
712433d6423SLionel Sambuc rep->re_tx[tx_head].ret_busy= TRUE;
7134081bff6SDavid van Moolenbroek rep->re_tx_busy++;
714433d6423SLionel Sambuc
715433d6423SLionel Sambuc if (++tx_head == N_TX_BUF)
716433d6423SLionel Sambuc tx_head= 0;
717433d6423SLionel Sambuc assert(tx_head < RL_N_TX);
718433d6423SLionel Sambuc rep->re_tx_head= tx_head;
719433d6423SLionel Sambuc
7204081bff6SDavid van Moolenbroek return OK;
721433d6423SLionel Sambuc }
722433d6423SLionel Sambuc
723433d6423SLionel Sambuc /*===========================================================================*
724433d6423SLionel Sambuc * rl_check_ints *
725433d6423SLionel Sambuc *===========================================================================*/
rl_check_ints(re_t * rep)7264081bff6SDavid van Moolenbroek static void rl_check_ints(re_t *rep)
727433d6423SLionel Sambuc {
728433d6423SLionel Sambuc #if 0
729433d6423SLionel Sambuc 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
730433d6423SLionel Sambuc 31 R CRS Carrier Sense Lost
731433d6423SLionel Sambuc 30 R TABT Transmit Abort
732433d6423SLionel Sambuc 29 R OWC Out of Window Collision
733433d6423SLionel Sambuc 27-24 R NCC[3-0] Number of Collision Count
734433d6423SLionel Sambuc 23-22 reserved
735433d6423SLionel Sambuc 21-16 R/W ERTXH[5-0] Early Tx Threshold
736433d6423SLionel Sambuc 15 R TOK Transmit OK
737433d6423SLionel Sambuc 14 R TUN Transmit FIFO Underrun
738433d6423SLionel Sambuc 13 R/W OWN OWN
739433d6423SLionel Sambuc 12-0 R/W SIZE Descriptor Size
740433d6423SLionel Sambuc 3e-3f R/W ISR Interrupt Status Register
741433d6423SLionel Sambuc 6 R/W FOVW Fx FIFO Overflow Interrupt
742433d6423SLionel Sambuc 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
743433d6423SLionel Sambuc 3 R/W TER Transmit Error Interrupt
744433d6423SLionel Sambuc 2 R/W TOK Transmit OK Interrupt
745433d6423SLionel Sambuc 3e-3f R/W ISR Interrupt Status Register
746433d6423SLionel Sambuc 15 R/W SERR System Error Interrupt
747433d6423SLionel Sambuc 14 R/W TimeOut Time Out Interrupt
748433d6423SLionel Sambuc 13 R/W LenChg Cable Length Change Interrupt
749433d6423SLionel Sambuc 3e-3f R/W ISR Interrupt Status Register
750433d6423SLionel Sambuc 4 R/W RXOVW Rx Buffer Overflow Interrupt
751433d6423SLionel Sambuc 1 R/W RER Receive Error Interrupt
752433d6423SLionel Sambuc 0 R/W ROK Receive OK Interrupt
753433d6423SLionel Sambuc 4c-4f R/W MPC Missed Packet Counter
754433d6423SLionel Sambuc 60-61 R TSAD Transmit Status of All Descriptors
755433d6423SLionel Sambuc 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
756433d6423SLionel Sambuc 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
757433d6423SLionel Sambuc 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
758433d6423SLionel Sambuc 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
759433d6423SLionel Sambuc 6c-6d R DIS Disconnect Counter
760433d6423SLionel Sambuc 15-0 R DCNT Disconnect Counter
761433d6423SLionel Sambuc 6e-6f R FCSC False Carrier Sense Counter
762433d6423SLionel Sambuc 15-0 R FCSCNT False Carrier event counter
763433d6423SLionel Sambuc 72-73 R REC RX_ER Counter
764433d6423SLionel Sambuc 15-0 R RXERCNT Received packet counter
765433d6423SLionel Sambuc #endif
766433d6423SLionel Sambuc
7674081bff6SDavid van Moolenbroek if (!rep->re_got_int)
7684081bff6SDavid van Moolenbroek return;
7694081bff6SDavid van Moolenbroek rep->re_got_int = FALSE;
770433d6423SLionel Sambuc
7714081bff6SDavid van Moolenbroek netdriver_recv();
772433d6423SLionel Sambuc
773433d6423SLionel Sambuc if (rep->re_clear_rx)
774433d6423SLionel Sambuc rl_clear_rx(rep);
775433d6423SLionel Sambuc
776433d6423SLionel Sambuc if (rep->re_need_reset)
777433d6423SLionel Sambuc rl_do_reset(rep);
778433d6423SLionel Sambuc
7794081bff6SDavid van Moolenbroek if (rep->re_send_int) {
7804081bff6SDavid van Moolenbroek rep->re_send_int = FALSE;
7814081bff6SDavid van Moolenbroek
7824081bff6SDavid van Moolenbroek netdriver_send();
783433d6423SLionel Sambuc }
784433d6423SLionel Sambuc
7854081bff6SDavid van Moolenbroek if (rep->re_report_link) {
7864081bff6SDavid van Moolenbroek rep->re_report_link = FALSE;
787433d6423SLionel Sambuc
788*f7df02e7SDavid van Moolenbroek netdriver_link();
789*f7df02e7SDavid van Moolenbroek #if VERBOSE
7904081bff6SDavid van Moolenbroek rl_report_link(rep);
791*f7df02e7SDavid van Moolenbroek #endif
7924081bff6SDavid van Moolenbroek }
793433d6423SLionel Sambuc }
794433d6423SLionel Sambuc
795433d6423SLionel Sambuc /*===========================================================================*
796*f7df02e7SDavid van Moolenbroek * rl_get_link *
797*f7df02e7SDavid van Moolenbroek *===========================================================================*/
rl_get_link(uint32_t * media)798*f7df02e7SDavid van Moolenbroek static unsigned int rl_get_link(uint32_t *media)
799*f7df02e7SDavid van Moolenbroek {
800*f7df02e7SDavid van Moolenbroek port_t port;
801*f7df02e7SDavid van Moolenbroek u8_t msr;
802*f7df02e7SDavid van Moolenbroek u16_t mii_ctrl;
803*f7df02e7SDavid van Moolenbroek re_t *rep;
804*f7df02e7SDavid van Moolenbroek
805*f7df02e7SDavid van Moolenbroek rep = &re_state;
806*f7df02e7SDavid van Moolenbroek
807*f7df02e7SDavid van Moolenbroek port= rep->re_base_port;
808*f7df02e7SDavid van Moolenbroek msr= rl_inb(port, RL_MSR);
809*f7df02e7SDavid van Moolenbroek
810*f7df02e7SDavid van Moolenbroek if (msr & RL_MSR_LINKB)
811*f7df02e7SDavid van Moolenbroek return NDEV_LINK_DOWN;
812*f7df02e7SDavid van Moolenbroek
813*f7df02e7SDavid van Moolenbroek if (msr & RL_MSR_SPEED_10)
814*f7df02e7SDavid van Moolenbroek *media = IFM_ETHER | IFM_10_T;
815*f7df02e7SDavid van Moolenbroek else
816*f7df02e7SDavid van Moolenbroek *media = IFM_ETHER | IFM_100_TX;
817*f7df02e7SDavid van Moolenbroek
818*f7df02e7SDavid van Moolenbroek mii_ctrl= rl_inw(port, RL_BMCR);
819*f7df02e7SDavid van Moolenbroek if (mii_ctrl & MII_CTRL_DM)
820*f7df02e7SDavid van Moolenbroek *media |= IFM_FDX;
821*f7df02e7SDavid van Moolenbroek else
822*f7df02e7SDavid van Moolenbroek *media |= IFM_HDX;
823*f7df02e7SDavid van Moolenbroek
824*f7df02e7SDavid van Moolenbroek return NDEV_LINK_UP;
825*f7df02e7SDavid van Moolenbroek }
826*f7df02e7SDavid van Moolenbroek
827*f7df02e7SDavid van Moolenbroek #if VERBOSE
828*f7df02e7SDavid van Moolenbroek /*===========================================================================*
829433d6423SLionel Sambuc * rl_report_link *
830433d6423SLionel Sambuc *===========================================================================*/
rl_report_link(re_t * rep)8314081bff6SDavid van Moolenbroek static void rl_report_link(re_t *rep)
832433d6423SLionel Sambuc {
833433d6423SLionel Sambuc port_t port;
834433d6423SLionel Sambuc u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
835433d6423SLionel Sambuc u8_t msr;
836433d6423SLionel Sambuc int f, link_up;
837433d6423SLionel Sambuc
838433d6423SLionel Sambuc port= rep->re_base_port;
839433d6423SLionel Sambuc msr= rl_inb(port, RL_MSR);
840433d6423SLionel Sambuc link_up= !(msr & RL_MSR_LINKB);
841433d6423SLionel Sambuc rep->re_link_up= link_up;
842433d6423SLionel Sambuc if (!link_up)
843433d6423SLionel Sambuc {
844*f7df02e7SDavid van Moolenbroek printf("%s: link down\n", netdriver_name());
845433d6423SLionel Sambuc return;
846433d6423SLionel Sambuc }
847433d6423SLionel Sambuc
848433d6423SLionel Sambuc mii_ctrl= rl_inw(port, RL_BMCR);
849433d6423SLionel Sambuc mii_status= rl_inw(port, RL_BMSR);
850433d6423SLionel Sambuc mii_ana= rl_inw(port, RL_ANAR);
851433d6423SLionel Sambuc mii_anlpa= rl_inw(port, RL_ANLPAR);
852433d6423SLionel Sambuc mii_ane= rl_inw(port, RL_ANER);
853433d6423SLionel Sambuc mii_extstat= 0;
854433d6423SLionel Sambuc
855433d6423SLionel Sambuc if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
856433d6423SLionel Sambuc {
857*f7df02e7SDavid van Moolenbroek printf("%s: PHY: ", netdriver_name());
858433d6423SLionel Sambuc f= 1;
859433d6423SLionel Sambuc if (mii_ctrl & MII_CTRL_LB)
860433d6423SLionel Sambuc {
861433d6423SLionel Sambuc printf("loopback mode");
862433d6423SLionel Sambuc f= 0;
863433d6423SLionel Sambuc }
864433d6423SLionel Sambuc if (mii_ctrl & MII_CTRL_PD)
865433d6423SLionel Sambuc {
866433d6423SLionel Sambuc if (!f) printf(", ");
867433d6423SLionel Sambuc f= 0;
868433d6423SLionel Sambuc printf("powered down");
869433d6423SLionel Sambuc }
870433d6423SLionel Sambuc if (mii_ctrl & MII_CTRL_ISO)
871433d6423SLionel Sambuc {
872433d6423SLionel Sambuc if (!f) printf(", ");
873433d6423SLionel Sambuc f= 0;
874433d6423SLionel Sambuc printf("isolated");
875433d6423SLionel Sambuc }
876433d6423SLionel Sambuc printf("\n");
877433d6423SLionel Sambuc return;
878433d6423SLionel Sambuc }
879433d6423SLionel Sambuc if (!(mii_ctrl & MII_CTRL_ANE))
880433d6423SLionel Sambuc {
881*f7df02e7SDavid van Moolenbroek printf("%s: manual config: ", netdriver_name());
882433d6423SLionel Sambuc switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
883433d6423SLionel Sambuc {
884433d6423SLionel Sambuc case MII_CTRL_SP_10: printf("10 Mbps"); break;
885433d6423SLionel Sambuc case MII_CTRL_SP_100: printf("100 Mbps"); break;
886433d6423SLionel Sambuc case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
887433d6423SLionel Sambuc case MII_CTRL_SP_RES: printf("reserved speed"); break;
888433d6423SLionel Sambuc }
889433d6423SLionel Sambuc if (mii_ctrl & MII_CTRL_DM)
890433d6423SLionel Sambuc printf(", full duplex");
891433d6423SLionel Sambuc else
892433d6423SLionel Sambuc printf(", half duplex");
893433d6423SLionel Sambuc printf("\n");
894433d6423SLionel Sambuc return;
895433d6423SLionel Sambuc }
896433d6423SLionel Sambuc
8974081bff6SDavid van Moolenbroek #if VERBOSE
898*f7df02e7SDavid van Moolenbroek printf("%s: ", netdriver_name());
899433d6423SLionel Sambuc mii_print_stat_speed(mii_status, mii_extstat);
900433d6423SLionel Sambuc printf("\n");
901433d6423SLionel Sambuc
902433d6423SLionel Sambuc if (!(mii_status & MII_STATUS_ANC))
903*f7df02e7SDavid van Moolenbroek printf("%s: auto-negotiation not complete\n",
904*f7df02e7SDavid van Moolenbroek netdriver_name());
905433d6423SLionel Sambuc if (mii_status & MII_STATUS_RF)
906*f7df02e7SDavid van Moolenbroek printf("%s: remote fault detected\n", netdriver_name());
907433d6423SLionel Sambuc if (!(mii_status & MII_STATUS_ANA))
908433d6423SLionel Sambuc {
909433d6423SLionel Sambuc printf("%s: local PHY has no auto-negotiation ability\n",
910*f7df02e7SDavid van Moolenbroek netdriver_name());
911433d6423SLionel Sambuc }
912433d6423SLionel Sambuc if (!(mii_status & MII_STATUS_LS))
913*f7df02e7SDavid van Moolenbroek printf("%s: link down\n", netdriver_name());
914433d6423SLionel Sambuc if (mii_status & MII_STATUS_JD)
915*f7df02e7SDavid van Moolenbroek printf("%s: jabber condition detected\n",
916*f7df02e7SDavid van Moolenbroek netdriver_name());
917433d6423SLionel Sambuc if (!(mii_status & MII_STATUS_EC))
918433d6423SLionel Sambuc {
919*f7df02e7SDavid van Moolenbroek printf("%s: no extended register set\n", netdriver_name());
920433d6423SLionel Sambuc goto resspeed;
921433d6423SLionel Sambuc }
922433d6423SLionel Sambuc if (!(mii_status & MII_STATUS_ANC))
923433d6423SLionel Sambuc goto resspeed;
924433d6423SLionel Sambuc
925*f7df02e7SDavid van Moolenbroek printf("%s: local cap.: ", netdriver_name());
926433d6423SLionel Sambuc mii_print_techab(mii_ana);
927433d6423SLionel Sambuc printf("\n");
928433d6423SLionel Sambuc
929433d6423SLionel Sambuc if (mii_ane & MII_ANE_PDF)
930*f7df02e7SDavid van Moolenbroek printf("%s: parallel detection fault\n", netdriver_name());
931433d6423SLionel Sambuc if (!(mii_ane & MII_ANE_LPANA))
932433d6423SLionel Sambuc {
933433d6423SLionel Sambuc printf("%s: link-partner does not support auto-negotiation\n",
934*f7df02e7SDavid van Moolenbroek netdriver_name());
935433d6423SLionel Sambuc goto resspeed;
936433d6423SLionel Sambuc }
937433d6423SLionel Sambuc
938*f7df02e7SDavid van Moolenbroek printf("%s: remote cap.: ", netdriver_name());
939433d6423SLionel Sambuc mii_print_techab(mii_anlpa);
940433d6423SLionel Sambuc printf("\n");
941433d6423SLionel Sambuc resspeed:
9424081bff6SDavid van Moolenbroek #endif
9434081bff6SDavid van Moolenbroek
944*f7df02e7SDavid van Moolenbroek printf("%s: ", netdriver_name());
945433d6423SLionel Sambuc printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
946433d6423SLionel Sambuc printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
947433d6423SLionel Sambuc
948433d6423SLionel Sambuc }
949433d6423SLionel Sambuc
mii_print_techab(u16_t techab)950433d6423SLionel Sambuc static void mii_print_techab(u16_t techab)
951433d6423SLionel Sambuc {
952433d6423SLionel Sambuc int fs, ft;
953433d6423SLionel Sambuc if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
954433d6423SLionel Sambuc {
955433d6423SLionel Sambuc printf("strange selector 0x%x, value 0x%x",
956433d6423SLionel Sambuc techab & MII_ANA_SEL_M,
957433d6423SLionel Sambuc (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
958433d6423SLionel Sambuc return;
959433d6423SLionel Sambuc }
960433d6423SLionel Sambuc fs= 1;
961433d6423SLionel Sambuc if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
962433d6423SLionel Sambuc {
963433d6423SLionel Sambuc printf("100 Mbps: ");
964433d6423SLionel Sambuc fs= 0;
965433d6423SLionel Sambuc ft= 1;
966433d6423SLionel Sambuc if (techab & MII_ANA_100T4)
967433d6423SLionel Sambuc {
968433d6423SLionel Sambuc printf("T4");
969433d6423SLionel Sambuc ft= 0;
970433d6423SLionel Sambuc }
971433d6423SLionel Sambuc if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
972433d6423SLionel Sambuc {
973433d6423SLionel Sambuc if (!ft)
974433d6423SLionel Sambuc printf(", ");
975433d6423SLionel Sambuc ft= 0;
976433d6423SLionel Sambuc printf("TX-");
977433d6423SLionel Sambuc switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
978433d6423SLionel Sambuc {
979433d6423SLionel Sambuc case MII_ANA_100TXFD: printf("FD"); break;
980433d6423SLionel Sambuc case MII_ANA_100TXHD: printf("HD"); break;
981433d6423SLionel Sambuc default: printf("FD/HD"); break;
982433d6423SLionel Sambuc }
983433d6423SLionel Sambuc }
984433d6423SLionel Sambuc }
985433d6423SLionel Sambuc if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
986433d6423SLionel Sambuc {
987433d6423SLionel Sambuc if (!fs)
988433d6423SLionel Sambuc printf(", ");
989433d6423SLionel Sambuc printf("10 Mbps: ");
990433d6423SLionel Sambuc fs= 0;
991433d6423SLionel Sambuc printf("T-");
992433d6423SLionel Sambuc switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
993433d6423SLionel Sambuc {
994433d6423SLionel Sambuc case MII_ANA_10TFD: printf("FD"); break;
995433d6423SLionel Sambuc case MII_ANA_10THD: printf("HD"); break;
996433d6423SLionel Sambuc default: printf("FD/HD"); break;
997433d6423SLionel Sambuc }
998433d6423SLionel Sambuc }
999433d6423SLionel Sambuc if (techab & MII_ANA_PAUSE_SYM)
1000433d6423SLionel Sambuc {
1001433d6423SLionel Sambuc if (!fs)
1002433d6423SLionel Sambuc printf(", ");
1003433d6423SLionel Sambuc fs= 0;
1004433d6423SLionel Sambuc printf("pause(SYM)");
1005433d6423SLionel Sambuc }
1006433d6423SLionel Sambuc if (techab & MII_ANA_PAUSE_ASYM)
1007433d6423SLionel Sambuc {
1008433d6423SLionel Sambuc if (!fs)
1009433d6423SLionel Sambuc printf(", ");
1010433d6423SLionel Sambuc fs= 0;
1011433d6423SLionel Sambuc printf("pause(ASYM)");
1012433d6423SLionel Sambuc }
1013433d6423SLionel Sambuc if (techab & MII_ANA_TAF_RES)
1014433d6423SLionel Sambuc {
1015433d6423SLionel Sambuc if (!fs)
1016433d6423SLionel Sambuc printf(", ");
1017433d6423SLionel Sambuc fs= 0;
1018433d6423SLionel Sambuc printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
1019433d6423SLionel Sambuc }
1020433d6423SLionel Sambuc }
1021433d6423SLionel Sambuc
mii_print_stat_speed(u16_t stat,u16_t extstat)1022433d6423SLionel Sambuc static void mii_print_stat_speed(u16_t stat, u16_t extstat)
1023433d6423SLionel Sambuc {
1024433d6423SLionel Sambuc int fs, ft;
1025433d6423SLionel Sambuc fs= 1;
1026433d6423SLionel Sambuc if (stat & MII_STATUS_EXT_STAT)
1027433d6423SLionel Sambuc {
1028433d6423SLionel Sambuc if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1029433d6423SLionel Sambuc MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1030433d6423SLionel Sambuc {
1031433d6423SLionel Sambuc printf("1000 Mbps: ");
1032433d6423SLionel Sambuc fs= 0;
1033433d6423SLionel Sambuc ft= 1;
1034433d6423SLionel Sambuc if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1035433d6423SLionel Sambuc {
1036433d6423SLionel Sambuc ft= 0;
1037433d6423SLionel Sambuc printf("X-");
1038433d6423SLionel Sambuc switch(extstat &
1039433d6423SLionel Sambuc (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1040433d6423SLionel Sambuc {
1041433d6423SLionel Sambuc case MII_ESTAT_1000XFD: printf("FD"); break;
1042433d6423SLionel Sambuc case MII_ESTAT_1000XHD: printf("HD"); break;
1043433d6423SLionel Sambuc default: printf("FD/HD"); break;
1044433d6423SLionel Sambuc }
1045433d6423SLionel Sambuc }
1046433d6423SLionel Sambuc if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1047433d6423SLionel Sambuc {
1048433d6423SLionel Sambuc if (!ft)
1049433d6423SLionel Sambuc printf(", ");
1050433d6423SLionel Sambuc ft= 0;
1051433d6423SLionel Sambuc printf("T-");
1052433d6423SLionel Sambuc switch(extstat &
1053433d6423SLionel Sambuc (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1054433d6423SLionel Sambuc {
1055433d6423SLionel Sambuc case MII_ESTAT_1000TFD: printf("FD"); break;
1056433d6423SLionel Sambuc case MII_ESTAT_1000THD: printf("HD"); break;
1057433d6423SLionel Sambuc default: printf("FD/HD"); break;
1058433d6423SLionel Sambuc }
1059433d6423SLionel Sambuc }
1060433d6423SLionel Sambuc }
1061433d6423SLionel Sambuc }
1062433d6423SLionel Sambuc if (stat & (MII_STATUS_100T4 |
1063433d6423SLionel Sambuc MII_STATUS_100XFD | MII_STATUS_100XHD |
1064433d6423SLionel Sambuc MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1065433d6423SLionel Sambuc {
1066433d6423SLionel Sambuc if (!fs)
1067433d6423SLionel Sambuc printf(", ");
1068433d6423SLionel Sambuc fs= 0;
1069433d6423SLionel Sambuc printf("100 Mbps: ");
1070433d6423SLionel Sambuc ft= 1;
1071433d6423SLionel Sambuc if (stat & MII_STATUS_100T4)
1072433d6423SLionel Sambuc {
1073433d6423SLionel Sambuc printf("T4");
1074433d6423SLionel Sambuc ft= 0;
1075433d6423SLionel Sambuc }
1076433d6423SLionel Sambuc if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1077433d6423SLionel Sambuc {
1078433d6423SLionel Sambuc if (!ft)
1079433d6423SLionel Sambuc printf(", ");
1080433d6423SLionel Sambuc ft= 0;
1081433d6423SLionel Sambuc printf("TX-");
1082433d6423SLionel Sambuc switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1083433d6423SLionel Sambuc {
1084433d6423SLionel Sambuc case MII_STATUS_100XFD: printf("FD"); break;
1085433d6423SLionel Sambuc case MII_STATUS_100XHD: printf("HD"); break;
1086433d6423SLionel Sambuc default: printf("FD/HD"); break;
1087433d6423SLionel Sambuc }
1088433d6423SLionel Sambuc }
1089433d6423SLionel Sambuc if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1090433d6423SLionel Sambuc {
1091433d6423SLionel Sambuc if (!ft)
1092433d6423SLionel Sambuc printf(", ");
1093433d6423SLionel Sambuc ft= 0;
1094433d6423SLionel Sambuc printf("T2-");
1095433d6423SLionel Sambuc switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1096433d6423SLionel Sambuc {
1097433d6423SLionel Sambuc case MII_STATUS_100T2FD: printf("FD"); break;
1098433d6423SLionel Sambuc case MII_STATUS_100T2HD: printf("HD"); break;
1099433d6423SLionel Sambuc default: printf("FD/HD"); break;
1100433d6423SLionel Sambuc }
1101433d6423SLionel Sambuc }
1102433d6423SLionel Sambuc }
1103433d6423SLionel Sambuc if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1104433d6423SLionel Sambuc {
1105433d6423SLionel Sambuc if (!fs)
1106433d6423SLionel Sambuc printf(", ");
1107433d6423SLionel Sambuc printf("10 Mbps: ");
1108433d6423SLionel Sambuc fs= 0;
1109433d6423SLionel Sambuc printf("T-");
1110433d6423SLionel Sambuc switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1111433d6423SLionel Sambuc {
1112433d6423SLionel Sambuc case MII_STATUS_10FD: printf("FD"); break;
1113433d6423SLionel Sambuc case MII_STATUS_10HD: printf("HD"); break;
1114433d6423SLionel Sambuc default: printf("FD/HD"); break;
1115433d6423SLionel Sambuc }
1116433d6423SLionel Sambuc }
1117433d6423SLionel Sambuc }
11184081bff6SDavid van Moolenbroek #endif /* VERBOSE */
1119433d6423SLionel Sambuc
1120433d6423SLionel Sambuc /*===========================================================================*
1121433d6423SLionel Sambuc * rl_clear_rx *
1122433d6423SLionel Sambuc *===========================================================================*/
rl_clear_rx(re_t * rep)1123433d6423SLionel Sambuc static void rl_clear_rx(re_t *rep)
1124433d6423SLionel Sambuc {
1125433d6423SLionel Sambuc port_t port;
1126433d6423SLionel Sambuc u8_t cr;
1127433d6423SLionel Sambuc
1128433d6423SLionel Sambuc rep->re_clear_rx= FALSE;
1129433d6423SLionel Sambuc port= rep->re_base_port;
1130433d6423SLionel Sambuc
1131433d6423SLionel Sambuc /* Reset the receiver */
1132433d6423SLionel Sambuc cr= rl_inb(port, RL_CR);
1133433d6423SLionel Sambuc cr &= ~RL_CR_RE;
1134433d6423SLionel Sambuc rl_outb(port, RL_CR, cr);
1135433d6423SLionel Sambuc SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000);
1136433d6423SLionel Sambuc if (rl_inb(port, RL_CR) & RL_CR_RE)
1137433d6423SLionel Sambuc panic("cannot disable receiver");
1138433d6423SLionel Sambuc
1139433d6423SLionel Sambuc #if 0
1140433d6423SLionel Sambuc printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1141433d6423SLionel Sambuc printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1142433d6423SLionel Sambuc printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1143433d6423SLionel Sambuc printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1144433d6423SLionel Sambuc #endif
1145433d6423SLionel Sambuc
1146433d6423SLionel Sambuc rl_outb(port, RL_CR, cr | RL_CR_RE);
1147433d6423SLionel Sambuc
1148433d6423SLionel Sambuc rl_outl(port, RL_RCR, RX_BUFBITS);
1149433d6423SLionel Sambuc
1150433d6423SLionel Sambuc rl_rec_mode(rep);
1151433d6423SLionel Sambuc
1152*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(1);
1153433d6423SLionel Sambuc }
1154433d6423SLionel Sambuc
1155433d6423SLionel Sambuc /*===========================================================================*
1156433d6423SLionel Sambuc * rl_do_reset *
1157433d6423SLionel Sambuc *===========================================================================*/
rl_do_reset(re_t * rep)11584081bff6SDavid van Moolenbroek static void rl_do_reset(re_t *rep)
1159433d6423SLionel Sambuc {
1160433d6423SLionel Sambuc rep->re_need_reset= FALSE;
1161433d6423SLionel Sambuc rl_reset_hw(rep);
1162433d6423SLionel Sambuc rl_rec_mode(rep);
1163433d6423SLionel Sambuc
1164433d6423SLionel Sambuc rep->re_tx_head= 0;
11654081bff6SDavid van Moolenbroek if (rep->re_tx[rep->re_tx_head].ret_busy)
11664081bff6SDavid van Moolenbroek rep->re_tx_busy--;
1167433d6423SLionel Sambuc rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1168433d6423SLionel Sambuc rep->re_send_int= TRUE;
1169433d6423SLionel Sambuc }
1170433d6423SLionel Sambuc
1171433d6423SLionel Sambuc #if 0
1172433d6423SLionel Sambuc /*===========================================================================*
1173433d6423SLionel Sambuc * dump_phy *
1174433d6423SLionel Sambuc *===========================================================================*/
11754081bff6SDavid van Moolenbroek static void dump_phy(re_t *rep)
1176433d6423SLionel Sambuc {
1177433d6423SLionel Sambuc port_t port;
1178433d6423SLionel Sambuc u32_t t;
1179433d6423SLionel Sambuc
1180433d6423SLionel Sambuc port= rep->re_base_port;
1181433d6423SLionel Sambuc
1182433d6423SLionel Sambuc t= rl_inb(port, RL_MSR);
1183433d6423SLionel Sambuc printf("MSR: 0x%02lx\n", t);
1184433d6423SLionel Sambuc if (t & RL_MSR_SPEED_10)
1185433d6423SLionel Sambuc printf("\t10 Mbps\n");
1186433d6423SLionel Sambuc if (t & RL_MSR_LINKB)
1187433d6423SLionel Sambuc printf("\tLink failed\n");
1188433d6423SLionel Sambuc
1189433d6423SLionel Sambuc t= rl_inb(port, RL_CONFIG1);
1190433d6423SLionel Sambuc printf("CONFIG1: 0x%02lx\n", t);
1191433d6423SLionel Sambuc
1192433d6423SLionel Sambuc t= rl_inb(port, RL_CONFIG3);
1193433d6423SLionel Sambuc printf("CONFIG3: 0x%02lx\n", t);
1194433d6423SLionel Sambuc
1195433d6423SLionel Sambuc t= rl_inb(port, RL_CONFIG4);
1196433d6423SLionel Sambuc printf("CONFIG4: 0x%02lx\n", t);
1197433d6423SLionel Sambuc
1198433d6423SLionel Sambuc t= rl_inw(port, RL_BMCR);
1199433d6423SLionel Sambuc printf("BMCR (MII_CTRL): 0x%04lx\n", t);
1200433d6423SLionel Sambuc
1201433d6423SLionel Sambuc t= rl_inw(port, RL_BMSR);
1202433d6423SLionel Sambuc printf("BMSR:");
1203433d6423SLionel Sambuc if (t & MII_STATUS_100T4)
1204433d6423SLionel Sambuc printf(" 100Base-T4");
1205433d6423SLionel Sambuc if (t & MII_STATUS_100XFD)
1206433d6423SLionel Sambuc printf(" 100Base-X-FD");
1207433d6423SLionel Sambuc if (t & MII_STATUS_100XHD)
1208433d6423SLionel Sambuc printf(" 100Base-X-HD");
1209433d6423SLionel Sambuc if (t & MII_STATUS_10FD)
1210433d6423SLionel Sambuc printf(" 10Mbps-FD");
1211433d6423SLionel Sambuc if (t & MII_STATUS_10HD)
1212433d6423SLionel Sambuc printf(" 10Mbps-HD");
1213433d6423SLionel Sambuc if (t & MII_STATUS_100T2FD)
1214433d6423SLionel Sambuc printf(" 100Base-T2-FD");
1215433d6423SLionel Sambuc if (t & MII_STATUS_100T2HD)
1216433d6423SLionel Sambuc printf(" 100Base-T2-HD");
1217433d6423SLionel Sambuc if (t & MII_STATUS_EXT_STAT)
1218433d6423SLionel Sambuc printf(" Ext-stat");
1219433d6423SLionel Sambuc if (t & MII_STATUS_RES)
1220433d6423SLionel Sambuc printf(" res-0x%lx", t & MII_STATUS_RES);
1221433d6423SLionel Sambuc if (t & MII_STATUS_MFPS)
1222433d6423SLionel Sambuc printf(" MFPS");
1223433d6423SLionel Sambuc if (t & MII_STATUS_ANC)
1224433d6423SLionel Sambuc printf(" ANC");
1225433d6423SLionel Sambuc if (t & MII_STATUS_RF)
1226433d6423SLionel Sambuc printf(" remote-fault");
1227433d6423SLionel Sambuc if (t & MII_STATUS_ANA)
1228433d6423SLionel Sambuc printf(" ANA");
1229433d6423SLionel Sambuc if (t & MII_STATUS_LS)
1230433d6423SLionel Sambuc printf(" Link");
1231433d6423SLionel Sambuc if (t & MII_STATUS_JD)
1232433d6423SLionel Sambuc printf(" Jabber");
1233433d6423SLionel Sambuc if (t & MII_STATUS_EC)
1234433d6423SLionel Sambuc printf(" Extended-capability");
1235433d6423SLionel Sambuc printf("\n");
1236433d6423SLionel Sambuc
1237433d6423SLionel Sambuc t= rl_inw(port, RL_ANAR);
1238433d6423SLionel Sambuc printf("ANAR (MII_ANA): 0x%04lx\n", t);
1239433d6423SLionel Sambuc
1240433d6423SLionel Sambuc t= rl_inw(port, RL_ANLPAR);
1241433d6423SLionel Sambuc printf("ANLPAR: 0x%04lx\n", t);
1242433d6423SLionel Sambuc
1243433d6423SLionel Sambuc t= rl_inw(port, RL_ANER);
1244433d6423SLionel Sambuc printf("ANER (MII_ANE): ");
1245433d6423SLionel Sambuc if (t & MII_ANE_RES)
1246433d6423SLionel Sambuc printf(" res-0x%lx", t & MII_ANE_RES);
1247433d6423SLionel Sambuc if (t & MII_ANE_PDF)
1248433d6423SLionel Sambuc printf(" Par-Detect-Fault");
1249433d6423SLionel Sambuc if (t & MII_ANE_LPNPA)
1250433d6423SLionel Sambuc printf(" LP-Next-Page-Able");
1251433d6423SLionel Sambuc if (t & MII_ANE_NPA)
1252433d6423SLionel Sambuc printf(" Loc-Next-Page-Able");
1253433d6423SLionel Sambuc if (t & MII_ANE_PR)
1254433d6423SLionel Sambuc printf(" Page-Received");
1255433d6423SLionel Sambuc if (t & MII_ANE_LPANA)
1256433d6423SLionel Sambuc printf(" LP-Auto-Neg-Able");
1257433d6423SLionel Sambuc printf("\n");
1258433d6423SLionel Sambuc
1259433d6423SLionel Sambuc t= rl_inw(port, RL_NWAYTR);
1260433d6423SLionel Sambuc printf("NWAYTR: 0x%04lx\n", t);
1261433d6423SLionel Sambuc t= rl_inw(port, RL_CSCR);
1262433d6423SLionel Sambuc printf("CSCR: 0x%04lx\n", t);
1263433d6423SLionel Sambuc
1264433d6423SLionel Sambuc t= rl_inb(port, RL_CONFIG5);
1265433d6423SLionel Sambuc printf("CONFIG5: 0x%02lx\n", t);
1266433d6423SLionel Sambuc }
1267433d6423SLionel Sambuc #endif
1268433d6423SLionel Sambuc
1269433d6423SLionel Sambuc /*===========================================================================*
1270433d6423SLionel Sambuc * rl_handler *
1271433d6423SLionel Sambuc *===========================================================================*/
rl_handler(re_t * rep)1272433d6423SLionel Sambuc static int rl_handler(re_t *rep)
1273433d6423SLionel Sambuc {
1274433d6423SLionel Sambuc int i, port, tx_head, tx_tail, link_up;
1275433d6423SLionel Sambuc u16_t isr, tsad;
1276433d6423SLionel Sambuc u32_t tsd, tcr, ertxth;
1277433d6423SLionel Sambuc
1278433d6423SLionel Sambuc port= rep->re_base_port;
1279433d6423SLionel Sambuc
1280433d6423SLionel Sambuc /* Ack interrupt */
1281433d6423SLionel Sambuc isr= rl_inw(port, RL_ISR);
1282433d6423SLionel Sambuc rl_outw(port, RL_ISR, isr);
1283433d6423SLionel Sambuc
1284433d6423SLionel Sambuc if (isr & RL_IMR_FOVW)
1285433d6423SLionel Sambuc {
1286433d6423SLionel Sambuc isr &= ~RL_IMR_FOVW;
1287433d6423SLionel Sambuc /* Should do anything? */
1288433d6423SLionel Sambuc }
1289433d6423SLionel Sambuc if (isr & RL_IMR_PUN)
1290433d6423SLionel Sambuc {
1291433d6423SLionel Sambuc isr &= ~RL_IMR_PUN;
1292433d6423SLionel Sambuc
1293433d6423SLionel Sambuc /* Either the link status changed or there was a TX fifo
1294433d6423SLionel Sambuc * underrun.
1295433d6423SLionel Sambuc */
1296433d6423SLionel Sambuc link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
1297433d6423SLionel Sambuc if (link_up != rep->re_link_up)
1298433d6423SLionel Sambuc {
1299433d6423SLionel Sambuc rep->re_report_link= TRUE;
1300433d6423SLionel Sambuc rep->re_got_int= TRUE;
1301433d6423SLionel Sambuc }
1302433d6423SLionel Sambuc }
1303433d6423SLionel Sambuc if (isr & RL_IMR_RXOVW)
1304433d6423SLionel Sambuc {
1305433d6423SLionel Sambuc isr &= ~RL_IMR_RXOVW;
1306433d6423SLionel Sambuc
1307433d6423SLionel Sambuc /* Clear the receive buffer */
1308433d6423SLionel Sambuc rep->re_clear_rx= TRUE;
1309433d6423SLionel Sambuc rep->re_got_int= TRUE;
1310433d6423SLionel Sambuc }
1311433d6423SLionel Sambuc
1312433d6423SLionel Sambuc if (isr & (RL_ISR_RER | RL_ISR_ROK))
1313433d6423SLionel Sambuc {
1314433d6423SLionel Sambuc isr &= ~(RL_ISR_RER | RL_ISR_ROK);
1315433d6423SLionel Sambuc
1316433d6423SLionel Sambuc rep->re_got_int= TRUE;
1317433d6423SLionel Sambuc }
1318433d6423SLionel Sambuc if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
1319433d6423SLionel Sambuc {
1320433d6423SLionel Sambuc isr &= ~(RL_ISR_TER | RL_ISR_TOK);
1321433d6423SLionel Sambuc
1322433d6423SLionel Sambuc tsad= rl_inw(port, RL_TSAD);
1323433d6423SLionel Sambuc if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
1324433d6423SLionel Sambuc RL_TSAD_TABT2|RL_TSAD_TABT3))
1325433d6423SLionel Sambuc {
1326433d6423SLionel Sambuc printf("rl_handler, TABT, tasd = 0x%04x\n",
1327433d6423SLionel Sambuc tsad);
1328433d6423SLionel Sambuc
1329433d6423SLionel Sambuc /* Find the aborted transmit request */
1330433d6423SLionel Sambuc for (i= 0; i< N_TX_BUF; i++)
1331433d6423SLionel Sambuc {
1332433d6423SLionel Sambuc tsd= rl_inl(port, RL_TSD0+i*4);
1333433d6423SLionel Sambuc if (tsd & RL_TSD_TABT)
1334433d6423SLionel Sambuc break;
1335433d6423SLionel Sambuc }
1336433d6423SLionel Sambuc if (i >= N_TX_BUF)
1337433d6423SLionel Sambuc {
1338433d6423SLionel Sambuc printf(
1339433d6423SLionel Sambuc "rl_handler: can't find aborted TX req.\n");
1340433d6423SLionel Sambuc }
1341433d6423SLionel Sambuc else
1342433d6423SLionel Sambuc {
1343433d6423SLionel Sambuc printf("TSD%d = 0x%04x\n", i, tsd);
1344433d6423SLionel Sambuc
1345433d6423SLionel Sambuc /* Set head and tail to this buffer */
1346433d6423SLionel Sambuc rep->re_tx_head= rep->re_tx_tail= i;
1347433d6423SLionel Sambuc }
1348433d6423SLionel Sambuc
1349433d6423SLionel Sambuc /* Aborted transmission, just kick the device
1350433d6423SLionel Sambuc * and be done with it.
1351433d6423SLionel Sambuc */
1352*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(1);
1353*f7df02e7SDavid van Moolenbroek
1354433d6423SLionel Sambuc tcr= rl_inl(port, RL_TCR);
1355433d6423SLionel Sambuc rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1356433d6423SLionel Sambuc }
1357433d6423SLionel Sambuc
1358433d6423SLionel Sambuc /* Transmit completed */
1359433d6423SLionel Sambuc tx_head= rep->re_tx_head;
1360433d6423SLionel Sambuc tx_tail= rep->re_tx_tail;
1361433d6423SLionel Sambuc for (i= 0; i< 2*N_TX_BUF; i++)
1362433d6423SLionel Sambuc {
1363*f7df02e7SDavid van Moolenbroek if (rep->re_tx_busy == 0)
1364*f7df02e7SDavid van Moolenbroek break;
1365433d6423SLionel Sambuc if (!rep->re_tx[tx_tail].ret_busy)
1366433d6423SLionel Sambuc {
1367433d6423SLionel Sambuc /* Strange, this buffer is not in-use.
1368433d6423SLionel Sambuc * Increment tx_tail until tx_head is
1369433d6423SLionel Sambuc * reached (or until we find a buffer that
1370433d6423SLionel Sambuc * is in-use.
1371433d6423SLionel Sambuc */
1372433d6423SLionel Sambuc if (tx_tail == tx_head)
1373433d6423SLionel Sambuc break;
1374433d6423SLionel Sambuc if (++tx_tail >= N_TX_BUF)
1375433d6423SLionel Sambuc tx_tail= 0;
1376433d6423SLionel Sambuc assert(tx_tail < RL_N_TX);
1377433d6423SLionel Sambuc rep->re_tx_tail= tx_tail;
1378433d6423SLionel Sambuc continue;
1379433d6423SLionel Sambuc }
1380433d6423SLionel Sambuc tsd= rl_inl(port, RL_TSD0+tx_tail*4);
1381*f7df02e7SDavid van Moolenbroek if (!(tsd & (RL_TSD_TABT | RL_TSD_TOK | RL_TSD_TUN)))
1382433d6423SLionel Sambuc {
1383433d6423SLionel Sambuc /* Buffer is not yet ready */
1384433d6423SLionel Sambuc break;
1385433d6423SLionel Sambuc }
1386433d6423SLionel Sambuc
1387433d6423SLionel Sambuc /* Should collect statistics */
1388433d6423SLionel Sambuc if (tsd & RL_TSD_TABT)
1389433d6423SLionel Sambuc {
1390433d6423SLionel Sambuc printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1391433d6423SLionel Sambuc tx_tail, tsd);
1392*f7df02e7SDavid van Moolenbroek panic("TX abort"); /* CLRABT is not all that
1393*f7df02e7SDavid van Moolenbroek * that effective, why not?
1394433d6423SLionel Sambuc */
1395433d6423SLionel Sambuc tcr= rl_inl(port, RL_TCR);
1396433d6423SLionel Sambuc rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1397433d6423SLionel Sambuc }
1398433d6423SLionel Sambuc
1399433d6423SLionel Sambuc /* What about collisions? */
1400*f7df02e7SDavid van Moolenbroek if (!(tsd & RL_TSD_TOK))
1401*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(1);
1402433d6423SLionel Sambuc if (tsd & RL_TSD_TUN)
1403433d6423SLionel Sambuc {
1404433d6423SLionel Sambuc /* Increase ERTXTH */
1405433d6423SLionel Sambuc ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
1406433d6423SLionel Sambuc ertxth &= RL_TSD_ERTXTH_M;
14074081bff6SDavid van Moolenbroek #if VERBOSE
14084081bff6SDavid van Moolenbroek if (ertxth > rep->re_ertxth)
1409433d6423SLionel Sambuc {
1410433d6423SLionel Sambuc printf("%s: new ertxth: %d bytes\n",
1411*f7df02e7SDavid van Moolenbroek netdriver_name(),
1412433d6423SLionel Sambuc (ertxth >> RL_TSD_ERTXTH_S) *
1413433d6423SLionel Sambuc 32);
1414433d6423SLionel Sambuc rep->re_ertxth= ertxth;
1415433d6423SLionel Sambuc }
14164081bff6SDavid van Moolenbroek #endif
1417433d6423SLionel Sambuc }
1418433d6423SLionel Sambuc rep->re_tx[tx_tail].ret_busy= FALSE;
14194081bff6SDavid van Moolenbroek rep->re_tx_busy--;
1420433d6423SLionel Sambuc
1421433d6423SLionel Sambuc #if 0
1422433d6423SLionel Sambuc printf("TSD%d: %08lx\n", tx_tail, tsd);
1423433d6423SLionel Sambuc printf(
1424433d6423SLionel Sambuc "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1425433d6423SLionel Sambuc tx_head, tx_tail,
1426433d6423SLionel Sambuc rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1427433d6423SLionel Sambuc rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1428433d6423SLionel Sambuc #endif
1429433d6423SLionel Sambuc
1430433d6423SLionel Sambuc if (++tx_tail >= N_TX_BUF)
1431433d6423SLionel Sambuc tx_tail= 0;
1432433d6423SLionel Sambuc assert(tx_tail < RL_N_TX);
1433433d6423SLionel Sambuc rep->re_tx_tail= tx_tail;
1434433d6423SLionel Sambuc
1435433d6423SLionel Sambuc rep->re_send_int= TRUE;
1436433d6423SLionel Sambuc rep->re_got_int= TRUE;
14374081bff6SDavid van Moolenbroek rep->re_tx_alive= TRUE;
1438433d6423SLionel Sambuc }
1439433d6423SLionel Sambuc assert(i < 2*N_TX_BUF);
1440433d6423SLionel Sambuc }
1441433d6423SLionel Sambuc if (isr)
1442433d6423SLionel Sambuc {
1443433d6423SLionel Sambuc printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1444433d6423SLionel Sambuc isr);
1445433d6423SLionel Sambuc }
1446433d6423SLionel Sambuc
1447433d6423SLionel Sambuc return 1;
1448433d6423SLionel Sambuc }
1449433d6423SLionel Sambuc
1450433d6423SLionel Sambuc /*===========================================================================*
1451*f7df02e7SDavid van Moolenbroek * rl_tick *
1452433d6423SLionel Sambuc *===========================================================================*/
rl_tick(void)1453*f7df02e7SDavid van Moolenbroek static void rl_tick(void)
1454433d6423SLionel Sambuc {
1455433d6423SLionel Sambuc re_t *rep;
14564081bff6SDavid van Moolenbroek
1457433d6423SLionel Sambuc rep= &re_state;
1458433d6423SLionel Sambuc
14594081bff6SDavid van Moolenbroek assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF);
14604081bff6SDavid van Moolenbroek if (rep->re_tx_busy == 0)
1461433d6423SLionel Sambuc {
1462433d6423SLionel Sambuc /* Assume that an idle system is alive */
1463433d6423SLionel Sambuc rep->re_tx_alive= TRUE;
1464433d6423SLionel Sambuc return;
1465433d6423SLionel Sambuc }
1466433d6423SLionel Sambuc if (rep->re_tx_alive)
1467433d6423SLionel Sambuc {
1468433d6423SLionel Sambuc rep->re_tx_alive= FALSE;
1469433d6423SLionel Sambuc return;
1470433d6423SLionel Sambuc }
1471*f7df02e7SDavid van Moolenbroek printf("%s: TX timeout, resetting\n", netdriver_name());
1472433d6423SLionel Sambuc printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1473433d6423SLionel Sambuc rl_inw(rep->re_base_port, RL_TSAD),
1474433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+0*4),
1475433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+1*4),
1476433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+2*4),
1477433d6423SLionel Sambuc rl_inl(rep->re_base_port, RL_TSD0+3*4));
1478433d6423SLionel Sambuc printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1479433d6423SLionel Sambuc rep->re_tx_head, rep->re_tx_tail,
1480433d6423SLionel Sambuc rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1481433d6423SLionel Sambuc rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1482433d6423SLionel Sambuc rep->re_need_reset= TRUE;
1483433d6423SLionel Sambuc rep->re_got_int= TRUE;
1484433d6423SLionel Sambuc
14854081bff6SDavid van Moolenbroek rl_check_ints(rep);
1486433d6423SLionel Sambuc }
1487433d6423SLionel Sambuc
14884081bff6SDavid van Moolenbroek /* TODO: obviously this needs a lot of work. */
tell_iommu(vir_bytes buf,size_t size,int pci_bus,int pci_dev,int pci_func)14894081bff6SDavid van Moolenbroek static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev,
14904081bff6SDavid van Moolenbroek int pci_func)
1491433d6423SLionel Sambuc {
1492433d6423SLionel Sambuc int r;
1493433d6423SLionel Sambuc endpoint_t dev_e;
1494433d6423SLionel Sambuc message m;
1495433d6423SLionel Sambuc
1496433d6423SLionel Sambuc r= ds_retrieve_label_endpt("amddev", &dev_e);
1497433d6423SLionel Sambuc if (r != OK)
1498433d6423SLionel Sambuc {
1499433d6423SLionel Sambuc #if 0
15004081bff6SDavid van Moolenbroek printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed "
15014081bff6SDavid van Moolenbroek "for 'amddev': %d\n", r);
1502433d6423SLionel Sambuc #endif
1503433d6423SLionel Sambuc return;
1504433d6423SLionel Sambuc }
1505433d6423SLionel Sambuc
1506433d6423SLionel Sambuc m.m_type= IOMMU_MAP;
1507433d6423SLionel Sambuc m.m2_i1= pci_bus;
1508433d6423SLionel Sambuc m.m2_i2= pci_dev;
1509433d6423SLionel Sambuc m.m2_i3= pci_func;
1510433d6423SLionel Sambuc m.m2_l1= buf;
1511433d6423SLionel Sambuc m.m2_l2= size;
1512433d6423SLionel Sambuc
1513433d6423SLionel Sambuc r= ipc_sendrec(dev_e, &m);
1514433d6423SLionel Sambuc if (r != OK)
1515433d6423SLionel Sambuc {
1516433d6423SLionel Sambuc printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n",
1517433d6423SLionel Sambuc dev_e, r);
1518433d6423SLionel Sambuc return;
1519433d6423SLionel Sambuc }
1520433d6423SLionel Sambuc if (m.m_type != OK)
1521433d6423SLionel Sambuc {
1522433d6423SLionel Sambuc printf("rtl8139`tell_dev: dma map request failed: %d\n",
1523433d6423SLionel Sambuc m.m_type);
1524433d6423SLionel Sambuc return;
1525433d6423SLionel Sambuc }
1526433d6423SLionel Sambuc }
1527433d6423SLionel Sambuc
1528433d6423SLionel Sambuc /*
1529433d6423SLionel Sambuc * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $
1530433d6423SLionel Sambuc */
1531