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
nexedi
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