Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
8a6d6a46
Commit
8a6d6a46
authored
May 27, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/spare/repo/netdev-2.6/farsync
into redhat.com:/spare/repo/net-drivers-2.6
parents
371969b3
b5a07f07
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
2328 additions
and
1183 deletions
+2328
-1183
drivers/net/wan/farsync.c
drivers/net/wan/farsync.c
+2179
-1181
drivers/net/wan/farsync.h
drivers/net/wan/farsync.h
+138
-2
include/linux/if.h
include/linux/if.h
+2
-0
include/linux/pci_ids.h
include/linux/pci_ids.h
+9
-0
No files found.
drivers/net/wan/farsync.c
View file @
8a6d6a46
/*
* FarSync
X21 driver for Linux (generic HDLC
version)
* FarSync
WAN driver for Linux (2.6.x kernel
version)
*
* Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
*
* Copyright (C) 2001 FarSite Communications Ltd.
* Copyright (C) 2001
-2004
FarSite Communications Ltd.
* www.farsite.co.uk
*
* This program is free software; you can redistribute it and/or
...
...
@@ -12,10 +12,12 @@
* 2 of the License, or (at your option) any later version.
*
* Author: R.J.Dunlop <bob.dunlop@farsite.co.uk>
* Maintainer: Kevin Curtis <kevin.curtis@farsite.co.uk>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/init.h>
...
...
@@ -25,29 +27,26 @@
#include "farsync.h"
/*
* Module info
*/
MODULE_AUTHOR
(
"R.J.Dunlop <bob.dunlop@farsite.co.uk>"
);
MODULE_DESCRIPTION
(
"FarSync T-Series X21 driver. FarSite Communications Ltd."
);
MODULE_DESCRIPTION
(
"FarSync T-Series WAN driver. FarSite Communications Ltd."
);
MODULE_PARM
(
fst_txq_low
,
"i"
);
MODULE_PARM
(
fst_txq_high
,
"i"
);
MODULE_PARM
(
fst_max_reads
,
"i"
);
MODULE_PARM
(
fst_excluded_cards
,
"i"
);
MODULE_PARM
(
fst_excluded_list
,
"0-32i"
);
MODULE_LICENSE
(
"GPL"
);
/* Driver configuration and global parameters
* ==========================================
*/
/* Number of ports (per card) supported
/* Number of ports (per card)
and cards
supported
*/
#define FST_MAX_PORTS 4
/* PCI vendor and device IDs
*/
#define FSC_PCI_VENDOR_ID 0x1619
/* FarSite Communications Ltd */
#define T2P_PCI_DEVICE_ID 0x0400
/* T2P X21 2 port card */
#define T4P_PCI_DEVICE_ID 0x0440
/* T4P X21 4 port card */
#define FST_MAX_CARDS 32
/* Default parameters for the link
*/
...
...
@@ -56,18 +55,34 @@ MODULE_LICENSE("GPL");
* this down assuming a slower line I
* guess.
*/
#define FST_TXQ_DEPTH 16
/* This one is for the buffering
* of frames on the way down to the card
* so that we can keep the card busy
* and maximise throughput
*/
#define FST_HIGH_WATER_MARK 12
/* Point at which we flow control
* network layer */
#define FST_LOW_WATER_MARK 8
/* Point at which we remove flow
* control from network layer */
#define FST_MAX_MTU 8000
/* Huge but possible */
#define FST_DEF_MTU 1500
/* Common sane value */
#define FST_TX_TIMEOUT (2*HZ)
#ifdef ARPHRD_RAWHDLC
#define ARPHRD_MYTYPE ARPHRD_RAWHDLC
/* Raw frames */
#else
#define ARPHRD_MYTYPE ARPHRD_HDLC
/* Cisco-HDLC (keepalives etc) */
#endif
/*
* Modules parameters and associated varaibles
*/
int
fst_txq_low
=
FST_LOW_WATER_MARK
;
int
fst_txq_high
=
FST_HIGH_WATER_MARK
;
int
fst_max_reads
=
7
;
int
fst_excluded_cards
=
0
;
int
fst_excluded_list
[
FST_MAX_CARDS
];
/* Card shared memory layout
* =========================
...
...
@@ -84,7 +99,7 @@ MODULE_LICENSE("GPL");
* be used to check that we have not got out of step with the firmware
* contained in the .CDE files.
*/
#define SMC_VERSION
11
#define SMC_VERSION
24
#define FST_MEMSIZE 0x100000
/* Size of card memory (1Mb) */
...
...
@@ -105,7 +120,6 @@ MODULE_LICENSE("GPL");
/* Interrupt retry time in milliseconds */
#define INT_RETRY_TIME 2
/* The Am186CH/CC processors support a SmartDMA mode using circular pools
* of buffer descriptors. The structure is almost identical to that used
* in the LANCE Ethernet controllers. Details available as PDF from the
...
...
@@ -157,8 +171,7 @@ struct rxdesc { /* Receive descriptor */
#define RX_STP 0x02
/* Rx: start of packet */
#define RX_ENP 0x01
/* Rx: end of packet */
/* Interrupts from the card are caused by various events and these are presented
/* Interrupts from the card are caused by various events which are presented
* in a circular buffer as several events may be processed on one physical int
*/
#define MAX_CIRBUFF 32
...
...
@@ -190,15 +203,58 @@ struct cirbuff {
#define TXC_UNDF 0x2A
#define TXD_UNDF 0x2B
#define F56_INT 0x2C
#define M32_INT 0x2D
#define TE1_ALMA 0x30
/* Port physical configuration. See farsync.h for field values */
struct
port_cfg
{
u16
lineInterface
;
/* Physical interface type */
u8
x25op
;
/* Unused at present */
u8
internalClock
;
/* 1 => internal clock, 0 => external */
u8
transparentMode
;
/* 1 => on, 0 => off */
u8
invertClock
;
/* 0 => normal, 1 => inverted */
u8
padBytes
[
6
];
/* Padding */
u32
lineSpeed
;
/* Speed in bps */
};
/* TE1 port physical configuration */
struct
su_config
{
u32
dataRate
;
u8
clocking
;
u8
framing
;
u8
structure
;
u8
interface
;
u8
coding
;
u8
lineBuildOut
;
u8
equalizer
;
u8
transparentMode
;
u8
loopMode
;
u8
range
;
u8
txBufferMode
;
u8
rxBufferMode
;
u8
startingSlot
;
u8
losThreshold
;
u8
enableIdleCode
;
u8
idleCode
;
u8
spare
[
44
];
};
/* TE1 Status */
struct
su_status
{
u32
receiveBufferDelay
;
u32
framingErrorCount
;
u32
codeViolationCount
;
u32
crcErrorCount
;
u32
lineAttenuation
;
u8
portStarted
;
u8
lossOfSignal
;
u8
receiveRemoteAlarm
;
u8
alarmIndicationSignal
;
u8
spare
[
40
];
};
/* Finally sling all the above together into the shared memory structure.
* Sorry it's a hodge podge of arrays, structures and unused bits, it's been
* evolving under NT for some time so I guess we're stuck with it.
...
...
@@ -256,14 +312,14 @@ struct fst_shared {
u16
portMailbox
[
FST_MAX_PORTS
][
2
];
/* command, modifier */
u16
cardMailbox
[
4
];
/* Not used */
/* Number of times that
card thinks the host has
/* Number of times the
card thinks the host has
* missed an interrupt by not acknowledging
* within 2mS (I guess NT has problems)
*/
u32
interruptRetryCount
;
/* Driver private data used as an ID. We'll not
* use this on Linux
I'd rather keep such things
* use this as
I'd rather keep such things
* in main memory rather than on the PCI bus
*/
u32
portHandle
[
FST_MAX_PORTS
];
...
...
@@ -290,9 +346,12 @@ struct fst_shared {
u16
portScheduleOffset
;
struct
su_config
suConfig
;
/* TE1 Bits */
struct
su_status
suStatus
;
u32
endOfSmcSignature
;
/* endOfSmcSignature MUST be the last member of
* the structure and marks the end of the
shared
* memory. Adapter code initializes its value
as
* the structure and marks the end of
shared
* memory. Adapter code initializes it
as
* END_SIG.
*/
};
...
...
@@ -309,6 +368,40 @@ struct fst_shared {
#define ABORTTX 5
/* Abort the transmitter for a port */
#define SETV24O 6
/* Set V24 outputs */
/* PLX Chip Register Offsets */
#define CNTRL_9052 0x50
/* Control Register */
#define CNTRL_9054 0x6c
/* Control Register */
#define INTCSR_9052 0x4c
/* Interrupt control/status register */
#define INTCSR_9054 0x68
/* Interrupt control/status register */
/* 9054 DMA Registers */
/*
* Note that we will be using DMA Channel 0 for copying rx data
* and Channel 1 for copying tx data
*/
#define DMAMODE0 0x80
#define DMAPADR0 0x84
#define DMALADR0 0x88
#define DMASIZ0 0x8c
#define DMADPR0 0x90
#define DMAMODE1 0x94
#define DMAPADR1 0x98
#define DMALADR1 0x9c
#define DMASIZ1 0xa0
#define DMADPR1 0xa4
#define DMACSR0 0xa8
#define DMACSR1 0xa9
#define DMAARB 0xac
#define DMATHR 0xb0
#define DMADAC0 0xb4
#define DMADAC1 0xb8
#define DMAMARBR 0xac
#define FST_MIN_DMA_LEN 64
#define FST_RX_DMA_INT 0x01
#define FST_TX_DMA_INT 0x02
#define FST_CARD_INT 0x04
/* Larger buffers are positioned in memory at offset BFM_BASE */
struct
buf_window
{
...
...
@@ -317,26 +410,33 @@ struct buf_window {
};
/* Calculate offset of a buffer object within the shared memory window */
#define BUF_OFFSET(X)
offsetof(struct buf_window, X
)
#define BUF_OFFSET(X)
((unsigned int)&(((struct buf_window *)BFM_BASE)->X)
)
#pragma pack()
/* Device driver private information
* =================================
*/
/* Per port (line or channel) information
*/
struct
fst_port_info
{
struct
net_device
*
dev
;
struct
net_device
*
dev
;
/* Device struct - must be first */
struct
fst_card_info
*
card
;
/* Card we're associated with */
int
index
;
/* Port index on the card */
int
hwif
;
/* Line hardware (lineInterface copy) */
int
run
;
/* Port is running */
int
mode
;
/* Normal or FarSync raw */
int
rxpos
;
/* Next Rx buffer to use */
int
txpos
;
/* Next Tx buffer to use */
int
txipos
;
/* Next Tx buffer to check for free */
int
txcnt
;
/* Count of Tx buffers in use */
int
start
;
/* Indication of start/stop to network */
/*
* A sixteen entry transmit queue
*/
int
txqs
;
/* index to get next buffer to tx */
int
txqe
;
/* index to queue next packet */
struct
sk_buff
*
txq
[
FST_TXQ_DEPTH
];
/* The queue */
int
rxqdepth
;
};
/* Per card information
...
...
@@ -353,7 +453,25 @@ struct fst_card_info {
spinlock_t
card_lock
;
/* Lock for SMP access */
unsigned
short
pci_conf
;
/* PCI card config in I/O space */
/* Per port info */
struct
fst_port_info
ports
[
FST_MAX_PORTS
];
struct
fst_port_info
ports
[
FST_MAX_PORTS
];
struct
pci_dev
*
device
;
/* Information about the pci device */
int
card_no
;
/* Inst of the card on the system */
int
family
;
/* TxP or TxU */
int
dmarx_in_progress
;
int
dmatx_in_progress
;
unsigned
long
int_count
;
unsigned
long
int_time_ave
;
void
*
rx_dma_handle_host
;
dma_addr_t
rx_dma_handle_card
;
void
*
tx_dma_handle_host
;
dma_addr_t
tx_dma_handle_card
;
struct
sk_buff
*
dma_skb_rx
;
struct
fst_port_info
*
dma_port_rx
;
struct
fst_port_info
*
dma_port_tx
;
int
dma_len_rx
;
int
dma_len_tx
;
int
dma_txpos
;
int
dma_rxpos
;
};
/* Convert an HDLC device pointer into a port info pointer and similar */
...
...
@@ -380,7 +498,6 @@ struct fst_card_info {
#define FST_WRW(C,E,W) writew ((W), (C)->mem + WIN_OFFSET(E))
#define FST_WRL(C,E,L) writel ((L), (C)->mem + WIN_OFFSET(E))
/*
* Debug support
*/
...
...
@@ -399,30 +516,151 @@ static int fst_debug_mask = { FST_DEBUG };
printk ( KERN_DEBUG FST_NAME ": " fmt, ## A )
#else
#
define dbg(X...)
/* NOP */
#
define dbg(X...)
/* NOP */
#endif
/* Printing short cuts
*/
#define printk_err(fmt,A...) printk ( KERN_ERR FST_NAME ": " fmt, ## A )
#define printk_warn(fmt,A...) printk ( KERN_WARNING FST_NAME ": " fmt, ## A )
#define printk_info(fmt,A...) printk ( KERN_INFO FST_NAME ": " fmt, ## A )
/*
* PCI ID lookup table
*/
static
struct
pci_device_id
fst_pci_dev_id
[]
=
{
{
FSC_PCI_VENDOR_ID
,
T2P_PCI_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T2P
},
{
FSC_PCI_VENDOR_ID
,
T4P_PCI_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T4P
},
{
0
,
}
/* End */
static
struct
pci_device_id
fst_pci_dev_id
[]
__devinitdata
=
{
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_T2P
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T2P
},
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_T4P
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T4P
},
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_T1U
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T1U
},
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_T2U
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T2U
},
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_T4U
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_T4U
},
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_TE1
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_TE1
},
{
PCI_VENDOR_ID_FARSITE
,
PCI_DEVICE_ID_FARSITE_TE1C
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
FST_TYPE_TE1
},
{
0
,}
/* End */
};
MODULE_DEVICE_TABLE
(
pci
,
fst_pci_dev_id
);
MODULE_DEVICE_TABLE
(
pci
,
fst_pci_dev_id
);
/*
* Device Driver Work Queues
*
* So that we don't spend too much time processing events in the
* Interrupt Service routine, we will declare a work queue per Card
* and make the ISR schedule a task in the queue for later execution.
* In the 2.4 Kernel we used to use the immediate queue for BH's
* Now that they are gone, tasklets seem to be much better than work
* queues.
*/
static
void
do_bottom_half_tx
(
struct
fst_card_info
*
card
);
static
void
do_bottom_half_rx
(
struct
fst_card_info
*
card
);
static
void
fst_process_tx_work_q
(
unsigned
long
work_q
);
static
void
fst_process_int_work_q
(
unsigned
long
work_q
);
DECLARE_TASKLET
(
fst_tx_task
,
fst_process_tx_work_q
,
0
);
DECLARE_TASKLET
(
fst_int_task
,
fst_process_int_work_q
,
0
);
struct
fst_card_info
*
fst_card_array
[
FST_MAX_CARDS
];
spinlock_t
fst_work_q_lock
;
u64
fst_work_txq
;
u64
fst_work_intq
;
static
void
fst_q_work_item
(
u64
*
queue
,
int
card_index
)
{
unsigned
long
flags
;
u64
mask
;
/*
* Grab the queue exclusively
*/
spin_lock_irqsave
(
&
fst_work_q_lock
,
flags
);
/*
* Making an entry in the queue is simply a matter of setting
* a bit for the card indicating that there is work to do in the
* bottom half for the card. Note the limitation of 64 cards.
* That ought to be enough
*/
mask
=
1
<<
card_index
;
*
queue
|=
mask
;
spin_unlock_irqrestore
(
&
fst_work_q_lock
,
flags
);
}
static
void
fst_process_tx_work_q
(
unsigned
long
/*void **/
work_q
)
{
unsigned
long
flags
;
u64
work_txq
;
int
i
;
/*
* Grab the queue exclusively
*/
dbg
(
DBG_TX
,
"fst_process_tx_work_q
\n
"
);
spin_lock_irqsave
(
&
fst_work_q_lock
,
flags
);
work_txq
=
fst_work_txq
;
fst_work_txq
=
0
;
spin_unlock_irqrestore
(
&
fst_work_q_lock
,
flags
);
/*
* Call the bottom half for each card with work waiting
*/
for
(
i
=
0
;
i
<
FST_MAX_CARDS
;
i
++
)
{
if
(
work_txq
&
0x01
)
{
if
(
fst_card_array
[
i
]
!=
NULL
)
{
dbg
(
DBG_TX
,
"Calling tx bh for card %d
\n
"
,
i
);
do_bottom_half_tx
(
fst_card_array
[
i
]);
}
}
work_txq
=
work_txq
>>
1
;
}
}
static
void
fst_process_int_work_q
(
unsigned
long
/*void **/
work_q
)
{
unsigned
long
flags
;
u64
work_intq
;
int
i
;
/*
* Grab the queue exclusively
*/
dbg
(
DBG_INTR
,
"fst_process_int_work_q
\n
"
);
spin_lock_irqsave
(
&
fst_work_q_lock
,
flags
);
work_intq
=
fst_work_intq
;
fst_work_intq
=
0
;
spin_unlock_irqrestore
(
&
fst_work_q_lock
,
flags
);
/*
* Call the bottom half for each card with work waiting
*/
for
(
i
=
0
;
i
<
FST_MAX_CARDS
;
i
++
)
{
if
(
work_intq
&
0x01
)
{
if
(
fst_card_array
[
i
]
!=
NULL
)
{
dbg
(
DBG_INTR
,
"Calling rx & tx bh for card %d
\n
"
,
i
);
do_bottom_half_rx
(
fst_card_array
[
i
]);
do_bottom_half_tx
(
fst_card_array
[
i
]);
}
}
work_intq
=
work_intq
>>
1
;
}
}
/* Card control functions
* ======================
...
...
@@ -432,52 +670,296 @@ MODULE_DEVICE_TABLE ( pci, fst_pci_dev_id );
* Used to be a simple write to card control space but a glitch in the latest
* AMD Am186CH processor means that we now have to do it by asserting and de-
* asserting the PLX chip PCI Adapter Software Reset. Bit 30 in CNTRL register
* at offset
0x50
.
* at offset
9052_CNTRL. Note the updates for the TXU
.
*/
static
inline
void
fst_cpureset
(
struct
fst_card_info
*
card
)
fst_cpureset
(
struct
fst_card_info
*
card
)
{
unsigned
char
interrupt_line_register
;
unsigned
long
j
=
jiffies
+
1
;
unsigned
int
regval
;
regval
=
inl
(
card
->
pci_conf
+
0x50
);
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
if
(
pci_read_config_byte
(
card
->
device
,
PCI_INTERRUPT_LINE
,
&
interrupt_line_register
))
{
dbg
(
DBG_ASS
,
"Error in reading interrupt line register
\n
"
);
}
/*
* Assert PLX software reset and Am186 hardware reset
* and then deassert the PLX software reset but 186 still in reset
*/
outw
(
0x440f
,
card
->
pci_conf
+
CNTRL_9054
+
2
);
outw
(
0x040f
,
card
->
pci_conf
+
CNTRL_9054
+
2
);
/*
* We are delaying here to allow the 9054 to reset itself
*/
j
=
jiffies
+
1
;
while
(
jiffies
<
j
)
/* Do nothing */
;
outw
(
0x240f
,
card
->
pci_conf
+
CNTRL_9054
+
2
);
/*
* We are delaying here to allow the 9054 to reload its eeprom
*/
j
=
jiffies
+
1
;
while
(
jiffies
<
j
)
/* Do nothing */
;
outw
(
0x040f
,
card
->
pci_conf
+
CNTRL_9054
+
2
);
if
(
pci_write_config_byte
(
card
->
device
,
PCI_INTERRUPT_LINE
,
interrupt_line_register
))
{
dbg
(
DBG_ASS
,
"Error in writing interrupt line register
\n
"
);
}
}
else
{
regval
=
inl
(
card
->
pci_conf
+
CNTRL_9052
);
outl
(
regval
|
0x40000000
,
card
->
pci_conf
+
0x50
);
outl
(
regval
&
~
0x40000000
,
card
->
pci_conf
+
0x50
);
outl
(
regval
|
0x40000000
,
card
->
pci_conf
+
CNTRL_9052
);
outl
(
regval
&
~
0x40000000
,
card
->
pci_conf
+
CNTRL_9052
);
}
}
/* Release the processor from reset
*/
static
inline
void
fst_cpurelease
(
struct
fst_card_info
*
card
)
fst_cpurelease
(
struct
fst_card_info
*
card
)
{
(
void
)
readb
(
card
->
ctlmem
);
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
/*
* Force posted writes to complete
*/
(
void
)
readb
(
card
->
mem
);
/*
* Release LRESET DO = 1
* Then release Local Hold, DO = 1
*/
outw
(
0x040e
,
card
->
pci_conf
+
CNTRL_9054
+
2
);
outw
(
0x040f
,
card
->
pci_conf
+
CNTRL_9054
+
2
);
}
else
{
(
void
)
readb
(
card
->
ctlmem
);
}
}
/* Clear the cards interrupt flag
*/
static
inline
void
fst_clear_intr
(
struct
fst_card_info
*
card
)
fst_clear_intr
(
struct
fst_card_info
*
card
)
{
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
(
void
)
readb
(
card
->
ctlmem
);
}
else
{
/* Poke the appropriate PLX chip register (same as enabling interrupts)
*/
outw
(
0x0543
,
card
->
pci_conf
+
0x4C
);
outw
(
0x0543
,
card
->
pci_conf
+
INTCSR_9052
);
}
}
/* Enable card interrupts
*/
static
inline
void
fst_enable_intr
(
struct
fst_card_info
*
card
)
{
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
outl
(
0x0f0c0900
,
card
->
pci_conf
+
INTCSR_9054
);
}
else
{
outw
(
0x0543
,
card
->
pci_conf
+
INTCSR_9052
);
}
}
/* Disable card interrupts
*/
static
inline
void
fst_disable_intr
(
struct
fst_card_info
*
card
)
fst_disable_intr
(
struct
fst_card_info
*
card
)
{
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
outl
(
0x00000000
,
card
->
pci_conf
+
INTCSR_9054
);
}
else
{
outw
(
0x0000
,
card
->
pci_conf
+
INTCSR_9052
);
}
}
/* Process the result of trying to pass a recieved frame up the stack
*/
static
void
fst_process_rx_status
(
int
rx_status
,
char
*
name
)
{
switch
(
rx_status
)
{
case
NET_RX_SUCCESS
:
{
/*
* Nothing to do here
*/
break
;
}
case
NET_RX_CN_LOW
:
{
dbg
(
DBG_ASS
,
"%s: Receive Low Congestion
\n
"
,
name
);
break
;
}
case
NET_RX_CN_MOD
:
{
dbg
(
DBG_ASS
,
"%s: Receive Moderate Congestion
\n
"
,
name
);
break
;
}
case
NET_RX_CN_HIGH
:
{
dbg
(
DBG_ASS
,
"%s: Receive High Congestion
\n
"
,
name
);
break
;
}
case
NET_RX_DROP
:
{
dbg
(
DBG_ASS
,
"%s: Received packet dropped
\n
"
,
name
);
break
;
}
}
}
/* Initilaise DMA for PLX 9054
*/
static
inline
void
fst_init_dma
(
struct
fst_card_info
*
card
)
{
outw
(
0x0000
,
card
->
pci_conf
+
0x4C
);
/*
* This is only required for the PLX 9054
*/
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
pci_set_master
(
card
->
device
);
outl
(
0x00020441
,
card
->
pci_conf
+
DMAMODE0
);
outl
(
0x00020441
,
card
->
pci_conf
+
DMAMODE1
);
outl
(
0x0
,
card
->
pci_conf
+
DMATHR
);
}
}
/* Tx dma complete interrupt
*/
static
void
fst_tx_dma_complete
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
int
len
,
int
txpos
)
{
struct
net_device
*
dev
=
port_to_dev
(
port
);
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
);
/*
* Everything is now set, just tell the card to go
*/
dbg
(
DBG_TX
,
"fst_tx_dma_complete
\n
"
);
FST_WRB
(
card
,
txDescrRing
[
port
->
index
][
txpos
].
bits
,
DMA_OWN
|
TX_STP
|
TX_ENP
);
stats
->
tx_packets
++
;
stats
->
tx_bytes
+=
len
;
dev
->
trans_start
=
jiffies
;
}
/* Rx dma complete interrupt
*/
static
void
fst_rx_dma_complete
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
int
len
,
struct
sk_buff
*
skb
,
int
rxp
)
{
struct
net_device
*
dev
=
port_to_dev
(
port
);
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
);
int
pi
;
int
rx_status
;
dbg
(
DBG_TX
,
"fst_rx_dma_complete
\n
"
);
pi
=
port
->
index
;
memcpy
(
skb_put
(
skb
,
len
),
card
->
rx_dma_handle_host
,
len
);
/* Reset buffer descriptor */
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
/* Update stats */
stats
->
rx_packets
++
;
stats
->
rx_bytes
+=
len
;
/* Push upstream */
dbg
(
DBG_RX
,
"Pushing the frame up the stack
\n
"
);
skb
->
mac
.
raw
=
skb
->
data
;
skb
->
dev
=
dev
;
if
(
port
->
mode
==
FST_RAW
)
{
/*
* Mark it for our own raw sockets interface
*/
skb
->
protocol
=
htons
(
ETH_P_CUST
);
skb
->
pkt_type
=
PACKET_HOST
;
}
else
{
skb
->
protocol
=
hdlc_type_trans
(
skb
,
skb
->
dev
);
}
rx_status
=
netif_rx
(
skb
);
fst_process_rx_status
(
rx_status
,
port_to_dev
(
port
)
->
name
);
if
(
rx_status
==
NET_RX_DROP
)
stats
->
rx_dropped
++
;
dev
->
last_rx
=
jiffies
;
}
/*
* Receive a frame through the DMA
*/
static
inline
void
fst_rx_dma
(
struct
fst_card_info
*
card
,
unsigned
char
*
skb
,
unsigned
char
*
mem
,
int
len
)
{
/*
* This routine will setup the DMA and start it
*/
dbg
(
DBG_RX
,
"In fst_rx_dma %p %p %d
\n
"
,
skb
,
mem
,
len
);
if
(
card
->
dmarx_in_progress
)
{
dbg
(
DBG_ASS
,
"In fst_rx_dma while dma in progress
\n
"
);
}
outl
((
unsigned
long
)
skb
,
card
->
pci_conf
+
DMAPADR0
);
/* Copy to here */
outl
((
unsigned
long
)
mem
,
card
->
pci_conf
+
DMALADR0
);
/* from here */
outl
(
len
,
card
->
pci_conf
+
DMASIZ0
);
/* for this length */
outl
(
0x00000000c
,
card
->
pci_conf
+
DMADPR0
);
/* In this direction */
/*
* We use the dmarx_in_progress flag to flag the channel as busy
*/
card
->
dmarx_in_progress
=
1
;
outb
(
0x03
,
card
->
pci_conf
+
DMACSR0
);
/* Start the transfer */
}
/*
* Send a frame through the DMA
*/
static
inline
void
fst_tx_dma
(
struct
fst_card_info
*
card
,
unsigned
char
*
skb
,
unsigned
char
*
mem
,
int
len
)
{
/*
* This routine will setup the DMA and start it.
*/
dbg
(
DBG_TX
,
"In fst_tx_dma %p %p %d
\n
"
,
skb
,
mem
,
len
);
if
(
card
->
dmatx_in_progress
)
{
dbg
(
DBG_ASS
,
"In fst_tx_dma while dma in progress
\n
"
);
}
outl
((
unsigned
long
)
skb
,
card
->
pci_conf
+
DMAPADR1
);
/* Copy from here */
outl
((
unsigned
long
)
mem
,
card
->
pci_conf
+
DMALADR1
);
/* to here */
outl
(
len
,
card
->
pci_conf
+
DMASIZ1
);
/* for this length */
outl
(
0x000000004
,
card
->
pci_conf
+
DMADPR1
);
/* In this direction */
/*
* We use the dmatx_in_progress to flag the channel as busy
*/
card
->
dmatx_in_progress
=
1
;
outb
(
0x03
,
card
->
pci_conf
+
DMACSR1
);
/* Start the transfer */
}
/* Issue a Mailbox command for a port.
* Note we issue them on a fire and forget basis, not expecting to see an
* error and not waiting for completion.
*/
static
void
fst_issue_cmd
(
struct
fst_port_info
*
port
,
unsigned
short
cmd
)
fst_issue_cmd
(
struct
fst_port_info
*
port
,
unsigned
short
cmd
)
{
struct
fst_card_info
*
card
;
unsigned
short
mbval
;
...
...
@@ -485,75 +967,68 @@ fst_issue_cmd ( struct fst_port_info *port, unsigned short cmd )
int
safety
;
card
=
port
->
card
;
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
mbval
=
FST_RDW
(
card
,
portMailbox
[
port
->
index
][
0
]);
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
mbval
=
FST_RDW
(
card
,
portMailbox
[
port
->
index
][
0
]);
safety
=
0
;
/* Wait for any previous command to complete */
while
(
mbval
>
NAK
)
{
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
schedule_timeout
(
1
);
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
while
(
mbval
>
NAK
)
{
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
schedule_timeout
(
1
);
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
if
(
++
safety
>
1000
)
{
printk_err
(
"Mailbox safety timeout
\n
"
);
if
(
++
safety
>
2000
)
{
printk_err
(
"Mailbox safety timeout
\n
"
);
break
;
}
mbval
=
FST_RDW
(
card
,
portMailbox
[
port
->
index
][
0
]);
mbval
=
FST_RDW
(
card
,
portMailbox
[
port
->
index
][
0
]);
}
if
(
safety
>
0
)
{
dbg
(
DBG_CMD
,
"Mailbox clear after %d jiffies
\n
"
,
safety
);
if
(
safety
>
0
)
{
dbg
(
DBG_CMD
,
"Mailbox clear after %d jiffies
\n
"
,
safety
);
}
if
(
mbval
==
NAK
)
{
dbg
(
DBG_CMD
,
"issue_cmd: previous command was NAK'd
\n
"
);
if
(
mbval
==
NAK
)
{
dbg
(
DBG_CMD
,
"issue_cmd: previous command was NAK'd
\n
"
);
}
FST_WRW
(
card
,
portMailbox
[
port
->
index
][
0
],
cmd
);
FST_WRW
(
card
,
portMailbox
[
port
->
index
][
0
],
cmd
);
if
(
cmd
==
ABORTTX
||
cmd
==
STARTPORT
)
{
if
(
cmd
==
ABORTTX
||
cmd
==
STARTPORT
)
{
port
->
txpos
=
0
;
port
->
txipos
=
0
;
port
->
txcnt
=
0
;
port
->
start
=
0
;
}
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
}
/* Port output signals control
*/
static
inline
void
fst_op_raise
(
struct
fst_port_info
*
port
,
unsigned
int
outputs
)
fst_op_raise
(
struct
fst_port_info
*
port
,
unsigned
int
outputs
)
{
outputs
|=
FST_RDL
(
port
->
card
,
v24OpSts
[
port
->
index
]);
FST_WRL
(
port
->
card
,
v24OpSts
[
port
->
index
],
outputs
);
outputs
|=
FST_RDL
(
port
->
card
,
v24OpSts
[
port
->
index
]);
FST_WRL
(
port
->
card
,
v24OpSts
[
port
->
index
],
outputs
);
if
(
port
->
run
)
fst_issue_cmd
(
port
,
SETV24O
);
if
(
port
->
run
)
fst_issue_cmd
(
port
,
SETV24O
);
}
static
inline
void
fst_op_lower
(
struct
fst_port_info
*
port
,
unsigned
int
outputs
)
fst_op_lower
(
struct
fst_port_info
*
port
,
unsigned
int
outputs
)
{
outputs
=
~
outputs
&
FST_RDL
(
port
->
card
,
v24OpSts
[
port
->
index
]);
FST_WRL
(
port
->
card
,
v24OpSts
[
port
->
index
],
outputs
);
outputs
=
~
outputs
&
FST_RDL
(
port
->
card
,
v24OpSts
[
port
->
index
]);
FST_WRL
(
port
->
card
,
v24OpSts
[
port
->
index
],
outputs
);
if
(
port
->
run
)
fst_issue_cmd
(
port
,
SETV24O
);
if
(
port
->
run
)
fst_issue_cmd
(
port
,
SETV24O
);
}
/*
* Setup port Rx buffers
*/
static
void
fst_rx_config
(
struct
fst_port_info
*
port
)
fst_rx_config
(
struct
fst_port_info
*
port
)
{
int
i
;
int
pi
;
...
...
@@ -563,28 +1038,25 @@ fst_rx_config ( struct fst_port_info *port )
pi
=
port
->
index
;
card
=
port
->
card
;
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
for
(
i
=
0
;
i
<
NUM_RX_BUFFER
;
i
++
)
{
offset
=
BUF_OFFSET
(
rxBuffer
[
pi
][
i
][
0
]);
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
for
(
i
=
0
;
i
<
NUM_RX_BUFFER
;
i
++
)
{
offset
=
BUF_OFFSET
(
rxBuffer
[
pi
][
i
][
0
]);
FST_WRW
(
card
,
rxDescrRing
[
pi
][
i
].
ladr
,
(
u16
)
offset
);
FST_WRB
(
card
,
rxDescrRing
[
pi
][
i
].
hadr
,
(
u8
)(
offset
>>
16
));
FST_WRW
(
card
,
rxDescrRing
[
pi
][
i
].
bcnt
,
cnv_bcnt
(
LEN_RX_BUFFER
));
FST_WRW
(
card
,
rxDescrRing
[
pi
][
i
].
mcnt
,
0
);
FST_WRB
(
card
,
rxDescrRing
[
pi
][
i
].
bits
,
DMA_OWN
);
FST_WRW
(
card
,
rxDescrRing
[
pi
][
i
].
ladr
,
(
u16
)
offset
);
FST_WRB
(
card
,
rxDescrRing
[
pi
][
i
].
hadr
,
(
u8
)
(
offset
>>
16
));
FST_WRW
(
card
,
rxDescrRing
[
pi
][
i
].
bcnt
,
cnv_bcnt
(
LEN_RX_BUFFER
));
FST_WRW
(
card
,
rxDescrRing
[
pi
][
i
].
mcnt
,
LEN_RX_BUFFER
);
FST_WRB
(
card
,
rxDescrRing
[
pi
][
i
].
bits
,
DMA_OWN
);
}
port
->
rxpos
=
0
;
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
}
/*
* Setup port Tx buffers
*/
static
void
fst_tx_config
(
struct
fst_port_info
*
port
)
fst_tx_config
(
struct
fst_port_info
*
port
)
{
int
i
;
int
pi
;
...
...
@@ -594,238 +1066,564 @@ fst_tx_config ( struct fst_port_info *port )
pi
=
port
->
index
;
card
=
port
->
card
;
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
for
(
i
=
0
;
i
<
NUM_TX_BUFFER
;
i
++
)
{
offset
=
BUF_OFFSET
(
txBuffer
[
pi
][
i
][
0
]);
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
for
(
i
=
0
;
i
<
NUM_TX_BUFFER
;
i
++
)
{
offset
=
BUF_OFFSET
(
txBuffer
[
pi
][
i
][
0
]);
FST_WRW
(
card
,
txDescrRing
[
pi
][
i
].
ladr
,
(
u16
)
offset
);
FST_WRB
(
card
,
txDescrRing
[
pi
][
i
].
hadr
,
(
u8
)(
offset
>>
16
));
FST_WRW
(
card
,
txDescrRing
[
pi
][
i
].
bcnt
,
0
);
FST_WRB
(
card
,
txDescrRing
[
pi
][
i
].
bits
,
0
);
FST_WRW
(
card
,
txDescrRing
[
pi
][
i
].
ladr
,
(
u16
)
offset
);
FST_WRB
(
card
,
txDescrRing
[
pi
][
i
].
hadr
,
(
u8
)
(
offset
>>
16
));
FST_WRW
(
card
,
txDescrRing
[
pi
][
i
].
bcnt
,
0
);
FST_WRB
(
card
,
txDescrRing
[
pi
][
i
].
bits
,
0
);
}
port
->
txpos
=
0
;
port
->
txipos
=
0
;
port
->
txcnt
=
0
;
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
port
->
start
=
0
;
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
}
/* TE1 Alarm change interrupt event
*/
static
void
fst_intr_te1_alarm
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
)
{
u8
los
;
u8
rra
;
u8
ais
;
los
=
FST_RDB
(
card
,
suStatus
.
lossOfSignal
);
rra
=
FST_RDB
(
card
,
suStatus
.
receiveRemoteAlarm
);
ais
=
FST_RDB
(
card
,
suStatus
.
alarmIndicationSignal
);
if
(
los
)
{
/*
* Lost the link
*/
if
(
netif_carrier_ok
(
port_to_dev
(
port
)))
{
dbg
(
DBG_INTR
,
"Net carrier off
\n
"
);
netif_carrier_off
(
port_to_dev
(
port
));
}
}
else
{
/*
* Link available
*/
if
(
!
netif_carrier_ok
(
port_to_dev
(
port
)))
{
dbg
(
DBG_INTR
,
"Net carrier on
\n
"
);
netif_carrier_on
(
port_to_dev
(
port
));
}
}
if
(
los
)
dbg
(
DBG_INTR
,
"Assert LOS Alarm
\n
"
);
else
dbg
(
DBG_INTR
,
"De-assert LOS Alarm
\n
"
);
if
(
rra
)
dbg
(
DBG_INTR
,
"Assert RRA Alarm
\n
"
);
else
dbg
(
DBG_INTR
,
"De-assert RRA Alarm
\n
"
);
if
(
ais
)
dbg
(
DBG_INTR
,
"Assert AIS Alarm
\n
"
);
else
dbg
(
DBG_INTR
,
"De-assert AIS Alarm
\n
"
);
}
/* Control signal change interrupt event
*/
static
irqreturn_t
fst_intr_ctlchg
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
)
static
void
fst_intr_ctlchg
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
)
{
int
signals
;
signals
=
FST_RDL
(
card
,
v24DebouncedSts
[
port
->
index
]);
signals
=
FST_RDL
(
card
,
v24DebouncedSts
[
port
->
index
]);
if
(
signals
&
((
port
->
hwif
==
X21
)
?
IPSTS_INDICATE
:
IPSTS_DCD
))
{
if
(
!
netif_carrier_ok
(
port_to_dev
(
port
)))
{
dbg
(
DBG_INTR
,
"DCD active
\n
"
);
netif_carrier_on
(
port_to_dev
(
port
));
if
(
signals
&
(((
port
->
hwif
==
X21
)
||
(
port
->
hwif
==
X21D
))
?
IPSTS_INDICATE
:
IPSTS_DCD
))
{
if
(
!
netif_carrier_ok
(
port_to_dev
(
port
)))
{
dbg
(
DBG_INTR
,
"DCD active
\n
"
);
netif_carrier_on
(
port_to_dev
(
port
));
}
}
else
{
if
(
netif_carrier_ok
(
port_to_dev
(
port
)))
{
dbg
(
DBG_INTR
,
"DCD lost
\n
"
);
netif_carrier_off
(
port_to_dev
(
port
));
}
else
{
if
(
netif_carrier_ok
(
port_to_dev
(
port
)))
{
dbg
(
DBG_INTR
,
"DCD lost
\n
"
);
netif_carrier_off
(
port_to_dev
(
port
));
}
}
/* Log Rx Errors
*/
static
void
fst_log_rx_error
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
unsigned
char
dmabits
,
int
rxp
,
unsigned
short
len
)
{
struct
net_device
*
dev
=
port_to_dev
(
port
);
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
);
/*
* Increment the appropriate error counter
*/
stats
->
rx_errors
++
;
if
(
dmabits
&
RX_OFLO
)
{
stats
->
rx_fifo_errors
++
;
dbg
(
DBG_ASS
,
"Rx fifo error on card %d port %d buffer %d
\n
"
,
card
->
card_no
,
port
->
index
,
rxp
);
}
if
(
dmabits
&
RX_CRC
)
{
stats
->
rx_crc_errors
++
;
dbg
(
DBG_ASS
,
"Rx crc error on card %d port %d
\n
"
,
card
->
card_no
,
port
->
index
);
}
if
(
dmabits
&
RX_FRAM
)
{
stats
->
rx_frame_errors
++
;
dbg
(
DBG_ASS
,
"Rx frame error on card %d port %d
\n
"
,
card
->
card_no
,
port
->
index
);
}
if
(
dmabits
==
(
RX_STP
|
RX_ENP
))
{
stats
->
rx_length_errors
++
;
dbg
(
DBG_ASS
,
"Rx length error (%d) on card %d port %d
\n
"
,
len
,
card
->
card_no
,
port
->
index
);
}
return
IRQ_HANDLED
;
}
/* Rx Error Recovery
*/
static
void
fst_recover_rx_error
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
unsigned
char
dmabits
,
int
rxp
,
unsigned
short
len
)
{
int
i
;
int
pi
;
pi
=
port
->
index
;
/*
* Discard buffer descriptors until we see the start of the
* next frame. Note that for long frames this could be in
* a subsequent interrupt.
*/
i
=
0
;
while
((
dmabits
&
(
DMA_OWN
|
RX_STP
))
==
0
)
{
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
rxp
=
(
rxp
+
1
)
%
NUM_RX_BUFFER
;
if
(
++
i
>
NUM_RX_BUFFER
)
{
dbg
(
DBG_ASS
,
"intr_rx: Discarding more bufs"
" than we have
\n
"
);
break
;
}
dmabits
=
FST_RDB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
);
dbg
(
DBG_ASS
,
"DMA Bits of next buffer was %x
\n
"
,
dmabits
);
}
dbg
(
DBG_ASS
,
"There were %d subsequent buffers in error
\n
"
,
i
);
/* Discard the terminal buffer */
if
(
!
(
dmabits
&
DMA_OWN
))
{
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
rxp
=
(
rxp
+
1
)
%
NUM_RX_BUFFER
;
}
port
->
rxpos
=
rxp
;
return
;
}
/* Rx complete interrupt
*/
static
void
fst_intr_rx
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
)
fst_intr_rx
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
)
{
unsigned
char
dmabits
;
int
pi
;
int
rxp
;
int
rx_status
;
unsigned
short
len
;
struct
sk_buff
*
skb
;
struct
net_device
*
dev
=
port_to_dev
(
port
);
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
);
int
i
;
/* Check we have a buffer to process */
pi
=
port
->
index
;
rxp
=
port
->
rxpos
;
dmabits
=
FST_RDB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
);
if
(
dmabits
&
DMA_OWN
)
{
dbg
(
DBG_RX
|
DBG_INTR
,
"intr_rx: No buffer port %d pos %d
\n
"
,
pi
,
rxp
);
dmabits
=
FST_RDB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
);
if
(
dmabits
&
DMA_OWN
)
{
dbg
(
DBG_RX
|
DBG_INTR
,
"intr_rx: No buffer port %d pos %d
\n
"
,
pi
,
rxp
);
return
;
}
if
(
card
->
dmarx_in_progress
)
{
return
;
}
/* Get buffer length */
len
=
FST_RDW
(
card
,
rxDescrRing
[
pi
][
rxp
].
mcnt
);
len
=
FST_RDW
(
card
,
rxDescrRing
[
pi
][
rxp
].
mcnt
);
/* Discard the CRC */
len
-=
2
;
/* Check buffer length and for other errors. We insist on one packet
* in one buffer. This simplifies things greatly and since we've
* allocated 8K it shouldn't be a real world limitation
if
(
len
==
0
)
{
/*
* This seems to happen on the TE1 interface sometimes
* so throw the frame away and log the event.
*/
dbg
(
DBG_RX
,
"intr_rx: %d,%d: flags %x len %d
\n
"
,
pi
,
rxp
,
dmabits
,
len
);
if
(
dmabits
!=
(
RX_STP
|
RX_ENP
)
||
len
>
LEN_RX_BUFFER
-
2
)
{
stats
->
rx_errors
++
;
printk_err
(
"Frame received with 0 length. Card %d Port %d
\n
"
,
card
->
card_no
,
port
->
index
);
/* Return descriptor to card */
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
/* Update error stats and discard buffer */
if
(
dmabits
&
RX_OFLO
)
{
stats
->
rx_fifo_errors
++
;
}
if
(
dmabits
&
RX_CRC
)
{
stats
->
rx_crc_errors
++
;
}
if
(
dmabits
&
RX_FRAM
)
{
stats
->
rx_frame_errors
++
;
}
if
(
dmabits
==
(
RX_STP
|
RX_ENP
))
{
stats
->
rx_length_errors
++
;
rxp
=
(
rxp
+
1
)
%
NUM_RX_BUFFER
;
port
->
rxpos
=
rxp
;
return
;
}
/* Discard buffer descriptors until we see the end of packet
* marker
/* Check buffer length and for other errors. We insist on one packet
* in one buffer. This simplifies things greatly and since we've
* allocated 8K it shouldn't be a real world limitation
*/
i
=
0
;
while
((
dmabits
&
(
DMA_OWN
|
RX_ENP
))
==
0
)
{
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
if
(
++
rxp
>=
NUM_RX_BUFFER
)
rxp
=
0
;
if
(
++
i
>
NUM_RX_BUFFER
)
{
dbg
(
DBG_ASS
,
"intr_rx: Discarding more bufs"
" than we have
\n
"
);
break
;
}
dmabits
=
FST_RDB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
);
}
/* Discard the terminal buffer */
if
(
!
(
dmabits
&
DMA_OWN
))
{
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
if
(
++
rxp
>=
NUM_RX_BUFFER
)
rxp
=
0
;
}
port
->
rxpos
=
rxp
;
dbg
(
DBG_RX
,
"intr_rx: %d,%d: flags %x len %d
\n
"
,
pi
,
rxp
,
dmabits
,
len
);
if
(
dmabits
!=
(
RX_STP
|
RX_ENP
)
||
len
>
LEN_RX_BUFFER
-
2
)
{
fst_log_rx_error
(
card
,
port
,
dmabits
,
rxp
,
len
);
fst_recover_rx_error
(
card
,
port
,
dmabits
,
rxp
,
len
);
return
;
}
/* Allocate SKB */
if
((
skb
=
dev_alloc_skb
(
len
))
==
NULL
)
{
dbg
(
DBG_RX
,
"intr_rx: can't allocate buffer
\n
"
);
if
((
skb
=
dev_alloc_skb
(
len
))
==
NULL
)
{
dbg
(
DBG_RX
,
"intr_rx: can't allocate buffer
\n
"
);
stats
->
rx_dropped
++
;
/* Return descriptor to card */
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
if
(
++
rxp
>=
NUM_RX_BUFFER
)
port
->
rxpos
=
0
;
else
rxp
=
(
rxp
+
1
)
%
NUM_RX_BUFFER
;
port
->
rxpos
=
rxp
;
return
;
}
memcpy_fromio
(
skb_put
(
skb
,
len
),
card
->
mem
+
BUF_OFFSET
(
rxBuffer
[
pi
][
rxp
][
0
]),
len
);
/*
* We know the length we need to receive, len.
* It's not worth using the DMA for reads of less than
* FST_MIN_DMA_LEN
*/
if
((
len
<
FST_MIN_DMA_LEN
)
||
(
card
->
family
==
FST_FAMILY_TXP
))
{
memcpy_fromio
(
skb_put
(
skb
,
len
),
card
->
mem
+
BUF_OFFSET
(
rxBuffer
[
pi
][
rxp
][
0
]),
len
);
/* Reset buffer descriptor */
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
if
(
++
rxp
>=
NUM_RX_BUFFER
)
port
->
rxpos
=
0
;
else
FST_WRB
(
card
,
rxDescrRing
[
pi
][
rxp
].
bits
,
DMA_OWN
);
/* Update stats */
stats
->
rx_packets
++
;
stats
->
rx_bytes
+=
len
;
/* Push upstream */
dbg
(
DBG_RX
,
"Pushing frame up the stack
\n
"
);
skb
->
mac
.
raw
=
skb
->
data
;
skb
->
dev
=
dev
;
if
(
port
->
mode
==
FST_RAW
)
{
/*
* Mark it for our own raw sockets interface
*/
skb
->
protocol
=
htons
(
ETH_P_CUST
);
skb
->
pkt_type
=
PACKET_HOST
;
}
else
{
skb
->
protocol
=
hdlc_type_trans
(
skb
,
skb
->
dev
);
}
rx_status
=
netif_rx
(
skb
);
fst_process_rx_status
(
rx_status
,
port_to_dev
(
port
)
->
name
);
if
(
rx_status
==
NET_RX_DROP
)
{
stats
->
rx_dropped
++
;
}
dev
->
last_rx
=
jiffies
;
}
else
{
card
->
dma_skb_rx
=
skb
;
card
->
dma_port_rx
=
port
;
card
->
dma_len_rx
=
len
;
card
->
dma_rxpos
=
rxp
;
fst_rx_dma
(
card
,
(
char
*
)
card
->
rx_dma_handle_card
,
(
char
*
)
BUF_OFFSET
(
rxBuffer
[
pi
][
rxp
][
0
]),
len
);
}
if
(
rxp
!=
port
->
rxpos
)
{
dbg
(
DBG_ASS
,
"About to increment rxpos by more than 1
\n
"
);
dbg
(
DBG_ASS
,
"rxp = %d rxpos = %d
\n
"
,
rxp
,
port
->
rxpos
);
}
rxp
=
(
rxp
+
1
)
%
NUM_RX_BUFFER
;
port
->
rxpos
=
rxp
;
}
/*
* The bottom halfs to the ISR
*
*/
static
void
do_bottom_half_tx
(
struct
fst_card_info
*
card
)
{
struct
fst_port_info
*
port
;
int
pi
;
int
txq_length
;
struct
sk_buff
*
skb
;
unsigned
long
flags
;
struct
net_device
*
dev
;
struct
net_device_stats
*
stats
;
/* Update stats */
stats
->
rx_packets
++
;
stats
->
rx_bytes
+=
len
;
/*
* Find a free buffer for the transmit
* Step through each port on this card
*/
/* Push upstream */
skb
->
mac
.
raw
=
skb
->
data
;
skb
->
dev
=
dev
;
skb
->
protocol
=
hdlc_type_trans
(
skb
,
skb
->
dev
);
netif_rx
(
skb
);
dbg
(
DBG_TX
,
"do_bottom_half_tx
\n
"
);
for
(
pi
=
0
,
port
=
card
->
ports
;
pi
<
card
->
nports
;
pi
++
,
port
++
)
{
if
(
!
port
->
run
)
continue
;
dev
->
last_rx
=
jiffies
;
dev
=
port_to_dev
(
port
);
stats
=
hdlc_stats
(
dev
);
while
(
!
(
FST_RDB
(
card
,
txDescrRing
[
pi
][
port
->
txpos
].
bits
)
&
DMA_OWN
)
&&
!
(
card
->
dmatx_in_progress
))
{
/*
* There doesn't seem to be a txdone event per-se
* We seem to have to deduce it, by checking the DMA_OWN
* bit on the next buffer we think we can use
*/
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
if
((
txq_length
=
port
->
txqe
-
port
->
txqs
)
<
0
)
{
/*
* This is the case where one has wrapped and the
* maths gives us a negative number
*/
txq_length
=
txq_length
+
FST_TXQ_DEPTH
;
}
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
if
(
txq_length
>
0
)
{
/*
* There is something to send
*/
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
skb
=
port
->
txq
[
port
->
txqs
];
port
->
txqs
++
;
if
(
port
->
txqs
==
FST_TXQ_DEPTH
)
{
port
->
txqs
=
0
;
}
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
/*
* copy the data and set the required indicators on the
* card.
*/
FST_WRW
(
card
,
txDescrRing
[
pi
][
port
->
txpos
].
bcnt
,
cnv_bcnt
(
skb
->
len
));
if
((
skb
->
len
<
FST_MIN_DMA_LEN
)
||
(
card
->
family
==
FST_FAMILY_TXP
))
{
/* Enqueue the packet with normal io */
memcpy_toio
(
card
->
mem
+
BUF_OFFSET
(
txBuffer
[
pi
]
[
port
->
txpos
][
0
]),
skb
->
data
,
skb
->
len
);
FST_WRB
(
card
,
txDescrRing
[
pi
][
port
->
txpos
].
bits
,
DMA_OWN
|
TX_STP
|
TX_ENP
);
stats
->
tx_packets
++
;
stats
->
tx_bytes
+=
skb
->
len
;
dev
->
trans_start
=
jiffies
;
}
else
{
/* Or do it through dma */
memcpy
(
card
->
tx_dma_handle_host
,
skb
->
data
,
skb
->
len
);
card
->
dma_port_tx
=
port
;
card
->
dma_len_tx
=
skb
->
len
;
card
->
dma_txpos
=
port
->
txpos
;
fst_tx_dma
(
card
,
(
char
*
)
card
->
tx_dma_handle_card
,
(
char
*
)
BUF_OFFSET
(
txBuffer
[
pi
]
[
port
->
txpos
][
0
]),
skb
->
len
);
}
if
(
++
port
->
txpos
>=
NUM_TX_BUFFER
)
port
->
txpos
=
0
;
/*
* If we have flow control on, can we now release it?
*/
if
(
port
->
start
)
{
if
(
txq_length
<
fst_txq_low
)
{
netif_wake_queue
(
port_to_dev
(
port
));
port
->
start
=
0
;
}
}
dev_kfree_skb
(
skb
);
}
else
{
/*
* Nothing to send so break out of the while loop
*/
break
;
}
}
}
}
static
void
do_bottom_half_rx
(
struct
fst_card_info
*
card
)
{
struct
fst_port_info
*
port
;
int
pi
;
int
rx_count
=
0
;
/* Check for rx completions on all ports on this card */
dbg
(
DBG_RX
,
"do_bottom_half_rx
\n
"
);
for
(
pi
=
0
,
port
=
card
->
ports
;
pi
<
card
->
nports
;
pi
++
,
port
++
)
{
if
(
!
port
->
run
)
continue
;
while
(
!
(
FST_RDB
(
card
,
rxDescrRing
[
pi
][
port
->
rxpos
].
bits
)
&
DMA_OWN
)
&&
!
(
card
->
dmarx_in_progress
))
{
if
(
rx_count
>
fst_max_reads
)
{
/*
* Don't spend forever in receive processing
* Schedule another event
*/
fst_q_work_item
(
&
fst_work_intq
,
card
->
card_no
);
tasklet_schedule
(
&
fst_int_task
);
break
;
/* Leave the loop */
}
fst_intr_rx
(
card
,
port
);
rx_count
++
;
}
}
}
/*
* The interrupt service routine
* Dev_id is our fst_card_info pointer
*/
static
irqreturn_t
fst_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
irqreturn_t
fst_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
fst_card_info
*
card
;
struct
fst_port_info
*
port
;
int
rdidx
;
/* Event buffer indices */
int
wridx
;
int
event
;
/* Actual event for processing */
int
pi
;
unsigned
int
dma_intcsr
=
0
;
unsigned
int
do_card_interrupt
;
unsigned
int
int_retry_count
;
if
((
card
=
dev_id
)
==
NULL
)
{
dbg
(
DBG_INTR
,
"intr: spurious %d
\n
"
,
irq
);
if
((
card
=
dev_id
)
==
NULL
)
{
dbg
(
DBG_INTR
,
"intr: spurious %d
\n
"
,
irq
);
return
IRQ_NONE
;
}
dbg
(
DBG_INTR
,
"intr: %d %p
\n
"
,
irq
,
card
);
/*
* Check to see if the interrupt was for this card
* return if not
* Note that the call to clear the interrupt is important
*/
dbg
(
DBG_INTR
,
"intr: %d %p
\n
"
,
irq
,
card
);
if
(
card
->
state
!=
FST_RUNNING
)
{
printk_err
(
"Interrupt received for card %d in a non running state (%d)
\n
"
,
card
->
card_no
,
card
->
state
);
spin_lock
(
&
card
->
card_lock
);
/*
* It is possible to really be running, i.e. we have re-loaded
* a running card
* Clear and reprime the interrupt source
*/
fst_clear_intr
(
card
);
return
IRQ_HANDLED
;
}
/* Clear and reprime the interrupt source */
fst_clear_intr
(
card
);
fst_clear_intr
(
card
);
/*
* Is the interrupt for this card (handshake == 1)
*/
do_card_interrupt
=
0
;
if
(
FST_RDB
(
card
,
interruptHandshake
)
==
1
)
{
do_card_interrupt
+=
FST_CARD_INT
;
/* Set the software acknowledge */
FST_WRB
(
card
,
interruptHandshake
,
0xEE
);
FST_WRB
(
card
,
interruptHandshake
,
0xEE
);
}
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
/*
* Is it a DMA Interrupt
*/
dma_intcsr
=
inl
(
card
->
pci_conf
+
INTCSR_9054
);
if
(
dma_intcsr
&
0x00200000
)
{
/*
* DMA Channel 0 (Rx transfer complete)
*/
dbg
(
DBG_RX
,
"DMA Rx xfer complete
\n
"
);
outb
(
0x8
,
card
->
pci_conf
+
DMACSR0
);
fst_rx_dma_complete
(
card
,
card
->
dma_port_rx
,
card
->
dma_len_rx
,
card
->
dma_skb_rx
,
card
->
dma_rxpos
);
card
->
dmarx_in_progress
=
0
;
do_card_interrupt
+=
FST_RX_DMA_INT
;
}
if
(
dma_intcsr
&
0x00400000
)
{
/*
* DMA Channel 1 (Tx transfer complete)
*/
dbg
(
DBG_TX
,
"DMA Tx xfer complete
\n
"
);
outb
(
0x8
,
card
->
pci_conf
+
DMACSR1
);
fst_tx_dma_complete
(
card
,
card
->
dma_port_tx
,
card
->
dma_len_tx
,
card
->
dma_txpos
);
card
->
dmatx_in_progress
=
0
;
do_card_interrupt
+=
FST_TX_DMA_INT
;
}
}
/* Drain the event queue */
rdidx
=
FST_RDB
(
card
,
interruptEvent
.
rdindex
);
wridx
=
FST_RDB
(
card
,
interruptEvent
.
wrindex
);
while
(
rdidx
!=
wridx
)
{
event
=
FST_RDB
(
card
,
interruptEvent
.
evntbuff
[
rdidx
]);
/*
* Have we been missing Interrupts
*/
int_retry_count
=
FST_RDL
(
card
,
interruptRetryCount
);
if
(
int_retry_count
)
{
dbg
(
DBG_ASS
,
"Card %d int_retry_count is %d
\n
"
,
card
->
card_no
,
int_retry_count
);
FST_WRL
(
card
,
interruptRetryCount
,
0
);
}
if
(
!
do_card_interrupt
)
{
return
IRQ_HANDLED
;
}
/* Scehdule the bottom half of the ISR */
fst_q_work_item
(
&
fst_work_intq
,
card
->
card_no
);
tasklet_schedule
(
&
fst_int_task
);
/* Drain the event queue */
rdidx
=
FST_RDB
(
card
,
interruptEvent
.
rdindex
)
&
0x1f
;
wridx
=
FST_RDB
(
card
,
interruptEvent
.
wrindex
)
&
0x1f
;
while
(
rdidx
!=
wridx
)
{
event
=
FST_RDB
(
card
,
interruptEvent
.
evntbuff
[
rdidx
]);
port
=
&
card
->
ports
[
event
&
0x03
];
dbg
(
DBG_INTR
,
"intr: %x
\n
"
,
event
);
dbg
(
DBG_INTR
,
"Processing Interrupt event: %x
\n
"
,
event
);
switch
(
event
)
{
case
TE1_ALMA
:
dbg
(
DBG_INTR
,
"TE1 Alarm intr
\n
"
);
if
(
port
->
run
)
fst_intr_te1_alarm
(
card
,
port
);
break
;
switch
(
event
)
{
case
CTLA_CHG
:
case
CTLB_CHG
:
case
CTLC_CHG
:
case
CTLD_CHG
:
if
(
port
->
run
)
fst_intr_ctlchg
(
card
,
port
);
if
(
port
->
run
)
fst_intr_ctlchg
(
card
,
port
);
break
;
case
ABTA_SENT
:
case
ABTB_SENT
:
case
ABTC_SENT
:
case
ABTD_SENT
:
dbg
(
DBG_TX
,
"Abort complete port %d
\n
"
,
event
&
0x03
);
dbg
(
DBG_TX
,
"Abort complete port %d
\n
"
,
port
->
index
);
break
;
case
TXA_UNDF
:
...
...
@@ -835,95 +1633,65 @@ fst_intr ( int irq, void *dev_id, struct pt_regs *regs )
/* Difficult to see how we'd get this given that we
* always load up the entire packet for DMA.
*/
dbg
(
DBG_TX
,
"Tx underflow port %d
\n
"
,
event
&
0x03
);
dbg
(
DBG_TX
,
"Tx underflow port %d
\n
"
,
port
->
index
);
hdlc_stats
(
port_to_dev
(
port
))
->
tx_errors
++
;
hdlc_stats
(
port_to_dev
(
port
))
->
tx_fifo_errors
++
;
hdlc_stats
(
port_to_dev
(
port
))
->
tx_fifo_errors
;
dbg
(
DBG_ASS
,
"Tx underflow on card %d port %d
\n
"
,
card
->
card_no
,
port
->
index
);
break
;
case
INIT_CPLT
:
dbg
(
DBG_INIT
,
"Card init OK intr
\n
"
);
dbg
(
DBG_INIT
,
"Card init OK intr
\n
"
);
break
;
case
INIT_FAIL
:
dbg
(
DBG_INIT
,
"Card init FAILED intr
\n
"
);
dbg
(
DBG_INIT
,
"Card init FAILED intr
\n
"
);
card
->
state
=
FST_IFAILED
;
break
;
default:
printk_err
(
"intr: unknown card event code. ignored
\n
"
);
printk_err
(
"intr: unknown card event %d. ignored
\n
"
,
event
);
break
;
}
/* Bump and wrap the index */
if
(
++
rdidx
>=
MAX_CIRBUFF
)
if
(
++
rdidx
>=
MAX_CIRBUFF
)
rdidx
=
0
;
}
FST_WRB
(
card
,
interruptEvent
.
rdindex
,
rdidx
);
for
(
pi
=
0
,
port
=
card
->
ports
;
pi
<
card
->
nports
;
pi
++
,
port
++
)
{
if
(
!
port
->
run
)
continue
;
/* Check for rx completions */
while
(
!
(
FST_RDB
(
card
,
rxDescrRing
[
pi
][
port
->
rxpos
].
bits
)
&
DMA_OWN
))
{
fst_intr_rx
(
card
,
port
);
}
/* Check for Tx completions */
while
(
port
->
txcnt
>
0
&&
!
(
FST_RDB
(
card
,
txDescrRing
[
pi
][
port
->
txipos
].
bits
)
&
DMA_OWN
))
{
--
port
->
txcnt
;
if
(
++
port
->
txipos
>=
NUM_TX_BUFFER
)
port
->
txipos
=
0
;
netif_wake_queue
(
port_to_dev
(
port
));
}
}
spin_unlock
(
&
card
->
card_lock
);
FST_WRB
(
card
,
interruptEvent
.
rdindex
,
rdidx
);
return
IRQ_HANDLED
;
}
/* Check that the shared memory configuration is one that we can handle
* and that some basic parameters are correct
*/
static
void
check_started_ok
(
struct
fst_card_info
*
card
)
check_started_ok
(
struct
fst_card_info
*
card
)
{
int
i
;
/* Check structure version and end marker */
if
(
FST_RDW
(
card
,
smcVersion
)
!=
SMC_VERSION
)
{
printk_err
(
"Bad shared memory version %d expected %d
\n
"
,
FST_RDW
(
card
,
smcVersion
),
SMC_VERSION
);
if
(
FST_RDW
(
card
,
smcVersion
)
!=
SMC_VERSION
)
{
printk_err
(
"Bad shared memory version %d expected %d
\n
"
,
FST_RDW
(
card
,
smcVersion
),
SMC_VERSION
);
card
->
state
=
FST_BADVERSION
;
return
;
}
if
(
FST_RDL
(
card
,
endOfSmcSignature
)
!=
END_SIG
)
{
printk_err
(
"Missing shared memory signature
\n
"
);
if
(
FST_RDL
(
card
,
endOfSmcSignature
)
!=
END_SIG
)
{
printk_err
(
"Missing shared memory signature
\n
"
);
card
->
state
=
FST_BADVERSION
;
return
;
}
/* Firmware status flag, 0x00 = initialising, 0x01 = OK, 0xFF = fail */
if
((
i
=
FST_RDB
(
card
,
taskStatus
))
==
0x01
)
{
if
((
i
=
FST_RDB
(
card
,
taskStatus
))
==
0x01
)
{
card
->
state
=
FST_RUNNING
;
}
else
if
(
i
==
0xFF
)
{
printk_err
(
"Firmware initialisation failed. Card halted
\n
"
);
}
else
if
(
i
==
0xFF
)
{
printk_err
(
"Firmware initialisation failed. Card halted
\n
"
);
card
->
state
=
FST_HALTED
;
return
;
}
else
if
(
i
!=
0x00
)
{
printk_err
(
"Unknown firmware status 0x%x
\n
"
,
i
);
}
else
if
(
i
!=
0x00
)
{
printk_err
(
"Unknown firmware status 0x%x
\n
"
,
i
);
card
->
state
=
FST_HALTED
;
return
;
}
...
...
@@ -932,52 +1700,113 @@ check_started_ok ( struct fst_card_info *card )
* number we assumed at card detection. Should never happen with
* existing firmware etc so we just report it for the moment.
*/
if
(
FST_RDL
(
card
,
numberOfPorts
)
!=
card
->
nports
)
{
printk_warn
(
"Port count mismatch."
" Firmware thinks %d we say %d
\n
"
,
FST_RDL
(
card
,
numberOfPorts
),
card
->
nports
);
if
(
FST_RDL
(
card
,
numberOfPorts
)
!=
card
->
nports
)
{
printk_warn
(
"Port count mismatch on card %d."
" Firmware thinks %d we say %d
\n
"
,
card
->
card_no
,
FST_RDL
(
card
,
numberOfPorts
),
card
->
nports
);
}
}
static
int
set_conf_from_info
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
fstioc_info
*
info
)
set_conf_from_info
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
fstioc_info
*
info
)
{
int
err
;
unsigned
char
my_framing
;
/* Set things according to the user set valid flags.
/* Set things according to the user set valid flags
* Several of the old options have been invalidated/replaced by the
* generic HDLC
package.
* generic hdlc
package.
*/
err
=
0
;
if
(
info
->
valid
&
FSTVAL_PROTO
)
err
=
-
EINVAL
;
if
(
info
->
valid
&
FSTVAL_CABLE
)
if
(
info
->
valid
&
FSTVAL_PROTO
)
{
if
(
info
->
proto
==
FST_RAW
)
port
->
mode
=
FST_RAW
;
else
port
->
mode
=
FST_GEN_HDLC
;
}
if
(
info
->
valid
&
FSTVAL_CABLE
)
err
=
-
EINVAL
;
if
(
info
->
valid
&
FSTVAL_SPEED
)
if
(
info
->
valid
&
FSTVAL_SPEED
)
err
=
-
EINVAL
;
if
(
info
->
valid
&
FSTVAL_MODE
)
FST_WRW
(
card
,
cardMode
,
info
->
cardMode
);
if
(
info
->
valid
&
FSTVAL_PHASE
)
FST_WRB
(
card
,
portConfig
[
port
->
index
].
invertClock
,
info
->
invertClock
);
if
(
info
->
valid
&
FSTVAL_MODE
)
FST_WRW
(
card
,
cardMode
,
info
->
cardMode
);
if
(
info
->
valid
&
FSTVAL_TE1
)
{
FST_WRL
(
card
,
suConfig
.
dataRate
,
info
->
lineSpeed
);
FST_WRB
(
card
,
suConfig
.
clocking
,
info
->
clockSource
);
my_framing
=
FRAMING_E1
;
if
(
info
->
framing
==
E1
)
my_framing
=
FRAMING_E1
;
if
(
info
->
framing
==
T1
)
my_framing
=
FRAMING_T1
;
if
(
info
->
framing
==
J1
)
my_framing
=
FRAMING_J1
;
FST_WRB
(
card
,
suConfig
.
framing
,
my_framing
);
FST_WRB
(
card
,
suConfig
.
structure
,
info
->
structure
);
FST_WRB
(
card
,
suConfig
.
interface
,
info
->
interface
);
FST_WRB
(
card
,
suConfig
.
coding
,
info
->
coding
);
FST_WRB
(
card
,
suConfig
.
lineBuildOut
,
info
->
lineBuildOut
);
FST_WRB
(
card
,
suConfig
.
equalizer
,
info
->
equalizer
);
FST_WRB
(
card
,
suConfig
.
transparentMode
,
info
->
transparentMode
);
FST_WRB
(
card
,
suConfig
.
loopMode
,
info
->
loopMode
);
FST_WRB
(
card
,
suConfig
.
range
,
info
->
range
);
FST_WRB
(
card
,
suConfig
.
txBufferMode
,
info
->
txBufferMode
);
FST_WRB
(
card
,
suConfig
.
rxBufferMode
,
info
->
rxBufferMode
);
FST_WRB
(
card
,
suConfig
.
startingSlot
,
info
->
startingSlot
);
FST_WRB
(
card
,
suConfig
.
losThreshold
,
info
->
losThreshold
);
if
(
info
->
idleCode
)
FST_WRB
(
card
,
suConfig
.
enableIdleCode
,
1
);
else
FST_WRB
(
card
,
suConfig
.
enableIdleCode
,
0
);
FST_WRB
(
card
,
suConfig
.
idleCode
,
info
->
idleCode
);
#if FST_DEBUG
if
(
info
->
valid
&
FSTVAL_TE1
)
{
printk
(
"Setting TE1 data
\n
"
);
printk
(
"Line Speed = %d
\n
"
,
info
->
lineSpeed
);
printk
(
"Start slot = %d
\n
"
,
info
->
startingSlot
);
printk
(
"Clock source = %d
\n
"
,
info
->
clockSource
);
printk
(
"Framing = %d
\n
"
,
my_framing
);
printk
(
"Structure = %d
\n
"
,
info
->
structure
);
printk
(
"interface = %d
\n
"
,
info
->
interface
);
printk
(
"Coding = %d
\n
"
,
info
->
coding
);
printk
(
"Line build out = %d
\n
"
,
info
->
lineBuildOut
);
printk
(
"Equaliser = %d
\n
"
,
info
->
equalizer
);
printk
(
"Transparent mode = %d
\n
"
,
info
->
transparentMode
);
printk
(
"Loop mode = %d
\n
"
,
info
->
loopMode
);
printk
(
"Range = %d
\n
"
,
info
->
range
);
printk
(
"Tx Buffer mode = %d
\n
"
,
info
->
txBufferMode
);
printk
(
"Rx Buffer mode = %d
\n
"
,
info
->
rxBufferMode
);
printk
(
"LOS Threshold = %d
\n
"
,
info
->
losThreshold
);
printk
(
"Idle Code = %d
\n
"
,
info
->
idleCode
);
}
#endif
}
#if FST_DEBUG
if
(
info
->
valid
&
FSTVAL_DEBUG
)
if
(
info
->
valid
&
FSTVAL_DEBUG
)
{
fst_debug_mask
=
info
->
debug
;
}
#endif
return
err
;
}
static
void
gather_conf_info
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
fstioc_info
*
info
)
gather_conf_info
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
fstioc_info
*
info
)
{
int
i
;
memset
(
info
,
0
,
sizeof
(
struct
fstioc_info
));
memset
(
info
,
0
,
sizeof
(
struct
fstioc_info
));
i
=
port
->
index
;
info
->
kernelVersion
=
LINUX_VERSION_CODE
;
info
->
nports
=
card
->
nports
;
info
->
type
=
card
->
type
;
info
->
state
=
card
->
state
;
...
...
@@ -990,58 +1819,132 @@ gather_conf_info ( struct fst_card_info *card, struct fst_port_info *port,
/* Only mark information as valid if card is running.
* Copy the data anyway in case it is useful for diagnostics
*/
info
->
valid
=
((
card
->
state
==
FST_RUNNING
)
?
FSTVAL_ALL
:
FSTVAL_CARD
)
info
->
valid
=
((
card
->
state
==
FST_RUNNING
)
?
FSTVAL_ALL
:
FSTVAL_CARD
)
#if FST_DEBUG
|
FSTVAL_DEBUG
#endif
;
info
->
lineInterface
=
FST_RDW
(
card
,
portConfig
[
i
].
lineInterface
);
info
->
internalClock
=
FST_RDB
(
card
,
portConfig
[
i
].
internalClock
);
info
->
lineSpeed
=
FST_RDL
(
card
,
portConfig
[
i
].
lineSpeed
);
info
->
v24IpSts
=
FST_RDL
(
card
,
v24IpSts
[
i
]
);
info
->
v24OpSts
=
FST_RDL
(
card
,
v24OpSts
[
i
]
);
info
->
clockStatus
=
FST_RDW
(
card
,
clockStatus
[
i
]
);
info
->
cableStatus
=
FST_RDW
(
card
,
cableStatus
);
info
->
cardMode
=
FST_RDW
(
card
,
cardMode
);
info
->
smcFirmwareVersion
=
FST_RDL
(
card
,
smcFirmwareVersion
);
info
->
lineInterface
=
FST_RDW
(
card
,
portConfig
[
i
].
lineInterface
);
info
->
internalClock
=
FST_RDB
(
card
,
portConfig
[
i
].
internalClock
);
info
->
lineSpeed
=
FST_RDL
(
card
,
portConfig
[
i
].
lineSpeed
);
info
->
invertClock
=
FST_RDB
(
card
,
portConfig
[
i
].
invertClock
);
info
->
v24IpSts
=
FST_RDL
(
card
,
v24IpSts
[
i
]);
info
->
v24OpSts
=
FST_RDL
(
card
,
v24OpSts
[
i
]);
info
->
clockStatus
=
FST_RDW
(
card
,
clockStatus
[
i
]);
info
->
cableStatus
=
FST_RDW
(
card
,
cableStatus
);
info
->
cardMode
=
FST_RDW
(
card
,
cardMode
);
info
->
smcFirmwareVersion
=
FST_RDL
(
card
,
smcFirmwareVersion
);
/*
* The T2U can report cable presence for both A or B
* in bits 0 and 1 of cableStatus. See which port we are and
* do the mapping.
*/
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
if
(
port
->
index
==
0
)
{
/*
* Port A
*/
info
->
cableStatus
=
info
->
cableStatus
&
1
;
}
else
{
/*
* Port B
*/
info
->
cableStatus
=
info
->
cableStatus
>>
1
;
info
->
cableStatus
=
info
->
cableStatus
&
1
;
}
}
/*
* Some additional bits if we are TE1
*/
if
(
card
->
type
==
FST_TYPE_TE1
)
{
info
->
lineSpeed
=
FST_RDL
(
card
,
suConfig
.
dataRate
);
info
->
clockSource
=
FST_RDB
(
card
,
suConfig
.
clocking
);
info
->
framing
=
FST_RDB
(
card
,
suConfig
.
framing
);
info
->
structure
=
FST_RDB
(
card
,
suConfig
.
structure
);
info
->
interface
=
FST_RDB
(
card
,
suConfig
.
interface
);
info
->
coding
=
FST_RDB
(
card
,
suConfig
.
coding
);
info
->
lineBuildOut
=
FST_RDB
(
card
,
suConfig
.
lineBuildOut
);
info
->
equalizer
=
FST_RDB
(
card
,
suConfig
.
equalizer
);
info
->
loopMode
=
FST_RDB
(
card
,
suConfig
.
loopMode
);
info
->
range
=
FST_RDB
(
card
,
suConfig
.
range
);
info
->
txBufferMode
=
FST_RDB
(
card
,
suConfig
.
txBufferMode
);
info
->
rxBufferMode
=
FST_RDB
(
card
,
suConfig
.
rxBufferMode
);
info
->
startingSlot
=
FST_RDB
(
card
,
suConfig
.
startingSlot
);
info
->
losThreshold
=
FST_RDB
(
card
,
suConfig
.
losThreshold
);
if
(
FST_RDB
(
card
,
suConfig
.
enableIdleCode
))
info
->
idleCode
=
FST_RDB
(
card
,
suConfig
.
idleCode
);
else
info
->
idleCode
=
0
;
info
->
receiveBufferDelay
=
FST_RDL
(
card
,
suStatus
.
receiveBufferDelay
);
info
->
framingErrorCount
=
FST_RDL
(
card
,
suStatus
.
framingErrorCount
);
info
->
codeViolationCount
=
FST_RDL
(
card
,
suStatus
.
codeViolationCount
);
info
->
crcErrorCount
=
FST_RDL
(
card
,
suStatus
.
crcErrorCount
);
info
->
lineAttenuation
=
FST_RDL
(
card
,
suStatus
.
lineAttenuation
);
info
->
lossOfSignal
=
FST_RDB
(
card
,
suStatus
.
lossOfSignal
);
info
->
receiveRemoteAlarm
=
FST_RDB
(
card
,
suStatus
.
receiveRemoteAlarm
);
info
->
alarmIndicationSignal
=
FST_RDB
(
card
,
suStatus
.
alarmIndicationSignal
);
}
}
static
int
fst_set_iface
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
ifreq
*
ifr
)
fst_set_iface
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
ifreq
*
ifr
)
{
sync_serial_settings
sync
;
int
i
;
if
(
copy_from_user
(
&
sync
,
ifr
->
ifr_settings
.
ifs_ifsu
.
sync
,
sizeof
(
sync
)))
if
(
ifr
->
ifr_settings
.
size
!=
sizeof
(
sync
))
{
return
-
ENOMEM
;
}
if
(
copy_from_user
(
&
sync
,
ifr
->
ifr_settings
.
ifs_ifsu
.
sync
,
sizeof
(
sync
)))
{
return
-
EFAULT
;
}
if
(
sync
.
loopback
)
if
(
sync
.
loopback
)
return
-
EINVAL
;
i
=
port
->
index
;
switch
(
ifr
->
ifr_settings
.
type
)
{
switch
(
ifr
->
ifr_settings
.
type
)
{
case
IF_IFACE_V35
:
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
V35
);
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
V35
);
port
->
hwif
=
V35
;
break
;
case
IF_IFACE_V24
:
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
V24
);
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
V24
);
port
->
hwif
=
V24
;
break
;
case
IF_IFACE_X21
:
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
X21
);
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
X21
);
port
->
hwif
=
X21
;
break
;
case
IF_IFACE_X21D
:
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
X21D
);
port
->
hwif
=
X21D
;
break
;
case
IF_IFACE_T1
:
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
T1
);
port
->
hwif
=
T1
;
break
;
case
IF_IFACE_E1
:
FST_WRW
(
card
,
portConfig
[
i
].
lineInterface
,
E1
);
port
->
hwif
=
E1
;
break
;
case
IF_IFACE_SYNC_SERIAL
:
break
;
...
...
@@ -1049,26 +1952,25 @@ fst_set_iface ( struct fst_card_info *card, struct fst_port_info *port,
return
-
EINVAL
;
}
switch
(
sync
.
clock_type
)
{
switch
(
sync
.
clock_type
)
{
case
CLOCK_EXT
:
FST_WRB
(
card
,
portConfig
[
i
].
internalClock
,
EXTCLK
);
FST_WRB
(
card
,
portConfig
[
i
].
internalClock
,
EXTCLK
);
break
;
case
CLOCK_INT
:
FST_WRB
(
card
,
portConfig
[
i
].
internalClock
,
INTCLK
);
FST_WRB
(
card
,
portConfig
[
i
].
internalClock
,
INTCLK
);
break
;
default:
return
-
EINVAL
;
}
FST_WRL
(
card
,
portConfig
[
i
].
lineSpeed
,
sync
.
clock_rate
);
FST_WRL
(
card
,
portConfig
[
i
].
lineSpeed
,
sync
.
clock_rate
);
return
0
;
}
static
int
fst_get_iface
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
ifreq
*
ifr
)
fst_get_iface
(
struct
fst_card_info
*
card
,
struct
fst_port_info
*
port
,
struct
ifreq
*
ifr
)
{
sync_serial_settings
sync
;
int
i
;
...
...
@@ -1077,41 +1979,51 @@ fst_get_iface ( struct fst_card_info *card, struct fst_port_info *port,
* if nothing is set as IF_IFACE_SYNC_SERIAL implies it can't be
* changed
*/
switch
(
port
->
hwif
)
{
switch
(
port
->
hwif
)
{
case
E1
:
ifr
->
ifr_settings
.
type
=
IF_IFACE_E1
;
break
;
case
T1
:
ifr
->
ifr_settings
.
type
=
IF_IFACE_T1
;
break
;
case
V35
:
ifr
->
ifr_settings
.
type
=
IF_IFACE_V35
;
break
;
case
V24
:
ifr
->
ifr_settings
.
type
=
IF_IFACE_V24
;
break
;
case
X21D
:
ifr
->
ifr_settings
.
type
=
IF_IFACE_X21D
;
break
;
case
X21
:
default:
ifr
->
ifr_settings
.
type
=
IF_IFACE_X21
;
break
;
}
if
(
ifr
->
ifr_settings
.
size
<
sizeof
(
sync
))
{
ifr
->
ifr_settings
.
size
=
sizeof
(
sync
);
/* data size wanted */
return
-
ENOBUFS
;
if
(
ifr
->
ifr_settings
.
size
==
0
)
{
return
0
;
/* only type requested */
}
if
(
ifr
->
ifr_settings
.
size
<
sizeof
(
sync
))
{
return
-
ENOMEM
;
}
i
=
port
->
index
;
sync
.
clock_rate
=
FST_RDL
(
card
,
portConfig
[
i
].
lineSpeed
);
sync
.
clock_rate
=
FST_RDL
(
card
,
portConfig
[
i
].
lineSpeed
);
/* Lucky card and linux use same encoding here */
sync
.
clock_type
=
FST_RDB
(
card
,
portConfig
[
i
].
internalClock
);
sync
.
clock_type
=
FST_RDB
(
card
,
portConfig
[
i
].
internalClock
)
==
INTCLK
?
CLOCK_INT
:
CLOCK_EXT
;
sync
.
loopback
=
0
;
if
(
copy_to_user
(
ifr
->
ifr_settings
.
ifs_ifsu
.
sync
,
&
sync
,
sizeof
(
sync
)))
if
(
copy_to_user
(
ifr
->
ifr_settings
.
ifs_ifsu
.
sync
,
&
sync
,
sizeof
(
sync
)))
{
return
-
EFAULT
;
}
ifr
->
ifr_settings
.
size
=
sizeof
(
sync
);
return
0
;
}
static
int
fst_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
)
fst_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
)
{
struct
fst_card_info
*
card
;
struct
fst_port_info
*
port
;
...
...
@@ -1119,23 +2031,22 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
struct
fstioc_info
info
;
unsigned
long
flags
;
dbg
(
DBG_IOCTL
,
"ioctl: %x, %p
\n
"
,
cmd
,
ifr
->
ifr_data
);
dbg
(
DBG_IOCTL
,
"ioctl: %x, %p
\n
"
,
cmd
,
ifr
->
ifr_data
);
port
=
dev_to_port
(
dev
);
port
=
dev_to_port
(
dev
);
card
=
port
->
card
;
if
(
!
capable
(
CAP_NET_ADMIN
))
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
FSTCPURESET
:
fst_cpureset
(
card
);
fst_cpureset
(
card
);
card
->
state
=
FST_RESET
;
return
0
;
case
FSTCPURELEASE
:
fst_cpurelease
(
card
);
fst_cpurelease
(
card
);
card
->
state
=
FST_STARTING
;
return
0
;
...
...
@@ -1144,22 +2055,19 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
/* First copy in the header with the length and offset of data
* to write
*/
if
(
ifr
->
ifr_data
==
NULL
)
{
if
(
ifr
->
ifr_data
==
NULL
)
{
return
-
EINVAL
;
}
if
(
copy_from_user
(
&
wrthdr
,
ifr
->
ifr_data
,
sizeof
(
struct
fstioc_write
)))
{
if
(
copy_from_user
(
&
wrthdr
,
ifr
->
ifr_data
,
sizeof
(
struct
fstioc_write
)))
{
return
-
EFAULT
;
}
/* Sanity check the parameters. We don't support partial writes
* when going over the top
*/
if
(
wrthdr
.
size
>
FST_MEMSIZE
||
wrthdr
.
offset
>
FST_MEMSIZE
||
wrthdr
.
size
+
wrthdr
.
offset
>
FST_MEMSIZE
)
{
if
(
wrthdr
.
size
>
FST_MEMSIZE
||
wrthdr
.
offset
>
FST_MEMSIZE
||
wrthdr
.
size
+
wrthdr
.
offset
>
FST_MEMSIZE
)
{
return
-
ENXIO
;
}
...
...
@@ -1167,18 +2075,16 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
* This will probably break on some architectures.
* I'll fix it when I have something to test on.
*/
if
(
copy_from_user
(
card
->
mem
+
wrthdr
.
offset
,
ifr
->
ifr_data
+
sizeof
(
struct
fstioc_write
),
wrthdr
.
size
))
{
if
(
copy_from_user
(
card
->
mem
+
wrthdr
.
offset
,
ifr
->
ifr_data
+
sizeof
(
struct
fstioc_write
),
wrthdr
.
size
))
{
return
-
EFAULT
;
}
/* Writes to the memory of a card in the reset state constitute
* a download
*/
if
(
card
->
state
==
FST_RESET
)
{
if
(
card
->
state
==
FST_RESET
)
{
card
->
state
=
FST_DOWNLOAD
;
}
return
0
;
...
...
@@ -1188,250 +2094,302 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
/* If card has just been started check the shared memory config
* version and marker
*/
if
(
card
->
state
==
FST_STARTING
)
{
check_started_ok
(
card
);
if
(
card
->
state
==
FST_STARTING
)
{
check_started_ok
(
card
);
/* If everything checked out enable card interrupts */
if
(
card
->
state
==
FST_RUNNING
)
{
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
fst_clear_intr
(
card
);
FST_WRB
(
card
,
interruptHandshake
,
0xEE
);
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
if
(
card
->
state
==
FST_RUNNING
)
{
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
fst_enable_intr
(
card
);
FST_WRB
(
card
,
interruptHandshake
,
0xEE
);
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
}
}
if
(
ifr
->
ifr_data
==
NULL
)
{
if
(
ifr
->
ifr_data
==
NULL
)
{
return
-
EINVAL
;
}
gather_conf_info
(
card
,
port
,
&
info
);
gather_conf_info
(
card
,
port
,
&
info
);
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
info
,
sizeof
(
info
)))
{
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
info
,
sizeof
(
info
)))
{
return
-
EFAULT
;
}
return
0
;
case
FSTSETCONF
:
/* Most of the setting have been moved to the generic ioctls
* this just covers debug and board ident mode now
/*
* Most of the settings have been moved to the generic ioctls
* this just covers debug and board ident now
*/
if
(
copy_from_user
(
&
info
,
ifr
->
ifr_data
,
sizeof
(
info
)))
{
if
(
card
->
state
!=
FST_RUNNING
)
{
printk_err
(
"Attempt to configure card %d in non-running state (%d)
\n
"
,
card
->
card_no
,
card
->
state
);
return
-
EIO
;
}
if
(
copy_from_user
(
&
info
,
ifr
->
ifr_data
,
sizeof
(
info
)))
{
return
-
EFAULT
;
}
return
set_conf_from_info
(
card
,
port
,
&
info
);
return
set_conf_from_info
(
card
,
port
,
&
info
);
case
SIOCWANDEV
:
switch
(
ifr
->
ifr_settings
.
type
)
{
switch
(
ifr
->
ifr_settings
.
type
)
{
case
IF_GET_IFACE
:
return
fst_get_iface
(
card
,
port
,
ifr
);
return
fst_get_iface
(
card
,
port
,
ifr
);
case
IF_IFACE_SYNC_SERIAL
:
case
IF_IFACE_V35
:
case
IF_IFACE_V24
:
case
IF_IFACE_X21
:
return
fst_set_iface
(
card
,
port
,
ifr
);
case
IF_IFACE_X21D
:
case
IF_IFACE_T1
:
case
IF_IFACE_E1
:
return
fst_set_iface
(
card
,
port
,
ifr
);
case
IF_PROTO_RAW
:
port
->
mode
=
FST_RAW
;
return
0
;
case
IF_GET_PROTO
:
if
(
port
->
mode
==
FST_RAW
)
{
ifr
->
ifr_settings
.
type
=
IF_PROTO_RAW
;
return
0
;
}
return
hdlc_ioctl
(
dev
,
ifr
,
cmd
);
default:
return
hdlc_ioctl
(
dev
,
ifr
,
cmd
);
port
->
mode
=
FST_GEN_HDLC
;
dbg
(
DBG_IOCTL
,
"Passing this type to hdlc %x
\n
"
,
ifr
->
ifr_settings
.
type
);
return
hdlc_ioctl
(
dev
,
ifr
,
cmd
);
}
default:
/* Not one of ours. Pass through to HDLC package */
return
hdlc_ioctl
(
dev
,
ifr
,
cmd
);
return
hdlc_ioctl
(
dev
,
ifr
,
cmd
);
}
}
static
void
fst_openport
(
struct
fst_port_info
*
port
)
fst_openport
(
struct
fst_port_info
*
port
)
{
int
signals
;
int
txq_length
;
/* Only init things if card is actually running. This allows open to
* succeed for downloads etc.
*/
if
(
port
->
card
->
state
==
FST_RUNNING
)
{
if
(
port
->
run
)
{
dbg
(
DBG_OPEN
,
"open: found port already running
\n
"
);
if
(
port
->
card
->
state
==
FST_RUNNING
)
{
if
(
port
->
run
)
{
dbg
(
DBG_OPEN
,
"open: found port already running
\n
"
);
fst_issue_cmd
(
port
,
STOPPORT
);
fst_issue_cmd
(
port
,
STOPPORT
);
port
->
run
=
0
;
}
fst_rx_config
(
port
);
fst_tx_config
(
port
);
fst_op_raise
(
port
,
OPSTS_RTS
|
OPSTS_DTR
);
fst_rx_config
(
port
);
fst_tx_config
(
port
);
fst_op_raise
(
port
,
OPSTS_RTS
|
OPSTS_DTR
);
fst_issue_cmd
(
port
,
STARTPORT
);
fst_issue_cmd
(
port
,
STARTPORT
);
port
->
run
=
1
;
signals
=
FST_RDL
(
port
->
card
,
v24DebouncedSts
[
port
->
index
]);
if
(
signals
&
((
port
->
hwif
==
X21
)
?
IPSTS_INDICATE
:
IPSTS_DCD
))
netif_carrier_on
(
port_to_dev
(
port
));
signals
=
FST_RDL
(
port
->
card
,
v24DebouncedSts
[
port
->
index
]);
if
(
signals
&
(((
port
->
hwif
==
X21
)
||
(
port
->
hwif
==
X21D
))
?
IPSTS_INDICATE
:
IPSTS_DCD
))
netif_carrier_on
(
port_to_dev
(
port
));
else
netif_carrier_off
(
port_to_dev
(
port
));
netif_carrier_off
(
port_to_dev
(
port
));
txq_length
=
port
->
txqe
-
port
->
txqs
;
port
->
txqe
=
0
;
port
->
txqs
=
0
;
}
}
static
void
fst_closeport
(
struct
fst_port_info
*
port
)
fst_closeport
(
struct
fst_port_info
*
port
)
{
if
(
port
->
card
->
state
==
FST_RUNNING
)
{
if
(
port
->
run
)
{
if
(
port
->
card
->
state
==
FST_RUNNING
)
{
if
(
port
->
run
)
{
port
->
run
=
0
;
fst_op_lower
(
port
,
OPSTS_RTS
|
OPSTS_DTR
);
fst_op_lower
(
port
,
OPSTS_RTS
|
OPSTS_DTR
);
fst_issue_cmd
(
port
,
STOPPORT
);
}
else
{
dbg
(
DBG_OPEN
,
"close: port not running
\n
"
);
fst_issue_cmd
(
port
,
STOPPORT
);
}
else
{
dbg
(
DBG_OPEN
,
"close: port not running
\n
"
);
}
}
}
static
int
fst_open
(
struct
net_device
*
dev
)
fst_open
(
struct
net_device
*
dev
)
{
int
err
;
struct
fst_port_info
*
port
;
port
=
dev_to_port
(
dev
);
if
(
!
try_module_get
(
THIS_MODULE
))
return
-
EBUSY
;
err
=
hdlc_open
(
dev
);
if
(
err
)
if
(
port
->
mode
!=
FST_RAW
)
{
err
=
hdlc_open
(
dev
);
if
(
err
)
return
err
;
}
fst_openport
(
dev_to_port
(
dev
)
);
netif_wake_queue
(
dev
);
fst_openport
(
port
);
netif_wake_queue
(
dev
);
return
0
;
}
static
int
fst_close
(
struct
net_device
*
dev
)
fst_close
(
struct
net_device
*
dev
)
{
netif_stop_queue
(
dev
);
fst_closeport
(
dev_to_port
(
dev
));
hdlc_close
(
dev
);
struct
fst_port_info
*
port
;
struct
fst_card_info
*
card
;
unsigned
char
tx_dma_done
;
unsigned
char
rx_dma_done
;
port
=
dev_to_port
(
dev
);
card
=
port
->
card
;
tx_dma_done
=
inb
(
card
->
pci_conf
+
DMACSR1
);
rx_dma_done
=
inb
(
card
->
pci_conf
+
DMACSR0
);
dbg
(
DBG_OPEN
,
"Port Close: tx_dma_in_progress = %d (%x) rx_dma_in_progress = %d (%x)
\n
"
,
card
->
dmatx_in_progress
,
tx_dma_done
,
card
->
dmarx_in_progress
,
rx_dma_done
);
netif_stop_queue
(
dev
);
fst_closeport
(
dev_to_port
(
dev
));
if
(
port
->
mode
!=
FST_RAW
)
{
hdlc_close
(
dev
);
}
module_put
(
THIS_MODULE
);
return
0
;
}
static
int
fst_attach
(
struct
net_device
*
dev
,
unsigned
short
encoding
,
unsigned
short
parity
)
fst_attach
(
struct
net_device
*
dev
,
unsigned
short
encoding
,
unsigned
short
parity
)
{
/* Setting currently fixed in FarSync card so we check and forget */
if
(
encoding
!=
ENCODING_NRZ
||
parity
!=
PARITY_CRC16_PR1_CCITT
)
/*
* Setting currently fixed in FarSync card so we check and forget
*/
if
(
encoding
!=
ENCODING_NRZ
||
parity
!=
PARITY_CRC16_PR1_CCITT
)
return
-
EINVAL
;
return
0
;
}
static
void
fst_tx_timeout
(
struct
net_device
*
dev
)
fst_tx_timeout
(
struct
net_device
*
dev
)
{
struct
fst_port_info
*
port
;
struct
fst_card_info
*
card
;
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
);
dbg
(
DBG_INTR
|
DBG_TX
,
"tx_timeout
\n
"
);
port
=
dev_to_port
(
dev
);
port
=
dev_to_port
(
dev
);
card
=
port
->
card
;
stats
->
tx_errors
++
;
stats
->
tx_aborted_errors
++
;
if
(
port
->
txcnt
>
0
)
fst_issue_cmd
(
port
,
ABORTTX
);
dbg
(
DBG_ASS
,
"Tx timeout card %d port %d
\n
"
,
card
->
card_no
,
port
->
index
);
fst_issue_cmd
(
port
,
ABORTTX
);
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
netif_wake_queue
(
dev
);
port
->
start
=
0
;
}
static
int
fst_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
fst_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
);
struct
fst_card_info
*
card
;
struct
fst_port_info
*
port
;
unsigned
char
dmabits
;
struct
net_device_stats
*
stats
=
hdlc_stats
(
dev
)
;
unsigned
long
flags
;
int
pi
;
int
txp
;
int
txq_length
;
port
=
dev_to_port
(
dev
);
port
=
dev_to_port
(
dev
);
card
=
port
->
card
;
dbg
(
DBG_TX
,
"fst_start_xmit: length = %d
\n
"
,
skb
->
len
);
/* Drop packet with error if we don't have carrier */
if
(
!
netif_carrier_ok
(
dev
))
{
dev_kfree_skb
(
skb
);
if
(
!
netif_carrier_ok
(
dev
))
{
dev_kfree_skb
(
skb
);
stats
->
tx_errors
++
;
stats
->
tx_carrier_errors
++
;
dbg
(
DBG_ASS
,
"Tried to transmit but no carrier on card %d port %d
\n
"
,
card
->
card_no
,
port
->
index
);
return
0
;
}
/* Drop it if it's too big! MTU failure ? */
if
(
skb
->
len
>
LEN_TX_BUFFER
)
{
dbg
(
DBG_TX
,
"Packet too large %d vs %d
\n
"
,
skb
->
len
,
LEN_TX_BUFFER
);
dev_kfree_skb
(
skb
);
if
(
skb
->
len
>
LEN_TX_BUFFER
)
{
dbg
(
DBG_ASS
,
"Packet too large %d vs %d
\n
"
,
skb
->
len
,
LEN_TX_BUFFER
);
dev_kfree_skb
(
skb
);
stats
->
tx_errors
++
;
return
0
;
}
/* Check we have a buffer */
pi
=
port
->
index
;
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
txp
=
port
->
txpos
;
dmabits
=
FST_RDB
(
card
,
txDescrRing
[
pi
][
txp
].
bits
);
if
(
dmabits
&
DMA_OWN
)
{
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
dbg
(
DBG_TX
,
"Out of Tx buffers
\n
"
);
dev_kfree_skb
(
skb
);
/*
* We are always going to queue the packet
* so that the bottom half is the only place we tx from
* Check there is room in the port txq
*/
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
if
((
txq_length
=
port
->
txqe
-
port
->
txqs
)
<
0
)
{
/*
* This is the case where the next free has wrapped but the
* last used hasn't
*/
txq_length
=
txq_length
+
FST_TXQ_DEPTH
;
}
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
if
(
txq_length
>
fst_txq_high
)
{
/*
* We have got enough buffers in the pipeline. Ask the network
* layer to stop sending frames down
*/
netif_stop_queue
(
dev
);
port
->
start
=
1
;
/* I'm using this to signal stop sent up */
}
if
(
txq_length
==
FST_TXQ_DEPTH
-
1
)
{
/*
* This shouldn't have happened but such is life
*/
dev_kfree_skb
(
skb
);
stats
->
tx_errors
++
;
dbg
(
DBG_ASS
,
"Tx queue overflow card %d port %d
\n
"
,
card
->
card_no
,
port
->
index
);
return
0
;
}
if
(
++
port
->
txpos
>=
NUM_TX_BUFFER
)
port
->
txpos
=
0
;
if
(
++
port
->
txcnt
>=
NUM_TX_BUFFER
)
netif_stop_queue
(
dev
);
/* Release the card lock before we copy the data as we now have
* exclusive access to the buffer.
/*
* queue the buffer
*/
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
/* Enqueue the packet */
memcpy_toio
(
card
->
mem
+
BUF_OFFSET
(
txBuffer
[
pi
][
txp
][
0
]),
skb
->
data
,
skb
->
len
);
FST_WRW
(
card
,
txDescrRing
[
pi
][
txp
].
bcnt
,
cnv_bcnt
(
skb
->
len
));
FST_WRB
(
card
,
txDescrRing
[
pi
][
txp
].
bits
,
DMA_OWN
|
TX_STP
|
TX_ENP
);
spin_lock_irqsave
(
&
card
->
card_lock
,
flags
);
port
->
txq
[
port
->
txqe
]
=
skb
;
port
->
txqe
++
;
if
(
port
->
txqe
==
FST_TXQ_DEPTH
)
port
->
txqe
=
0
;
spin_unlock_irqrestore
(
&
card
->
card_lock
,
flags
);
stats
->
tx_packets
++
;
stats
->
tx_bytes
+=
skb
->
len
;
/* Scehdule the bottom half which now does transmit processing */
fst_q_work_item
(
&
fst_work_txq
,
card
->
card_no
);
tasklet_schedule
(
&
fst_tx_task
);
dev_kfree_skb
(
skb
);
dev
->
trans_start
=
jiffies
;
return
0
;
}
/*
* Card setup having checked hardware resources.
* Should be pretty bizarre if we get an error here (kernel memory
...
...
@@ -1442,11 +2400,15 @@ fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
static
char
*
type_strings
[]
__devinitdata
=
{
"no hardware"
,
/* Should never be seen */
"FarSync T2P"
,
"FarSync T4P"
"FarSync T4P"
,
"FarSync T1U"
,
"FarSync T2U"
,
"FarSync T4U"
,
"FarSync TE1"
};
static
void
__devinit
fst_init_card
(
struct
fst_card_info
*
card
)
fst_init_card
(
struct
fst_card_info
*
card
)
{
int
i
;
int
err
;
...
...
@@ -1455,7 +2417,7 @@ fst_init_card ( struct fst_card_info *card )
* firmware detects something different later (should never happen)
* we'll have to revise it in some way then.
*/
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
{
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
{
err
=
register_hdlc_device
(
card
->
ports
[
i
].
dev
);
if
(
err
<
0
)
{
int
j
;
...
...
@@ -1470,60 +2432,118 @@ fst_init_card ( struct fst_card_info *card )
}
}
printk
(
KERN_INFO
"%s-%s: %s IRQ%d, %d ports
\n
"
,
printk_info
(
"%s-%s: %s IRQ%d, %d ports
\n
"
,
port_to_dev
(
&
card
->
ports
[
0
])
->
name
,
port_to_dev
(
&
card
->
ports
[
card
->
nports
-
1
])
->
name
,
type_strings
[
card
->
type
],
card
->
irq
,
card
->
nports
);
port_to_dev
(
&
card
->
ports
[
card
->
nports
-
1
])
->
name
,
type_strings
[
card
->
type
],
card
->
irq
,
card
->
nports
);
}
/*
* Initialise card when detected.
* Returns 0 to indicate success, or errno otherwise.
*/
static
int
__devinit
fst_add_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
fst_add_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
int
firsttime_done
=
0
;
static
int
no_of_cards_added
=
0
;
struct
fst_card_info
*
card
;
int
err
=
0
;
int
i
;
if
(
!
firsttime_done
)
{
printk
(
KERN_INFO
"FarSync X21 driver "
FST_USER_VERSION
" (c) 2001 FarSite Communications Ltd.
\n
"
);
if
(
!
firsttime_done
)
{
printk_info
(
"FarSync WAN driver "
FST_USER_VERSION
" (c) 2001-2004 FarSite Communications Ltd.
\n
"
);
firsttime_done
=
1
;
dbg
(
DBG_ASS
,
"The value of debug mask is %x
\n
"
,
fst_debug_mask
);
}
/*
* We are going to be clever and allow certain cards not to be
* configured. An exclude list can be provided in /etc/modules.conf
*/
if
(
fst_excluded_cards
!=
0
)
{
/*
* There are cards to exclude
*
*/
for
(
i
=
0
;
i
<
fst_excluded_cards
;
i
++
)
{
if
((
pdev
->
devfn
)
>>
3
==
fst_excluded_list
[
i
])
{
printk_info
(
"FarSync PCI device %d not assigned
\n
"
,
(
pdev
->
devfn
)
>>
3
);
return
-
EBUSY
;
}
}
}
/* Allocate driver private data */
card
=
kmalloc
(
sizeof
(
struct
fst_card_info
),
GFP_KERNEL
);
if
(
card
==
NULL
)
{
printk_err
(
"FarSync card found but insufficient memory for"
card
=
kmalloc
(
sizeof
(
struct
fst_card_info
),
GFP_KERNEL
);
if
(
card
==
NULL
)
{
printk_err
(
"FarSync card found but insufficient memory for"
" driver storage
\n
"
);
return
-
ENOMEM
;
}
memset
(
card
,
0
,
sizeof
(
struct
fst_card_info
));
memset
(
card
,
0
,
sizeof
(
struct
fst_card_info
));
/* Try to enable the device */
if
((
err
=
pci_enable_device
(
pdev
))
!=
0
)
{
printk_err
(
"Failed to enable card. Err %d
\n
"
,
-
err
);
goto
error_free_card
;
if
((
err
=
pci_enable_device
(
pdev
))
!=
0
)
{
printk_err
(
"Failed to enable card. Err %d
\n
"
,
-
err
);
kfree
(
card
);
return
err
;
}
/* Record info we need*/
card
->
irq
=
pdev
->
irq
;
card
->
pci_conf
=
pci_resource_start
(
pdev
,
1
);
card
->
phys_mem
=
pci_resource_start
(
pdev
,
2
);
card
->
phys_ctlmem
=
pci_resource_start
(
pdev
,
3
);
if
((
err
=
pci_request_regions
(
pdev
,
"FarSync"
))
!=
0
)
{
printk_err
(
"Failed to allocate regions. Err %d
\n
"
,
-
err
);
pci_disable_device
(
pdev
);
kfree
(
card
);
return
err
;
}
/* Get virtual addresses of memory regions */
card
->
pci_conf
=
pci_resource_start
(
pdev
,
1
);
card
->
phys_mem
=
pci_resource_start
(
pdev
,
2
);
card
->
phys_ctlmem
=
pci_resource_start
(
pdev
,
3
);
if
((
card
->
mem
=
ioremap
(
card
->
phys_mem
,
FST_MEMSIZE
))
==
NULL
)
{
printk_err
(
"Physical memory remap failed
\n
"
);
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
kfree
(
card
);
return
-
ENODEV
;
}
if
((
card
->
ctlmem
=
ioremap
(
card
->
phys_ctlmem
,
0x10
))
==
NULL
)
{
printk_err
(
"Control memory remap failed
\n
"
);
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
kfree
(
card
);
return
-
ENODEV
;
}
dbg
(
DBG_PCI
,
"kernel mem %p, ctlmem %p
\n
"
,
card
->
mem
,
card
->
ctlmem
);
/* Register the interrupt handler */
if
(
request_irq
(
pdev
->
irq
,
fst_intr
,
SA_SHIRQ
,
FST_DEV_NAME
,
card
))
{
printk_err
(
"Unable to register interrupt %d
\n
"
,
card
->
irq
);
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
iounmap
(
card
->
ctlmem
);
iounmap
(
card
->
mem
);
kfree
(
card
);
return
-
ENODEV
;
}
/* Record info we need */
card
->
irq
=
pdev
->
irq
;
card
->
type
=
ent
->
driver_data
;
card
->
nports
=
(
ent
->
driver_data
==
FST_TYPE_T2P
)
?
2
:
4
;
card
->
family
=
((
ent
->
driver_data
==
FST_TYPE_T2P
)
||
(
ent
->
driver_data
==
FST_TYPE_T4P
))
?
FST_FAMILY_TXP
:
FST_FAMILY_TXU
;
if
((
ent
->
driver_data
==
FST_TYPE_T1U
)
||
(
ent
->
driver_data
==
FST_TYPE_TE1
))
card
->
nports
=
1
;
else
card
->
nports
=
((
ent
->
driver_data
==
FST_TYPE_T2P
)
||
(
ent
->
driver_data
==
FST_TYPE_T2U
))
?
2
:
4
;
card
->
state
=
FST_UNINIT
;
spin_lock_init
(
&
card
->
card_lock
);
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
{
...
...
@@ -1533,7 +2553,13 @@ fst_add_one ( struct pci_dev *pdev, const struct pci_device_id *ent )
while
(
i
--
)
free_netdev
(
card
->
ports
[
i
].
dev
);
printk_err
(
"FarSync: out of memory
\n
"
);
goto
error_free_card
;
free_irq
(
card
->
irq
,
card
);
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
iounmap
(
card
->
ctlmem
);
iounmap
(
card
->
mem
);
kfree
(
card
);
return
-
ENODEV
;
}
card
->
ports
[
i
].
dev
=
dev
;
card
->
ports
[
i
].
card
=
card
;
...
...
@@ -1564,128 +2590,95 @@ fst_add_one ( struct pci_dev *pdev, const struct pci_device_id *ent )
hdlc
->
xmit
=
fst_start_xmit
;
}
dbg
(
DBG_PCI
,
"type %d nports %d irq %d
\n
"
,
card
->
type
,
card
->
nports
,
card
->
irq
);
dbg
(
DBG_PCI
,
"conf %04x mem %08x ctlmem %08x
\n
"
,
card
->
pci_conf
,
card
->
phys_mem
,
card
->
phys_ctlmem
);
/* Check we can get access to the memory and I/O regions */
if
(
!
request_region
(
card
->
pci_conf
,
0x80
,
"PLX config regs"
))
{
printk_err
(
"Unable to get config I/O @ 0x%04X
\n
"
,
card
->
pci_conf
);
err
=
-
ENODEV
;
goto
error_free_ports
;
}
if
(
!
request_mem_region
(
card
->
phys_mem
,
FST_MEMSIZE
,
"Shared RAM"
))
{
printk_err
(
"Unable to get main memory @ 0x%08X
\n
"
,
card
->
phys_mem
);
err
=
-
ENODEV
;
goto
error_release_io
;
}
if
(
!
request_mem_region
(
card
->
phys_ctlmem
,
0x10
,
"Control memory"
))
{
printk_err
(
"Unable to get control memory @ 0x%08X
\n
"
,
card
->
phys_ctlmem
);
err
=
-
ENODEV
;
goto
error_release_mem
;
}
card
->
device
=
pdev
;
/* Get virtual addresses of memory regions */
if
((
card
->
mem
=
ioremap
(
card
->
phys_mem
,
FST_MEMSIZE
))
==
NULL
)
{
printk_err
(
"Physical memory remap failed
\n
"
);
err
=
-
ENODEV
;
goto
error_release_ctlmem
;
}
if
((
card
->
ctlmem
=
ioremap
(
card
->
phys_ctlmem
,
0x10
))
==
NULL
)
{
printk_err
(
"Control memory remap failed
\n
"
);
err
=
-
ENODEV
;
goto
error_unmap_mem
;
}
dbg
(
DBG_PCI
,
"kernel mem %p, ctlmem %p
\n
"
,
card
->
mem
,
card
->
ctlmem
);
dbg
(
DBG_PCI
,
"type %d nports %d irq %d
\n
"
,
card
->
type
,
card
->
nports
,
card
->
irq
);
dbg
(
DBG_PCI
,
"conf %04x mem %08x ctlmem %08x
\n
"
,
card
->
pci_conf
,
card
->
phys_mem
,
card
->
phys_ctlmem
);
/* Reset the card's processor */
fst_cpureset
(
card
);
fst_cpureset
(
card
);
card
->
state
=
FST_RESET
;
/* Register the interrupt handler */
if
(
request_irq
(
card
->
irq
,
fst_intr
,
SA_SHIRQ
,
FST_DEV_NAME
,
card
))
{
printk_err
(
"Unable to register interrupt %d
\n
"
,
card
->
irq
);
err
=
-
ENODEV
;
goto
error_unmap_ctlmem
;
}
/* Initialise DMA (if required) */
fst_init_dma
(
card
);
/* Record driver data for later use */
pci_set_drvdata
(
pdev
,
card
);
/* Remainder of card setup */
fst_init_card
(
card
);
fst_card_array
[
no_of_cards_added
]
=
card
;
card
->
card_no
=
no_of_cards_added
++
;
/* Record instance and bump it */
fst_init_card
(
card
);
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
/*
* Allocate a dma buffer for transmit and receives
*/
card
->
rx_dma_handle_host
=
pci_alloc_consistent
(
card
->
device
,
FST_MAX_MTU
,
&
card
->
rx_dma_handle_card
);
if
(
card
->
rx_dma_handle_host
==
NULL
)
{
printk_err
(
"Could not allocate rx dma buffer
\n
"
);
fst_disable_intr
(
card
);
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
iounmap
(
card
->
ctlmem
);
iounmap
(
card
->
mem
);
kfree
(
card
);
return
-
ENOMEM
;
}
card
->
tx_dma_handle_host
=
pci_alloc_consistent
(
card
->
device
,
FST_MAX_MTU
,
&
card
->
tx_dma_handle_card
);
if
(
card
->
tx_dma_handle_host
==
NULL
)
{
printk_err
(
"Could not allocate tx dma buffer
\n
"
);
fst_disable_intr
(
card
);
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
iounmap
(
card
->
ctlmem
);
iounmap
(
card
->
mem
);
kfree
(
card
);
return
-
ENOMEM
;
}
}
return
0
;
/* Success */
/* Failure. Release resources */
error_unmap_ctlmem:
iounmap
(
card
->
ctlmem
);
error_unmap_mem:
iounmap
(
card
->
mem
);
error_release_ctlmem:
release_mem_region
(
card
->
phys_ctlmem
,
0x10
);
error_release_mem:
release_mem_region
(
card
->
phys_mem
,
FST_MEMSIZE
);
error_release_io:
release_region
(
card
->
pci_conf
,
0x80
);
error_free_ports:
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
free_netdev
(
card
->
ports
[
i
].
dev
);
error_free_card:
kfree
(
card
);
return
err
;
}
/*
* Cleanup and close down a card
*/
static
void
__devexit
fst_remove_one
(
struct
pci_dev
*
pdev
)
fst_remove_one
(
struct
pci_dev
*
pdev
)
{
struct
fst_card_info
*
card
;
int
i
;
card
=
pci_get_drvdata
(
pdev
);
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
{
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
{
struct
net_device
*
dev
=
port_to_dev
(
&
card
->
ports
[
i
]);
unregister_hdlc_device
(
dev
);
}
fst_disable_intr
(
card
);
free_irq
(
card
->
irq
,
card
);
iounmap
(
card
->
ctlmem
);
iounmap
(
card
->
mem
);
fst_disable_intr
(
card
);
free_irq
(
card
->
irq
,
card
);
release_mem_region
(
card
->
phys_ctlmem
,
0x10
);
release_mem_region
(
card
->
phys_mem
,
FST_MEMSIZE
);
release_region
(
card
->
pci_conf
,
0x80
);
for
(
i
=
0
;
i
<
card
->
nports
;
i
++
)
free_netdev
(
card
->
ports
[
i
].
dev
);
kfree
(
card
);
iounmap
(
card
->
ctlmem
);
iounmap
(
card
->
mem
);
pci_release_regions
(
pdev
);
if
(
card
->
family
==
FST_FAMILY_TXU
)
{
/*
* Free dma buffers
*/
pci_free_consistent
(
card
->
device
,
FST_MAX_MTU
,
card
->
rx_dma_handle_host
,
card
->
rx_dma_handle_card
);
pci_free_consistent
(
card
->
device
,
FST_MAX_MTU
,
card
->
tx_dma_handle_host
,
card
->
tx_dma_handle_card
);
}
fst_card_array
[
card
->
card_no
]
=
NULL
;
}
static
struct
pci_driver
fst_driver
=
{
...
...
@@ -1700,15 +2693,20 @@ static struct pci_driver fst_driver = {
static
int
__init
fst_init
(
void
)
{
return
pci_module_init
(
&
fst_driver
);
int
i
;
for
(
i
=
0
;
i
<
FST_MAX_CARDS
;
i
++
)
fst_card_array
[
i
]
=
NULL
;
spin_lock_init
(
&
fst_work_q_lock
);
return
pci_module_init
(
&
fst_driver
);
}
static
void
__exit
fst_cleanup_module
(
void
)
{
pci_unregister_driver
(
&
fst_driver
);
printk_info
(
"FarSync WAN driver unloading
\n
"
);
pci_unregister_driver
(
&
fst_driver
);
}
module_init
(
fst_init
);
module_exit
(
fst_cleanup_module
);
module_init
(
fst_init
);
module_exit
(
fst_cleanup_module
);
drivers/net/wan/farsync.h
View file @
8a6d6a46
...
...
@@ -32,8 +32,13 @@
* A short common prefix is useful for routines within the driver to avoid
* conflict with other similar drivers and I chosen to use "fst_" for this
* purpose (FarSite T-series).
*
* Finally the device driver needs a short network interface name. Since
* "hdlc" is already in use I've chosen the even less informative "sync"
* for the present.
*/
#define FST_NAME "fst"
/* In debug/info etc */
#define FST_NDEV_NAME "sync"
/* For net interface */
#define FST_DEV_NAME "farsync"
/* For misc interfaces */
...
...
@@ -45,7 +50,7 @@
* have individual versions (or IDs) that move much faster than the
* the release version as individual updates are tracked.
*/
#define FST_USER_VERSION "
0.09
"
#define FST_USER_VERSION "
1.04
"
/* Ioctl call command values
...
...
@@ -100,6 +105,7 @@ struct fstioc_info {
unsigned
int
state
;
/* State of card */
unsigned
int
index
;
/* Index of port ioctl was issued on */
unsigned
int
smcFirmwareVersion
;
unsigned
long
kernelVersion
;
/* What Kernel version we are working with */
unsigned
short
lineInterface
;
/* Physical interface type */
unsigned
char
proto
;
/* Line protocol */
unsigned
char
internalClock
;
/* 1 => internal clock, 0 => external */
...
...
@@ -110,6 +116,31 @@ struct fstioc_info {
unsigned
short
cableStatus
;
/* lsb: 0=> present, 1=> absent */
unsigned
short
cardMode
;
/* lsb: LED id mode */
unsigned
short
debug
;
/* Debug flags */
unsigned
char
transparentMode
;
/* Not used always 0 */
unsigned
char
invertClock
;
/* Invert clock feature for syncing */
unsigned
char
startingSlot
;
/* Time slot to use for start of tx */
unsigned
char
clockSource
;
/* External or internal */
unsigned
char
framing
;
/* E1, T1 or J1 */
unsigned
char
structure
;
/* unframed, double, crc4, f4, f12, */
/* f24 f72 */
unsigned
char
interface
;
/* rj48c or bnc */
unsigned
char
coding
;
/* hdb3 b8zs */
unsigned
char
lineBuildOut
;
/* 0, -7.5, -15, -22 */
unsigned
char
equalizer
;
/* short or lon haul settings */
unsigned
char
loopMode
;
/* various loopbacks */
unsigned
char
range
;
/* cable lengths */
unsigned
char
txBufferMode
;
/* tx elastic buffer depth */
unsigned
char
rxBufferMode
;
/* rx elastic buffer depth */
unsigned
char
losThreshold
;
/* Attenuation on LOS signal */
unsigned
char
idleCode
;
/* Value to send as idle timeslot */
unsigned
int
receiveBufferDelay
;
/* delay thro rx buffer timeslots */
unsigned
int
framingErrorCount
;
/* framing errors */
unsigned
int
codeViolationCount
;
/* code violations */
unsigned
int
crcErrorCount
;
/* CRC errors */
int
lineAttenuation
;
/* in dB*/
unsigned
short
lossOfSignal
;
unsigned
short
receiveRemoteAlarm
;
unsigned
short
alarmIndicationSignal
;
};
/* "valid" bitmask */
...
...
@@ -131,13 +162,23 @@ struct fstioc_info {
*/
#define FSTVAL_PROTO 0x00000200
/* proto */
#define FSTVAL_MODE 0x00000400
/* cardMode */
#define FSTVAL_PHASE 0x00000800
/* Clock phase */
#define FSTVAL_TE1 0x00001000
/* T1E1 Configuration */
#define FSTVAL_DEBUG 0x80000000
/* debug */
#define FSTVAL_ALL 0x0000
07
FF
/* Note: does not include DEBUG flag */
#define FSTVAL_ALL 0x0000
1F
FF
/* Note: does not include DEBUG flag */
/* "type" */
#define FST_TYPE_NONE 0
/* Probably should never happen */
#define FST_TYPE_T2P 1
/* T2P X21 2 port card */
#define FST_TYPE_T4P 2
/* T4P X21 4 port card */
#define FST_TYPE_T1U 3
/* T1U X21 1 port card */
#define FST_TYPE_T2U 4
/* T2U X21 2 port card */
#define FST_TYPE_T4U 5
/* T4U X21 4 port card */
#define FST_TYPE_TE1 6
/* T1E1 X21 1 port card */
/* "family" */
#define FST_FAMILY_TXP 0
/* T2P or T4P */
#define FST_FAMILY_TXU 1
/* T1U or T2U or T4U */
/* "state" */
#define FST_UNINIT 0
/* Raw uninitialised state following
...
...
@@ -155,6 +196,10 @@ struct fstioc_info {
#define V24 1
#define X21 2
#define V35 3
#define X21D 4
#define T1 5
#define E1 6
#define J1 7
/* "proto" */
#define FST_HDLC 1
/* Cisco compatible HDLC */
...
...
@@ -187,6 +232,97 @@ struct fstioc_info {
/* "cardMode" bitmask */
#define CARD_MODE_IDENTIFY 0x0001
/*
* Constants for T1/E1 configuration
*/
/*
* Clock source
*/
#define CLOCKING_SLAVE 0
#define CLOCKING_MASTER 1
/*
* Framing
*/
#define FRAMING_E1 0
#define FRAMING_J1 1
#define FRAMING_T1 2
/*
* Structure
*/
#define STRUCTURE_UNFRAMED 0
#define STRUCTURE_E1_DOUBLE 1
#define STRUCTURE_E1_CRC4 2
#define STRUCTURE_E1_CRC4M 3
#define STRUCTURE_T1_4 4
#define STRUCTURE_T1_12 5
#define STRUCTURE_T1_24 6
#define STRUCTURE_T1_72 7
/*
* Interface
*/
#define INTERFACE_RJ48C 0
#define INTERFACE_BNC 1
/*
* Coding
*/
#define CODING_HDB3 0
#define CODING_NRZ 1
#define CODING_CMI 2
#define CODING_CMI_HDB3 3
#define CODING_CMI_B8ZS 4
#define CODING_AMI 5
#define CODING_AMI_ZCS 6
#define CODING_B8ZS 7
/*
* Line Build Out
*/
#define LBO_0dB 0
#define LBO_7dB5 1
#define LBO_15dB 2
#define LBO_22dB5 3
/*
* Range for long haul t1 > 655ft
*/
#define RANGE_0_133_FT 0
#define RANGE_0_40_M RANGE_0_133_FT
#define RANGE_133_266_FT 1
#define RANGE_40_81_M RANGE_133_266_FT
#define RANGE_266_399_FT 2
#define RANGE_81_122_M RANGE_266_399_FT
#define RANGE_399_533_FT 3
#define RANGE_122_162_M RANGE_399_533_FT
#define RANGE_533_655_FT 4
#define RANGE_162_200_M RANGE_533_655_FT
/*
* Receive Equaliser
*/
#define EQUALIZER_SHORT 0
#define EQUALIZER_LONG 1
/*
* Loop modes
*/
#define LOOP_NONE 0
#define LOOP_LOCAL 1
#define LOOP_PAYLOAD_EXC_TS0 2
#define LOOP_PAYLOAD_INC_TS0 3
#define LOOP_REMOTE 4
/*
* Buffer modes
*/
#define BUFFER_2_FRAME 0
#define BUFFER_1_FRAME 1
#define BUFFER_96_BIT 2
#define BUFFER_NONE 3
/* Debug support
*
...
...
include/linux/if.h
View file @
8a6d6a46
...
...
@@ -63,6 +63,7 @@
#define IF_IFACE_T1 0x1003
/* T1 telco serial interface */
#define IF_IFACE_E1 0x1004
/* E1 telco serial interface */
#define IF_IFACE_SYNC_SERIAL 0x1005
/* can't be set by software */
#define IF_IFACE_X21D 0x1006
/* X.21 Dual Clocking (FarSite) */
/* For definitions see hdlc.h */
#define IF_PROTO_HDLC 0x2000
/* raw HDLC protocol */
...
...
@@ -77,6 +78,7 @@
#define IF_PROTO_FR_DEL_ETH_PVC 0x2009
/* Delete FR Ethernet-bridged PVC */
#define IF_PROTO_FR_PVC 0x200A
/* for reading PVC status */
#define IF_PROTO_FR_ETH_PVC 0x200B
#define IF_PROTO_RAW 0x200C
/* RAW Socket */
/*
...
...
include/linux/pci_ids.h
View file @
8a6d6a46
...
...
@@ -1886,6 +1886,15 @@
#define PCI_DEVICE_ID_MACROLINK_MCCR8 0x2000
#define PCI_DEVICE_ID_MACROLINK_MCCR 0x2001
#define PCI_VENDOR_ID_FARSITE 0x1619
#define PCI_DEVICE_ID_FARSITE_T2P 0x0400
#define PCI_DEVICE_ID_FARSITE_T4P 0x0440
#define PCI_DEVICE_ID_FARSITE_T1U 0x0610
#define PCI_DEVICE_ID_FARSITE_T2U 0x0620
#define PCI_DEVICE_ID_FARSITE_T4U 0x0640
#define PCI_DEVICE_ID_FARSITE_TE1 0x1610
#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612
#define PCI_VENDOR_ID_ALTIMA 0x173b
#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8
#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment