2005-04-16 15:20:36 -07:00
/*
* Driver for the Macintosh 68 K onboard MACE controller with PSC
* driven DMA . The MACE driver code is derived from mace . c . The
* Mac68k theory of operation is courtesy of the MacBSD wizards .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* Copyright ( C ) 1996 Paul Mackerras .
* Copyright ( C ) 1998 Alan Cox < alan @ redhat . com >
*
* Modified heavily by Joshua M . Thompson based on Dave Huang ' s NetBSD driver
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/crc32.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/irq.h>
# include <asm/macintosh.h>
# include <asm/macints.h>
# include <asm/mac_psc.h>
# include <asm/page.h>
# include "mace.h"
# define N_TX_RING 1
# define N_RX_RING 8
# define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE)
# define TX_TIMEOUT HZ
/* Bits in transmit DMA status */
# define TX_DMA_ERR 0x80
/* The MACE is simply wired down on a Mac68K box */
# define MACE_BASE (void *)(0x50F1C000)
# define MACE_PROM (void *)(0x50F08001)
struct mace_data {
volatile struct mace * mace ;
volatile unsigned char * tx_ring ;
volatile unsigned char * tx_ring_phys ;
volatile unsigned char * rx_ring ;
volatile unsigned char * rx_ring_phys ;
int dma_intr ;
struct net_device_stats stats ;
int rx_slot , rx_tail ;
int tx_slot , tx_sloti , tx_count ;
} ;
struct mace_frame {
u16 len ;
u16 status ;
u16 rntpc ;
u16 rcvcc ;
u32 pad1 ;
u32 pad2 ;
2006-09-13 13:24:59 -04:00
u8 data [ 1 ] ;
2005-04-16 15:20:36 -07:00
/* And frame continues.. */
} ;
# define PRIV_BYTES sizeof(struct mace_data)
extern void psc_debug_dump ( void ) ;
static int mace_open ( struct net_device * dev ) ;
static int mace_close ( struct net_device * dev ) ;
static int mace_xmit_start ( struct sk_buff * skb , struct net_device * dev ) ;
static struct net_device_stats * mace_stats ( struct net_device * dev ) ;
static void mace_set_multicast ( struct net_device * dev ) ;
static int mace_set_address ( struct net_device * dev , void * addr ) ;
static irqreturn_t mace_interrupt ( int irq , void * dev_id , struct pt_regs * regs ) ;
static irqreturn_t mace_dma_intr ( int irq , void * dev_id , struct pt_regs * regs ) ;
static void mace_tx_timeout ( struct net_device * dev ) ;
/* Bit-reverse one byte of an ethernet hardware address. */
static int bitrev ( int b )
{
int d = 0 , i ;
for ( i = 0 ; i < 8 ; + + i , b > > = 1 ) {
d = ( d < < 1 ) | ( b & 1 ) ;
}
return d ;
}
/*
* Load a receive DMA channel with a base address and ring length
*/
static void mace_load_rxdma_base ( struct net_device * dev , int set )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
psc_write_word ( PSC_ENETRD_CMD + set , 0x0100 ) ;
psc_write_long ( PSC_ENETRD_ADDR + set , ( u32 ) mp - > rx_ring_phys ) ;
psc_write_long ( PSC_ENETRD_LEN + set , N_RX_RING ) ;
psc_write_word ( PSC_ENETRD_CMD + set , 0x9800 ) ;
mp - > rx_tail = 0 ;
}
/*
* Reset the receive DMA subsystem
*/
static void mace_rxdma_reset ( struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mace = mp - > mace ;
u8 maccc = mace - > maccc ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
mace - > maccc = maccc & ~ ENRCV ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
psc_write_word ( PSC_ENETRD_CTL , 0x8800 ) ;
mace_load_rxdma_base ( dev , 0x00 ) ;
psc_write_word ( PSC_ENETRD_CTL , 0x0400 ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
psc_write_word ( PSC_ENETRD_CTL , 0x8800 ) ;
mace_load_rxdma_base ( dev , 0x10 ) ;
psc_write_word ( PSC_ENETRD_CTL , 0x0400 ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
mace - > maccc = maccc ;
mp - > rx_slot = 0 ;
psc_write_word ( PSC_ENETRD_CMD + PSC_SET0 , 0x9800 ) ;
psc_write_word ( PSC_ENETRD_CMD + PSC_SET1 , 0x9800 ) ;
}
/*
* Reset the transmit DMA subsystem
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static void mace_txdma_reset ( struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mace = mp - > mace ;
u8 maccc ;
psc_write_word ( PSC_ENETWR_CTL , 0x8800 ) ;
maccc = mace - > maccc ;
mace - > maccc = maccc & ~ ENXMT ;
mp - > tx_slot = mp - > tx_sloti = 0 ;
mp - > tx_count = N_TX_RING ;
psc_write_word ( PSC_ENETWR_CTL , 0x0400 ) ;
mace - > maccc = maccc ;
}
/*
* Disable DMA
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static void mace_dma_off ( struct net_device * dev )
{
psc_write_word ( PSC_ENETRD_CTL , 0x8800 ) ;
psc_write_word ( PSC_ENETRD_CTL , 0x1000 ) ;
psc_write_word ( PSC_ENETRD_CMD + PSC_SET0 , 0x1100 ) ;
psc_write_word ( PSC_ENETRD_CMD + PSC_SET1 , 0x1100 ) ;
psc_write_word ( PSC_ENETWR_CTL , 0x8800 ) ;
psc_write_word ( PSC_ENETWR_CTL , 0x1000 ) ;
psc_write_word ( PSC_ENETWR_CMD + PSC_SET0 , 0x1100 ) ;
psc_write_word ( PSC_ENETWR_CMD + PSC_SET1 , 0x1100 ) ;
}
/*
* Not really much of a probe . The hardware table tells us if this
* model of Macintrash has a MACE ( AV macintoshes )
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
struct net_device * mace_probe ( int unit )
{
int j ;
struct mace_data * mp ;
unsigned char * addr ;
struct net_device * dev ;
unsigned char checksum = 0 ;
static int found = 0 ;
int err ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( found | | macintosh_config - > ether_type ! = MAC_ETHER_MACE )
return ERR_PTR ( - ENODEV ) ;
found = 1 ; /* prevent 'finding' one on every device probe */
dev = alloc_etherdev ( PRIV_BYTES ) ;
if ( ! dev )
return ERR_PTR ( - ENOMEM ) ;
if ( unit > = 0 )
sprintf ( dev - > name , " eth%d " , unit ) ;
mp = ( struct mace_data * ) dev - > priv ;
dev - > base_addr = ( u32 ) MACE_BASE ;
mp - > mace = ( volatile struct mace * ) MACE_BASE ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
dev - > irq = IRQ_MAC_MACE ;
mp - > dma_intr = IRQ_MAC_MACE_DMA ;
/*
* The PROM contains 8 bytes which total 0xFF when XOR ' d
* together . Due to the usual peculiar apple brain damage
* the bytes are spaced out in a strange boundary and the
* bits are reversed .
*/
addr = ( void * ) MACE_PROM ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
for ( j = 0 ; j < 6 ; + + j ) {
u8 v = bitrev ( addr [ j < < 4 ] ) ;
checksum ^ = v ;
dev - > dev_addr [ j ] = v ;
}
for ( ; j < 8 ; + + j ) {
checksum ^ = bitrev ( addr [ j < < 4 ] ) ;
}
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( checksum ! = 0xFF ) {
free_netdev ( dev ) ;
return ERR_PTR ( - ENODEV ) ;
}
memset ( & mp - > stats , 0 , sizeof ( mp - > stats ) ) ;
dev - > open = mace_open ;
dev - > stop = mace_close ;
dev - > hard_start_xmit = mace_xmit_start ;
dev - > tx_timeout = mace_tx_timeout ;
dev - > watchdog_timeo = TX_TIMEOUT ;
dev - > get_stats = mace_stats ;
dev - > set_multicast_list = mace_set_multicast ;
dev - > set_mac_address = mace_set_address ;
printk ( KERN_INFO " %s: 68K MACE, hardware address %.2X " , dev - > name , dev - > dev_addr [ 0 ] ) ;
for ( j = 1 ; j < 6 ; j + + ) printk ( " :%.2X " , dev - > dev_addr [ j ] ) ;
printk ( " \n " ) ;
err = register_netdev ( dev ) ;
if ( ! err )
return dev ;
free_netdev ( dev ) ;
return ERR_PTR ( err ) ;
}
/*
* Load the address on a mace controller .
*/
static int mace_set_address ( struct net_device * dev , void * addr )
{
unsigned char * p = addr ;
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mb = mp - > mace ;
int i ;
unsigned long flags ;
u8 maccc ;
local_irq_save ( flags ) ;
maccc = mb - > maccc ;
/* load up the hardware address */
mb - > iac = ADDRCHG | PHYADDR ;
while ( ( mb - > iac & ADDRCHG ) ! = 0 ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 6 ; + + i ) {
mb - > padr = dev - > dev_addr [ i ] = p [ i ] ;
}
mb - > maccc = maccc ;
local_irq_restore ( flags ) ;
return 0 ;
}
/*
* Open the Macintosh MACE . Most of this is playing with the DMA
* engine . The ethernet chip is quite friendly .
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static int mace_open ( struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mb = mp - > mace ;
#if 0
int i ;
i = 200 ;
while ( - - i ) {
mb - > biucc = SWRST ;
if ( mb - > biucc & SWRST ) {
udelay ( 10 ) ;
continue ;
}
break ;
}
if ( ! i ) {
printk ( KERN_ERR " %s: software reset failed!! \n " , dev - > name ) ;
return - EAGAIN ;
}
# endif
mb - > biucc = XMTSP_64 ;
mb - > fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST ;
mb - > xmtfc = AUTO_PAD_XMIT ;
mb - > plscc = PORTSEL_AUI ;
/* mb->utr = RTRD; */
if ( request_irq ( dev - > irq , mace_interrupt , 0 , dev - > name , dev ) ) {
printk ( KERN_ERR " %s: can't get irq %d \n " , dev - > name , dev - > irq ) ;
return - EAGAIN ;
}
if ( request_irq ( mp - > dma_intr , mace_dma_intr , 0 , dev - > name , dev ) ) {
printk ( KERN_ERR " %s: can't get irq %d \n " , dev - > name , mp - > dma_intr ) ;
free_irq ( dev - > irq , dev ) ;
return - EAGAIN ;
}
/* Allocate the DMA ring buffers */
mp - > rx_ring = ( void * ) __get_free_pages ( GFP_KERNEL | GFP_DMA , N_RX_PAGES ) ;
mp - > tx_ring = ( void * ) __get_free_pages ( GFP_KERNEL | GFP_DMA , 0 ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( mp - > tx_ring = = NULL | | mp - > rx_ring = = NULL ) {
if ( mp - > rx_ring ) free_pages ( ( u32 ) mp - > rx_ring , N_RX_PAGES ) ;
if ( mp - > tx_ring ) free_pages ( ( u32 ) mp - > tx_ring , 0 ) ;
free_irq ( dev - > irq , dev ) ;
free_irq ( mp - > dma_intr , dev ) ;
printk ( KERN_ERR " %s: unable to allocate DMA buffers \n " , dev - > name ) ;
return - ENOMEM ;
}
mp - > rx_ring_phys = ( unsigned char * ) virt_to_bus ( ( void * ) mp - > rx_ring ) ;
mp - > tx_ring_phys = ( unsigned char * ) virt_to_bus ( ( void * ) mp - > tx_ring ) ;
/* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
2006-09-13 13:24:59 -04:00
kernel_set_cachemode ( ( void * ) mp - > rx_ring , N_RX_PAGES * PAGE_SIZE , IOMAP_NOCACHE_NONSER ) ;
2005-04-16 15:20:36 -07:00
kernel_set_cachemode ( ( void * ) mp - > tx_ring , PAGE_SIZE , IOMAP_WRITETHROUGH ) ;
mace_dma_off ( dev ) ;
/* Not sure what these do */
psc_write_word ( PSC_ENETWR_CTL , 0x9000 ) ;
psc_write_word ( PSC_ENETRD_CTL , 0x9000 ) ;
psc_write_word ( PSC_ENETWR_CTL , 0x0400 ) ;
psc_write_word ( PSC_ENETRD_CTL , 0x0400 ) ;
#if 0
/* load up the hardware address */
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
mb - > iac = ADDRCHG | PHYADDR ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
while ( ( mb - > iac & ADDRCHG ) ! = 0 ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 6 ; + + i )
mb - > padr = dev - > dev_addr [ i ] ;
/* clear the multicast filter */
mb - > iac = ADDRCHG | LOGADDR ;
while ( ( mb - > iac & ADDRCHG ) ! = 0 ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 8 ; + + i )
mb - > ladrf = 0 ;
mb - > plscc = PORTSEL_GPSI + ENPLSIO ;
mb - > maccc = ENXMT | ENRCV ;
mb - > imr = RCVINT ;
# endif
mace_rxdma_reset ( dev ) ;
mace_txdma_reset ( dev ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
/*
* Shut down the mace and its interrupt channel
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static int mace_close ( struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mb = mp - > mace ;
mb - > maccc = 0 ; /* disable rx and tx */
mb - > imr = 0xFF ; /* disable all irqs */
mace_dma_off ( dev ) ; /* disable rx and tx dma */
free_irq ( dev - > irq , dev ) ;
free_irq ( IRQ_MAC_MACE_DMA , dev ) ;
free_pages ( ( u32 ) mp - > rx_ring , N_RX_PAGES ) ;
free_pages ( ( u32 ) mp - > tx_ring , 0 ) ;
return 0 ;
}
/*
* Transmit a frame
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static int mace_xmit_start ( struct sk_buff * skb , struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
/* Stop the queue if the buffer is full */
if ( ! mp - > tx_count ) {
netif_stop_queue ( dev ) ;
return 1 ;
}
mp - > tx_count - - ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
mp - > stats . tx_packets + + ;
mp - > stats . tx_bytes + = skb - > len ;
/* We need to copy into our xmit buffer to take care of alignment and caching issues */
memcpy ( ( void * ) mp - > tx_ring , skb - > data , skb - > len ) ;
/* load the Tx DMA and fire it off */
psc_write_long ( PSC_ENETWR_ADDR + mp - > tx_slot , ( u32 ) mp - > tx_ring_phys ) ;
psc_write_long ( PSC_ENETWR_LEN + mp - > tx_slot , skb - > len ) ;
psc_write_word ( PSC_ENETWR_CMD + mp - > tx_slot , 0x9800 ) ;
mp - > tx_slot ^ = 0x10 ;
dev_kfree_skb ( skb ) ;
return 0 ;
}
static struct net_device_stats * mace_stats ( struct net_device * dev )
{
struct mace_data * p = ( struct mace_data * ) dev - > priv ;
return & p - > stats ;
}
static void mace_set_multicast ( struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mb = mp - > mace ;
int i , j ;
u32 crc ;
u8 maccc ;
maccc = mb - > maccc ;
mb - > maccc & = ~ PROM ;
if ( dev - > flags & IFF_PROMISC ) {
mb - > maccc | = PROM ;
} else {
unsigned char multicast_filter [ 8 ] ;
struct dev_mc_list * dmi = dev - > mc_list ;
if ( dev - > flags & IFF_ALLMULTI ) {
for ( i = 0 ; i < 8 ; i + + ) {
multicast_filter [ i ] = 0xFF ;
}
} else {
for ( i = 0 ; i < 8 ; i + + )
multicast_filter [ i ] = 0 ;
for ( i = 0 ; i < dev - > mc_count ; i + + ) {
crc = ether_crc_le ( 6 , dmi - > dmi_addr ) ;
j = crc > > 26 ; /* bit number in multicast_filter */
multicast_filter [ j > > 3 ] | = 1 < < ( j & 7 ) ;
dmi = dmi - > next ;
}
}
mb - > iac = ADDRCHG | LOGADDR ;
while ( mb - > iac & ADDRCHG ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 8 ; + + i ) {
mb - > ladrf = multicast_filter [ i ] ;
}
}
mb - > maccc = maccc ;
}
/*
2006-09-13 13:24:59 -04:00
* Miscellaneous interrupts are handled here . We may end up
2005-04-16 15:20:36 -07:00
* having to bash the chip on the head for bad errors
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static void mace_handle_misc_intrs ( struct mace_data * mp , int intr )
{
volatile struct mace * mb = mp - > mace ;
static int mace_babbles , mace_jabbers ;
if ( intr & MPCO ) {
mp - > stats . rx_missed_errors + = 256 ;
}
mp - > stats . rx_missed_errors + = mb - > mpc ; /* reading clears it */
if ( intr & RNTPCO ) {
mp - > stats . rx_length_errors + = 256 ;
}
mp - > stats . rx_length_errors + = mb - > rntpc ; /* reading clears it */
if ( intr & CERR ) {
+ + mp - > stats . tx_heartbeat_errors ;
}
if ( intr & BABBLE ) {
if ( mace_babbles + + < 4 ) {
printk ( KERN_DEBUG " mace: babbling transmitter \n " ) ;
}
}
if ( intr & JABBER ) {
if ( mace_jabbers + + < 4 ) {
printk ( KERN_DEBUG " mace: jabbering transceiver \n " ) ;
}
}
}
/*
* A transmit error has occurred . ( We kick the transmit side from
* the DMA completion )
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static void mace_xmit_error ( struct net_device * dev )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mb = mp - > mace ;
u8 xmtfs , xmtrc ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
xmtfs = mb - > xmtfs ;
xmtrc = mb - > xmtrc ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( xmtfs & XMTSV ) {
if ( xmtfs & UFLO ) {
printk ( " %s: DMA underrun. \n " , dev - > name ) ;
mp - > stats . tx_errors + + ;
mp - > stats . tx_fifo_errors + + ;
mace_txdma_reset ( dev ) ;
}
if ( xmtfs & RTRY ) {
mp - > stats . collisions + + ;
}
2006-09-13 13:24:59 -04:00
}
2005-04-16 15:20:36 -07:00
}
/*
* A receive interrupt occurred .
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static void mace_recv_interrupt ( struct net_device * dev )
{
/* struct mace_data *mp = (struct mace_data *) dev->priv; */
// volatile struct mace *mb = mp->mace;
}
/*
* Process the chip interrupt
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static irqreturn_t mace_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
volatile struct mace * mb = mp - > mace ;
u8 ir ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
ir = mb - > ir ;
mace_handle_misc_intrs ( mp , ir ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( ir & XMTINT ) {
mace_xmit_error ( dev ) ;
}
if ( ir & RCVINT ) {
mace_recv_interrupt ( dev ) ;
}
return IRQ_HANDLED ;
}
static void mace_tx_timeout ( struct net_device * dev )
{
/* struct mace_data *mp = (struct mace_data *) dev->priv; */
// volatile struct mace *mb = mp->mace;
}
/*
* Handle a newly arrived frame
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static void mace_dma_rx_frame ( struct net_device * dev , struct mace_frame * mf )
{
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
struct sk_buff * skb ;
if ( mf - > status & RS_OFLO ) {
printk ( " %s: fifo overflow. \n " , dev - > name ) ;
mp - > stats . rx_errors + + ;
mp - > stats . rx_fifo_errors + + ;
}
if ( mf - > status & ( RS_CLSN | RS_FRAMERR | RS_FCSERR ) )
mp - > stats . rx_errors + + ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( mf - > status & RS_CLSN ) {
mp - > stats . collisions + + ;
}
if ( mf - > status & RS_FRAMERR ) {
mp - > stats . rx_frame_errors + + ;
}
if ( mf - > status & RS_FCSERR ) {
mp - > stats . rx_crc_errors + + ;
}
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
skb = dev_alloc_skb ( mf - > len + 2 ) ;
if ( ! skb ) {
mp - > stats . rx_dropped + + ;
return ;
}
skb_reserve ( skb , 2 ) ;
memcpy ( skb_put ( skb , mf - > len ) , mf - > data , mf - > len ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
skb - > dev = dev ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
netif_rx ( skb ) ;
dev - > last_rx = jiffies ;
mp - > stats . rx_packets + + ;
mp - > stats . rx_bytes + = mf - > len ;
}
/*
* The PSC has passed us a DMA interrupt event .
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
static irqreturn_t mace_dma_intr ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct mace_data * mp = ( struct mace_data * ) dev - > priv ;
int left , head ;
u16 status ;
u32 baka ;
/* Not sure what this does */
while ( ( baka = psc_read_long ( PSC_MYSTERY ) ) ! = psc_read_long ( PSC_MYSTERY ) ) ;
if ( ! ( baka & 0x60000000 ) ) return IRQ_NONE ;
/*
* Process the read queue
*/
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
status = psc_read_word ( PSC_ENETRD_CTL ) ;
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
if ( status & 0x2000 ) {
mace_rxdma_reset ( dev ) ;
} else if ( status & 0x0100 ) {
psc_write_word ( PSC_ENETRD_CMD + mp - > rx_slot , 0x1100 ) ;
left = psc_read_long ( PSC_ENETRD_LEN + mp - > rx_slot ) ;
head = N_RX_RING - left ;
/* Loop through the ring buffer and process new packages */
while ( mp - > rx_tail < head ) {
mace_dma_rx_frame ( dev , ( struct mace_frame * ) ( mp - > rx_ring + ( mp - > rx_tail * 0x0800 ) ) ) ;
mp - > rx_tail + + ;
}
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
/* If we're out of buffers in this ring then switch to */
/* the other set, otherwise just reactivate this one. */
if ( ! left ) {
mace_load_rxdma_base ( dev , mp - > rx_slot ) ;
mp - > rx_slot ^ = 0x10 ;
} else {
psc_write_word ( PSC_ENETRD_CMD + mp - > rx_slot , 0x9800 ) ;
}
}
2006-09-13 13:24:59 -04:00
2005-04-16 15:20:36 -07:00
/*
* Process the write queue
*/
status = psc_read_word ( PSC_ENETWR_CTL ) ;
if ( status & 0x2000 ) {
mace_txdma_reset ( dev ) ;
} else if ( status & 0x0100 ) {
psc_write_word ( PSC_ENETWR_CMD + mp - > tx_sloti , 0x0100 ) ;
mp - > tx_sloti ^ = 0x10 ;
mp - > tx_count + + ;
netif_wake_queue ( dev ) ;
}
return IRQ_HANDLED ;
}
MODULE_LICENSE ( " GPL " ) ;