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>
43 #include <proto/oop.h>
44 #include <proto/exec.h>
45 #include <proto/dos.h>
46 #include <proto/battclock.h>
50 #include "via-rhine.h"
52 #include LC_LIBDEFS_FILE
54 /* A bit fixed linux stuff here :) */
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
));
70 void udelay(LONG usec
)
73 usec
= usec2tick(usec
);
76 oldtick
= BYTEIN(0x42);
77 oldtick
+= BYTEIN(0x42) << 8;
83 tick
+= BYTEIN(0x42) << 8;
85 usec
-= (oldtick
- tick
);
86 if (tick
> oldtick
) usec
-= 0x10000;
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
);
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
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
);
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
);
200 WORDOUT(base
+ VIAR_ChipCmd
, CmdReset
);
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
)
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
);
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
);
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
);
270 D(bug("%s: request_irq()\n", dev
->rhineu_name
));
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
);
289 static void free_irq(struct net_device
*dev
)
291 OOP_Object
*irq
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
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
));
314 else if (dev
->rhineu_flags
& IFF_ALLMULTI
)
316 D(bug("%s: viarhinenic_rx_setmode: ALL MULTICAST Enabled\n", dev
->rhineu_name
));
318 mc_filter
[1] = mc_filter
[0] = 0xffffffff;
322 D(bug("%s: viarhinenic_rx_setmode: Default Rx Mode (no Multi or Promisc)\n", dev
->rhineu_name
));
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
);
333 static void viarhinenic_set_mac(struct net_device
*dev
)
335 UBYTE
*base
= get_hwbase(dev
);
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
);
349 ULONG txb_size
, rxb_size
;
351 txb_size
= BUFFER_SIZE
* TX_BUFFERS
;
352 rxb_size
= BUFFER_SIZE
* RX_BUFFERS
;
356 ret
= request_irq(dev
);
360 np
->tx_buffer
= HIDD_PCIDriver_AllocPCIMem(
361 dev
->rhineu_PCIDriver
,
364 if (np
->tx_buffer
== NULL
)
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
,
387 if (np
->rx_buffer
== NULL
)
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];
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
));
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))
444 if ((mii_reg5 == 0 ) || !(mii_reg5 & 0x0180))
446 dev->rhineu_rtl_LinkSpeed = 10000000;
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
));
476 static int viarhinenic_close(struct net_device
*dev
)
478 struct fe_priv
*np
= get_pcnpriv(dev
);
481 dev
->rhineu_flags
&= ~IFF_UP
;
483 ObtainSemaphore(&np
->lock
);
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
);
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
);
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
;