Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / devs / networks / via-rhine / via-rhine.c
blob7a1a52eac2720d8d7315e66743f32ea28a9f3c31
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>
41 #include <hidd/irq.h>
43 #include <proto/oop.h>
44 #include <proto/exec.h>
45 #include <proto/dos.h>
46 #include <proto/battclock.h>
48 #include <stdlib.h>
50 #include "via-rhine.h"
51 #include "unit.h"
52 #include LC_LIBDEFS_FILE
54 /* A bit fixed linux stuff here :) */
56 #undef LIBBASE
57 #define LIBBASE (dev->rhineu_device)
59 #define net_device VIARHINEUnit
61 #define TIMER_RPROK 3599597124UL
63 static ULONG usec2tick(ULONG usec)
65 ULONG ret, timer_rpr = TIMER_RPROK;
66 asm volatile("movl $0,%%eax; divl %2":"=a"(ret):"d"(usec),"m"(timer_rpr));
67 return ret;
70 void udelay(LONG usec)
72 int oldtick, tick;
73 usec = usec2tick(usec);
75 BYTEOUT(0x43, 0x80);
76 oldtick = BYTEIN(0x42);
77 oldtick += BYTEIN(0x42) << 8;
79 while (usec > 0)
81 BYTEOUT(0x43, 0x80);
82 tick = BYTEIN(0x42);
83 tick += BYTEIN(0x42) << 8;
85 usec -= (oldtick - tick);
86 if (tick > oldtick) usec -= 0x10000;
87 oldtick = tick;
91 static inline struct fe_priv *get_pcnpriv(struct net_device *dev)
93 return dev->rhineu_fe_priv;
96 static inline UBYTE *get_hwbase(struct net_device *dev)
98 return (UBYTE*)dev->rhineu_BaseMem;
101 static int mdio_read(struct net_device *dev, int phy_id, int location)
103 UBYTE *base = get_hwbase(dev);
105 int i = 1024;
107 while ((BYTEIN(base + VIAR_MIICmd) & 0x60) && --i > 0)
111 BYTEOUT(base + VIAR_MIICmd, 0x00);
112 BYTEOUT(base + VIAR_MIIPhyAddr, phy_id);
113 BYTEOUT(base + VIAR_MIIRegAddr, location);
114 BYTEOUT(base + VIAR_MIICmd, 0x40); //Trigger the read
116 i = 1024;
118 while ((BYTEIN(base + VIAR_MIICmd) & 0x40) && --i > 0)
122 return WORDIN(base + VIAR_MIIData);
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 #warning "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 #warning "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 #warning "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 #warning "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));
168 * viarhinenic_set_multicast: dev->set_multicast function
169 * Called with dev->xmit_lock held.
171 static void viarhinenic_set_multicast(struct net_device *dev)
173 struct fe_priv *np = get_pcnpriv(dev);
174 UBYTE *base = get_hwbase(dev);
175 ULONG addr[2];
176 ULONG mask[2];
177 ULONG pff;
179 D(bug("%s: viarhinenic_set_multicast()\n", dev->rhineu_name));
181 memset(addr, 0, sizeof(addr));
182 memset(mask, 0, sizeof(mask));
185 static void viarhinenic_deinitialize(struct net_device *dev)
187 // dev->write_csr(dev->rhineu_BaseMem, 0, (1 << 2)); /* Stop the PCnet32 by setting the stop bit.. */
188 D(bug("%s: PCnet32 chipset STOPPED\n", dev->rhineu_name));
190 // dev->write_bcr(dev->rhineu_BaseMem, 20, 4); /* Set pcnet32 into 16bit mode */
191 D(bug("%s: Chipset put into 16bit mode\n", dev->rhineu_name));
194 static void viarhinenic_initialize(struct net_device *dev)
196 struct fe_priv *np = dev->rhineu_fe_priv;
197 UBYTE *base = get_hwbase(dev);
198 int i, config1;
200 WORDOUT(base + VIAR_ChipCmd, CmdReset);
201 udelay(20000);
202 D(bug("%s: VIA Rhine Reset.\n", dev->rhineu_name));
204 for (i = 0; i < 6; i++)
206 np->orig_mac[i] = BYTEIN(base + VIAR_StationAddr + i);
209 int phy, phy_idx = 0;
210 if (dev->rhineu_chipcapabilities & RTLc_CanHaveMII)
212 np->mii_phys[0] = 1;
213 for (phy = 0; (phy < 32) && (phy_idx < 4); phy++)
215 int mii_status = mdio_read(dev, phy, 1);
216 if (mii_status != 0xffff && mii_status != 0x0000)
218 np->mii_phys[phy_idx++] = phy;
219 np->mii_advertising = mdio_read(dev, phy, 4);
220 D(bug("%s: MII transceiver %d status 0x%4.4x advertising %4.4x\n", dev->rhineu_name,
221 phy, mii_status, np->mii_advertising));
227 dev->rhineu_dev_addr[0] = dev->rhineu_org_addr[0] = np->orig_mac[0];
228 dev->rhineu_dev_addr[1] = dev->rhineu_org_addr[1] = np->orig_mac[1];
229 dev->rhineu_dev_addr[2] = dev->rhineu_org_addr[2] = np->orig_mac[2];
230 dev->rhineu_dev_addr[3] = dev->rhineu_org_addr[3] = np->orig_mac[3];
232 dev->rhineu_dev_addr[4] = dev->rhineu_org_addr[4] = np->orig_mac[4];
233 dev->rhineu_dev_addr[5] = dev->rhineu_org_addr[5] = np->orig_mac[5];
235 D(bug("%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->rhineu_name,
236 dev->rhineu_dev_addr[0], dev->rhineu_dev_addr[1], dev->rhineu_dev_addr[2],
237 dev->rhineu_dev_addr[3], dev->rhineu_dev_addr[4], dev->rhineu_dev_addr[5]));
240 static void viarhinenic_drain_tx(struct net_device *dev)
242 struct fe_priv *np = get_pcnpriv(dev);
243 int i;
244 for (i = 0; i < TX_BUFFERS; i++) {
245 #warning "TODO: viarhinenic_drain_tx does nothing atm."
249 static void viarhinenic_drain_rx(struct net_device *dev)
251 struct fe_priv *np = get_pcnpriv(dev);
252 int i;
253 for (i = 0; i < RX_BUFFERS; i++) {
254 #warning "TODO: viarhinenic_drain_rx does nothing atm."
259 static void drain_ring(struct net_device *dev)
261 viarhinenic_drain_tx(dev);
262 viarhinenic_drain_rx(dev);
265 static int request_irq(struct net_device *dev)
267 OOP_Object *irq = OOP_NewObject(NULL, CLID_Hidd_IRQ, NULL);
268 BOOL ret;
270 D(bug("%s: request_irq()\n", dev->rhineu_name));
272 if (irq)
274 ret = HIDD_IRQ_AddHandler(irq, dev->rhineu_irqhandler, dev->rhineu_IRQ);
275 HIDD_IRQ_AddHandler(irq, dev->rhineu_touthandler, vHidd_IRQ_Timer);
277 D(bug("%s: request_irq: IRQ Handlers configured\n", dev->rhineu_name));
279 OOP_DisposeObject(irq);
281 if (ret)
283 return 0;
286 return 1;
289 static void free_irq(struct net_device *dev)
291 OOP_Object *irq = OOP_NewObject(NULL, CLID_Hidd_IRQ, NULL);
292 if (irq)
294 HIDD_IRQ_RemHandler(irq, dev->rhineu_irqhandler);
295 HIDD_IRQ_RemHandler(irq, dev->rhineu_touthandler);
296 OOP_DisposeObject(irq);
300 int viarhinenic_rx_setmode(struct net_device *dev)
302 struct fe_priv *np = get_pcnpriv(dev);
303 UBYTE *base = get_hwbase(dev);
304 unsigned long mc_filter[2]; //Multicast hash filter.
305 unsigned int rx_mode;
307 mc_filter[1] = mc_filter[0] = 0x0;
309 if (dev->rhineu_flags & IFF_PROMISC)
311 D(bug("%s: viarhinenic_rx_setmode: PROMISCUOUS Mode\n", dev->rhineu_name));
312 rx_mode = 0x1c;
314 else if (dev->rhineu_flags & IFF_ALLMULTI)
316 D(bug("%s: viarhinenic_rx_setmode: ALL MULTICAST Enabled\n", dev->rhineu_name));
317 rx_mode = 0x0c;
318 mc_filter[1] = mc_filter[0] = 0xffffffff;
320 else
322 D(bug("%s: viarhinenic_rx_setmode: Default Rx Mode (no Multi or Promisc)\n", dev->rhineu_name));
323 rx_mode = 0x1a;
326 LONGOUT(base + VIAR_MulticastFilter0, mc_filter[0]);
327 LONGOUT(base + VIAR_MulticastFilter1, mc_filter[1]);
328 BYTEOUT(base + VIAR_RxConfig, np->rx_thresh | rx_mode);
330 return 0;
333 static void viarhinenic_set_mac(struct net_device *dev)
335 UBYTE *base = get_hwbase(dev);
336 int i;
338 for (i = 0; i < 6; i++)
340 BYTEOUT(base + VIAR_StationAddr + i, dev->rhineu_dev_addr[i]);
344 static int viarhinenic_open(struct net_device *dev)
346 struct fe_priv *np = get_pcnpriv(dev);
347 UBYTE *base = get_hwbase(dev);
348 int ret, oom, i;
349 ULONG txb_size, rxb_size;
351 txb_size = BUFFER_SIZE * TX_BUFFERS;
352 rxb_size = BUFFER_SIZE * RX_BUFFERS;
354 oom = 0;
356 ret = request_irq(dev);
357 if (ret)
358 goto out_drain;
360 np->tx_buffer = HIDD_PCIDriver_AllocPCIMem(
361 dev->rhineu_PCIDriver,
362 txb_size);
364 if (np->tx_buffer == NULL)
366 oom = 1;
368 else
370 D(bug("%s: viarhinenic_open: Tx Ring buffers allocated @ %x\n", dev->rhineu_name, np->tx_buffer));
371 for (i=0; i< TX_BUFFERS; i++)
373 np->tx_desc[i].tx_status = 0;
374 np->tx_desc[i].desc_length = 0;
375 np->tx_desc[i].addr = (IPTR)(np->tx_buffer + (i * BUFFER_SIZE));
376 np->tx_desc[i].next = &np->tx_desc[i + 1];
377 D(bug("%s: viarhinenic_open: Tx Ring %d @ %x, Buffer = %x\n",dev->rhineu_name,
378 i, &np->tx_desc[i], np->tx_desc[i].addr));
380 np->tx_desc[i-1].next = &np->tx_desc[0];
383 np->rx_buffer = HIDD_PCIDriver_AllocPCIMem(
384 dev->rhineu_PCIDriver,
385 rxb_size);
387 if (np->rx_buffer == NULL)
389 oom = 1;
391 else
393 D(bug("%s: viarhinenic_open: Rx Ring buffers allocated @ %x\n", dev->rhineu_name, np->rx_buffer));
394 for (i=0; i< RX_BUFFERS; i++)
396 np->rx_desc[i].rx_status = DescOwn;
397 np->rx_desc[i].desc_length = MAX_FRAME_SIZE;
398 np->rx_desc[i].addr = (IPTR)( np->rx_buffer + (i * BUFFER_SIZE));
399 np->rx_desc[i].next = &np->rx_desc[i + 1];
400 D(bug("%s: viarhinenic_open: Rx Ring %d @ %x, Buffer = %x\n",dev->rhineu_name,
401 i, &np->rx_desc[i], np->rx_desc[i].addr));
403 np->rx_desc[i-1].next = &np->rx_desc[0];
406 if (oom == 0)
408 D(bug("%s: viarhinenic_open: Allocated IO Buffers [ %d x Tx @ %x] [ %d x Rx @ %x]\n",dev->rhineu_name,
409 TX_BUFFERS, np->tx_buffer,
410 RX_BUFFERS, np->rx_buffer));
412 viarhinenic_set_mac(dev);
413 D(bug("%s: viarhinenic_open: copied MAC address\n",dev->rhineu_name));
415 //Set up Frame Buffer Ring Descriptors
416 LONGOUT(base + VIAR_TxRingPtr, &np->tx_desc[0]);
417 LONGOUT(base + VIAR_RxRingPtr, &np->rx_desc[0]);
419 D(bug("%s: viarhinenic_open: Frame Buffer Ring Descriptors set\n",dev->rhineu_name));
421 //Initialise other registers
422 WORDOUT(base + VIAR_PCIBusConfig, 0x0006);
424 np->tx_thresh = 0x20;
425 np->rx_thresh = 0x60;
427 BYTEOUT(base + VIAR_TxConfig, np->tx_thresh);
428 viarhinenic_rx_setmode(dev);
430 D(bug("%s: viarhinenic_open: Tx/Rx Configuration set\n",dev->rhineu_name));
432 /* check_duplex *//*
433 if (np->mii_phys[0] >= 0 || (dev->rhineu_rtl_chipcapabilities & RTLc_HAS_MII_XCVR))
435 unsigned short mii_reg5 = mdio_read(dev, np->mii_phys[0], 5);
436 if (mii_reg5 != 0xffff)
438 if (((mii_reg5 & 0x0100) == 0x0100) || ((mii_reg5 & 0x00c0) == 0x0040))
440 np->full_duplex = 1;
444 if ((mii_reg5 == 0 ) || !(mii_reg5 & 0x0180))
446 dev->rhineu_rtl_LinkSpeed = 10000000;
448 else
450 dev->rhineu_rtl_LinkSpeed = 100000000;
453 D(bug("%s: viarhinenic_open: Setting %s%s-duplex based on auto-neg partner ability %4.4x\n",dev->rhineu_name,
454 mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
455 np->full_duplex ? "full" : "half", mii_reg5));
458 //Enable all known interrupts by setting the interrupt mask ..
459 WORDOUT(base + VIAR_IntrEnable, (IntrRxDone | IntrRxErr | IntrRxEmpty | IntrRxOverflow| IntrRxDropped | IntrTxDone | IntrTxAbort | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange));
461 np->cmd = CmdStart | CmdTxOn | CmdRxOn | CmdRxDemand;
463 WORDOUT(base + VIAR_ChipCmd, np->cmd);
465 dev->rhineu_flags |= IFF_UP;
466 ReportEvents(LIBBASE, dev, S2EVENT_ONLINE);
467 D(bug("%s: viarhinenic_open: Device set as ONLINE\n",dev->rhineu_name));
469 return 0;
471 out_drain:
472 drain_ring(dev);
473 return ret;
476 static int viarhinenic_close(struct net_device *dev)
478 struct fe_priv *np = get_pcnpriv(dev);
479 UBYTE *base;
481 dev->rhineu_flags &= ~IFF_UP;
483 ObtainSemaphore(&np->lock);
484 np->in_shutdown = 1;
485 ReleaseSemaphore(&np->lock);
487 dev->rhineu_toutNEED = FALSE;
489 netif_stop_queue(dev);
490 ObtainSemaphore(&np->lock);
492 viarhinenic_deinitialize(dev); // Stop the chipset and set it in 16bit-mode
494 base = get_hwbase(dev);
496 ReleaseSemaphore(&np->lock);
498 free_irq(dev);
500 drain_ring(dev);
502 HIDD_PCIDriver_FreePCIMem(dev->rhineu_PCIDriver, np->rx_buffer);
503 HIDD_PCIDriver_FreePCIMem(dev->rhineu_PCIDriver, np->tx_buffer);
505 ReportEvents(LIBBASE, dev, S2EVENT_OFFLINE);
507 return 0;
511 void viarhinenic_get_functions(struct net_device *Unit)
513 Unit->initialize = viarhinenic_initialize;
514 Unit->deinitialize = viarhinenic_deinitialize;
515 Unit->start = viarhinenic_open;
516 Unit->stop = viarhinenic_close;
517 Unit->set_mac_address = viarhinenic_set_mac;
518 Unit->set_multicast = viarhinenic_set_multicast;