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,
22 #include <exec/types.h>
23 #include <exec/resident.h>
25 #include <exec/ports.h>
27 #include <aros/libcall.h>
28 #include <aros/macros.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>
42 #include <proto/oop.h>
43 #include <proto/exec.h>
44 #include <proto/dos.h>
45 #include <proto/battclock.h>
49 #include "via-rhine.h"
51 #include LC_LIBDEFS_FILE
53 /* A bit fixed linux stuff here :) */
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
));
69 void udelay(LONG usec
)
72 usec
= usec2tick(usec
);
75 oldtick
= BYTEIN(0x42);
76 oldtick
+= BYTEIN(0x42) << 8;
82 tick
+= BYTEIN(0x42) << 8;
84 usec
-= (oldtick
- tick
);
85 if (tick
> oldtick
) usec
-= 0x10000;
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
);
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
117 while ((BYTEIN(base
+ VIAR_MIICmd
) & 0x40) && --i
> 0)
121 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 /* 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
));
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);
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
);
202 WORDOUT(base
+ VIAR_ChipCmd
, CmdReset
);
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
)
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);
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);
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
));
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
));
306 else if (dev
->rhineu_flags
& IFF_ALLMULTI
)
308 D(bug("%s: viarhinenic_rx_setmode: ALL MULTICAST Enabled\n", dev
->rhineu_name
));
310 mc_filter
[1] = mc_filter
[0] = 0xffffffff;
314 D(bug("%s: viarhinenic_rx_setmode: Default Rx Mode (no Multi or Promisc)\n", dev
->rhineu_name
));
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
);
325 static void viarhinenic_set_mac(struct net_device
*dev
)
327 UBYTE
*base
= get_hwbase(dev
);
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
);
341 ULONG txb_size
, rxb_size
;
343 txb_size
= BUFFER_SIZE
* TX_BUFFERS
;
344 rxb_size
= BUFFER_SIZE
* RX_BUFFERS
;
348 ret
= request_irq(dev
);
352 np
->tx_buffer
= HIDD_PCIDriver_AllocPCIMem(
353 dev
->rhineu_PCIDriver
,
356 if (np
->tx_buffer
== NULL
)
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
,
379 if (np
->rx_buffer
== NULL
)
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];
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
));
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))
436 if ((mii_reg5 == 0 ) || !(mii_reg5 & 0x0180))
438 dev->rhineu_rtl_LinkSpeed = 10000000;
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
));
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
);
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
);
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
);
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
;