Here's an idea: don't add interrupt handlers when they've already been
[AROS.git] / workbench / devs / networks / via-rhine / via-rhine.c
blobe4724269881bf824d9f1fc86bb2de5433ba51f3f
1 /*
2 * $Id$
3 */
5 /*
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
22 #include <exec/types.h>
23 #include <exec/resident.h>
24 #include <exec/io.h>
25 #include <exec/ports.h>
27 #include <aros/libcall.h>
28 #include <aros/macros.h>
29 #include <aros/io.h>
31 #include <oop/oop.h>
33 #include <devices/sana2.h>
34 #include <devices/sana2specialstats.h>
36 #include <utility/utility.h>
37 #include <utility/tagitem.h>
38 #include <utility/hooks.h>
40 #include <hidd/pci.h>
42 #include <proto/oop.h>
43 #include <proto/exec.h>
44 #include <proto/dos.h>
45 #include <proto/battclock.h>
47 #include <stdlib.h>
49 #include "via-rhine.h"
50 #include "unit.h"
51 #include LC_LIBDEFS_FILE
53 /* A bit fixed linux stuff here :) */
55 #undef LIBBASE
56 #define LIBBASE (dev->rhineu_device)
58 #define net_device VIARHINEUnit
60 #define TIMER_RPROK 3599597124UL
62 static ULONG usec2tick(ULONG usec)
64 ULONG ret, timer_rpr = TIMER_RPROK;
65 asm volatile("movl $0,%%eax; divl %2":"=a"(ret):"d"(usec),"m"(timer_rpr));
66 return ret;
69 void udelay(LONG usec)
71 int oldtick, tick;
72 usec = usec2tick(usec);
74 BYTEOUT(0x43, 0x80);
75 oldtick = BYTEIN(0x42);
76 oldtick += BYTEIN(0x42) << 8;
78 while (usec > 0)
80 BYTEOUT(0x43, 0x80);
81 tick = BYTEIN(0x42);
82 tick += BYTEIN(0x42) << 8;
84 usec -= (oldtick - tick);
85 if (tick > oldtick) usec -= 0x10000;
86 oldtick = tick;
90 static inline struct fe_priv *get_pcnpriv(struct net_device *dev)
92 return dev->rhineu_fe_priv;
95 static inline UBYTE *get_hwbase(struct net_device *dev)
97 return (UBYTE*)dev->rhineu_BaseMem;
100 static int mdio_read(struct net_device *dev, int phy_id, int location)
102 UBYTE *base = get_hwbase(dev);
104 int i = 1024;
106 while ((BYTEIN(base + VIAR_MIICmd) & 0x60) && --i > 0)
110 BYTEOUT(base + VIAR_MIICmd, 0x00);
111 BYTEOUT(base + VIAR_MIIPhyAddr, phy_id);
112 BYTEOUT(base + VIAR_MIIRegAddr, location);
113 BYTEOUT(base + VIAR_MIICmd, 0x40); //Trigger the read
115 i = 1024;
117 while ((BYTEIN(base + VIAR_MIICmd) & 0x40) && --i > 0)
121 return WORDIN(base + VIAR_MIIData);
124 #if 0
125 static void viarhinenic_start_rx(struct net_device *dev)
127 // struct fe_priv *np = get_pcnpriv(dev);
128 // UBYTE *base = get_hwbase(dev);
130 D(bug("%s: viarhinenic_start_rx\n", dev->rhineu_name));
131 // Already running? Stop it.
132 /* TODO: Handle starting/stopping Rx */
135 static void viarhinenic_stop_rx(struct net_device *dev)
137 // UBYTE *base = get_hwbase(dev);
139 D(bug("%s: viarhinenic_stop_rx\n", dev->rhineu_name));
140 /* TODO: Handle starting/stopping Rx */
143 static void viarhinenic_start_tx(struct net_device *dev)
145 // UBYTE *base = get_hwbase(dev);
147 D(bug("%s: viarhinenic_start_tx()\n", dev->rhineu_name));
148 /* TODO: Handle starting/stopping Tx */
151 static void viarhinenic_stop_tx(struct net_device *dev)
153 // UBYTE *base = get_hwbase(dev);
155 D(bug("%s: viarhinenic_stop_tx()\n", dev->rhineu_name));
156 /* TODO: Handle starting/stopping Tx */
159 static void viarhinenic_txrx_reset(struct net_device *dev)
161 // struct fe_priv *np = get_pcnpriv(dev);
162 // UBYTE *base = get_hwbase(dev);
164 D(bug("%s: viarhinenic_txrx_reset()\n", dev->rhineu_name));
166 #endif
169 * viarhinenic_set_multicast: dev->set_multicast function
170 * Called with dev->xmit_lock held.
172 static void viarhinenic_set_multicast(struct net_device *dev)
174 // struct fe_priv *np = get_pcnpriv(dev);
175 // UBYTE *base = get_hwbase(dev);
176 ULONG addr[2];
177 ULONG mask[2];
178 // ULONG pff;
180 D(bug("%s: viarhinenic_set_multicast()\n", dev->rhineu_name));
182 memset(addr, 0, sizeof(addr));
183 memset(mask, 0, sizeof(mask));
186 static void viarhinenic_deinitialize(struct net_device *dev)
188 // dev->write_csr(dev->rhineu_BaseMem, 0, (1 << 2)); /* Stop the PCnet32 by setting the stop bit.. */
189 D(bug("%s: PCnet32 chipset STOPPED\n", dev->rhineu_name));
191 // dev->write_bcr(dev->rhineu_BaseMem, 20, 4); /* Set pcnet32 into 16bit mode */
192 D(bug("%s: Chipset put into 16bit mode\n", dev->rhineu_name));
195 static void viarhinenic_initialize(struct net_device *dev)
197 struct fe_priv *np = dev->rhineu_fe_priv;
198 UBYTE *base = get_hwbase(dev);
199 int i;
200 // int config1;
202 WORDOUT(base + VIAR_ChipCmd, CmdReset);
203 udelay(20000);
204 D(bug("%s: VIA Rhine Reset.\n", dev->rhineu_name));
206 for (i = 0; i < 6; i++)
208 np->orig_mac[i] = BYTEIN(base + VIAR_StationAddr + i);
211 int phy, phy_idx = 0;
212 if (dev->rhineu_chipcapabilities & RTLc_CanHaveMII)
214 np->mii_phys[0] = 1;
215 for (phy = 0; (phy < 32) && (phy_idx < 4); phy++)
217 int mii_status = mdio_read(dev, phy, 1);
218 if (mii_status != 0xffff && mii_status != 0x0000)
220 np->mii_phys[phy_idx++] = phy;
221 np->mii_advertising = mdio_read(dev, phy, 4);
222 D(bug("%s: MII transceiver %d status 0x%4.4x advertising %4.4x\n", dev->rhineu_name,
223 phy, mii_status, np->mii_advertising));
229 dev->rhineu_dev_addr[0] = dev->rhineu_org_addr[0] = np->orig_mac[0];
230 dev->rhineu_dev_addr[1] = dev->rhineu_org_addr[1] = np->orig_mac[1];
231 dev->rhineu_dev_addr[2] = dev->rhineu_org_addr[2] = np->orig_mac[2];
232 dev->rhineu_dev_addr[3] = dev->rhineu_org_addr[3] = np->orig_mac[3];
234 dev->rhineu_dev_addr[4] = dev->rhineu_org_addr[4] = np->orig_mac[4];
235 dev->rhineu_dev_addr[5] = dev->rhineu_org_addr[5] = np->orig_mac[5];
237 D(bug("%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->rhineu_name,
238 dev->rhineu_dev_addr[0], dev->rhineu_dev_addr[1], dev->rhineu_dev_addr[2],
239 dev->rhineu_dev_addr[3], dev->rhineu_dev_addr[4], dev->rhineu_dev_addr[5]));
242 static void viarhinenic_drain_tx(struct net_device *dev)
244 // struct fe_priv *np = get_pcnpriv(dev);
245 int i;
246 for (i = 0; i < TX_BUFFERS; i++) {
247 /* TODO: viarhinenic_drain_tx does nothing atm. */
251 static void viarhinenic_drain_rx(struct net_device *dev)
253 // struct fe_priv *np = get_pcnpriv(dev);
254 int i;
255 for (i = 0; i < RX_BUFFERS; i++) {
256 /* TODO: viarhinenic_drain_rx does nothing atm. */
261 static void drain_ring(struct net_device *dev)
263 viarhinenic_drain_tx(dev);
264 viarhinenic_drain_rx(dev);
267 static int request_irq(struct net_device *dev)
269 D(bug("%s: request_irq()\n", dev->rhineu_name));
271 if (!dev->rhineu_IntsAdded)
273 AddIntServer(INTB_KERNEL + dev->rhineu_IRQ, &dev->rhineu_irqhandler);
274 AddIntServer(INTB_VERTB, &dev->rhineu_touthandler);
275 dev->rhineu_IntsAdded = TRUE;
278 D(bug("%s: request_irq: IRQ Handlers configured\n", dev->rhineu_name));
279 return 0;
282 static void free_irq(struct net_device *dev)
284 if (dev->rhineu_IntsAdded)
286 RemIntServer(INTB_KERNEL + dev->rhineu_IRQ, &dev->rhineu_irqhandler);
287 RemIntServer(INTB_VERTB, &dev->rhineu_touthandler);
288 dev->rhineu_IntsAdded = FALSE;
292 int viarhinenic_rx_setmode(struct net_device *dev)
294 struct fe_priv *np = get_pcnpriv(dev);
295 UBYTE *base = get_hwbase(dev);
296 unsigned long mc_filter[2]; //Multicast hash filter.
297 unsigned int rx_mode;
299 mc_filter[1] = mc_filter[0] = 0x0;
301 if (dev->rhineu_flags & IFF_PROMISC)
303 D(bug("%s: viarhinenic_rx_setmode: PROMISCUOUS Mode\n", dev->rhineu_name));
304 rx_mode = 0x1c;
306 else if (dev->rhineu_flags & IFF_ALLMULTI)
308 D(bug("%s: viarhinenic_rx_setmode: ALL MULTICAST Enabled\n", dev->rhineu_name));
309 rx_mode = 0x0c;
310 mc_filter[1] = mc_filter[0] = 0xffffffff;
312 else
314 D(bug("%s: viarhinenic_rx_setmode: Default Rx Mode (no Multi or Promisc)\n", dev->rhineu_name));
315 rx_mode = 0x1a;
318 LONGOUT(base + VIAR_MulticastFilter0, mc_filter[0]);
319 LONGOUT(base + VIAR_MulticastFilter1, mc_filter[1]);
320 BYTEOUT(base + VIAR_RxConfig, np->rx_thresh | rx_mode);
322 return 0;
325 static void viarhinenic_set_mac(struct net_device *dev)
327 UBYTE *base = get_hwbase(dev);
328 int i;
330 for (i = 0; i < 6; i++)
332 BYTEOUT(base + VIAR_StationAddr + i, dev->rhineu_dev_addr[i]);
336 static int viarhinenic_open(struct net_device *dev)
338 struct fe_priv *np = get_pcnpriv(dev);
339 UBYTE *base = get_hwbase(dev);
340 int ret, oom, i;
341 ULONG txb_size, rxb_size;
343 txb_size = BUFFER_SIZE * TX_BUFFERS;
344 rxb_size = BUFFER_SIZE * RX_BUFFERS;
346 oom = 0;
348 ret = request_irq(dev);
349 if (ret)
350 goto out_drain;
352 np->tx_buffer = HIDD_PCIDriver_AllocPCIMem(
353 dev->rhineu_PCIDriver,
354 txb_size);
356 if (np->tx_buffer == NULL)
358 oom = 1;
360 else
362 D(bug("%s: viarhinenic_open: Tx Ring buffers allocated @ %x\n", dev->rhineu_name, np->tx_buffer));
363 for (i=0; i< TX_BUFFERS; i++)
365 np->tx_desc[i].tx_status = 0;
366 np->tx_desc[i].desc_length = 0;
367 np->tx_desc[i].addr = (IPTR)(np->tx_buffer + (i * BUFFER_SIZE));
368 np->tx_desc[i].next = (IPTR)&np->tx_desc[i + 1];
369 D(bug("%s: viarhinenic_open: Tx Ring %d @ %x, Buffer = %x\n",dev->rhineu_name,
370 i, &np->tx_desc[i], np->tx_desc[i].addr));
372 np->tx_desc[i-1].next = (IPTR)&np->tx_desc[0];
375 np->rx_buffer = HIDD_PCIDriver_AllocPCIMem(
376 dev->rhineu_PCIDriver,
377 rxb_size);
379 if (np->rx_buffer == NULL)
381 oom = 1;
383 else
385 D(bug("%s: viarhinenic_open: Rx Ring buffers allocated @ %x\n", dev->rhineu_name, np->rx_buffer));
386 for (i=0; i< RX_BUFFERS; i++)
388 np->rx_desc[i].rx_status = DescOwn;
389 np->rx_desc[i].desc_length = MAX_FRAME_SIZE;
390 np->rx_desc[i].addr = (IPTR)( np->rx_buffer + (i * BUFFER_SIZE));
391 np->rx_desc[i].next = (IPTR)&np->rx_desc[i + 1];
392 D(bug("%s: viarhinenic_open: Rx Ring %d @ %x, Buffer = %x\n",dev->rhineu_name,
393 i, &np->rx_desc[i], np->rx_desc[i].addr));
395 np->rx_desc[i-1].next = (IPTR)&np->rx_desc[0];
398 if (oom == 0)
400 D(bug("%s: viarhinenic_open: Allocated IO Buffers [ %d x Tx @ %x] [ %d x Rx @ %x]\n",dev->rhineu_name,
401 TX_BUFFERS, np->tx_buffer,
402 RX_BUFFERS, np->rx_buffer));
404 viarhinenic_set_mac(dev);
405 D(bug("%s: viarhinenic_open: copied MAC address\n",dev->rhineu_name));
407 //Set up Frame Buffer Ring Descriptors
408 LONGOUT(base + VIAR_TxRingPtr, (IPTR)&np->tx_desc[0]);
409 LONGOUT(base + VIAR_RxRingPtr, (IPTR)&np->rx_desc[0]);
411 D(bug("%s: viarhinenic_open: Frame Buffer Ring Descriptors set\n",dev->rhineu_name));
413 //Initialise other registers
414 WORDOUT(base + VIAR_PCIBusConfig, 0x0006);
416 np->tx_thresh = 0x20;
417 np->rx_thresh = 0x60;
419 BYTEOUT(base + VIAR_TxConfig, np->tx_thresh);
420 viarhinenic_rx_setmode(dev);
422 D(bug("%s: viarhinenic_open: Tx/Rx Configuration set\n",dev->rhineu_name));
424 /* check_duplex *//*
425 if (np->mii_phys[0] >= 0 || (dev->rhineu_rtl_chipcapabilities & RTLc_HAS_MII_XCVR))
427 unsigned short mii_reg5 = mdio_read(dev, np->mii_phys[0], 5);
428 if (mii_reg5 != 0xffff)
430 if (((mii_reg5 & 0x0100) == 0x0100) || ((mii_reg5 & 0x00c0) == 0x0040))
432 np->full_duplex = 1;
436 if ((mii_reg5 == 0 ) || !(mii_reg5 & 0x0180))
438 dev->rhineu_rtl_LinkSpeed = 10000000;
440 else
442 dev->rhineu_rtl_LinkSpeed = 100000000;
445 D(bug("%s: viarhinenic_open: Setting %s%s-duplex based on auto-neg partner ability %4.4x\n",dev->rhineu_name,
446 mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
447 np->full_duplex ? "full" : "half", mii_reg5));
450 //Enable all known interrupts by setting the interrupt mask ..
451 WORDOUT(base + VIAR_IntrEnable, (IntrRxDone | IntrRxErr | IntrRxEmpty | IntrRxOverflow| IntrRxDropped | IntrTxDone | IntrTxAbort | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange));
453 np->cmd = CmdStart | CmdTxOn | CmdRxOn | CmdRxDemand;
455 WORDOUT(base + VIAR_ChipCmd, np->cmd);
457 dev->rhineu_flags |= IFF_UP;
458 ReportEvents(LIBBASE, dev, S2EVENT_ONLINE);
459 D(bug("%s: viarhinenic_open: Device set as ONLINE\n",dev->rhineu_name));
461 return 0;
463 out_drain:
464 drain_ring(dev);
465 return ret;
468 static int viarhinenic_close(struct net_device *dev)
470 struct fe_priv *np = get_pcnpriv(dev);
472 dev->rhineu_flags &= ~IFF_UP;
474 ObtainSemaphore(&np->lock);
475 np->in_shutdown = 1;
476 ReleaseSemaphore(&np->lock);
478 dev->rhineu_toutNEED = FALSE;
480 netif_stop_queue(dev);
481 ObtainSemaphore(&np->lock);
483 viarhinenic_deinitialize(dev); // Stop the chipset and set it in 16bit-mode
485 ReleaseSemaphore(&np->lock);
487 free_irq(dev);
489 drain_ring(dev);
491 HIDD_PCIDriver_FreePCIMem(dev->rhineu_PCIDriver, np->rx_buffer);
492 HIDD_PCIDriver_FreePCIMem(dev->rhineu_PCIDriver, np->tx_buffer);
494 ReportEvents(LIBBASE, dev, S2EVENT_OFFLINE);
496 return 0;
500 void viarhinenic_get_functions(struct net_device *Unit)
502 Unit->initialize = viarhinenic_initialize;
503 Unit->deinitialize = viarhinenic_deinitialize;
504 Unit->start = viarhinenic_open;
505 Unit->stop = viarhinenic_close;
506 Unit->set_mac_address = viarhinenic_set_mac;
507 Unit->set_multicast = viarhinenic_set_multicast;