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>
47 #include <hardware/intbits.h>
53 #include LC_LIBDEFS_FILE
55 /* A bit fixed linux stuff here :) */
58 #define LIBBASE (dev->pcnu_device)
60 #define net_device PCN32Unit
62 #define TIMER_RPROK 3599597124UL
65 extern volatile UBYTE
readb(APTR base
);
66 extern volatile void writeb(UBYTE val
, APTR base
);
69 extern volatile UWORD
readw(APTR base
);
70 extern volatile void writew(UWORD val
, APTR base
);
73 extern volatile ULONG
readl(APTR base
);
74 extern volatile void writel(ULONG val
, APTR base
);
76 static ULONG
usec2tick(ULONG usec
)
78 ULONG ret
, timer_rpr
= TIMER_RPROK
;
79 asm volatile("movl $0,%%eax; divl %2":"=a"(ret
):"d"(usec
),"m"(timer_rpr
));
83 void udelay(LONG usec
)
86 usec
= usec2tick(usec
);
89 oldtick
= BYTEIN(0x42);
90 oldtick
+= BYTEIN(0x42) << 8;
96 tick
+= BYTEIN(0x42) << 8;
98 usec
-= (oldtick
- tick
);
99 if (tick
> oldtick
) usec
-= 0x10000;
104 static inline struct fe_priv
*get_pcnpriv(struct net_device
*dev
)
106 return dev
->pcnu_fe_priv
;
109 static inline UBYTE
*get_hwbase(struct net_device
*dev
)
111 return (UBYTE
*)dev
->pcnu_BaseMem
;
114 static inline void pci_push(UBYTE
*base
)
116 /* force out pending posted writes */
121 static void pcn32_start_rx(struct net_device
*dev
)
123 // struct fe_priv *np = get_pcnpriv(dev);
124 // UBYTE *base = get_hwbase(dev);
126 D(bug("%s: pcn32_start_rx\n", dev
->pcnu_name
));
127 // Already running? Stop it.
128 /* TODO: Handle starting/stopping Rx */
131 static void pcn32_stop_rx(struct net_device
*dev
)
133 // UBYTE *base = get_hwbase(dev);
135 D(bug("%s: pcn32_stop_rx\n", dev
->pcnu_name
));
136 /* TODO: Handle starting/stopping Rx */
139 static void pcn32_start_tx(struct net_device
*dev
)
141 // UBYTE *base = get_hwbase(dev);
143 D(bug("%s: pcn32_start_tx()\n", dev
->pcnu_name
));
144 /* TODO: Handle starting/stopping Tx */
147 static void pcn32_stop_tx(struct net_device
*dev
)
149 // UBYTE *base = get_hwbase(dev);
151 D(bug("%s: pcn32_stop_tx()\n", dev
->pcnu_name
));
152 /* TODO: Handle starting/stopping Tx */
155 static void pcn32_txrx_reset(struct net_device
*dev
)
157 // struct fe_priv *np = get_pcnpriv(dev);
158 // UBYTE *base = get_hwbase(dev);
160 D(bug("%s: pcn32_txrx_reset()\n", dev
->pcnu_name
));
165 * pcn32_set_multicast: dev->set_multicast function
166 * Called with dev->xmit_lock held.
168 static void pcn32_set_multicast(struct net_device
*dev
)
170 // struct fe_priv *np = get_pcnpriv(dev);
171 // UBYTE *base = get_hwbase(dev);
176 D(bug("%s: pcn32_set_multicast()\n", dev
->pcnu_name
));
178 memset(addr
, 0, sizeof(addr
));
179 memset(mask
, 0, sizeof(mask
));
182 static void pcnet32_deinitialize(struct net_device
*dev
)
184 dev
->write_csr(dev
->pcnu_BaseMem
, 0, (1 << 2)); /* Stop the PCnet32 by setting the stop bit.. */
185 D(bug("%s: PCnet32 chipset STOPPED\n", dev
->pcnu_name
));
187 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 4); /* Set pcnet32 into 16bit mode */
188 D(bug("%s: Chipset put into 16bit mode\n", dev
->pcnu_name
));
191 static void pcnet32_initialize(struct net_device
*dev
)
193 struct fe_priv
*np
= dev
->pcnu_fe_priv
;
194 UBYTE
*base
= get_hwbase(dev
);
197 dev
->reset(base
); /* Cause the PCnet Chipset to reset */
198 D(bug("%s: Chipset RESET\n", dev
->pcnu_name
));
200 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
202 np
->ring_addr
= HIDD_PCIDriver_AllocPCIMem(
204 sizeof(struct rx_ring_desc
) * (RX_RING_SIZE
+ TX_RING_SIZE
));
206 np
->fep_pcnet_init_block
->rx_ring
= AROS_LONG2LE((IPTR
)np
->ring_addr
);
207 np
->fep_pcnet_init_block
->tx_ring
= AROS_LONG2LE((IPTR
)&((struct rx_ring_desc
*)np
->ring_addr
)[RX_RING_SIZE
]);
209 D(bug("%s: Allocated IO Rings [%d x Tx @ %x : %x] [%d x Rx @ %x : %x]\n",
211 TX_RING_SIZE
, np
->ring_addr
+ (RX_RING_SIZE
* sizeof(struct rx_ring_desc
)), np
->fep_pcnet_init_block
->tx_ring
,
212 RX_RING_SIZE
, np
->ring_addr
, np
->fep_pcnet_init_block
->rx_ring
));
214 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 2); /* Set pcnet32 into 32bit mode */
215 D(bug("%s: PCnet Chipset put into 32bit mode\n", dev
->pcnu_name
));
217 np
->orig_mac
[0] = ( (readb(base
+ 0) << 24) | (readb(base
+ 1) << 16) | (readb(base
+ 2) << 8) | readb(base
+ 3) );
218 np
->orig_mac
[1] = ( (readb(base
+ 4) << 8) | readb(base
+ 5) );
220 dev
->pcnu_dev_addr
[0] = dev
->pcnu_org_addr
[0] = (np
->orig_mac
[0] >> 24) & 0xff;
221 dev
->pcnu_dev_addr
[1] = dev
->pcnu_org_addr
[1] = (np
->orig_mac
[0] >> 16) & 0xff;
222 dev
->pcnu_dev_addr
[2] = dev
->pcnu_org_addr
[2] = (np
->orig_mac
[0] >> 8) & 0xff;
223 dev
->pcnu_dev_addr
[3] = dev
->pcnu_org_addr
[3] = (np
->orig_mac
[0] >> 0) & 0xff;
225 dev
->pcnu_dev_addr
[4] = dev
->pcnu_org_addr
[4] = (np
->orig_mac
[1] >> 8) & 0xff;
226 dev
->pcnu_dev_addr
[5] = dev
->pcnu_org_addr
[5] = (np
->orig_mac
[1] >> 0) & 0xff;
228 D(bug("%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", dev
->pcnu_name
,
229 dev
->pcnu_dev_addr
[0], dev
->pcnu_dev_addr
[1], dev
->pcnu_dev_addr
[2],
230 dev
->pcnu_dev_addr
[3], dev
->pcnu_dev_addr
[4], dev
->pcnu_dev_addr
[5]));
233 static void pcn32_drain_tx(struct net_device
*dev
)
235 // struct fe_priv *np = get_pcnpriv(dev);
237 for (i
= 0; i
< TX_RING_SIZE
; i
++) {
238 /* TODO: pcn32_drain_tx does nothing atm. */
239 // np->fep_pcnet_init_block->tx_ring[i].FlagLen = 0;
243 static void pcn32_drain_rx(struct net_device
*dev
)
245 // struct fe_priv *np = get_pcnpriv(dev);
247 for (i
= 0; i
< RX_RING_SIZE
; i
++) {
248 /* TODO: pcn32_drain_rx does nothing atm. */
249 // np->fep_pcnet_init_block->rx_ring[i].FlagLen = 0;
254 static void drain_ring(struct net_device
*dev
)
260 static int request_irq(struct net_device
*dev
)
262 D(bug("%s: request_irq()\n", dev
->pcnu_name
));
264 if (!dev
->pcnu_IntsAdded
)
266 AddIntServer(INTB_KERNEL
+ dev
->pcnu_IRQ
, &dev
->pcnu_irqhandler
);
267 AddIntServer(INTB_VERTB
, &dev
->pcnu_touthandler
);
268 dev
->pcnu_IntsAdded
= TRUE
;
274 static void free_irq(struct net_device
*dev
)
276 if (dev
->pcnu_IntsAdded
)
278 RemIntServer(INTB_KERNEL
+ dev
->pcnu_IRQ
, &dev
->pcnu_irqhandler
);
279 RemIntServer(INTB_VERTB
, &dev
->pcnu_touthandler
);
280 dev
->pcnu_IntsAdded
= FALSE
;
284 static void pcnet32_set_mac(struct net_device
*dev
)
286 // UBYTE *base = get_hwbase(dev);
289 for (i
= 0; i
< 6; i
++) // Copy MAC Address to init block
291 dev
->pcnu_fe_priv
->fep_pcnet_init_block
->phys_addr
[i
] = dev
->pcnu_dev_addr
[i
];
295 static int pcnet32_open(struct net_device
*dev
)
297 struct fe_priv
*np
= get_pcnpriv(dev
);
302 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
304 np
->rx_buffer
= HIDD_PCIDriver_AllocPCIMem(
306 RX_RING_SIZE
* RXTX_ALLOC_BUFSIZE
);
308 if (np
->rx_buffer
== NULL
)
311 np
->tx_buffer
= HIDD_PCIDriver_AllocPCIMem(
313 TX_RING_SIZE
* RXTX_ALLOC_BUFSIZE
);
315 if (np
->tx_buffer
== NULL
)
318 D(bug("%s: pcnet32_open: begin\n",dev
->pcnu_name
));
322 D(bug("%s: pcnet32_open: Allocated IO Buffers [ %d x Tx @ %x] [ %d x Rx @ %x]\n",dev
->pcnu_name
,
323 TX_RING_SIZE
, np
->tx_buffer
,
324 RX_RING_SIZE
, np
->rx_buffer
));
327 np
->fep_pcnet_init_block
->mode
= AROS_WORD2LE(0x0003); /* Disable Rx and Tx */
328 np
->fep_pcnet_init_block
->tlen_rlen
= AROS_WORD2LE(TX_RING_LEN_BITS
| RX_RING_LEN_BITS
);
330 D(bug("%s: pcnet32_open: Interrupts disabled\n",dev
->pcnu_name
));
332 pcnet32_set_mac(dev
);
334 D(bug("%s: pcnet32_open: copied MAC address\n",dev
->pcnu_name
));
336 np
->fep_pcnet_init_block
->filter
[0] = 0xffffffff;
337 np
->fep_pcnet_init_block
->filter
[1] = 0xffffffff;
339 D(bug("%s: pcnet32_open: reset filter\n"));
341 ret
= request_irq(dev
);
345 for (i
=0; i
< TX_RING_SIZE
; i
++)
347 ((struct tx_ring_desc
*)np
->ring_addr
)[i
+ RX_RING_SIZE
].PacketBuffer
= 0;
348 ((struct tx_ring_desc
*)np
->ring_addr
)[i
+ RX_RING_SIZE
].BufferStatus
= 0;
351 D(bug("%s: pcnet32_open: Tx Ring initialised\n",dev
->pcnu_name
));
353 for (i
=0; i
< RX_RING_SIZE
; i
++)
355 ((struct rx_ring_desc
*)np
->ring_addr
)[i
].PacketBuffer
= AROS_LONG2LE((IPTR
)&np
->rx_buffer
[i
]);
356 ((struct rx_ring_desc
*)np
->ring_addr
)[i
].BufferLength
= AROS_WORD2LE(-RXTX_ALLOC_BUFSIZE
);
357 ((struct rx_ring_desc
*)np
->ring_addr
)[i
].BufferStatus
= AROS_WORD2LE((1 << 8)|(1 << 9)|(1 << 15));
360 D(bug("%s: pcnet32_open: Rx Ring initialised\n",dev
->pcnu_name
));
362 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 2); /* Set pcnet32 into 32bit mode */
363 D(bug("%s: PCnet Chipset put into 32bit mode\n", dev
->pcnu_name
));
365 dev
->write_csr(dev
->pcnu_BaseMem
, 1, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) & 0xffff)); /* Store the pointer to the pcnet32_init_block */
366 dev
->write_csr(dev
->pcnu_BaseMem
, 2, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) >> 16));
368 D(bug("%s: pcnet32_open: set init_block (@ %x)\n",dev
->pcnu_name
,np
->fep_pcnet_init_block
));
370 dev
->write_csr(dev
->pcnu_BaseMem
, 0, ((1 << 6)|(1 << 0))); /* Trigger an initialisation for the interrupt (INEA|INIT)*/
372 D(bug("%s: pcnet32_open: triggered init int\n",dev
->pcnu_name
));
374 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
376 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 2); /* Set pcnet32 into 32bit mode */
377 D(bug("%s: PCnet Chipset put into 32bit mode\n", dev
->pcnu_name
));
379 dev
->write_bcr(dev
->pcnu_BaseMem
, 2, ((dev
->read_bcr(dev
->pcnu_BaseMem
, 2) & ~2) | 2)); /* Set autoselect bit */
381 D(bug("%s: pcnet32_open: autoselect bit set\n",dev
->pcnu_name
));
383 /** Handle Link setup **/
385 if ((dev
->pcnu_pcnet_supported
& support_mii
) \
386 // && (!(option & enable_autoneg))
389 dev
->write_bcr(dev
->pcnu_BaseMem
, 32, ((dev
->read_bcr(dev
->pcnu_BaseMem
, 32) & ~0x38) | 0x10 | 0x08 ));
390 D(bug("%s: pcnet32_open: Chipset set into AutoNeg:OFF FullDuplex:ON LinkSpeed:100\n",dev
->pcnu_name
));
394 dev
->write_bcr(dev
->pcnu_BaseMem
, 32, ((dev
->read_bcr(dev
->pcnu_BaseMem
, 32) & ~0x98) | 0x20 ));
395 D(bug("%s: pcnet32_open: Chipset set into AutoNeg:ON\n",dev
->pcnu_name
));
398 /** Set GPSI bit in test register **/
400 /** Handle Transmit stop on underflow **/
401 if (dev
->pcnu_pcnet_supported
& support_dxsuflo
)
403 dev
->write_csr(dev
->pcnu_BaseMem
, 3, (dev
->read_csr(dev
->pcnu_BaseMem
, 3) | 0x40));
404 D(bug("%s: pcnet32_open: Enabled Tx_STOP_ON_UNDERFLOW\n",dev
->pcnu_name
));
407 /** Enable TxDone intr inhibitor **/
408 if (dev
->pcnu_pcnet_supported
& support_ltint
)
410 dev
->write_csr(dev
->pcnu_BaseMem
, 5, (dev
->read_csr(dev
->pcnu_BaseMem
, 5) | (1 << 14)));
411 D(bug("%s: pcnet32_open: Enabled Tx_DONE_INTR_INHIBITOR\n",dev
->pcnu_name
));
414 np
->fep_pcnet_init_block
->mode
= 0x0000; /* Enable Rx and Tx */
416 D(bug("%s: pcnet32_open: Enable Rx & Tx\n",dev
->pcnu_name
));
418 dev
->write_csr(dev
->pcnu_BaseMem
, 1, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) & 0xffff)); /* Re initialise the PCnet chipset */
419 dev
->write_csr(dev
->pcnu_BaseMem
, 2, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) >> 16));
421 D(bug("%s: pcnet32_open: re-initialised chipset\n",dev
->pcnu_name
));
423 dev
->write_csr(dev
->pcnu_BaseMem
, 4, 0x0915); /* ? */
424 dev
->write_csr(dev
->pcnu_BaseMem
, 0, ((1 << 6)|(1 << 1)|(1 << 0)));
428 if (dev
->read_csr(dev
->pcnu_BaseMem
, 0) & 0x0100)
431 D(bug("%s: pcnet32_open: chipset ENABLED, csr[0] = %x\n",dev
->pcnu_name
, dev
->read_csr(dev
->pcnu_BaseMem
, 0)));
433 dev
->pcnu_flags
|= IFF_UP
;
434 ReportEvents(LIBBASE
, dev
, S2EVENT_ONLINE
);
435 D(bug("%s: pcnet32_open: Device set as ONLINE\n",dev
->pcnu_name
));
444 static int pcn32_close(struct net_device
*dev
)
446 struct fe_priv
*np
= get_pcnpriv(dev
);
448 dev
->pcnu_flags
&= ~IFF_UP
;
450 ObtainSemaphore(&np
->lock
);
452 ReleaseSemaphore(&np
->lock
);
454 dev
->pcnu_toutNEED
= FALSE
;
456 netif_stop_queue(dev
);
457 ObtainSemaphore(&np
->lock
);
459 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
461 ReleaseSemaphore(&np
->lock
);
467 HIDD_PCIDriver_FreePCIMem(dev
->pcnu_PCIDriver
, np
->rx_buffer
);
468 HIDD_PCIDriver_FreePCIMem(dev
->pcnu_PCIDriver
, np
->tx_buffer
);
470 ReportEvents(LIBBASE
, dev
, S2EVENT_OFFLINE
);
476 void pcn32_get_functions(struct net_device
*Unit
)
478 Unit
->initialize
= pcnet32_initialize
;
479 Unit
->deinitialize
= pcnet32_deinitialize
;
480 Unit
->start
= pcnet32_open
;
481 Unit
->stop
= pcn32_close
;
482 Unit
->set_mac_address
= pcnet32_set_mac
;
483 Unit
->set_multicast
= pcn32_set_multicast
;