2005-04-16 15:20:36 -07:00
/*
* rrunner . c : Linux driver for the Essential RoadRunner HIPPI board .
*
* Copyright ( C ) 1998 - 2002 by Jes Sorensen , < jes @ wildopensource . com > .
*
* Thanks to Essential Communication for providing us with hardware
* and very comprehensive documentation without which I would not have
* been able to write this driver . A special thank you to John Gibbon
* for sorting out the legal issues , with the NDA , allowing the code to
* be released under the GPL .
*
* 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 .
*
* Thanks to Jayaram Bhat from ODS / Essential for fixing some of the
* stupid bugs in my code .
*
* Softnet support and various other patches from Val Henson of
* ODS / Essential .
*
* PCI DMA mapping code partly based on work by Francois Romieu .
*/
# define DEBUG 1
# define RX_DMA_SKBUFF 1
# define PKT_COPY_THRESHOLD 512
# include <linux/config.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/ioport.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/netdevice.h>
# include <linux/hippidevice.h>
# include <linux/skbuff.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/mm.h>
# include <net/sock.h>
# include <asm/system.h>
# include <asm/cache.h>
# include <asm/byteorder.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/uaccess.h>
# define rr_if_busy(dev) netif_queue_stopped(dev)
# define rr_if_running(dev) netif_running(dev)
# include "rrunner.h"
# define RUN_AT(x) (jiffies + (x))
MODULE_AUTHOR ( " Jes Sorensen <jes@wildopensource.com> " ) ;
MODULE_DESCRIPTION ( " Essential RoadRunner HIPPI driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
static char version [ ] __devinitdata = " rrunner.c: v0.50 11/11/2002 Jes Sorensen (jes@wildopensource.com) \n " ;
/*
* Implementation notes :
*
* The DMA engine only allows for DMA within physical 64 KB chunks of
* memory . The current approach of the driver ( and stack ) is to use
* linear blocks of memory for the skbuffs . However , as the data block
* is always the first part of the skb and skbs are 2 ^ n aligned so we
* are guarantted to get the whole block within one 64 KB align 64 KB
* chunk .
*
* On the long term , relying on being able to allocate 64 KB linear
* chunks of memory is not feasible and the skb handling code and the
* stack will need to know about I / O vectors or something similar .
*/
/*
* These are checked at init time to see if they are at least 256 KB
* and increased to 256 KB if they are not . This is done to avoid ending
* up with socket buffers smaller than the MTU size ,
*/
extern __u32 sysctl_wmem_max ;
extern __u32 sysctl_rmem_max ;
static int __devinit rr_init_one ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
{
struct net_device * dev ;
static int version_disp ;
u8 pci_latency ;
struct rr_private * rrpriv ;
void * tmpptr ;
dma_addr_t ring_dma ;
int ret = - ENOMEM ;
dev = alloc_hippi_dev ( sizeof ( struct rr_private ) ) ;
if ( ! dev )
goto out3 ;
ret = pci_enable_device ( pdev ) ;
if ( ret ) {
ret = - ENODEV ;
goto out2 ;
}
rrpriv = netdev_priv ( dev ) ;
SET_MODULE_OWNER ( dev ) ;
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
if ( pci_request_regions ( pdev , " rrunner " ) ) {
ret = - EIO ;
goto out ;
}
pci_set_drvdata ( pdev , dev ) ;
rrpriv - > pci_dev = pdev ;
spin_lock_init ( & rrpriv - > lock ) ;
dev - > irq = pdev - > irq ;
dev - > open = & rr_open ;
dev - > hard_start_xmit = & rr_start_xmit ;
dev - > stop = & rr_close ;
dev - > get_stats = & rr_get_stats ;
dev - > do_ioctl = & rr_ioctl ;
dev - > base_addr = pci_resource_start ( pdev , 0 ) ;
/* display version info if adapter is found */
if ( ! version_disp ) {
/* set display flag to TRUE so that */
/* we only display this string ONCE */
version_disp = 1 ;
printk ( version ) ;
}
pci_read_config_byte ( pdev , PCI_LATENCY_TIMER , & pci_latency ) ;
if ( pci_latency < = 0x58 ) {
pci_latency = 0x58 ;
pci_write_config_byte ( pdev , PCI_LATENCY_TIMER , pci_latency ) ;
}
pci_set_master ( pdev ) ;
printk ( KERN_INFO " %s: Essential RoadRunner serial HIPPI "
" at 0x%08lx, irq %i, PCI latency %i \n " , dev - > name ,
dev - > base_addr , dev - > irq , pci_latency ) ;
/*
* Remap the regs into kernel space .
*/
rrpriv - > regs = ioremap ( dev - > base_addr , 0x1000 ) ;
if ( ! rrpriv - > regs ) {
printk ( KERN_ERR " %s: Unable to map I/O register, "
" RoadRunner will be disabled. \n " , dev - > name ) ;
ret = - EIO ;
goto out ;
}
tmpptr = pci_alloc_consistent ( pdev , TX_TOTAL_SIZE , & ring_dma ) ;
rrpriv - > tx_ring = tmpptr ;
rrpriv - > tx_ring_dma = ring_dma ;
if ( ! tmpptr ) {
ret = - ENOMEM ;
goto out ;
}
tmpptr = pci_alloc_consistent ( pdev , RX_TOTAL_SIZE , & ring_dma ) ;
rrpriv - > rx_ring = tmpptr ;
rrpriv - > rx_ring_dma = ring_dma ;
if ( ! tmpptr ) {
ret = - ENOMEM ;
goto out ;
}
tmpptr = pci_alloc_consistent ( pdev , EVT_RING_SIZE , & ring_dma ) ;
rrpriv - > evt_ring = tmpptr ;
rrpriv - > evt_ring_dma = ring_dma ;
if ( ! tmpptr ) {
ret = - ENOMEM ;
goto out ;
}
/*
* Don ' t access any register before this point !
*/
# ifdef __BIG_ENDIAN
writel ( readl ( & rrpriv - > regs - > HostCtrl ) | NO_SWAP ,
& rrpriv - > regs - > HostCtrl ) ;
# endif
/*
* Need to add a case for little - endian 64 - bit hosts here .
*/
rr_init ( dev ) ;
dev - > base_addr = 0 ;
ret = register_netdev ( dev ) ;
if ( ret )
goto out ;
return 0 ;
out :
if ( rrpriv - > rx_ring )
pci_free_consistent ( pdev , RX_TOTAL_SIZE , rrpriv - > rx_ring ,
rrpriv - > rx_ring_dma ) ;
if ( rrpriv - > tx_ring )
pci_free_consistent ( pdev , TX_TOTAL_SIZE , rrpriv - > tx_ring ,
rrpriv - > tx_ring_dma ) ;
if ( rrpriv - > regs )
iounmap ( rrpriv - > regs ) ;
if ( pdev ) {
pci_release_regions ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
}
out2 :
free_netdev ( dev ) ;
out3 :
return ret ;
}
static void __devexit rr_remove_one ( struct pci_dev * pdev )
{
struct net_device * dev = pci_get_drvdata ( pdev ) ;
if ( dev ) {
struct rr_private * rr = netdev_priv ( dev ) ;
if ( ! ( readl ( & rr - > regs - > HostCtrl ) & NIC_HALTED ) ) {
printk ( KERN_ERR " %s: trying to unload running NIC \n " ,
dev - > name ) ;
writel ( HALT_NIC , & rr - > regs - > HostCtrl ) ;
}
pci_free_consistent ( pdev , EVT_RING_SIZE , rr - > evt_ring ,
rr - > evt_ring_dma ) ;
pci_free_consistent ( pdev , RX_TOTAL_SIZE , rr - > rx_ring ,
rr - > rx_ring_dma ) ;
pci_free_consistent ( pdev , TX_TOTAL_SIZE , rr - > tx_ring ,
rr - > tx_ring_dma ) ;
unregister_netdev ( dev ) ;
iounmap ( rr - > regs ) ;
free_netdev ( dev ) ;
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
}
}
/*
* Commands are considered to be slow , thus there is no reason to
* inline this .
*/
static void rr_issue_cmd ( struct rr_private * rrpriv , struct cmd * cmd )
{
struct rr_regs __iomem * regs ;
u32 idx ;
regs = rrpriv - > regs ;
/*
* This is temporary - it will go away in the final version .
* We probably also want to make this function inline .
*/
if ( readl ( & regs - > HostCtrl ) & NIC_HALTED ) {
printk ( " issuing command for halted NIC, code 0x%x, "
" HostCtrl %08x \n " , cmd - > code , readl ( & regs - > HostCtrl ) ) ;
if ( readl ( & regs - > Mode ) & FATAL_ERR )
printk ( " error codes Fail1 %02x, Fail2 %02x \n " ,
readl ( & regs - > Fail1 ) , readl ( & regs - > Fail2 ) ) ;
}
idx = rrpriv - > info - > cmd_ctrl . pi ;
writel ( * ( u32 * ) ( cmd ) , & regs - > CmdRing [ idx ] ) ;
wmb ( ) ;
idx = ( idx - 1 ) % CMD_RING_ENTRIES ;
rrpriv - > info - > cmd_ctrl . pi = idx ;
wmb ( ) ;
if ( readl ( & regs - > Mode ) & FATAL_ERR )
printk ( " error code %02x \n " , readl ( & regs - > Fail1 ) ) ;
}
/*
* Reset the board in a sensible manner . The NIC is already halted
* when we get here and a spin - lock is held .
*/
static int rr_reset ( struct net_device * dev )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
struct eeprom * hw = NULL ;
u32 start_pc ;
int i ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
rr_load_firmware ( dev ) ;
writel ( 0x01000000 , & regs - > TX_state ) ;
writel ( 0xff800000 , & regs - > RX_state ) ;
writel ( 0 , & regs - > AssistState ) ;
writel ( CLEAR_INTA , & regs - > LocalCtrl ) ;
writel ( 0x01 , & regs - > BrkPt ) ;
writel ( 0 , & regs - > Timer ) ;
writel ( 0 , & regs - > TimerRef ) ;
writel ( RESET_DMA , & regs - > DmaReadState ) ;
writel ( RESET_DMA , & regs - > DmaWriteState ) ;
writel ( 0 , & regs - > DmaWriteHostHi ) ;
writel ( 0 , & regs - > DmaWriteHostLo ) ;
writel ( 0 , & regs - > DmaReadHostHi ) ;
writel ( 0 , & regs - > DmaReadHostLo ) ;
writel ( 0 , & regs - > DmaReadLen ) ;
writel ( 0 , & regs - > DmaWriteLen ) ;
writel ( 0 , & regs - > DmaWriteLcl ) ;
writel ( 0 , & regs - > DmaWriteIPchecksum ) ;
writel ( 0 , & regs - > DmaReadLcl ) ;
writel ( 0 , & regs - > DmaReadIPchecksum ) ;
writel ( 0 , & regs - > PciState ) ;
# if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN
writel ( SWAP_DATA | PTR64BIT | PTR_WD_SWAP , & regs - > Mode ) ;
# elif (BITS_PER_LONG == 64)
writel ( SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP , & regs - > Mode ) ;
# else
writel ( SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP , & regs - > Mode ) ;
# endif
#if 0
/*
* Don ' t worry , this is just black magic .
*/
writel ( 0xdf000 , & regs - > RxBase ) ;
writel ( 0xdf000 , & regs - > RxPrd ) ;
writel ( 0xdf000 , & regs - > RxCon ) ;
writel ( 0xce000 , & regs - > TxBase ) ;
writel ( 0xce000 , & regs - > TxPrd ) ;
writel ( 0xce000 , & regs - > TxCon ) ;
writel ( 0 , & regs - > RxIndPro ) ;
writel ( 0 , & regs - > RxIndCon ) ;
writel ( 0 , & regs - > RxIndRef ) ;
writel ( 0 , & regs - > TxIndPro ) ;
writel ( 0 , & regs - > TxIndCon ) ;
writel ( 0 , & regs - > TxIndRef ) ;
writel ( 0xcc000 , & regs - > pad10 [ 0 ] ) ;
writel ( 0 , & regs - > DrCmndPro ) ;
writel ( 0 , & regs - > DrCmndCon ) ;
writel ( 0 , & regs - > DwCmndPro ) ;
writel ( 0 , & regs - > DwCmndCon ) ;
writel ( 0 , & regs - > DwCmndRef ) ;
writel ( 0 , & regs - > DrDataPro ) ;
writel ( 0 , & regs - > DrDataCon ) ;
writel ( 0 , & regs - > DrDataRef ) ;
writel ( 0 , & regs - > DwDataPro ) ;
writel ( 0 , & regs - > DwDataCon ) ;
writel ( 0 , & regs - > DwDataRef ) ;
# endif
writel ( 0xffffffff , & regs - > MbEvent ) ;
writel ( 0 , & regs - > Event ) ;
writel ( 0 , & regs - > TxPi ) ;
writel ( 0 , & regs - > IpRxPi ) ;
writel ( 0 , & regs - > EvtCon ) ;
writel ( 0 , & regs - > EvtPrd ) ;
rrpriv - > info - > evt_ctrl . pi = 0 ;
for ( i = 0 ; i < CMD_RING_ENTRIES ; i + + )
writel ( 0 , & regs - > CmdRing [ i ] ) ;
/*
* Why 32 ? is this not cache line size dependent ?
*/
writel ( RBURST_64 | WBURST_64 , & regs - > PciState ) ;
wmb ( ) ;
start_pc = rr_read_eeprom_word ( rrpriv , & hw - > rncd_info . FwStart ) ;
# if (DEBUG > 1)
printk ( " %s: Executing firmware at address 0x%06x \n " ,
dev - > name , start_pc ) ;
# endif
writel ( start_pc + 0x800 , & regs - > Pc ) ;
wmb ( ) ;
udelay ( 5 ) ;
writel ( start_pc , & regs - > Pc ) ;
wmb ( ) ;
return 0 ;
}
/*
* Read a string from the EEPROM .
*/
static unsigned int rr_read_eeprom ( struct rr_private * rrpriv ,
unsigned long offset ,
unsigned char * buf ,
unsigned long length )
{
struct rr_regs __iomem * regs = rrpriv - > regs ;
u32 misc , io , host , i ;
io = readl ( & regs - > ExtIo ) ;
writel ( 0 , & regs - > ExtIo ) ;
misc = readl ( & regs - > LocalCtrl ) ;
writel ( 0 , & regs - > LocalCtrl ) ;
host = readl ( & regs - > HostCtrl ) ;
writel ( host | HALT_NIC , & regs - > HostCtrl ) ;
mb ( ) ;
for ( i = 0 ; i < length ; i + + ) {
writel ( ( EEPROM_BASE + ( ( offset + i ) < < 3 ) ) , & regs - > WinBase ) ;
mb ( ) ;
buf [ i ] = ( readl ( & regs - > WinData ) > > 24 ) & 0xff ;
mb ( ) ;
}
writel ( host , & regs - > HostCtrl ) ;
writel ( misc , & regs - > LocalCtrl ) ;
writel ( io , & regs - > ExtIo ) ;
mb ( ) ;
return i ;
}
/*
* Shortcut to read one word ( 4 bytes ) out of the EEPROM and convert
* it to our CPU byte - order .
*/
static u32 rr_read_eeprom_word ( struct rr_private * rrpriv ,
void * offset )
{
u32 word ;
if ( ( rr_read_eeprom ( rrpriv , ( unsigned long ) offset ,
( char * ) & word , 4 ) = = 4 ) )
return be32_to_cpu ( word ) ;
return 0 ;
}
/*
* Write a string to the EEPROM .
*
* This is only called when the firmware is not running .
*/
static unsigned int write_eeprom ( struct rr_private * rrpriv ,
unsigned long offset ,
unsigned char * buf ,
unsigned long length )
{
struct rr_regs __iomem * regs = rrpriv - > regs ;
u32 misc , io , data , i , j , ready , error = 0 ;
io = readl ( & regs - > ExtIo ) ;
writel ( 0 , & regs - > ExtIo ) ;
misc = readl ( & regs - > LocalCtrl ) ;
writel ( ENABLE_EEPROM_WRITE , & regs - > LocalCtrl ) ;
mb ( ) ;
for ( i = 0 ; i < length ; i + + ) {
writel ( ( EEPROM_BASE + ( ( offset + i ) < < 3 ) ) , & regs - > WinBase ) ;
mb ( ) ;
data = buf [ i ] < < 24 ;
/*
* Only try to write the data if it is not the same
* value already .
*/
if ( ( readl ( & regs - > WinData ) & 0xff000000 ) ! = data ) {
writel ( data , & regs - > WinData ) ;
ready = 0 ;
j = 0 ;
mb ( ) ;
while ( ! ready ) {
udelay ( 20 ) ;
if ( ( readl ( & regs - > WinData ) & 0xff000000 ) = =
data )
ready = 1 ;
mb ( ) ;
if ( j + + > 5000 ) {
printk ( " data mismatch: %08x, "
" WinData %08x \n " , data ,
readl ( & regs - > WinData ) ) ;
ready = 1 ;
error = 1 ;
}
}
}
}
writel ( misc , & regs - > LocalCtrl ) ;
writel ( io , & regs - > ExtIo ) ;
mb ( ) ;
return error ;
}
static int __init rr_init ( struct net_device * dev )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
struct eeprom * hw = NULL ;
u32 sram_size , rev ;
int i ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
rev = readl ( & regs - > FwRev ) ;
rrpriv - > fw_rev = rev ;
if ( rev > 0x00020024 )
printk ( " Firmware revision: %i.%i.%i \n " , ( rev > > 16 ) ,
( ( rev > > 8 ) & 0xff ) , ( rev & 0xff ) ) ;
else if ( rev > = 0x00020000 ) {
printk ( " Firmware revision: %i.%i.%i (2.0.37 or "
" later is recommended) \n " , ( rev > > 16 ) ,
( ( rev > > 8 ) & 0xff ) , ( rev & 0xff ) ) ;
} else {
printk ( " Firmware revision too old: %i.%i.%i, please "
" upgrade to 2.0.37 or later. \n " ,
( rev > > 16 ) , ( ( rev > > 8 ) & 0xff ) , ( rev & 0xff ) ) ;
}
# if (DEBUG > 2)
printk ( " Maximum receive rings %i \n " , readl ( & regs - > MaxRxRng ) ) ;
# endif
/*
* Read the hardware address from the eeprom . The HW address
* is not really necessary for HIPPI but awfully convenient .
* The pointer arithmetic to put it in dev_addr is ugly , but
* Donald Becker does it this way for the GigE version of this
* card and it ' s shorter and more portable than any
* other method I ' ve seen . - VAL
*/
* ( u16 * ) ( dev - > dev_addr ) =
htons ( rr_read_eeprom_word ( rrpriv , & hw - > manf . BoardULA ) ) ;
* ( u32 * ) ( dev - > dev_addr + 2 ) =
htonl ( rr_read_eeprom_word ( rrpriv , & hw - > manf . BoardULA [ 4 ] ) ) ;
printk ( " MAC: " ) ;
for ( i = 0 ; i < 5 ; i + + )
printk ( " %2.2x: " , dev - > dev_addr [ i ] ) ;
printk ( " %2.2x \n " , dev - > dev_addr [ i ] ) ;
sram_size = rr_read_eeprom_word ( rrpriv , ( void * ) 8 ) ;
printk ( " SRAM size 0x%06x \n " , sram_size ) ;
if ( sysctl_rmem_max < 262144 ) {
printk ( " Receive socket buffer limit too low (%i), "
" setting to 262144 \n " , sysctl_rmem_max ) ;
sysctl_rmem_max = 262144 ;
}
if ( sysctl_wmem_max < 262144 ) {
printk ( " Transmit socket buffer limit too low (%i), "
" setting to 262144 \n " , sysctl_wmem_max ) ;
sysctl_wmem_max = 262144 ;
}
return 0 ;
}
static int rr_init1 ( struct net_device * dev )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
unsigned long myjif , flags ;
struct cmd cmd ;
u32 hostctrl ;
int ecode = 0 ;
short i ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
hostctrl = readl ( & regs - > HostCtrl ) ;
writel ( hostctrl | HALT_NIC | RR_CLEAR_INT , & regs - > HostCtrl ) ;
wmb ( ) ;
if ( hostctrl & PARITY_ERR ) {
printk ( " %s: Parity error halting NIC - this is serious! \n " ,
dev - > name ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
ecode = - EFAULT ;
goto error ;
}
set_rxaddr ( regs , rrpriv - > rx_ctrl_dma ) ;
set_infoaddr ( regs , rrpriv - > info_dma ) ;
rrpriv - > info - > evt_ctrl . entry_size = sizeof ( struct event ) ;
rrpriv - > info - > evt_ctrl . entries = EVT_RING_ENTRIES ;
rrpriv - > info - > evt_ctrl . mode = 0 ;
rrpriv - > info - > evt_ctrl . pi = 0 ;
set_rraddr ( & rrpriv - > info - > evt_ctrl . rngptr , rrpriv - > evt_ring_dma ) ;
rrpriv - > info - > cmd_ctrl . entry_size = sizeof ( struct cmd ) ;
rrpriv - > info - > cmd_ctrl . entries = CMD_RING_ENTRIES ;
rrpriv - > info - > cmd_ctrl . mode = 0 ;
rrpriv - > info - > cmd_ctrl . pi = 15 ;
for ( i = 0 ; i < CMD_RING_ENTRIES ; i + + ) {
writel ( 0 , & regs - > CmdRing [ i ] ) ;
}
for ( i = 0 ; i < TX_RING_ENTRIES ; i + + ) {
rrpriv - > tx_ring [ i ] . size = 0 ;
set_rraddr ( & rrpriv - > tx_ring [ i ] . addr , 0 ) ;
rrpriv - > tx_skbuff [ i ] = NULL ;
}
rrpriv - > info - > tx_ctrl . entry_size = sizeof ( struct tx_desc ) ;
rrpriv - > info - > tx_ctrl . entries = TX_RING_ENTRIES ;
rrpriv - > info - > tx_ctrl . mode = 0 ;
rrpriv - > info - > tx_ctrl . pi = 0 ;
set_rraddr ( & rrpriv - > info - > tx_ctrl . rngptr , rrpriv - > tx_ring_dma ) ;
/*
* Set dirty_tx before we start receiving interrupts , otherwise
* the interrupt handler might think it is supposed to process
* tx ints before we are up and running , which may cause a null
* pointer access in the int handler .
*/
rrpriv - > tx_full = 0 ;
rrpriv - > cur_rx = 0 ;
rrpriv - > dirty_rx = rrpriv - > dirty_tx = 0 ;
rr_reset ( dev ) ;
/* Tuning values */
writel ( 0x5000 , & regs - > ConRetry ) ;
writel ( 0x100 , & regs - > ConRetryTmr ) ;
writel ( 0x500000 , & regs - > ConTmout ) ;
writel ( 0x60 , & regs - > IntrTmr ) ;
writel ( 0x500000 , & regs - > TxDataMvTimeout ) ;
writel ( 0x200000 , & regs - > RxDataMvTimeout ) ;
writel ( 0x80 , & regs - > WriteDmaThresh ) ;
writel ( 0x80 , & regs - > ReadDmaThresh ) ;
rrpriv - > fw_running = 0 ;
wmb ( ) ;
hostctrl & = ~ ( HALT_NIC | INVALID_INST_B | PARITY_ERR ) ;
writel ( hostctrl , & regs - > HostCtrl ) ;
wmb ( ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
for ( i = 0 ; i < RX_RING_ENTRIES ; i + + ) {
struct sk_buff * skb ;
dma_addr_t addr ;
rrpriv - > rx_ring [ i ] . mode = 0 ;
skb = alloc_skb ( dev - > mtu + HIPPI_HLEN , GFP_ATOMIC ) ;
if ( ! skb ) {
printk ( KERN_WARNING " %s: Unable to allocate memory "
" for receive ring - halting NIC \n " , dev - > name ) ;
ecode = - ENOMEM ;
goto error ;
}
rrpriv - > rx_skbuff [ i ] = skb ;
addr = pci_map_single ( rrpriv - > pci_dev , skb - > data ,
dev - > mtu + HIPPI_HLEN , PCI_DMA_FROMDEVICE ) ;
/*
* Sanity test to see if we conflict with the DMA
* limitations of the Roadrunner .
*/
if ( ( ( ( unsigned long ) skb - > data ) & 0xfff ) > ~ 65320 )
printk ( " skb alloc error \n " ) ;
set_rraddr ( & rrpriv - > rx_ring [ i ] . addr , addr ) ;
rrpriv - > rx_ring [ i ] . size = dev - > mtu + HIPPI_HLEN ;
}
rrpriv - > rx_ctrl [ 4 ] . entry_size = sizeof ( struct rx_desc ) ;
rrpriv - > rx_ctrl [ 4 ] . entries = RX_RING_ENTRIES ;
rrpriv - > rx_ctrl [ 4 ] . mode = 8 ;
rrpriv - > rx_ctrl [ 4 ] . pi = 0 ;
wmb ( ) ;
set_rraddr ( & rrpriv - > rx_ctrl [ 4 ] . rngptr , rrpriv - > rx_ring_dma ) ;
udelay ( 1000 ) ;
/*
* Now start the FirmWare .
*/
cmd . code = C_START_FW ;
cmd . ring = 0 ;
cmd . index = 0 ;
rr_issue_cmd ( rrpriv , & cmd ) ;
/*
* Give the FirmWare time to chew on the ` get running ' command .
*/
myjif = jiffies + 5 * HZ ;
while ( time_before ( jiffies , myjif ) & & ! rrpriv - > fw_running )
cpu_relax ( ) ;
netif_start_queue ( dev ) ;
return ecode ;
error :
/*
* We might have gotten here because we are out of memory ,
* make sure we release everything we allocated before failing
*/
for ( i = 0 ; i < RX_RING_ENTRIES ; i + + ) {
struct sk_buff * skb = rrpriv - > rx_skbuff [ i ] ;
if ( skb ) {
pci_unmap_single ( rrpriv - > pci_dev ,
rrpriv - > rx_ring [ i ] . addr . addrlo ,
dev - > mtu + HIPPI_HLEN ,
PCI_DMA_FROMDEVICE ) ;
rrpriv - > rx_ring [ i ] . size = 0 ;
set_rraddr ( & rrpriv - > rx_ring [ i ] . addr , 0 ) ;
dev_kfree_skb ( skb ) ;
rrpriv - > rx_skbuff [ i ] = NULL ;
}
}
return ecode ;
}
/*
* All events are considered to be slow ( RX / TX ints do not generate
* events ) and are handled here , outside the main interrupt handler ,
* to reduce the size of the handler .
*/
static u32 rr_handle_event ( struct net_device * dev , u32 prodidx , u32 eidx )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
u32 tmp ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
while ( prodidx ! = eidx ) {
switch ( rrpriv - > evt_ring [ eidx ] . code ) {
case E_NIC_UP :
tmp = readl ( & regs - > FwRev ) ;
printk ( KERN_INFO " %s: Firmware revision %i.%i.%i "
" up and running \n " , dev - > name ,
( tmp > > 16 ) , ( ( tmp > > 8 ) & 0xff ) , ( tmp & 0xff ) ) ;
rrpriv - > fw_running = 1 ;
writel ( RX_RING_ENTRIES - 1 , & regs - > IpRxPi ) ;
wmb ( ) ;
break ;
case E_LINK_ON :
printk ( KERN_INFO " %s: Optical link ON \n " , dev - > name ) ;
break ;
case E_LINK_OFF :
printk ( KERN_INFO " %s: Optical link OFF \n " , dev - > name ) ;
break ;
case E_RX_IDLE :
printk ( KERN_WARNING " %s: RX data not moving \n " ,
dev - > name ) ;
goto drop ;
case E_WATCHDOG :
printk ( KERN_INFO " %s: The watchdog is here to see "
" us \n " , dev - > name ) ;
break ;
case E_INTERN_ERR :
printk ( KERN_ERR " %s: HIPPI Internal NIC error \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_HOST_ERR :
printk ( KERN_ERR " %s: Host software error \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
/*
* TX events .
*/
case E_CON_REJ :
printk ( KERN_WARNING " %s: Connection rejected \n " ,
dev - > name ) ;
rrpriv - > stats . tx_aborted_errors + + ;
break ;
case E_CON_TMOUT :
printk ( KERN_WARNING " %s: Connection timeout \n " ,
dev - > name ) ;
break ;
case E_DISC_ERR :
printk ( KERN_WARNING " %s: HIPPI disconnect error \n " ,
dev - > name ) ;
rrpriv - > stats . tx_aborted_errors + + ;
break ;
case E_INT_PRTY :
printk ( KERN_ERR " %s: HIPPI Internal Parity error \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_TX_IDLE :
printk ( KERN_WARNING " %s: Transmitter idle \n " ,
dev - > name ) ;
break ;
case E_TX_LINK_DROP :
printk ( KERN_WARNING " %s: Link lost during transmit \n " ,
dev - > name ) ;
rrpriv - > stats . tx_aborted_errors + + ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_TX_INV_RNG :
printk ( KERN_ERR " %s: Invalid send ring block \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_TX_INV_BUF :
printk ( KERN_ERR " %s: Invalid send buffer address \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_TX_INV_DSC :
printk ( KERN_ERR " %s: Invalid descriptor address \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
/*
* RX events .
*/
case E_RX_RNG_OUT :
printk ( KERN_INFO " %s: Receive ring full \n " , dev - > name ) ;
break ;
case E_RX_PAR_ERR :
printk ( KERN_WARNING " %s: Receive parity error \n " ,
dev - > name ) ;
goto drop ;
case E_RX_LLRC_ERR :
printk ( KERN_WARNING " %s: Receive LLRC error \n " ,
dev - > name ) ;
goto drop ;
case E_PKT_LN_ERR :
printk ( KERN_WARNING " %s: Receive packet length "
" error \n " , dev - > name ) ;
goto drop ;
case E_DTA_CKSM_ERR :
printk ( KERN_WARNING " %s: Data checksum error \n " ,
dev - > name ) ;
goto drop ;
case E_SHT_BST :
printk ( KERN_WARNING " %s: Unexpected short burst "
" error \n " , dev - > name ) ;
goto drop ;
case E_STATE_ERR :
printk ( KERN_WARNING " %s: Recv. state transition "
" error \n " , dev - > name ) ;
goto drop ;
case E_UNEXP_DATA :
printk ( KERN_WARNING " %s: Unexpected data error \n " ,
dev - > name ) ;
goto drop ;
case E_LST_LNK_ERR :
printk ( KERN_WARNING " %s: Link lost error \n " ,
dev - > name ) ;
goto drop ;
case E_FRM_ERR :
printk ( KERN_WARNING " %s: Framming Error \n " ,
dev - > name ) ;
goto drop ;
case E_FLG_SYN_ERR :
printk ( KERN_WARNING " %s: Flag sync. lost during "
" packet \n " , dev - > name ) ;
goto drop ;
case E_RX_INV_BUF :
printk ( KERN_ERR " %s: Invalid receive buffer "
" address \n " , dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_RX_INV_DSC :
printk ( KERN_ERR " %s: Invalid receive descriptor "
" address \n " , dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
case E_RNG_BLK :
printk ( KERN_ERR " %s: Invalid ring block \n " ,
dev - > name ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
wmb ( ) ;
break ;
drop :
/* Label packet to be dropped.
* Actual dropping occurs in rx
* handling .
*
* The index of packet we get to drop is
* the index of the packet following
* the bad packet . - kbf
*/
{
u16 index = rrpriv - > evt_ring [ eidx ] . index ;
index = ( index + ( RX_RING_ENTRIES - 1 ) ) %
RX_RING_ENTRIES ;
rrpriv - > rx_ring [ index ] . mode | =
( PACKET_BAD | PACKET_END ) ;
}
break ;
default :
printk ( KERN_WARNING " %s: Unhandled event 0x%02x \n " ,
dev - > name , rrpriv - > evt_ring [ eidx ] . code ) ;
}
eidx = ( eidx + 1 ) % EVT_RING_ENTRIES ;
}
rrpriv - > info - > evt_ctrl . pi = eidx ;
wmb ( ) ;
return eidx ;
}
static void rx_int ( struct net_device * dev , u32 rxlimit , u32 index )
{
struct rr_private * rrpriv = netdev_priv ( dev ) ;
struct rr_regs __iomem * regs = rrpriv - > regs ;
do {
struct rx_desc * desc ;
u32 pkt_len ;
desc = & ( rrpriv - > rx_ring [ index ] ) ;
pkt_len = desc - > size ;
# if (DEBUG > 2)
printk ( " index %i, rxlimit %i \n " , index , rxlimit ) ;
printk ( " len %x, mode %x \n " , pkt_len , desc - > mode ) ;
# endif
if ( ( rrpriv - > rx_ring [ index ] . mode & PACKET_BAD ) = = PACKET_BAD ) {
rrpriv - > stats . rx_dropped + + ;
goto defer ;
}
if ( pkt_len > 0 ) {
struct sk_buff * skb , * rx_skb ;
rx_skb = rrpriv - > rx_skbuff [ index ] ;
if ( pkt_len < PKT_COPY_THRESHOLD ) {
skb = alloc_skb ( pkt_len , GFP_ATOMIC ) ;
if ( skb = = NULL ) {
printk ( KERN_WARNING " %s: Unable to allocate skb (%i bytes), deferring packet \n " , dev - > name , pkt_len ) ;
rrpriv - > stats . rx_dropped + + ;
goto defer ;
} else {
pci_dma_sync_single_for_cpu ( rrpriv - > pci_dev ,
desc - > addr . addrlo ,
pkt_len ,
PCI_DMA_FROMDEVICE ) ;
memcpy ( skb_put ( skb , pkt_len ) ,
rx_skb - > data , pkt_len ) ;
pci_dma_sync_single_for_device ( rrpriv - > pci_dev ,
desc - > addr . addrlo ,
pkt_len ,
PCI_DMA_FROMDEVICE ) ;
}
} else {
struct sk_buff * newskb ;
newskb = alloc_skb ( dev - > mtu + HIPPI_HLEN ,
GFP_ATOMIC ) ;
if ( newskb ) {
dma_addr_t addr ;
pci_unmap_single ( rrpriv - > pci_dev ,
desc - > addr . addrlo , dev - > mtu +
HIPPI_HLEN , PCI_DMA_FROMDEVICE ) ;
skb = rx_skb ;
skb_put ( skb , pkt_len ) ;
rrpriv - > rx_skbuff [ index ] = newskb ;
addr = pci_map_single ( rrpriv - > pci_dev ,
newskb - > data ,
dev - > mtu + HIPPI_HLEN ,
PCI_DMA_FROMDEVICE ) ;
set_rraddr ( & desc - > addr , addr ) ;
} else {
printk ( " %s: Out of memory, deferring "
" packet \n " , dev - > name ) ;
rrpriv - > stats . rx_dropped + + ;
goto defer ;
}
}
skb - > dev = dev ;
skb - > protocol = hippi_type_trans ( skb , dev ) ;
netif_rx ( skb ) ; /* send it up */
dev - > last_rx = jiffies ;
rrpriv - > stats . rx_packets + + ;
rrpriv - > stats . rx_bytes + = pkt_len ;
}
defer :
desc - > mode = 0 ;
desc - > size = dev - > mtu + HIPPI_HLEN ;
if ( ( index & 7 ) = = 7 )
writel ( index , & regs - > IpRxPi ) ;
index = ( index + 1 ) % RX_RING_ENTRIES ;
} while ( index ! = rxlimit ) ;
rrpriv - > cur_rx = index ;
wmb ( ) ;
}
static irqreturn_t rr_interrupt ( int irq , void * dev_id , struct pt_regs * ptregs )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
struct net_device * dev = ( struct net_device * ) dev_id ;
u32 prodidx , rxindex , eidx , txcsmr , rxlimit , txcon ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
if ( ! ( readl ( & regs - > HostCtrl ) & RR_INT ) )
return IRQ_NONE ;
spin_lock ( & rrpriv - > lock ) ;
prodidx = readl ( & regs - > EvtPrd ) ;
txcsmr = ( prodidx > > 8 ) & 0xff ;
rxlimit = ( prodidx > > 16 ) & 0xff ;
prodidx & = 0xff ;
# if (DEBUG > 2)
printk ( " %s: interrupt, prodidx = %i, eidx = %i \n " , dev - > name ,
prodidx , rrpriv - > info - > evt_ctrl . pi ) ;
# endif
/*
* Order here is important . We must handle events
* before doing anything else in order to catch
* such things as LLRC errors , etc - kbf
*/
eidx = rrpriv - > info - > evt_ctrl . pi ;
if ( prodidx ! = eidx )
eidx = rr_handle_event ( dev , prodidx , eidx ) ;
rxindex = rrpriv - > cur_rx ;
if ( rxindex ! = rxlimit )
rx_int ( dev , rxlimit , rxindex ) ;
txcon = rrpriv - > dirty_tx ;
if ( txcsmr ! = txcon ) {
do {
/* Due to occational firmware TX producer/consumer out
* of sync . error need to check entry in ring - kbf
*/
if ( rrpriv - > tx_skbuff [ txcon ] ) {
struct tx_desc * desc ;
struct sk_buff * skb ;
desc = & ( rrpriv - > tx_ring [ txcon ] ) ;
skb = rrpriv - > tx_skbuff [ txcon ] ;
rrpriv - > stats . tx_packets + + ;
rrpriv - > stats . tx_bytes + = skb - > len ;
pci_unmap_single ( rrpriv - > pci_dev ,
desc - > addr . addrlo , skb - > len ,
PCI_DMA_TODEVICE ) ;
dev_kfree_skb_irq ( skb ) ;
rrpriv - > tx_skbuff [ txcon ] = NULL ;
desc - > size = 0 ;
set_rraddr ( & rrpriv - > tx_ring [ txcon ] . addr , 0 ) ;
desc - > mode = 0 ;
}
txcon = ( txcon + 1 ) % TX_RING_ENTRIES ;
} while ( txcsmr ! = txcon ) ;
wmb ( ) ;
rrpriv - > dirty_tx = txcon ;
if ( rrpriv - > tx_full & & rr_if_busy ( dev ) & &
( ( ( rrpriv - > info - > tx_ctrl . pi + 1 ) % TX_RING_ENTRIES )
! = rrpriv - > dirty_tx ) ) {
rrpriv - > tx_full = 0 ;
netif_wake_queue ( dev ) ;
}
}
eidx | = ( ( txcsmr < < 8 ) | ( rxlimit < < 16 ) ) ;
writel ( eidx , & regs - > EvtCon ) ;
wmb ( ) ;
spin_unlock ( & rrpriv - > lock ) ;
return IRQ_HANDLED ;
}
static inline void rr_raz_tx ( struct rr_private * rrpriv ,
struct net_device * dev )
{
int i ;
for ( i = 0 ; i < TX_RING_ENTRIES ; i + + ) {
struct sk_buff * skb = rrpriv - > tx_skbuff [ i ] ;
if ( skb ) {
struct tx_desc * desc = & ( rrpriv - > tx_ring [ i ] ) ;
pci_unmap_single ( rrpriv - > pci_dev , desc - > addr . addrlo ,
skb - > len , PCI_DMA_TODEVICE ) ;
desc - > size = 0 ;
set_rraddr ( & desc - > addr , 0 ) ;
dev_kfree_skb ( skb ) ;
rrpriv - > tx_skbuff [ i ] = NULL ;
}
}
}
static inline void rr_raz_rx ( struct rr_private * rrpriv ,
struct net_device * dev )
{
int i ;
for ( i = 0 ; i < RX_RING_ENTRIES ; i + + ) {
struct sk_buff * skb = rrpriv - > rx_skbuff [ i ] ;
if ( skb ) {
struct rx_desc * desc = & ( rrpriv - > rx_ring [ i ] ) ;
pci_unmap_single ( rrpriv - > pci_dev , desc - > addr . addrlo ,
dev - > mtu + HIPPI_HLEN , PCI_DMA_FROMDEVICE ) ;
desc - > size = 0 ;
set_rraddr ( & desc - > addr , 0 ) ;
dev_kfree_skb ( skb ) ;
rrpriv - > rx_skbuff [ i ] = NULL ;
}
}
}
static void rr_timer ( unsigned long data )
{
struct net_device * dev = ( struct net_device * ) data ;
struct rr_private * rrpriv = netdev_priv ( dev ) ;
struct rr_regs __iomem * regs = rrpriv - > regs ;
unsigned long flags ;
if ( readl ( & regs - > HostCtrl ) & NIC_HALTED ) {
printk ( " %s: Restarting nic \n " , dev - > name ) ;
memset ( rrpriv - > rx_ctrl , 0 , 256 * sizeof ( struct ring_ctrl ) ) ;
memset ( rrpriv - > info , 0 , sizeof ( struct rr_info ) ) ;
wmb ( ) ;
rr_raz_tx ( rrpriv , dev ) ;
rr_raz_rx ( rrpriv , dev ) ;
if ( rr_init1 ( dev ) ) {
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT ,
& regs - > HostCtrl ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
}
}
rrpriv - > timer . expires = RUN_AT ( 5 * HZ ) ;
add_timer ( & rrpriv - > timer ) ;
}
static int rr_open ( struct net_device * dev )
{
struct rr_private * rrpriv = netdev_priv ( dev ) ;
struct pci_dev * pdev = rrpriv - > pci_dev ;
struct rr_regs __iomem * regs ;
int ecode = 0 ;
unsigned long flags ;
dma_addr_t dma_addr ;
regs = rrpriv - > regs ;
if ( rrpriv - > fw_rev < 0x00020000 ) {
printk ( KERN_WARNING " %s: trying to configure device with "
" obsolete firmware \n " , dev - > name ) ;
ecode = - EBUSY ;
goto error ;
}
rrpriv - > rx_ctrl = pci_alloc_consistent ( pdev ,
256 * sizeof ( struct ring_ctrl ) ,
& dma_addr ) ;
if ( ! rrpriv - > rx_ctrl ) {
ecode = - ENOMEM ;
goto error ;
}
rrpriv - > rx_ctrl_dma = dma_addr ;
memset ( rrpriv - > rx_ctrl , 0 , 256 * sizeof ( struct ring_ctrl ) ) ;
rrpriv - > info = pci_alloc_consistent ( pdev , sizeof ( struct rr_info ) ,
& dma_addr ) ;
if ( ! rrpriv - > info ) {
ecode = - ENOMEM ;
goto error ;
}
rrpriv - > info_dma = dma_addr ;
memset ( rrpriv - > info , 0 , sizeof ( struct rr_info ) ) ;
wmb ( ) ;
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT , & regs - > HostCtrl ) ;
readl ( & regs - > HostCtrl ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
if ( request_irq ( dev - > irq , rr_interrupt , SA_SHIRQ , dev - > name , dev ) ) {
printk ( KERN_WARNING " %s: Requested IRQ %d is busy \n " ,
dev - > name , dev - > irq ) ;
ecode = - EAGAIN ;
goto error ;
}
if ( ( ecode = rr_init1 ( dev ) ) )
goto error ;
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type . */
init_timer ( & rrpriv - > timer ) ;
rrpriv - > timer . expires = RUN_AT ( 5 * HZ ) ; /* 5 sec. watchdog */
rrpriv - > timer . data = ( unsigned long ) dev ;
rrpriv - > timer . function = & rr_timer ; /* timer handler */
add_timer ( & rrpriv - > timer ) ;
netif_start_queue ( dev ) ;
return ecode ;
error :
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
writel ( readl ( & regs - > HostCtrl ) | HALT_NIC | RR_CLEAR_INT , & regs - > HostCtrl ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
if ( rrpriv - > info ) {
pci_free_consistent ( pdev , sizeof ( struct rr_info ) , rrpriv - > info ,
rrpriv - > info_dma ) ;
rrpriv - > info = NULL ;
}
if ( rrpriv - > rx_ctrl ) {
pci_free_consistent ( pdev , sizeof ( struct ring_ctrl ) ,
rrpriv - > rx_ctrl , rrpriv - > rx_ctrl_dma ) ;
rrpriv - > rx_ctrl = NULL ;
}
netif_stop_queue ( dev ) ;
return ecode ;
}
static void rr_dump ( struct net_device * dev )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
u32 index , cons ;
short i ;
int len ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
printk ( " %s: dumping NIC TX rings \n " , dev - > name ) ;
printk ( " RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x \n " ,
readl ( & regs - > RxPrd ) , readl ( & regs - > TxPrd ) ,
readl ( & regs - > EvtPrd ) , readl ( & regs - > TxPi ) ,
rrpriv - > info - > tx_ctrl . pi ) ;
printk ( " Error code 0x%x \n " , readl ( & regs - > Fail1 ) ) ;
index = ( ( ( readl ( & regs - > EvtPrd ) > > 8 ) & 0xff ) - 1 ) % EVT_RING_ENTRIES ;
cons = rrpriv - > dirty_tx ;
printk ( " TX ring index %i, TX consumer %i \n " ,
index , cons ) ;
if ( rrpriv - > tx_skbuff [ index ] ) {
len = min_t ( int , 0x80 , rrpriv - > tx_skbuff [ index ] - > len ) ;
printk ( " skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x) \n " , index , len , rrpriv - > tx_ring [ index ] . size ) ;
for ( i = 0 ; i < len ; i + + ) {
if ( ! ( i & 7 ) )
printk ( " \n " ) ;
printk ( " %02x " , ( unsigned char ) rrpriv - > tx_skbuff [ index ] - > data [ i ] ) ;
}
printk ( " \n " ) ;
}
if ( rrpriv - > tx_skbuff [ cons ] ) {
len = min_t ( int , 0x80 , rrpriv - > tx_skbuff [ cons ] - > len ) ;
printk ( " skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x) \n " , cons , len , rrpriv - > tx_skbuff [ cons ] - > len ) ;
printk ( " mode 0x%x, size 0x%x, \n phys %08Lx, skbuff-addr %08lx, truesize 0x%x \n " ,
rrpriv - > tx_ring [ cons ] . mode ,
rrpriv - > tx_ring [ cons ] . size ,
( unsigned long long ) rrpriv - > tx_ring [ cons ] . addr . addrlo ,
( unsigned long ) rrpriv - > tx_skbuff [ cons ] - > data ,
( unsigned int ) rrpriv - > tx_skbuff [ cons ] - > truesize ) ;
for ( i = 0 ; i < len ; i + + ) {
if ( ! ( i & 7 ) )
printk ( " \n " ) ;
printk ( " %02x " , ( unsigned char ) rrpriv - > tx_ring [ cons ] . size ) ;
}
printk ( " \n " ) ;
}
printk ( " dumping TX ring info: \n " ) ;
for ( i = 0 ; i < TX_RING_ENTRIES ; i + + )
printk ( " mode 0x%x, size 0x%x, phys-addr %08Lx \n " ,
rrpriv - > tx_ring [ i ] . mode ,
rrpriv - > tx_ring [ i ] . size ,
( unsigned long long ) rrpriv - > tx_ring [ i ] . addr . addrlo ) ;
}
static int rr_close ( struct net_device * dev )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
unsigned long flags ;
u32 tmp ;
short i ;
netif_stop_queue ( dev ) ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
/*
* Lock to make sure we are not cleaning up while another CPU
* is handling interrupts .
*/
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
tmp = readl ( & regs - > HostCtrl ) ;
if ( tmp & NIC_HALTED ) {
printk ( " %s: NIC already halted \n " , dev - > name ) ;
rr_dump ( dev ) ;
} else {
tmp | = HALT_NIC | RR_CLEAR_INT ;
writel ( tmp , & regs - > HostCtrl ) ;
readl ( & regs - > HostCtrl ) ;
}
rrpriv - > fw_running = 0 ;
del_timer_sync ( & rrpriv - > timer ) ;
writel ( 0 , & regs - > TxPi ) ;
writel ( 0 , & regs - > IpRxPi ) ;
writel ( 0 , & regs - > EvtCon ) ;
writel ( 0 , & regs - > EvtPrd ) ;
for ( i = 0 ; i < CMD_RING_ENTRIES ; i + + )
writel ( 0 , & regs - > CmdRing [ i ] ) ;
rrpriv - > info - > tx_ctrl . entries = 0 ;
rrpriv - > info - > cmd_ctrl . pi = 0 ;
rrpriv - > info - > evt_ctrl . pi = 0 ;
rrpriv - > rx_ctrl [ 4 ] . entries = 0 ;
rr_raz_tx ( rrpriv , dev ) ;
rr_raz_rx ( rrpriv , dev ) ;
pci_free_consistent ( rrpriv - > pci_dev , 256 * sizeof ( struct ring_ctrl ) ,
rrpriv - > rx_ctrl , rrpriv - > rx_ctrl_dma ) ;
rrpriv - > rx_ctrl = NULL ;
pci_free_consistent ( rrpriv - > pci_dev , sizeof ( struct rr_info ) ,
rrpriv - > info , rrpriv - > info_dma ) ;
rrpriv - > info = NULL ;
free_irq ( dev - > irq , dev ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
return 0 ;
}
static int rr_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct rr_private * rrpriv = netdev_priv ( dev ) ;
struct rr_regs __iomem * regs = rrpriv - > regs ;
2005-08-09 19:31:17 -07:00
struct hippi_cb * hcb = ( struct hippi_cb * ) skb - > cb ;
2005-04-16 15:20:36 -07:00
struct ring_ctrl * txctrl ;
unsigned long flags ;
u32 index , len = skb - > len ;
u32 * ifield ;
struct sk_buff * new_skb ;
if ( readl ( & regs - > Mode ) & FATAL_ERR )
printk ( " error codes Fail1 %02x, Fail2 %02x \n " ,
readl ( & regs - > Fail1 ) , readl ( & regs - > Fail2 ) ) ;
/*
* We probably need to deal with tbusy here to prevent overruns .
*/
if ( skb_headroom ( skb ) < 8 ) {
printk ( " incoming skb too small - reallocating \n " ) ;
if ( ! ( new_skb = dev_alloc_skb ( len + 8 ) ) ) {
dev_kfree_skb ( skb ) ;
netif_wake_queue ( dev ) ;
return - EBUSY ;
}
skb_reserve ( new_skb , 8 ) ;
skb_put ( new_skb , len ) ;
memcpy ( new_skb - > data , skb - > data , len ) ;
dev_kfree_skb ( skb ) ;
skb = new_skb ;
}
ifield = ( u32 * ) skb_push ( skb , 8 ) ;
ifield [ 0 ] = 0 ;
2005-08-09 19:31:17 -07:00
ifield [ 1 ] = hcb - > ifield ;
2005-04-16 15:20:36 -07:00
/*
* We don ' t need the lock before we are actually going to start
* fiddling with the control blocks .
*/
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
txctrl = & rrpriv - > info - > tx_ctrl ;
index = txctrl - > pi ;
rrpriv - > tx_skbuff [ index ] = skb ;
set_rraddr ( & rrpriv - > tx_ring [ index ] . addr , pci_map_single (
rrpriv - > pci_dev , skb - > data , len + 8 , PCI_DMA_TODEVICE ) ) ;
rrpriv - > tx_ring [ index ] . size = len + 8 ; /* include IFIELD */
rrpriv - > tx_ring [ index ] . mode = PACKET_START | PACKET_END ;
txctrl - > pi = ( index + 1 ) % TX_RING_ENTRIES ;
wmb ( ) ;
writel ( txctrl - > pi , & regs - > TxPi ) ;
if ( txctrl - > pi = = rrpriv - > dirty_tx ) {
rrpriv - > tx_full = 1 ;
netif_stop_queue ( dev ) ;
}
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
dev - > trans_start = jiffies ;
return 0 ;
}
static struct net_device_stats * rr_get_stats ( struct net_device * dev )
{
struct rr_private * rrpriv ;
rrpriv = netdev_priv ( dev ) ;
return ( & rrpriv - > stats ) ;
}
/*
* Read the firmware out of the EEPROM and put it into the SRAM
* ( or from user space - later )
*
* This operation requires the NIC to be halted and is performed with
* interrupts disabled and with the spinlock hold .
*/
static int rr_load_firmware ( struct net_device * dev )
{
struct rr_private * rrpriv ;
struct rr_regs __iomem * regs ;
unsigned long eptr , segptr ;
int i , j ;
u32 localctrl , sptr , len , tmp ;
u32 p2len , p2size , nr_seg , revision , io , sram_size ;
struct eeprom * hw = NULL ;
rrpriv = netdev_priv ( dev ) ;
regs = rrpriv - > regs ;
if ( dev - > flags & IFF_UP )
return - EBUSY ;
if ( ! ( readl ( & regs - > HostCtrl ) & NIC_HALTED ) ) {
printk ( " %s: Trying to load firmware to a running NIC. \n " ,
dev - > name ) ;
return - EBUSY ;
}
localctrl = readl ( & regs - > LocalCtrl ) ;
writel ( 0 , & regs - > LocalCtrl ) ;
writel ( 0 , & regs - > EvtPrd ) ;
writel ( 0 , & regs - > RxPrd ) ;
writel ( 0 , & regs - > TxPrd ) ;
/*
* First wipe the entire SRAM , otherwise we might run into all
* kinds of trouble . . . sigh , this took almost all afternoon
* to track down ; - (
*/
io = readl ( & regs - > ExtIo ) ;
writel ( 0 , & regs - > ExtIo ) ;
sram_size = rr_read_eeprom_word ( rrpriv , ( void * ) 8 ) ;
for ( i = 200 ; i < sram_size / 4 ; i + + ) {
writel ( i * 4 , & regs - > WinBase ) ;
mb ( ) ;
writel ( 0 , & regs - > WinData ) ;
mb ( ) ;
}
writel ( io , & regs - > ExtIo ) ;
mb ( ) ;
eptr = ( unsigned long ) rr_read_eeprom_word ( rrpriv ,
& hw - > rncd_info . AddrRunCodeSegs ) ;
eptr = ( ( eptr & 0x1fffff ) > > 3 ) ;
p2len = rr_read_eeprom_word ( rrpriv , ( void * ) ( 0x83 * 4 ) ) ;
p2len = ( p2len < < 2 ) ;
p2size = rr_read_eeprom_word ( rrpriv , ( void * ) ( 0x84 * 4 ) ) ;
p2size = ( ( p2size & 0x1fffff ) > > 3 ) ;
if ( ( eptr < p2size ) | | ( eptr > ( p2size + p2len ) ) ) {
printk ( " %s: eptr is invalid \n " , dev - > name ) ;
goto out ;
}
revision = rr_read_eeprom_word ( rrpriv , & hw - > manf . HeaderFmt ) ;
if ( revision ! = 1 ) {
printk ( " %s: invalid firmware format (%i) \n " ,
dev - > name , revision ) ;
goto out ;
}
nr_seg = rr_read_eeprom_word ( rrpriv , ( void * ) eptr ) ;
eptr + = 4 ;
# if (DEBUG > 1)
printk ( " %s: nr_seg %i \n " , dev - > name , nr_seg ) ;
# endif
for ( i = 0 ; i < nr_seg ; i + + ) {
sptr = rr_read_eeprom_word ( rrpriv , ( void * ) eptr ) ;
eptr + = 4 ;
len = rr_read_eeprom_word ( rrpriv , ( void * ) eptr ) ;
eptr + = 4 ;
segptr = ( unsigned long ) rr_read_eeprom_word ( rrpriv , ( void * ) eptr ) ;
segptr = ( ( segptr & 0x1fffff ) > > 3 ) ;
eptr + = 4 ;
# if (DEBUG > 1)
printk ( " %s: segment %i, sram address %06x, length %04x, segptr %06x \n " ,
dev - > name , i , sptr , len , segptr ) ;
# endif
for ( j = 0 ; j < len ; j + + ) {
tmp = rr_read_eeprom_word ( rrpriv , ( void * ) segptr ) ;
writel ( sptr , & regs - > WinBase ) ;
mb ( ) ;
writel ( tmp , & regs - > WinData ) ;
mb ( ) ;
segptr + = 4 ;
sptr + = 4 ;
}
}
out :
writel ( localctrl , & regs - > LocalCtrl ) ;
mb ( ) ;
return 0 ;
}
static int rr_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd )
{
struct rr_private * rrpriv ;
unsigned char * image , * oldimage ;
unsigned long flags ;
unsigned int i ;
int error = - EOPNOTSUPP ;
rrpriv = netdev_priv ( dev ) ;
switch ( cmd ) {
case SIOCRRGFW :
if ( ! capable ( CAP_SYS_RAWIO ) ) {
return - EPERM ;
}
image = kmalloc ( EEPROM_WORDS * sizeof ( u32 ) , GFP_KERNEL ) ;
if ( ! image ) {
printk ( KERN_ERR " %s: Unable to allocate memory "
" for EEPROM image \n " , dev - > name ) ;
return - ENOMEM ;
}
if ( rrpriv - > fw_running ) {
printk ( " %s: Firmware already running \n " , dev - > name ) ;
error = - EPERM ;
goto gf_out ;
}
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
i = rr_read_eeprom ( rrpriv , 0 , image , EEPROM_BYTES ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
if ( i ! = EEPROM_BYTES ) {
printk ( KERN_ERR " %s: Error reading EEPROM \n " ,
dev - > name ) ;
error = - EFAULT ;
goto gf_out ;
}
error = copy_to_user ( rq - > ifr_data , image , EEPROM_BYTES ) ;
if ( error )
error = - EFAULT ;
gf_out :
kfree ( image ) ;
return error ;
case SIOCRRPFW :
if ( ! capable ( CAP_SYS_RAWIO ) ) {
return - EPERM ;
}
image = kmalloc ( EEPROM_WORDS * sizeof ( u32 ) , GFP_KERNEL ) ;
oldimage = kmalloc ( EEPROM_WORDS * sizeof ( u32 ) , GFP_KERNEL ) ;
if ( ! image | | ! oldimage ) {
printk ( KERN_ERR " %s: Unable to allocate memory "
" for EEPROM image \n " , dev - > name ) ;
error = - ENOMEM ;
goto wf_out ;
}
error = copy_from_user ( image , rq - > ifr_data , EEPROM_BYTES ) ;
if ( error ) {
error = - EFAULT ;
goto wf_out ;
}
if ( rrpriv - > fw_running ) {
printk ( " %s: Firmware already running \n " , dev - > name ) ;
error = - EPERM ;
goto wf_out ;
}
printk ( " %s: Updating EEPROM firmware \n " , dev - > name ) ;
spin_lock_irqsave ( & rrpriv - > lock , flags ) ;
error = write_eeprom ( rrpriv , 0 , image , EEPROM_BYTES ) ;
if ( error )
printk ( KERN_ERR " %s: Error writing EEPROM \n " ,
dev - > name ) ;
i = rr_read_eeprom ( rrpriv , 0 , oldimage , EEPROM_BYTES ) ;
spin_unlock_irqrestore ( & rrpriv - > lock , flags ) ;
if ( i ! = EEPROM_BYTES )
printk ( KERN_ERR " %s: Error reading back EEPROM "
" image \n " , dev - > name ) ;
error = memcmp ( image , oldimage , EEPROM_BYTES ) ;
if ( error ) {
printk ( KERN_ERR " %s: Error verifying EEPROM image \n " ,
dev - > name ) ;
error = - EFAULT ;
}
wf_out :
if ( oldimage )
kfree ( oldimage ) ;
if ( image )
kfree ( image ) ;
return error ;
case SIOCRRID :
return put_user ( 0x52523032 , ( int __user * ) rq - > ifr_data ) ;
default :
return error ;
}
}
static struct pci_device_id rr_pci_tbl [ ] = {
{ PCI_VENDOR_ID_ESSENTIAL , PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER ,
PCI_ANY_ID , PCI_ANY_ID , } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , rr_pci_tbl ) ;
static struct pci_driver rr_driver = {
. name = " rrunner " ,
. id_table = rr_pci_tbl ,
. probe = rr_init_one ,
. remove = __devexit_p ( rr_remove_one ) ,
} ;
static int __init rr_init_module ( void )
{
return pci_module_init ( & rr_driver ) ;
}
static void __exit rr_cleanup_module ( void )
{
pci_unregister_driver ( & rr_driver ) ;
}
module_init ( rr_init_module ) ;
module_exit ( rr_cleanup_module ) ;
/*
* Local variables :
* compile - command : " gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c "
* End :
*/