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>
52 #include LC_LIBDEFS_FILE
54 /* A bit fixed linux stuff here :) */
57 #define LIBBASE (dev->pcnu_device)
59 #define net_device PCN32Unit
61 #define TIMER_RPROK 3599597124UL
64 extern volatile UBYTE
readb(APTR base
);
65 extern volatile void writeb(UBYTE val
, APTR base
);
68 extern volatile UWORD
readw(APTR base
);
69 extern volatile void writew(UWORD val
, APTR base
);
72 extern volatile ULONG
readl(APTR base
);
73 extern volatile void writel(ULONG val
, APTR base
);
75 static ULONG
usec2tick(ULONG usec
)
77 ULONG ret
, timer_rpr
= TIMER_RPROK
;
78 asm volatile("movl $0,%%eax; divl %2":"=a"(ret
):"d"(usec
),"m"(timer_rpr
));
82 void udelay(LONG usec
)
85 usec
= usec2tick(usec
);
88 oldtick
= BYTEIN(0x42);
89 oldtick
+= BYTEIN(0x42) << 8;
95 tick
+= BYTEIN(0x42) << 8;
97 usec
-= (oldtick
- tick
);
98 if (tick
> oldtick
) usec
-= 0x10000;
103 static inline struct fe_priv
*get_pcnpriv(struct net_device
*dev
)
105 return dev
->pcnu_fe_priv
;
108 static inline UBYTE
*get_hwbase(struct net_device
*dev
)
110 return (UBYTE
*)dev
->pcnu_BaseMem
;
113 static inline void pci_push(UBYTE
*base
)
115 /* force out pending posted writes */
119 static void pcn32_start_rx(struct net_device
*dev
)
121 struct fe_priv
*np
= get_pcnpriv(dev
);
122 UBYTE
*base
= get_hwbase(dev
);
124 D(bug("%s: pcn32_start_rx\n", dev
->pcnu_name
));
125 // Already running? Stop it.
126 #warning "TODO: Handle starting/stopping Rx"
129 static void pcn32_stop_rx(struct net_device
*dev
)
131 UBYTE
*base
= get_hwbase(dev
);
133 D(bug("%s: pcn32_stop_rx\n", dev
->pcnu_name
));
134 #warning "TODO: Handle starting/stopping Rx"
137 static void pcn32_start_tx(struct net_device
*dev
)
139 UBYTE
*base
= get_hwbase(dev
);
141 D(bug("%s: pcn32_start_tx()\n", dev
->pcnu_name
));
142 #warning "TODO: Handle starting/stopping Tx"
145 static void pcn32_stop_tx(struct net_device
*dev
)
147 UBYTE
*base
= get_hwbase(dev
);
149 D(bug("%s: pcn32_stop_tx()\n", dev
->pcnu_name
));
150 #warning "TODO: Handle starting/stopping Tx"
153 static void pcn32_txrx_reset(struct net_device
*dev
)
155 struct fe_priv
*np
= get_pcnpriv(dev
);
156 UBYTE
*base
= get_hwbase(dev
);
158 D(bug("%s: pcn32_txrx_reset()\n", dev
->pcnu_name
));
162 * pcn32_set_multicast: dev->set_multicast function
163 * Called with dev->xmit_lock held.
165 static void pcn32_set_multicast(struct net_device
*dev
)
167 struct fe_priv
*np
= get_pcnpriv(dev
);
168 UBYTE
*base
= get_hwbase(dev
);
173 D(bug("%s: pcn32_set_multicast()\n", dev
->pcnu_name
));
175 memset(addr
, 0, sizeof(addr
));
176 memset(mask
, 0, sizeof(mask
));
179 static void pcnet32_deinitialize(struct net_device
*dev
)
181 dev
->write_csr(dev
->pcnu_BaseMem
, 0, (1 << 2)); /* Stop the PCnet32 by setting the stop bit.. */
182 D(bug("%s: PCnet32 chipset STOPPED\n", dev
->pcnu_name
));
184 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 4); /* Set pcnet32 into 16bit mode */
185 D(bug("%s: Chipset put into 16bit mode\n", dev
->pcnu_name
));
188 static void pcnet32_initialize(struct net_device
*dev
)
190 struct fe_priv
*np
= dev
->pcnu_fe_priv
;
191 UBYTE
*base
= get_hwbase(dev
);
194 dev
->reset(base
); /* Cause the PCnet Chipset to reset */
195 D(bug("%s: Chipset RESET\n", dev
->pcnu_name
));
197 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
199 np
->ring_addr
= HIDD_PCIDriver_AllocPCIMem(
201 sizeof(struct rx_ring_desc
) * (RX_RING_SIZE
+ TX_RING_SIZE
));
203 np
->fep_pcnet_init_block
->rx_ring
= AROS_LONG2LE(np
->ring_addr
);
204 np
->fep_pcnet_init_block
->tx_ring
= AROS_LONG2LE(&((struct rx_ring_desc
*)np
->ring_addr
)[RX_RING_SIZE
]);
206 D(bug("%s: Allocated IO Rings [%d x Tx @ %x : %x] [%d x Rx @ %x : %x]\n",
208 TX_RING_SIZE
, np
->ring_addr
+ (RX_RING_SIZE
* sizeof(struct rx_ring_desc
)), np
->fep_pcnet_init_block
->tx_ring
,
209 RX_RING_SIZE
, np
->ring_addr
, np
->fep_pcnet_init_block
->rx_ring
));
211 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 2); /* Set pcnet32 into 32bit mode */
212 D(bug("%s: PCnet Chipset put into 32bit mode\n", dev
->pcnu_name
));
214 np
->orig_mac
[0] = ( (readb(base
+ 0) << 24) | (readb(base
+ 1) << 16) | (readb(base
+ 2) << 8) | readb(base
+ 3) );
215 np
->orig_mac
[1] = ( (readb(base
+ 4) << 8) | readb(base
+ 5) );
217 dev
->pcnu_dev_addr
[0] = dev
->pcnu_org_addr
[0] = (np
->orig_mac
[0] >> 24) & 0xff;
218 dev
->pcnu_dev_addr
[1] = dev
->pcnu_org_addr
[1] = (np
->orig_mac
[0] >> 16) & 0xff;
219 dev
->pcnu_dev_addr
[2] = dev
->pcnu_org_addr
[2] = (np
->orig_mac
[0] >> 8) & 0xff;
220 dev
->pcnu_dev_addr
[3] = dev
->pcnu_org_addr
[3] = (np
->orig_mac
[0] >> 0) & 0xff;
222 dev
->pcnu_dev_addr
[4] = dev
->pcnu_org_addr
[4] = (np
->orig_mac
[1] >> 8) & 0xff;
223 dev
->pcnu_dev_addr
[5] = dev
->pcnu_org_addr
[5] = (np
->orig_mac
[1] >> 0) & 0xff;
225 D(bug("%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", dev
->pcnu_name
,
226 dev
->pcnu_dev_addr
[0], dev
->pcnu_dev_addr
[1], dev
->pcnu_dev_addr
[2],
227 dev
->pcnu_dev_addr
[3], dev
->pcnu_dev_addr
[4], dev
->pcnu_dev_addr
[5]));
230 static void pcn32_drain_tx(struct net_device
*dev
)
232 struct fe_priv
*np
= get_pcnpriv(dev
);
234 for (i
= 0; i
< TX_RING_SIZE
; i
++) {
235 #warning "TODO: pcn32_drain_tx does nothing atm."
236 // np->fep_pcnet_init_block->tx_ring[i].FlagLen = 0;
240 static void pcn32_drain_rx(struct net_device
*dev
)
242 struct fe_priv
*np
= get_pcnpriv(dev
);
244 for (i
= 0; i
< RX_RING_SIZE
; i
++) {
245 #warning "TODO: pcn32_drain_rx does nothing atm."
246 // np->fep_pcnet_init_block->rx_ring[i].FlagLen = 0;
251 static void drain_ring(struct net_device
*dev
)
257 static int request_irq(struct net_device
*dev
)
259 OOP_Object
*irq
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
262 D(bug("%s: request_irq()\n", dev
->pcnu_name
));
266 ret
= HIDD_IRQ_AddHandler(irq
, dev
->pcnu_irqhandler
, dev
->pcnu_IRQ
);
267 HIDD_IRQ_AddHandler(irq
, dev
->pcnu_touthandler
, vHidd_IRQ_Timer
);
269 D(bug("%s: request_irq: IRQ Handlers configured\n", dev
->pcnu_name
));
271 OOP_DisposeObject(irq
);
281 static void free_irq(struct net_device
*dev
)
283 OOP_Object
*irq
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
286 HIDD_IRQ_RemHandler(irq
, dev
->pcnu_irqhandler
);
287 HIDD_IRQ_RemHandler(irq
, dev
->pcnu_touthandler
);
288 OOP_DisposeObject(irq
);
292 static void pcnet32_set_mac(struct net_device
*dev
)
294 UBYTE
*base
= get_hwbase(dev
);
297 for (i
= 0; i
< 6; i
++) // Copy MAC Address to init block
299 dev
->pcnu_fe_priv
->fep_pcnet_init_block
->phys_addr
[i
] = dev
->pcnu_dev_addr
[i
];
303 static int pcnet32_open(struct net_device
*dev
)
305 struct fe_priv
*np
= get_pcnpriv(dev
);
306 UBYTE
*base
= get_hwbase(dev
);
311 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
313 np
->rx_buffer
= HIDD_PCIDriver_AllocPCIMem(
315 RX_RING_SIZE
* RXTX_ALLOC_BUFSIZE
);
317 if (np
->rx_buffer
== NULL
)
320 np
->tx_buffer
= HIDD_PCIDriver_AllocPCIMem(
322 TX_RING_SIZE
* RXTX_ALLOC_BUFSIZE
);
324 if (np
->tx_buffer
== NULL
)
327 D(bug("%s: pcnet32_open: begin\n",dev
->pcnu_name
));
331 D(bug("%s: pcnet32_open: Allocated IO Buffers [ %d x Tx @ %x] [ %d x Rx @ %x]\n",dev
->pcnu_name
,
332 TX_RING_SIZE
, np
->tx_buffer
,
333 RX_RING_SIZE
, np
->rx_buffer
));
336 np
->fep_pcnet_init_block
->mode
= AROS_WORD2LE(0x0003); /* Disable Rx and Tx */
337 np
->fep_pcnet_init_block
->tlen_rlen
= AROS_WORD2LE(TX_RING_LEN_BITS
| RX_RING_LEN_BITS
);
339 D(bug("%s: pcnet32_open: Interrupts disabled\n",dev
->pcnu_name
));
341 pcnet32_set_mac(dev
);
343 D(bug("%s: pcnet32_open: copied MAC address\n",dev
->pcnu_name
));
345 np
->fep_pcnet_init_block
->filter
[0] = 0xffffffff;
346 np
->fep_pcnet_init_block
->filter
[1] = 0xffffffff;
348 D(bug("%s: pcnet32_open: reset filter\n"));
350 ret
= request_irq(dev
);
354 for (i
=0; i
< TX_RING_SIZE
; i
++)
356 ((struct tx_ring_desc
*)np
->ring_addr
)[i
+ RX_RING_SIZE
].PacketBuffer
= 0;
357 ((struct tx_ring_desc
*)np
->ring_addr
)[i
+ RX_RING_SIZE
].BufferStatus
= 0;
360 D(bug("%s: pcnet32_open: Tx Ring initialised\n",dev
->pcnu_name
));
362 for (i
=0; i
< RX_RING_SIZE
; i
++)
364 ((struct rx_ring_desc
*)np
->ring_addr
)[i
].PacketBuffer
= AROS_LONG2LE((IPTR
)&np
->rx_buffer
[i
]);
365 ((struct rx_ring_desc
*)np
->ring_addr
)[i
].BufferLength
= AROS_WORD2LE(-RXTX_ALLOC_BUFSIZE
);
366 ((struct rx_ring_desc
*)np
->ring_addr
)[i
].BufferStatus
= AROS_WORD2LE((1 << 8)|(1 << 9)|(1 << 15));
369 D(bug("%s: pcnet32_open: Rx Ring initialised\n",dev
->pcnu_name
));
371 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 2); /* Set pcnet32 into 32bit mode */
372 D(bug("%s: PCnet Chipset put into 32bit mode\n", dev
->pcnu_name
));
374 dev
->write_csr(dev
->pcnu_BaseMem
, 1, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) & 0xffff)); /* Store the pointer to the pcnet32_init_block */
375 dev
->write_csr(dev
->pcnu_BaseMem
, 2, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) >> 16));
377 D(bug("%s: pcnet32_open: set init_block (@ %x)\n",dev
->pcnu_name
,np
->fep_pcnet_init_block
));
379 dev
->write_csr(dev
->pcnu_BaseMem
, 0, ((1 << 6)|(1 << 0))); /* Trigger an initialisation for the interrupt (INEA|INIT)*/
381 D(bug("%s: pcnet32_open: triggered init int\n",dev
->pcnu_name
));
383 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
385 dev
->write_bcr(dev
->pcnu_BaseMem
, 20, 2); /* Set pcnet32 into 32bit mode */
386 D(bug("%s: PCnet Chipset put into 32bit mode\n", dev
->pcnu_name
));
388 dev
->write_bcr(dev
->pcnu_BaseMem
, 2, ((dev
->read_bcr(dev
->pcnu_BaseMem
, 2) & ~2) | 2)); /* Set autoselect bit */
390 D(bug("%s: pcnet32_open: autoselect bit set\n",dev
->pcnu_name
));
392 /** Handle Link setup **/
394 if ((dev
->pcnu_pcnet_supported
& support_mii
) \
395 // && (!(option & enable_autoneg))
398 dev
->write_bcr(dev
->pcnu_BaseMem
, 32, ((dev
->read_bcr(dev
->pcnu_BaseMem
, 32) & ~0x38) | 0x10 | 0x08 ));
399 D(bug("%s: pcnet32_open: Chipset set into AutoNeg:OFF FullDuplex:ON LinkSpeed:100\n",dev
->pcnu_name
));
403 dev
->write_bcr(dev
->pcnu_BaseMem
, 32, ((dev
->read_bcr(dev
->pcnu_BaseMem
, 32) & ~0x98) | 0x20 ));
404 D(bug("%s: pcnet32_open: Chipset set into AutoNeg:ON\n",dev
->pcnu_name
));
407 /** Set GPSI bit in test register **/
409 /** Handle Transmit stop on underflow **/
410 if (dev
->pcnu_pcnet_supported
& support_dxsuflo
)
412 dev
->write_csr(dev
->pcnu_BaseMem
, 3, (dev
->read_csr(dev
->pcnu_BaseMem
, 3) | 0x40));
413 D(bug("%s: pcnet32_open: Enabled Tx_STOP_ON_UNDERFLOW\n",dev
->pcnu_name
));
416 /** Enable TxDone intr inhibitor **/
417 if (dev
->pcnu_pcnet_supported
& support_ltint
)
419 dev
->write_csr(dev
->pcnu_BaseMem
, 5, (dev
->read_csr(dev
->pcnu_BaseMem
, 5) | (1 << 14)));
420 D(bug("%s: pcnet32_open: Enabled Tx_DONE_INTR_INHIBITOR\n",dev
->pcnu_name
));
423 np
->fep_pcnet_init_block
->mode
= 0x0000; /* Enable Rx and Tx */
425 D(bug("%s: pcnet32_open: Enable Rx & Tx\n",dev
->pcnu_name
));
427 dev
->write_csr(dev
->pcnu_BaseMem
, 1, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) & 0xffff)); /* Re initialise the PCnet chipset */
428 dev
->write_csr(dev
->pcnu_BaseMem
, 2, (AROS_LONG2LE((IPTR
)np
->fep_pcnet_init_block
) >> 16));
430 D(bug("%s: pcnet32_open: re-initialised chipset\n",dev
->pcnu_name
));
432 dev
->write_csr(dev
->pcnu_BaseMem
, 4, 0x0915); /* ? */
433 dev
->write_csr(dev
->pcnu_BaseMem
, 0, ((1 << 6)|(1 << 1)|(1 << 0)));
437 if (dev
->read_csr(dev
->pcnu_BaseMem
, 0) & 0x0100)
440 D(bug("%s: pcnet32_open: chipset ENABLED, csr[0] = %x\n",dev
->pcnu_name
, dev
->read_csr(dev
->pcnu_BaseMem
, 0)));
442 dev
->pcnu_flags
|= IFF_UP
;
443 ReportEvents(LIBBASE
, dev
, S2EVENT_ONLINE
);
444 D(bug("%s: pcnet32_open: Device set as ONLINE\n",dev
->pcnu_name
));
453 static int pcn32_close(struct net_device
*dev
)
455 struct fe_priv
*np
= get_pcnpriv(dev
);
458 dev
->pcnu_flags
&= ~IFF_UP
;
460 ObtainSemaphore(&np
->lock
);
462 ReleaseSemaphore(&np
->lock
);
464 dev
->pcnu_toutNEED
= FALSE
;
466 netif_stop_queue(dev
);
467 ObtainSemaphore(&np
->lock
);
469 pcnet32_deinitialize(dev
); // Stop the chipset and set it in 16bit-mode
471 base
= get_hwbase(dev
);
473 ReleaseSemaphore(&np
->lock
);
479 HIDD_PCIDriver_FreePCIMem(dev
->pcnu_PCIDriver
, np
->rx_buffer
);
480 HIDD_PCIDriver_FreePCIMem(dev
->pcnu_PCIDriver
, np
->tx_buffer
);
482 ReportEvents(LIBBASE
, dev
, S2EVENT_OFFLINE
);
488 void pcn32_get_functions(struct net_device
*Unit
)
490 Unit
->initialize
= pcnet32_initialize
;
491 Unit
->deinitialize
= pcnet32_deinitialize
;
492 Unit
->start
= pcnet32_open
;
493 Unit
->stop
= pcn32_close
;
494 Unit
->set_mac_address
= pcnet32_set_mac
;
495 Unit
->set_multicast
= pcn32_set_multicast
;