2007-04-01 21:40:56 +03:00
/* r6040.c: A RDC R6040 FastEthernet driver for linux. */
2007-03-31 00:56:07 +03:00
/*
Re - written 2004 by Sten Wang .
Copyright 1994 - 2000 by Donald Becker .
Copyright 1993 United States Government as represented by the
Director , National Security Agency . This software may be used and
distributed according to the terms of the GNU General Public License ,
incorporated herein by reference .
2007-04-01 21:40:56 +03:00
This driver is for RDC R6040 FastEthernet MAC series .
2007-03-31 00:56:07 +03:00
For kernel version after 2.4 .22
Modification List
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-10-08 11:01:30 +03:00
10 - 07 - 2007 Clean up the driver using checkpatch
2007-04-01 21:40:56 +03:00
08 - 24 - 2006 Support at linux 2.6 .10 above
03 - 24 - 2006 Support NAPI
2007-10-08 11:01:30 +03:00
03 - 21 - 2006 By Charies , change spin_lock_irqsave ( lp - > lock , flags )
to spin_lock_irqsave ( & lp - > lock , flags )
in set_multicast_list
2007-04-01 21:40:56 +03:00
03 - 15 - 2006 Modify the set_multicast_list , due to when re - plug the ethernet ,
it will forget the previous setting
2007-10-08 11:01:30 +03:00
07 - 12 - 2005 Tim , modify the set_multicast_list
03 - 28 - 2005 Tim , modify some error mac register offset in
function set_multicast_list
2007-04-01 21:40:56 +03:00
03 - 27 - 2005 Tim , Add the internal state machine reset
Sten , If multicast address more than 4 , enter PROM mode
Changed rdc to r6040
2007-03-31 00:56:07 +03:00
12 - 22 - 2004 Sten Init MAC MBCR register = 0x012A
PHY_CAP = 0x01E1
2007-04-01 21:40:56 +03:00
Need to Do LIst :
1. If multicast address more than 4 , use the multicast address hash
*/
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
# define DRV_NAME "r6040"
# define DRV_VERSION "0.13"
# define DRV_RELDATE "24Aug2006"
2007-03-31 00:56:07 +03:00
/* PHY CHIP Address */
# define PHY1_ADDR 1 /* For MAC1 */
# define PHY2_ADDR 2 /* For MAC2 */
# define PHY_MODE 0x3100 /* PHY CHIP Register 0 */
# define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */
/* Time in jiffies before concluding the transmitter is hung. */
2007-04-01 21:40:56 +03:00
# define TX_TIMEOUT (6000 * HZ / 1000)
2007-03-31 00:56:07 +03:00
# define TIMER_WUT (jiffies + HZ * 1) /* timer wakeup time : 1 second */
/* RDC MAC ID */
# define RDC_MAC_ID 0x6040
/* RDC MAC I/O Size */
# define R6040_IO_SIZE 256
/* RDC Chip PCI Command */
# define R6040_PCI_CMD 0x0005 /* IO, Master */
/* MAX RDC MAC */
# define MAX_MAC 2
/* MAC setting */
2007-04-01 21:40:56 +03:00
# define TX_DCNT 0x80 /* TX descriptor count */
# define RX_DCNT 0x80 /* RX descriptor count */
2007-03-31 00:56:07 +03:00
# define MAX_BUF_SIZE 0x600
2007-04-01 21:40:56 +03:00
# define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT)*sizeof(struct r6040_descriptor)+0x10)
# define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */
2007-03-31 00:56:07 +03:00
2007-10-08 11:01:30 +03:00
/* PHY settings */
# define ICPLUS_PHY_ID 0x0243
2007-03-31 00:56:07 +03:00
/* Debug enable or not */
# define RDC_DEBUG 0
# if RDC_DEBUG > 1
2007-10-08 11:01:30 +03:00
# define RDC_DBUG(msg, value) printk(KERN_ERR "%s %x\n", msg, value);
2007-03-31 00:56:07 +03:00
# else
# define RDC_DBUG(msg, value)
# endif
# include <linux/module.h>
2007-04-01 21:40:56 +03:00
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
# include <linux/moduleparam.h>
# endif
2007-03-31 00:56:07 +03:00
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/errno.h>
# include <linux/ioport.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/pci.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
# include <linux/init.h>
2007-10-08 11:01:30 +03:00
# include <linux/delay.h>
2007-03-31 00:56:07 +03:00
# include <linux/mii.h>
# include <linux/ethtool.h>
# include <linux/crc32.h>
# include <linux/spinlock.h>
# include <asm/processor.h>
# include <asm/bitops.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/uaccess.h>
2007-10-08 11:01:30 +03:00
MODULE_AUTHOR ( " Sten Wang <sten.wang@rdc.com.tw>, Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>, Florian Fainelli <florian@openwrt.org> " ) ;
2007-03-31 00:56:07 +03:00
MODULE_LICENSE ( " GPL " ) ;
2007-04-01 21:40:56 +03:00
# ifdef CONFIG_R6040_NAPI
MODULE_DESCRIPTION ( " RDC R6040 NAPI PCI FastEthernet Driver " ) ;
# else
MODULE_DESCRIPTION ( " RDC R6040 PCI FastEthernet Driver " ) ;
# endif
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
# define R6040_INT_MASK 0x0011
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
struct r6040_descriptor {
2007-03-31 00:56:07 +03:00
u16 status , len ; /* 0-3 */
u32 buf ; /* 4-7 */
u32 ndesc ; /* 8-B */
u32 rev1 ; /* C-F */
char * vbufp ; /* 10-13 */
2007-04-01 21:40:56 +03:00
struct r6040_descriptor * vndescp ; /* 14-17 */
2007-03-31 00:56:07 +03:00
struct sk_buff * skb_ptr ; /* 18-1B */
u32 rev2 ; /* 1C-1F */
2007-10-08 11:01:30 +03:00
} __attribute__ ( ( aligned ( 32 ) ) ) ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
struct r6040_private {
2007-03-31 00:56:07 +03:00
struct net_device_stats stats ;
2007-10-08 11:01:30 +03:00
spinlock_t lock ; /* driver lock */
struct timer_list timer ;
2007-03-31 00:56:07 +03:00
struct pci_dev * pdev ;
2007-04-01 21:40:56 +03:00
struct r6040_descriptor * rx_insert_ptr ;
struct r6040_descriptor * rx_remove_ptr ;
struct r6040_descriptor * tx_insert_ptr ;
struct r6040_descriptor * tx_remove_ptr ;
2007-03-31 00:56:07 +03:00
u16 tx_free_desc , rx_free_desc , phy_addr , phy_mode ;
u16 mcr0 , mcr1 ;
dma_addr_t desc_dma ;
char * desc_pool ;
2007-07-25 12:16:20 +03:00
u16 switch_sig ;
2007-03-31 00:56:07 +03:00
} ;
2007-04-01 21:40:56 +03:00
struct r6040_chip_info {
2007-03-31 00:56:07 +03:00
const char * name ;
u16 pci_flags ;
int io_size ;
int drv_flags ;
} ;
2007-04-01 21:40:56 +03:00
# ifdef CONFIG_R6040_NAPI
static int NAPI_status ;
# endif
2007-03-31 00:56:07 +03:00
static int __devinitdata printed_version ;
2007-04-01 21:40:56 +03:00
# ifdef CONFIG_R6040_NAPI
2007-03-31 00:56:07 +03:00
static char version [ ] __devinitdata =
2007-10-08 11:01:30 +03:00
KERN_INFO DRV_NAME " : RDC R6040 NAPI net driver, version " DRV_VERSION " ( " DRV_RELDATE " ) \n " ;
2007-04-01 21:40:56 +03:00
# else
static char version [ ] __devinitdata =
2007-10-08 11:01:30 +03:00
KERN_INFO DRV_NAME " : RDC R6040 net driver, version " DRV_VERSION " ( " DRV_RELDATE " ) \n " ;
2007-04-01 21:40:56 +03:00
# endif
static struct r6040_chip_info r6040_chip_info [ ] __devinitdata =
2007-03-31 00:56:07 +03:00
{
{ " RDC R6040 Knight " , R6040_PCI_CMD , R6040_IO_SIZE , 0 }
} ;
2007-10-08 11:01:30 +03:00
static char * parent ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
static int NUM_MAC_TABLE = 2 ;
2007-07-25 12:16:20 +03:00
module_param ( parent , charp , 0444 ) ;
# else
MODULE_PARM ( parent , " s " ) ;
2007-04-01 21:40:56 +03:00
# endif
2007-07-25 12:16:20 +03:00
MODULE_PARM_DESC ( parent , " Parent network device name " ) ;
2007-04-01 21:40:56 +03:00
2007-03-31 00:56:07 +03:00
static int phy_table [ ] = { 0x1 , 0x2 } ;
2007-10-08 11:01:30 +03:00
static u8 adr_table [ 2 ] [ 8 ] = {
{ 0x00 , 0x00 , 0x60 , 0x00 , 0x00 , 0x01 } ,
{ 0x00 , 0x00 , 0x60 , 0x00 , 0x00 , 0x02 }
} ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
module_param_array ( adr_table , int , & NUM_MAC_TABLE , 0644 ) ;
2007-10-08 11:01:30 +03:00
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
2007-04-01 21:40:56 +03:00
module_param_array ( adr_table , int , NUM_MAC_TABLE , 0644 ) ;
# else
MODULE_PARM ( adr_table , " 2-4i " ) ;
2007-10-08 11:01:30 +03:00
# endif
2007-04-01 21:40:56 +03:00
MODULE_PARM_DESC ( adr_table , " MAC Address (assigned) " ) ;
static int r6040_open ( struct net_device * dev ) ;
static int r6040_start_xmit ( struct sk_buff * skb , struct net_device * dev ) ;
2007-04-02 00:33:42 +03:00
static irqreturn_t r6040_interrupt ( int irq , void * dev_id ) ;
2007-04-01 21:40:56 +03:00
static struct net_device_stats * r6040_get_stats ( struct net_device * dev ) ;
static int r6040_close ( struct net_device * dev ) ;
2007-03-31 00:56:07 +03:00
static void set_multicast_list ( struct net_device * dev ) ;
static struct ethtool_ops netdev_ethtool_ops ;
2007-07-25 12:16:20 +03:00
static int netdev_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd ) ;
2007-04-01 21:40:56 +03:00
static void r6040_down ( struct net_device * dev ) ;
static void r6040_up ( struct net_device * dev ) ;
static void r6040_tx_timeout ( struct net_device * dev ) ;
static void r6040_timer ( unsigned long ) ;
2007-03-31 00:56:07 +03:00
static int phy_mode_chk ( struct net_device * dev ) ;
static int phy_read ( int ioaddr , int phy_adr , int reg_idx ) ;
static void phy_write ( int ioaddr , int phy_adr , int reg_idx , int dat ) ;
2007-10-08 11:01:30 +03:00
static void rx_buf_alloc ( struct r6040_private * lp , struct net_device * dev ) ;
2007-04-01 21:40:56 +03:00
# ifdef CONFIG_R6040_NAPI
static int r6040_poll ( struct net_device * netdev , int * budget ) ;
2007-03-31 00:56:07 +03:00
# endif
2007-04-01 21:40:56 +03:00
static int __devinit r6040_init_one ( struct pci_dev * pdev ,
2007-03-31 00:56:07 +03:00
const struct pci_device_id * ent )
{
struct net_device * dev ;
2007-04-01 21:40:56 +03:00
struct r6040_private * lp ;
2007-03-31 00:56:07 +03:00
int ioaddr , io_size , err ;
2007-10-08 11:01:30 +03:00
static int card_idx = - 1 ;
2007-03-31 00:56:07 +03:00
int chip_id = ( int ) ent - > driver_data ;
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_init_one() " , 0 ) ;
2007-03-31 00:56:07 +03:00
if ( printed_version + + )
2007-10-08 11:01:30 +03:00
printk ( KERN_INFO version ) ;
2007-03-31 00:56:07 +03:00
2007-10-08 11:01:30 +03:00
err = pci_enable_device ( pdev ) ;
if ( err )
2007-03-31 00:56:07 +03:00
return err ;
/* this should always be supported */
if ( pci_set_dma_mask ( pdev , 0xffffffff ) ) {
printk ( KERN_ERR DRV_NAME " 32-bit PCI DMA addresses not supported by the card!? \n " ) ;
return - ENODEV ;
}
/* IO Size check */
2007-04-01 21:40:56 +03:00
io_size = r6040_chip_info [ chip_id ] . io_size ;
2007-03-31 00:56:07 +03:00
if ( pci_resource_len ( pdev , 0 ) < io_size ) {
return - ENODEV ;
}
ioaddr = pci_resource_start ( pdev , 0 ) ; /* IO map base address */
pci_set_master ( pdev ) ;
2007-04-01 21:40:56 +03:00
dev = alloc_etherdev ( sizeof ( struct r6040_private ) ) ;
2007-03-31 00:56:07 +03:00
if ( dev = = NULL )
return - ENOMEM ;
SET_MODULE_OWNER ( dev ) ;
if ( pci_request_regions ( pdev , DRV_NAME ) ) {
printk ( KERN_ERR DRV_NAME " : Failed to request PCI regions \n " ) ;
err = - ENODEV ;
goto err_out_disable ;
}
/* Init system & device */
lp = dev - > priv ;
dev - > base_addr = ioaddr ;
dev - > irq = pdev - > irq ;
spin_lock_init ( & lp - > lock ) ;
pci_set_drvdata ( pdev , dev ) ;
/* Set MAC address */
card_idx + + ;
memcpy ( dev - > dev_addr , ( u8 * ) & adr_table [ card_idx ] [ 0 ] , 6 ) ;
2007-04-01 21:40:56 +03:00
/* Link new device into r6040_root_dev */
2007-03-31 00:56:07 +03:00
lp - > pdev = pdev ;
/* Init RDC private data */
lp - > mcr0 = 0x1002 ;
lp - > phy_addr = phy_table [ card_idx ] ;
2007-07-25 12:16:20 +03:00
lp - > switch_sig = 0 ;
2007-03-31 00:56:07 +03:00
/* The RDC-specific entries in the device structure. */
2007-04-01 21:40:56 +03:00
dev - > open = & r6040_open ;
dev - > hard_start_xmit = & r6040_start_xmit ;
dev - > stop = & r6040_close ;
dev - > get_stats = & r6040_get_stats ;
2007-03-31 00:56:07 +03:00
dev - > set_multicast_list = & set_multicast_list ;
2007-07-25 12:16:20 +03:00
dev - > do_ioctl = & netdev_ioctl ;
2007-03-31 00:56:07 +03:00
dev - > ethtool_ops = & netdev_ethtool_ops ;
2007-04-01 21:40:56 +03:00
dev - > tx_timeout = & r6040_tx_timeout ;
2007-03-31 00:56:07 +03:00
dev - > watchdog_timeo = TX_TIMEOUT ;
2007-04-01 21:40:56 +03:00
# ifdef CONFIG_R6040_NAPI
dev - > poll = & r6040_poll ;
dev - > weight = 64 ;
# endif
2007-03-31 00:56:07 +03:00
/* Register net device. After this dev->name assign */
2007-10-08 11:01:30 +03:00
err = register_netdev ( dev ) ;
if ( err ) {
2007-03-31 00:56:07 +03:00
printk ( KERN_ERR DRV_NAME " : Failed to register net device \n " ) ;
goto err_out_res ;
}
netif_carrier_on ( dev ) ;
return 0 ;
err_out_res :
pci_release_regions ( pdev ) ;
err_out_disable :
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
kfree ( dev ) ;
return err ;
}
2007-04-01 21:40:56 +03:00
static void __devexit r6040_remove_one ( struct pci_dev * pdev )
2007-03-31 00:56:07 +03:00
{
struct net_device * dev = pci_get_drvdata ( pdev ) ;
unregister_netdev ( dev ) ;
pci_release_regions ( pdev ) ;
kfree ( dev ) ;
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
}
static int
2007-04-01 21:40:56 +03:00
r6040_open ( struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
int i ;
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_open() " , 0 ) ;
2007-03-31 00:56:07 +03:00
/* Request IRQ and Register interrupt handler */
2007-04-01 21:40:56 +03:00
i = request_irq ( dev - > irq , & r6040_interrupt , SA_SHIRQ , dev - > name , dev ) ;
2007-03-31 00:56:07 +03:00
if ( i ) return i ;
/* Allocate Descriptor memory */
2007-10-08 11:01:30 +03:00
lp - > desc_pool = pci_alloc_consistent ( lp - > pdev , ALLOC_DESC_SIZE , & lp - > desc_dma ) ;
if ( ! lp - > desc_pool )
return - ENOMEM ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
r6040_up ( dev ) ;
2007-03-31 00:56:07 +03:00
netif_start_queue ( dev ) ;
2007-10-08 11:01:30 +03:00
if ( lp - > switch_sig ! = ICPLUS_PHY_ID ) {
/* set and active a timer process */
init_timer ( & lp - > timer ) ;
lp - > timer . expires = TIMER_WUT ;
lp - > timer . data = ( unsigned long ) dev ;
lp - > timer . function = & r6040_timer ;
add_timer ( & lp - > timer ) ;
2007-07-25 12:16:20 +03:00
}
2007-03-31 00:56:07 +03:00
return 0 ;
}
static void
2007-04-01 21:40:56 +03:00
r6040_tx_timeout ( struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-10-08 11:01:30 +03:00
/* int ioaddr = dev->base_addr;
struct r6040_descriptor * descptr = lp - > tx_remove_ptr ; */
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_tx_timeout() " , 0 ) ;
2007-03-31 00:56:07 +03:00
/* Transmitter timeout, serious problems. */
/* Sten: Nothing need to do so far. */
2007-10-08 11:01:30 +03:00
printk ( KERN_ERR DRV_NAME " : Big Trobule, transmit timeout/n " ) ;
2007-03-31 00:56:07 +03:00
lp - > stats . tx_errors + + ;
netif_stop_queue ( dev ) ;
//printk("<RDC> XMT timedout: CR0 %x, CR40 %x, CR3C %x, CR2C %x, CR30 %x, CR34 %x, CR38 %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c), inw(ioaddr+0x2c), inw(ioaddr+0x30), inw(ioaddr+0x34), inw(ioaddr+0x38));
//printk("<RDC> XMT_TO: %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);
}
static int
2007-04-01 21:40:56 +03:00
r6040_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
struct r6040_descriptor * descptr ;
2007-03-31 00:56:07 +03:00
int ioaddr = dev - > base_addr ;
unsigned long flags ;
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_start_xmit() " , 0 ) ;
2007-03-31 00:56:07 +03:00
2007-10-08 11:01:30 +03:00
if ( skb = = NULL ) /* NULL skb directly return */
2007-03-31 00:56:07 +03:00
return 0 ;
if ( skb - > len > = MAX_BUF_SIZE ) { /* Packet too long, drop it */
dev_kfree_skb ( skb ) ;
return 0 ;
}
/* Critical Section */
spin_lock_irqsave ( & lp - > lock , flags ) ;
/* TX resource check */
if ( ! lp - > tx_free_desc ) {
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2007-10-08 11:01:30 +03:00
printk ( KERN_ERR DRV_NAME " : NO TX DESC " ) ;
2007-03-31 00:56:07 +03:00
return 1 ;
}
/* Statistic Counter */
lp - > stats . tx_packets + + ;
lp - > stats . tx_bytes + = skb - > len ;
/* Set TX descriptor & Transmit it */
lp - > tx_free_desc - - ;
descptr = lp - > tx_insert_ptr ;
2007-10-08 11:01:30 +03:00
if ( skb - > len < 0x3c )
descptr - > len = 0x3c ;
else
descptr - > len = skb - > len ;
2007-03-31 00:56:07 +03:00
descptr - > skb_ptr = skb ;
descptr - > buf = cpu_to_le32 ( pci_map_single ( lp - > pdev , skb - > data , skb - > len , PCI_DMA_TODEVICE ) ) ;
descptr - > status = 0x8000 ;
outw ( 0x01 , ioaddr + 0x14 ) ;
lp - > tx_insert_ptr = descptr - > vndescp ;
# if RDC_DEBUG
printk ( " Xmit(): %08lx:%04x %04x %08lx %08lx %08lx %08lx \n " , descptr , descptr - > status , descptr - > len , descptr - > buf , descptr - > skb_ptr , descptr - > ndesc , descptr - > vndescp ) ;
2007-10-08 11:01:30 +03:00
# endif
2007-03-31 00:56:07 +03:00
/* If no tx resource, stop */
if ( ! lp - > tx_free_desc )
netif_stop_queue ( dev ) ;
dev - > trans_start = jiffies ;
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
return 0 ;
}
/* The RDC interrupt handler. */
static irqreturn_t
2007-04-02 00:33:42 +03:00
r6040_interrupt ( int irq , void * dev_id )
2007-03-31 00:56:07 +03:00
{
struct net_device * dev = dev_id ;
2007-04-01 21:40:56 +03:00
struct r6040_private * lp ;
struct r6040_descriptor * descptr ;
2007-03-31 00:56:07 +03:00
struct sk_buff * skb_ptr ;
int ioaddr , status ;
unsigned long flags ;
2007-10-08 11:01:30 +03:00
# ifdef CONFIG_R6040_NAPI
2007-04-01 21:40:56 +03:00
int handled = 1 ;
# else
2007-03-31 00:56:07 +03:00
int handled = 0 ;
2007-10-08 11:01:30 +03:00
# endif
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_interrupt() " , 0 ) ;
2007-03-31 00:56:07 +03:00
if ( dev = = NULL ) {
printk ( KERN_ERR DRV_NAME " : INT() unknown device. \n " ) ;
return IRQ_RETVAL ( handled ) ;
}
2007-04-01 21:40:56 +03:00
lp = ( struct r6040_private * ) dev - > priv ;
2007-03-31 00:56:07 +03:00
spin_lock_irqsave ( & lp - > lock , flags ) ;
/* Check MAC Interrupt status */
ioaddr = dev - > base_addr ;
outw ( 0x0 , ioaddr + 0x40 ) ; /* Mask Off RDC MAC interrupt */
status = inw ( ioaddr + 0x3c ) ; /* Read INTR status and clear */
2007-04-01 21:40:56 +03:00
2007-10-08 11:01:30 +03:00
# ifdef CONFIG_R6040_NAPI
if ( netif_rx_schedule_prep ( dev ) ) {
NAPI_status = status ;
2007-04-01 21:40:56 +03:00
__netif_rx_schedule ( dev ) ;
2007-10-08 11:01:30 +03:00
}
2007-04-01 21:40:56 +03:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2007-10-08 11:01:30 +03:00
return IRQ_RETVAL ( handled ) ;
2007-04-01 21:40:56 +03:00
# else
2007-03-31 00:56:07 +03:00
/* TX interrupt request */
if ( status & 0x10 ) {
handled = 1 ;
descptr = lp - > tx_remove_ptr ;
2007-10-08 11:01:30 +03:00
while ( lp - > tx_free_desc < TX_DCNT ) {
if ( descptr - > status & 0x8000 )
break ; /* Not complte */
2007-03-31 00:56:07 +03:00
skb_ptr = descptr - > skb_ptr ;
pci_unmap_single ( lp - > pdev , descptr - > buf , skb_ptr - > len , PCI_DMA_TODEVICE ) ;
dev_kfree_skb_irq ( skb_ptr ) ; /* Free buffer */
descptr - > skb_ptr = 0 ;
descptr = descptr - > vndescp ; /* To next descriptor */
lp - > tx_free_desc + + ;
}
lp - > tx_remove_ptr = descptr ;
2007-10-08 11:01:30 +03:00
if ( lp - > tx_free_desc )
netif_wake_queue ( dev ) ;
2007-03-31 00:56:07 +03:00
}
/* RX interrupt request */
if ( status & 0x01 ) {
handled = 1 ;
descptr = lp - > rx_remove_ptr ;
while ( lp - > rx_free_desc ) {
if ( descptr - > status & 0x8000 ) break ; /* No Rx packet */
skb_ptr = descptr - > skb_ptr ;
descptr - > skb_ptr = 0 ;
skb_ptr - > dev = dev ;
skb_put ( skb_ptr , descptr - > len - 4 ) ;
pci_unmap_single ( lp - > pdev , descptr - > buf , MAX_BUF_SIZE , PCI_DMA_FROMDEVICE ) ;
skb_ptr - > protocol = eth_type_trans ( skb_ptr , dev ) ;
netif_rx ( skb_ptr ) ; /* Send to upper layer */
lp - > stats . rx_packets + + ;
lp - > stats . rx_bytes + = descptr - > len ;
descptr = descptr - > vndescp ; /* To next descriptor */
lp - > rx_free_desc - - ;
}
lp - > rx_remove_ptr = descptr ;
}
/* Allocate new RX buffer */
2007-04-01 21:40:56 +03:00
if ( lp - > rx_free_desc < RX_DCNT ) rx_buf_alloc ( lp , dev ) ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
outw ( R6040_INT_MASK , ioaddr + 0x40 ) ; /* TX/RX interrupt enable */
2007-03-31 00:56:07 +03:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2007-04-01 21:40:56 +03:00
# endif
2007-03-31 00:56:07 +03:00
return IRQ_RETVAL ( handled ) ;
}
static struct net_device_stats *
2007-04-01 21:40:56 +03:00
r6040_get_stats ( struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_get_stats() " , 0 ) ;
2007-03-31 00:56:07 +03:00
return & lp - > stats ;
}
/*
* Set or clear the multicast filter for this adaptor .
*/
static void
set_multicast_list ( struct net_device * dev )
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
struct dev_mc_list * mcptr ;
int ioaddr = dev - > base_addr ;
u16 * adrp , i ;
unsigned long flags ;
RDC_DBUG ( " set_multicast_list() " , 0 ) ;
2007-10-08 11:01:30 +03:00
/* MAC Address */
2007-03-31 00:56:07 +03:00
adrp = ( u16 * ) dev - > dev_addr ;
2007-10-08 11:01:30 +03:00
outw ( adrp [ 0 ] , ioaddr + 0x68 ) ;
outw ( adrp [ 1 ] , ioaddr + 0x6A ) ;
outw ( adrp [ 2 ] , ioaddr + 0x6C ) ;
2007-04-01 21:40:56 +03:00
2007-03-31 00:56:07 +03:00
2007-10-08 11:01:30 +03:00
# if RDC_DEBUG
2007-03-31 00:56:07 +03:00
printk ( " MAC ADDR: %04x %04x %04x \n " , adrp [ 0 ] , adrp [ 1 ] , adrp [ 2 ] ) ;
# endif
/* Promiscous Mode */
2007-04-01 21:40:56 +03:00
spin_lock_irqsave ( & lp - > lock , flags ) ;
2007-03-31 00:56:07 +03:00
i = inw ( ioaddr ) & ~ 0x0120 ; /* Clear AMCP & PROM */
2007-10-08 11:01:30 +03:00
if ( dev - > flags & IFF_PROMISC ) {
i | = 0x0020 ;
lp - > mcr0 | = 0x0020 ;
}
if ( dev - > mc_count > 4 )
i | = 0x0020 ; /* Too many multicast address */
2007-03-31 00:56:07 +03:00
outw ( i , ioaddr ) ;
2007-04-01 21:40:56 +03:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2007-03-31 00:56:07 +03:00
/* Multicast Address */
if ( dev - > mc_count > 4 ) /* Wait to do: Hash Table for multicast */
return ;
/* Multicast Address 1~4 case */
2007-10-08 11:01:30 +03:00
for ( i = 0 , mcptr = dev - > mc_list ; ( i < dev - > mc_count ) & & ( i < 4 ) ; i + + ) {
2007-03-31 00:56:07 +03:00
adrp = ( u16 * ) mcptr - > dmi_addr ;
2007-10-08 11:01:30 +03:00
outw ( adrp [ 0 ] , ioaddr + 0x70 + 8 * i ) ;
outw ( adrp [ 1 ] , ioaddr + 0x72 + 8 * i ) ;
outw ( adrp [ 2 ] , ioaddr + 0x74 + 8 * i ) ;
2007-03-31 00:56:07 +03:00
mcptr = mcptr - > next ;
2007-10-08 11:01:30 +03:00
# if RDC_DEBUG
2007-03-31 00:56:07 +03:00
printk ( " M_ADDR: %04x %04x %04x \n " , adrp [ 0 ] , adrp [ 1 ] , adrp [ 2 ] ) ;
# endif
}
for ( i = dev - > mc_count ; i < 4 ; i + + ) {
2007-10-08 11:01:30 +03:00
outw ( 0xffff , ioaddr + 0x68 + 8 * i ) ;
outw ( 0xffff , ioaddr + 0x6A + 8 * i ) ;
outw ( 0xffff , ioaddr + 0x6C + 8 * i ) ;
2007-03-31 00:56:07 +03:00
}
}
static void netdev_get_drvinfo ( struct net_device * dev , struct ethtool_drvinfo * info )
{
2007-04-01 21:40:56 +03:00
struct r6040_private * rp = dev - > priv ;
2007-03-31 00:56:07 +03:00
strcpy ( info - > driver , DRV_NAME ) ;
strcpy ( info - > version , DRV_VERSION ) ;
strcpy ( info - > bus_info , pci_name ( rp - > pdev ) ) ;
}
static struct ethtool_ops netdev_ethtool_ops = {
. get_drvinfo = netdev_get_drvinfo ,
} ;
static int
2007-04-01 21:40:56 +03:00
r6040_close ( struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_close() " , 0 ) ;
2007-03-31 00:56:07 +03:00
/* deleted timer */
2007-10-08 11:01:30 +03:00
del_timer_sync ( & lp - > timer ) ;
2007-03-31 00:56:07 +03:00
spin_lock_irq ( & lp - > lock ) ;
netif_stop_queue ( dev ) ;
2007-04-01 21:40:56 +03:00
r6040_down ( dev ) ;
2007-03-31 00:56:07 +03:00
spin_unlock_irq ( & lp - > lock ) ;
return 0 ;
}
2007-07-25 12:16:20 +03:00
static int netdev_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd )
{
struct r6040_private * lp = dev - > priv ;
RDC_DBUG ( " netdev_ioctl() " , 0 ) ;
2007-10-08 11:01:30 +03:00
if ( lp - > switch_sig = = ICPLUS_PHY_ID & & cmd = = SIOCDEVPRIVATE ) {
2007-07-25 12:16:20 +03:00
unsigned long * data = ( unsigned long * ) rq - > ifr_data , args [ 4 ] ;
int ioaddr = dev - > base_addr ;
unsigned int val ;
data = ( unsigned long * ) rq - > ifr_data ;
if ( copy_from_user ( args , data , 4 * sizeof ( unsigned long ) ) )
return - EFAULT ;
/* port priority */
2007-10-08 11:01:30 +03:00
if ( args [ 0 ] & ( 1 < < 31 ) ) phy_write ( ioaddr , 29 , 19 , ( phy_read ( ioaddr , 29 , 19 ) | 0x2000 ) ) ; /* port 0 */
if ( args [ 0 ] & ( 1 < < 29 ) ) phy_write ( ioaddr , 29 , 19 , ( phy_read ( ioaddr , 29 , 19 ) | 0x0020 ) ) ; /* port 1 */
if ( args [ 0 ] & ( 1 < < 27 ) ) phy_write ( ioaddr , 29 , 20 , ( phy_read ( ioaddr , 29 , 20 ) | 0x2000 ) ) ; /* port 2 */
if ( args [ 0 ] & ( 1 < < 25 ) ) phy_write ( ioaddr , 29 , 20 , ( phy_read ( ioaddr , 29 , 20 ) | 0x0020 ) ) ; /* port 3 */
2007-07-25 12:16:20 +03:00
2007-10-08 11:01:30 +03:00
}
2007-08-06 23:28:10 +03:00
return - EOPNOTSUPP ;
2007-07-25 12:16:20 +03:00
}
2007-03-31 00:56:07 +03:00
/**
Stop RDC MAC and Free the allocated resource
*/
2007-04-01 21:40:56 +03:00
static void r6040_down ( struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
int i ;
int ioaddr = dev - > base_addr ;
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_down() " , 0 ) ;
2007-03-31 00:56:07 +03:00
/* Stop MAC */
outw ( 0x0000 , ioaddr + 0x40 ) ; /* Mask Off Interrupt */
outw ( 0x0001 , ioaddr + 0x04 ) ; /* Reset RDC MAC */
i = 0 ;
do { } while ( ( i + + < 2048 ) & & ( inw ( ioaddr + 0x04 ) & 0x1 ) ) ;
free_irq ( dev - > irq , dev ) ;
/* Free RX buffer */
for ( i = 0 ; i < RX_DCNT ; i + + ) {
if ( lp - > rx_insert_ptr - > skb_ptr ) {
pci_unmap_single ( lp - > pdev , lp - > rx_insert_ptr - > buf , MAX_BUF_SIZE , PCI_DMA_FROMDEVICE ) ;
dev_kfree_skb ( lp - > rx_insert_ptr - > skb_ptr ) ;
lp - > rx_insert_ptr - > skb_ptr = 0 ;
}
lp - > rx_insert_ptr = lp - > rx_insert_ptr - > vndescp ;
}
/* Free TX buffer */
for ( i = 0 ; i < TX_DCNT ; i + + ) {
if ( lp - > tx_insert_ptr - > skb_ptr ) {
pci_unmap_single ( lp - > pdev , lp - > tx_insert_ptr - > buf , MAX_BUF_SIZE , PCI_DMA_TODEVICE ) ;
dev_kfree_skb ( lp - > tx_insert_ptr - > skb_ptr ) ;
lp - > rx_insert_ptr - > skb_ptr = 0 ;
}
lp - > tx_insert_ptr = lp - > tx_insert_ptr - > vndescp ;
}
/* Free Descriptor memory */
pci_free_consistent ( lp - > pdev , ALLOC_DESC_SIZE , lp - > desc_pool , lp - > desc_dma ) ;
}
2007-04-01 21:40:56 +03:00
# ifdef CONFIG_R6040_NAPI
static int r6040_poll ( struct net_device * dev , int * budget )
{
struct r6040_private * lp ;
struct r6040_descriptor * descptr ;
struct sk_buff * skb_ptr ;
int ioaddr , status ;
unsigned long flags ;
2007-10-08 11:01:30 +03:00
ioaddr = dev - > base_addr ;
2007-04-01 21:40:56 +03:00
lp = ( struct r6040_private * ) dev - > priv ;
2007-10-08 11:01:30 +03:00
unsigned long rx_work = dev - > quota ;
unsigned long rx ;
2007-04-01 21:40:56 +03:00
# if 1
/* TX interrupt request */
if ( NAPI_status & 0x10 ) {
descptr = lp - > tx_remove_ptr ;
2007-10-08 11:01:30 +03:00
while ( lp - > tx_free_desc < TX_DCNT ) {
if ( descptr - > status & 0x8000 )
break ; /* Not complte */
2007-04-01 21:40:56 +03:00
skb_ptr = descptr - > skb_ptr ;
pci_unmap_single ( lp - > pdev , descptr - > buf , skb_ptr - > len , PCI_DMA_TODEVICE ) ;
dev_kfree_skb_irq ( skb_ptr ) ; /* Free buffer */
descptr - > skb_ptr = 0 ;
descptr = descptr - > vndescp ; /* To next descriptor */
lp - > tx_free_desc + + ;
}
lp - > tx_remove_ptr = descptr ;
if ( lp - > tx_free_desc ) netif_wake_queue ( dev ) ;
2007-10-08 11:01:30 +03:00
}
2007-04-01 21:40:56 +03:00
# endif
# if 1
/* RX interrupt request */
2007-10-08 11:01:30 +03:00
if ( NAPI_status & 0x01 ) {
2007-04-01 21:40:56 +03:00
descptr = lp - > rx_remove_ptr ;
2007-10-08 11:01:30 +03:00
while ( lp - > rx_free_desc ) {
if ( descptr - > status & 0x8000 )
break ; /* No Rx packet */
2007-04-01 21:40:56 +03:00
skb_ptr = descptr - > skb_ptr ;
descptr - > skb_ptr = 0 ;
skb_ptr - > dev = dev ;
skb_put ( skb_ptr , descptr - > len - 4 ) ;
pci_unmap_single ( lp - > pdev , descptr - > buf , MAX_BUF_SIZE , PCI_DMA_FROMDEVICE ) ;
2007-10-08 11:01:30 +03:00
skb_ptr - > protocol = eth_type_trans ( skb_ptr , dev ) ;
netif_receive_skb ( skb_ptr ) ; /* Send to upper layer */
2007-04-01 21:40:56 +03:00
lp - > stats . rx_packets + + ;
lp - > stats . rx_bytes + = descptr - > len ;
descptr = descptr - > vndescp ; /* To next descriptor */
lp - > rx_free_desc - - ;
}
lp - > rx_remove_ptr = descptr ;
}
/* Allocate new RX buffer */
2007-10-08 11:01:30 +03:00
if ( lp - > rx_free_desc < RX_DCNT )
rx_buf_alloc ( lp , dev ) ;
2007-04-01 21:40:56 +03:00
local_irq_disable ( ) ;
netif_rx_complete ( dev ) ;
2007-10-08 11:01:30 +03:00
outw ( R6040_INT_MASK , ioaddr + 0x40 ) ;
2007-04-01 21:40:56 +03:00
local_irq_enable ( ) ;
return 0 ;
# endif
}
# endif
2007-03-31 00:56:07 +03:00
/* Init RDC MAC */
2007-04-01 21:40:56 +03:00
static void r6040_up ( struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
struct r6040_descriptor * descptr ;
2007-03-31 00:56:07 +03:00
int i ;
int ioaddr = dev - > base_addr ;
u32 tmp_addr ;
dma_addr_t desc_dma , start_dma ;
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_up() " , 0 ) ;
2007-03-31 00:56:07 +03:00
/* Initilize */
lp - > tx_free_desc = TX_DCNT ;
lp - > rx_free_desc = 0 ;
/* Init descriptor */
memset ( lp - > desc_pool , 0 , ALLOC_DESC_SIZE ) ; /* Let all descriptor = 0 */
2007-04-01 21:40:56 +03:00
lp - > tx_insert_ptr = ( struct r6040_descriptor * ) lp - > desc_pool ;
2007-03-31 00:56:07 +03:00
lp - > tx_remove_ptr = lp - > tx_insert_ptr ;
2007-04-01 21:40:56 +03:00
lp - > rx_insert_ptr = ( struct r6040_descriptor * ) lp - > tx_insert_ptr + TX_DCNT ;
2007-03-31 00:56:07 +03:00
lp - > rx_remove_ptr = lp - > rx_insert_ptr ;
2007-10-08 11:01:30 +03:00
2007-03-31 00:56:07 +03:00
/* Init TX descriptor */
descptr = lp - > tx_insert_ptr ;
desc_dma = lp - > desc_dma ;
start_dma = desc_dma ;
for ( i = 0 ; i < TX_DCNT ; i + + ) {
2007-04-01 21:40:56 +03:00
descptr - > ndesc = cpu_to_le32 ( desc_dma + sizeof ( struct r6040_descriptor ) ) ;
2007-03-31 00:56:07 +03:00
descptr - > vndescp = ( descptr + 1 ) ;
descptr = ( descptr + 1 ) ;
2007-04-01 21:40:56 +03:00
desc_dma + = sizeof ( struct r6040_descriptor ) ;
2007-03-31 00:56:07 +03:00
}
( descptr - 1 ) - > ndesc = cpu_to_le32 ( start_dma ) ;
( descptr - 1 ) - > vndescp = lp - > tx_insert_ptr ;
/* Init RX descriptor */
start_dma = desc_dma ;
descptr = lp - > rx_insert_ptr ;
for ( i = 0 ; i < RX_DCNT ; i + + ) {
2007-04-01 21:40:56 +03:00
descptr - > ndesc = cpu_to_le32 ( desc_dma + sizeof ( struct r6040_descriptor ) ) ;
2007-03-31 00:56:07 +03:00
descptr - > vndescp = ( descptr + 1 ) ;
descptr = ( descptr + 1 ) ;
2007-04-01 21:40:56 +03:00
desc_dma + = sizeof ( struct r6040_descriptor ) ;
2007-03-31 00:56:07 +03:00
}
( descptr - 1 ) - > ndesc = cpu_to_le32 ( start_dma ) ;
( descptr - 1 ) - > vndescp = lp - > rx_insert_ptr ;
/* Allocate buffer for RX descriptor */
2007-10-08 11:01:30 +03:00
rx_buf_alloc ( lp , dev ) ;
2007-03-31 00:56:07 +03:00
2007-10-08 11:01:30 +03:00
# if RDC_DEBUG
2007-03-31 00:56:07 +03:00
descptr = lp - > tx_insert_ptr ;
for ( i = 0 ; i < TX_DCNT ; i + + ) {
printk ( " %08lx:%04x %04x %08lx %08lx %08lx %08lx \n " , descptr , descptr - > status , descptr - > len , descptr - > buf , descptr - > skb_ptr , descptr - > ndesc , descptr - > vndescp ) ;
descptr = descptr - > vndescp ;
}
descptr = lp - > rx_insert_ptr ;
for ( i = 0 ; i < RX_DCNT ; i + + ) {
printk ( " %08lx:%04x %04x %08lx %08lx %08lx %08lx \n " , descptr , descptr - > status , descptr - > len , descptr - > buf , descptr - > skb_ptr , descptr - > ndesc , descptr - > vndescp ) ;
descptr = descptr - > vndescp ;
}
# endif
/* MAC operation register */
2007-04-01 21:40:56 +03:00
outw ( 0x01 , ioaddr + 0x04 ) ; /* Reset MAC */
2007-10-08 11:01:30 +03:00
outw ( 2 , ioaddr + 0xAC ) ; /* Reset internal state machine */
outw ( 0 , ioaddr + 0xAC ) ;
2007-03-31 00:56:07 +03:00
udelay ( 5000 ) ;
/* TX and RX descriptor start Register */
tmp_addr = cpu_to_le32 ( lp - > tx_insert_ptr ) ;
tmp_addr = virt_to_bus ( ( volatile void * ) tmp_addr ) ;
outw ( ( u16 ) tmp_addr , ioaddr + 0x2c ) ;
outw ( tmp_addr > > 16 , ioaddr + 0x30 ) ;
tmp_addr = cpu_to_le32 ( lp - > rx_insert_ptr ) ;
tmp_addr = virt_to_bus ( ( volatile void * ) tmp_addr ) ;
outw ( ( u16 ) tmp_addr , ioaddr + 0x34 ) ;
outw ( tmp_addr > > 16 , ioaddr + 0x38 ) ;
/* Buffer Size Register */
outw ( MAX_BUF_SIZE , ioaddr + 0x18 ) ;
2007-10-08 11:01:30 +03:00
if ( ( lp - > switch_sig = phy_read ( ioaddr , 0 , 2 ) ) = = ICPLUS_PHY_ID ) {
phy_write ( ioaddr , 29 , 31 , 0x175C ) ; /* Enable registers */
2007-08-06 21:40:28 +03:00
lp - > phy_mode = 0x8000 ;
} else {
/* PHY Mode Check */
phy_write ( ioaddr , lp - > phy_addr , 4 , PHY_CAP ) ;
phy_write ( ioaddr , lp - > phy_addr , 0 , PHY_MODE ) ;
if ( PHY_MODE = = 0x3100 )
lp - > phy_mode = phy_mode_chk ( dev ) ;
else
lp - > phy_mode = ( PHY_MODE & 0x0100 ) ? 0x8000 : 0x0 ;
}
2007-03-31 00:56:07 +03:00
/* MAC Bus Control Register */
outw ( MBCR_DEFAULT , ioaddr + 0x8 ) ;
/* MAC TX/RX Enable */
lp - > mcr0 | = lp - > phy_mode ;
outw ( lp - > mcr0 , ioaddr ) ;
2007-08-06 21:40:28 +03:00
/* set interrupt waiting time and packet numbers */
outw ( 0x0802 , ioaddr + 0x0C ) ;
outw ( 0x0802 , ioaddr + 0x10 ) ;
/* upgrade performance (by RDC guys) */
2007-10-08 11:01:30 +03:00
phy_write ( ioaddr , 30 , 17 , ( phy_read ( ioaddr , 30 , 17 ) | 0x4000 ) ) ; //bit 14=1
phy_write ( ioaddr , 30 , 17 , ~ ( ( ~ phy_read ( ioaddr , 30 , 17 ) ) | 0x2000 ) ) ; //bit 13=0
phy_write ( ioaddr , 0 , 19 , 0x0000 ) ;
phy_write ( ioaddr , 0 , 30 , 0x01F0 ) ;
2007-08-06 21:40:28 +03:00
2007-03-31 00:56:07 +03:00
/* Interrupt Mask Register */
2007-04-01 21:40:56 +03:00
outw ( R6040_INT_MASK , ioaddr + 0x40 ) ;
2007-03-31 00:56:07 +03:00
}
/*
A periodic timer routine
Polling PHY Chip Link Status
*/
2007-04-01 21:40:56 +03:00
static void r6040_timer ( unsigned long data )
2007-03-31 00:56:07 +03:00
{
2007-10-08 11:01:30 +03:00
struct net_device * dev = ( struct net_device * ) data ;
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
u16 ioaddr = dev - > base_addr , phy_mode ;
2007-10-08 11:01:30 +03:00
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_timer() " , 0 ) ;
2007-03-31 00:56:07 +03:00
/* Polling PHY Chip Status */
if ( PHY_MODE = = 0x3100 )
phy_mode = phy_mode_chk ( dev ) ;
2007-10-08 11:01:30 +03:00
else
phy_mode = ( PHY_MODE & 0x0100 ) ? 0x8000 : 0x0 ;
2007-03-31 00:56:07 +03:00
if ( phy_mode ! = lp - > phy_mode ) {
lp - > phy_mode = phy_mode ;
lp - > mcr0 = ( lp - > mcr0 & 0x7fff ) | phy_mode ;
outw ( lp - > mcr0 , ioaddr ) ;
2007-10-08 11:01:30 +03:00
printk ( KERN_INFO " Link Change %x \n " , inw ( ioaddr ) ) ;
2007-03-31 00:56:07 +03:00
}
/* Debug */
// printk("<RDC> Timer: CR0 %x CR40 %x CR3C %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c));
2007-10-08 11:01:30 +03:00
/* Timer active again */
lp - > timer . expires = TIMER_WUT ;
add_timer ( & lp - > timer ) ;
2007-03-31 00:56:07 +03:00
}
/* Allocate skb buffer for rx descriptor */
2007-10-08 11:01:30 +03:00
static void rx_buf_alloc ( struct r6040_private * lp , struct net_device * dev )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
struct r6040_descriptor * descptr ;
int ioaddr = dev - > base_addr ;
2007-03-31 00:56:07 +03:00
RDC_DBUG ( " rx_buf_alloc() " , 0 ) ;
2007-10-08 11:01:30 +03:00
2007-03-31 00:56:07 +03:00
descptr = lp - > rx_insert_ptr ;
2007-10-08 11:01:30 +03:00
while ( lp - > rx_free_desc < RX_DCNT ) {
2007-03-31 00:56:07 +03:00
descptr - > skb_ptr = dev_alloc_skb ( MAX_BUF_SIZE ) ;
2007-10-08 11:01:30 +03:00
if ( ! descptr - > skb_ptr )
break ;
2007-03-31 00:56:07 +03:00
descptr - > buf = cpu_to_le32 ( pci_map_single ( lp - > pdev , descptr - > skb_ptr - > tail , MAX_BUF_SIZE , PCI_DMA_FROMDEVICE ) ) ;
descptr - > status = 0x8000 ;
descptr = descptr - > vndescp ;
lp - > rx_free_desc + + ;
2007-10-08 11:01:30 +03:00
outw ( lp - > mcr0 | 0x0002 , ioaddr ) ; /* Trigger Rx DMA */
2007-03-31 00:56:07 +03:00
}
lp - > rx_insert_ptr = descptr ;
}
/* Status of PHY CHIP */
static int phy_mode_chk ( struct net_device * dev )
{
2007-04-01 21:40:56 +03:00
struct r6040_private * lp = dev - > priv ;
2007-03-31 00:56:07 +03:00
int ioaddr = dev - > base_addr , phy_dat ;
RDC_DBUG ( " phy_mode_chk() " , 0 ) ;
2007-04-01 21:40:56 +03:00
2007-03-31 00:56:07 +03:00
/* PHY Link Status Check */
phy_dat = phy_read ( ioaddr , lp - > phy_addr , 1 ) ;
2007-10-08 11:01:30 +03:00
if ( ! ( phy_dat & 0x4 ) )
return 0x8000 ; /* Link Failed, full duplex */
2007-03-31 00:56:07 +03:00
/* PHY Chip Auto-Negotiation Status */
phy_dat = phy_read ( ioaddr , lp - > phy_addr , 1 ) ;
if ( phy_dat & 0x0020 ) {
/* Auto Negotiation Mode */
phy_dat = phy_read ( ioaddr , lp - > phy_addr , 5 ) ;
phy_dat & = phy_read ( ioaddr , lp - > phy_addr , 4 ) ;
2007-10-08 11:01:30 +03:00
if ( phy_dat & 0x140 )
phy_dat = 0x8000 ;
else
phy_dat = 0 ;
2007-03-31 00:56:07 +03:00
} else {
/* Force Mode */
phy_dat = phy_read ( ioaddr , lp - > phy_addr , 0 ) ;
if ( phy_dat & 0x100 ) phy_dat = 0x8000 ;
else phy_dat = 0x0000 ;
}
return phy_dat ;
} ;
/* Read a word data from PHY Chip */
static int phy_read ( int ioaddr , int phy_addr , int reg_idx )
{
int i = 0 ;
RDC_DBUG ( " phy_read() " , 0 ) ;
outw ( 0x2000 + reg_idx + ( phy_addr < < 8 ) , ioaddr + 0x20 ) ;
2007-10-08 11:01:30 +03:00
do { } while ( ( i + + < 2048 ) & & ( inw ( ioaddr + 0x20 ) & 0x2000 ) ) ;
2007-03-31 00:56:07 +03:00
return inw ( ioaddr + 0x24 ) ;
}
/* Write a word data from PHY Chip */
static void phy_write ( int ioaddr , int phy_addr , int reg_idx , int dat )
{
int i = 0 ;
RDC_DBUG ( " phy_write() " , 0 ) ;
outw ( dat , ioaddr + 0x28 ) ;
outw ( 0x4000 + reg_idx + ( phy_addr < < 8 ) , ioaddr + 0x20 ) ;
do { } while ( ( i + + < 2048 ) & & ( inw ( ioaddr + 0x20 ) & 0x4000 ) ) ;
}
enum {
RDC_6040 = 0
} ;
2007-04-01 21:40:56 +03:00
static struct pci_device_id r6040_pci_tbl [ ] = {
2007-03-31 00:56:07 +03:00
{ 0x17F3 , 0x6040 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , RDC_6040 } ,
2007-10-08 11:01:30 +03:00
/* {PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_R6040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},*/
/*{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},*/
{ 0 , }
2007-03-31 00:56:07 +03:00
} ;
2007-04-01 21:40:56 +03:00
MODULE_DEVICE_TABLE ( pci , r6040_pci_tbl ) ;
2007-03-31 00:56:07 +03:00
2007-04-01 21:40:56 +03:00
static struct pci_driver r6040_driver = {
2007-03-31 00:56:07 +03:00
. name = " r6040 " ,
2007-04-01 21:40:56 +03:00
. id_table = r6040_pci_tbl ,
. probe = r6040_init_one ,
. remove = __devexit_p ( r6040_remove_one ) ,
2007-03-31 00:56:07 +03:00
} ;
2007-04-01 21:40:56 +03:00
static int __init r6040_init ( void )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_init() " , 0 ) ;
2007-03-31 00:56:07 +03:00
2007-10-08 11:01:30 +03:00
printk ( KERN_INFO version ) ;
2007-03-31 00:56:07 +03:00
printed_version = 1 ;
2007-10-08 11:01:30 +03:00
if ( parent ! = NULL ) {
2007-07-25 12:16:20 +03:00
struct net_device * the_parent = dev_get_by_name ( parent ) ;
2007-10-08 11:01:30 +03:00
if ( the_parent = = NULL ) {
2007-07-25 12:16:20 +03:00
printk ( KERN_ERR DRV_NAME " : Unknown device \" %s \" specified. \n " , parent ) ;
return - EINVAL ;
}
memcpy ( ( u8 * ) & adr_table [ 0 ] [ 0 ] , the_parent - > dev_addr , 6 ) ;
memcpy ( ( u8 * ) & adr_table [ 1 ] [ 0 ] , the_parent - > dev_addr , 6 ) ;
+ + * ( u8 * ) & adr_table [ 0 ] [ 5 ] ;
}
2007-07-12 13:29:54 +03:00
return pci_register_driver ( & r6040_driver ) ;
2007-03-31 00:56:07 +03:00
}
2007-04-01 21:40:56 +03:00
static void __exit r6040_cleanup ( void )
2007-03-31 00:56:07 +03:00
{
2007-04-01 21:40:56 +03:00
RDC_DBUG ( " r6040_cleanup() " , 0 ) ;
pci_unregister_driver ( & r6040_driver ) ;
2007-03-31 00:56:07 +03:00
}
2007-04-01 21:40:56 +03:00
module_init ( r6040_init ) ;
module_exit ( r6040_cleanup ) ;