162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*      FarSync WAN driver for Linux (2.6.x kernel version)
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *      Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *      Copyright (C) 2001-2004 FarSite Communications Ltd.
762306a36Sopenharmony_ci *      www.farsite.co.uk
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *      Author:      R.J.Dunlop    <bob.dunlop@farsite.co.uk>
1062306a36Sopenharmony_ci *      Maintainer:  Kevin Curtis  <kevin.curtis@farsite.co.uk>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/version.h>
1862306a36Sopenharmony_ci#include <linux/pci.h>
1962306a36Sopenharmony_ci#include <linux/sched.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/ioport.h>
2262306a36Sopenharmony_ci#include <linux/init.h>
2362306a36Sopenharmony_ci#include <linux/interrupt.h>
2462306a36Sopenharmony_ci#include <linux/delay.h>
2562306a36Sopenharmony_ci#include <linux/if.h>
2662306a36Sopenharmony_ci#include <linux/hdlc.h>
2762306a36Sopenharmony_ci#include <asm/io.h>
2862306a36Sopenharmony_ci#include <linux/uaccess.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "farsync.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*      Module info
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ciMODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");
3562306a36Sopenharmony_ciMODULE_DESCRIPTION("FarSync T-Series WAN driver. FarSite Communications Ltd.");
3662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/*      Driver configuration and global parameters
3962306a36Sopenharmony_ci *      ==========================================
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*      Number of ports (per card) and cards supported
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci#define FST_MAX_PORTS           4
4562306a36Sopenharmony_ci#define FST_MAX_CARDS           32
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*      Default parameters for the link
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci#define FST_TX_QUEUE_LEN        100	/* At 8Mbps a longer queue length is
5062306a36Sopenharmony_ci					 * useful
5162306a36Sopenharmony_ci					 */
5262306a36Sopenharmony_ci#define FST_TXQ_DEPTH           16	/* This one is for the buffering
5362306a36Sopenharmony_ci					 * of frames on the way down to the card
5462306a36Sopenharmony_ci					 * so that we can keep the card busy
5562306a36Sopenharmony_ci					 * and maximise throughput
5662306a36Sopenharmony_ci					 */
5762306a36Sopenharmony_ci#define FST_HIGH_WATER_MARK     12	/* Point at which we flow control
5862306a36Sopenharmony_ci					 * network layer
5962306a36Sopenharmony_ci					 */
6062306a36Sopenharmony_ci#define FST_LOW_WATER_MARK      8	/* Point at which we remove flow
6162306a36Sopenharmony_ci					 * control from network layer
6262306a36Sopenharmony_ci					 */
6362306a36Sopenharmony_ci#define FST_MAX_MTU             8000	/* Huge but possible */
6462306a36Sopenharmony_ci#define FST_DEF_MTU             1500	/* Common sane value */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define FST_TX_TIMEOUT          (2 * HZ)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#ifdef ARPHRD_RAWHDLC
6962306a36Sopenharmony_ci#define ARPHRD_MYTYPE   ARPHRD_RAWHDLC	/* Raw frames */
7062306a36Sopenharmony_ci#else
7162306a36Sopenharmony_ci#define ARPHRD_MYTYPE   ARPHRD_HDLC	/* Cisco-HDLC (keepalives etc) */
7262306a36Sopenharmony_ci#endif
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* Modules parameters and associated variables
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistatic int fst_txq_low = FST_LOW_WATER_MARK;
7762306a36Sopenharmony_cistatic int fst_txq_high = FST_HIGH_WATER_MARK;
7862306a36Sopenharmony_cistatic int fst_max_reads = 7;
7962306a36Sopenharmony_cistatic int fst_excluded_cards;
8062306a36Sopenharmony_cistatic int fst_excluded_list[FST_MAX_CARDS];
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cimodule_param(fst_txq_low, int, 0);
8362306a36Sopenharmony_cimodule_param(fst_txq_high, int, 0);
8462306a36Sopenharmony_cimodule_param(fst_max_reads, int, 0);
8562306a36Sopenharmony_cimodule_param(fst_excluded_cards, int, 0);
8662306a36Sopenharmony_cimodule_param_array(fst_excluded_list, int, NULL, 0);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*      Card shared memory layout
8962306a36Sopenharmony_ci *      =========================
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_ci#pragma pack(1)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*      This information is derived in part from the FarSite FarSync Smc.h
9462306a36Sopenharmony_ci *      file. Unfortunately various name clashes and the non-portability of the
9562306a36Sopenharmony_ci *      bit field declarations in that file have meant that I have chosen to
9662306a36Sopenharmony_ci *      recreate the information here.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci *      The SMC (Shared Memory Configuration) has a version number that is
9962306a36Sopenharmony_ci *      incremented every time there is a significant change. This number can
10062306a36Sopenharmony_ci *      be used to check that we have not got out of step with the firmware
10162306a36Sopenharmony_ci *      contained in the .CDE files.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_ci#define SMC_VERSION 24
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define FST_MEMSIZE 0x100000	/* Size of card memory (1Mb) */
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define SMC_BASE 0x00002000L	/* Base offset of the shared memory window main
10862306a36Sopenharmony_ci				 * configuration structure
10962306a36Sopenharmony_ci				 */
11062306a36Sopenharmony_ci#define BFM_BASE 0x00010000L	/* Base offset of the shared memory window DMA
11162306a36Sopenharmony_ci				 * buffers
11262306a36Sopenharmony_ci				 */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define LEN_TX_BUFFER 8192	/* Size of packet buffers */
11562306a36Sopenharmony_ci#define LEN_RX_BUFFER 8192
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define LEN_SMALL_TX_BUFFER 256	/* Size of obsolete buffs used for DOS diags */
11862306a36Sopenharmony_ci#define LEN_SMALL_RX_BUFFER 256
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define NUM_TX_BUFFER 2		/* Must be power of 2. Fixed by firmware */
12162306a36Sopenharmony_ci#define NUM_RX_BUFFER 8
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* Interrupt retry time in milliseconds */
12462306a36Sopenharmony_ci#define INT_RETRY_TIME 2
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*      The Am186CH/CC processors support a SmartDMA mode using circular pools
12762306a36Sopenharmony_ci *      of buffer descriptors. The structure is almost identical to that used
12862306a36Sopenharmony_ci *      in the LANCE Ethernet controllers. Details available as PDF from the
12962306a36Sopenharmony_ci *      AMD web site: https://www.amd.com/products/epd/processors/\
13062306a36Sopenharmony_ci *                    2.16bitcont/3.am186cxfa/a21914/21914.pdf
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_cistruct txdesc {			/* Transmit descriptor */
13362306a36Sopenharmony_ci	volatile u16 ladr;	/* Low order address of packet. This is a
13462306a36Sopenharmony_ci				 * linear address in the Am186 memory space
13562306a36Sopenharmony_ci				 */
13662306a36Sopenharmony_ci	volatile u8 hadr;	/* High order address. Low 4 bits only, high 4
13762306a36Sopenharmony_ci				 * bits must be zero
13862306a36Sopenharmony_ci				 */
13962306a36Sopenharmony_ci	volatile u8 bits;	/* Status and config */
14062306a36Sopenharmony_ci	volatile u16 bcnt;	/* 2s complement of packet size in low 15 bits.
14162306a36Sopenharmony_ci				 * Transmit terminal count interrupt enable in
14262306a36Sopenharmony_ci				 * top bit.
14362306a36Sopenharmony_ci				 */
14462306a36Sopenharmony_ci	u16 unused;		/* Not used in Tx */
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct rxdesc {			/* Receive descriptor */
14862306a36Sopenharmony_ci	volatile u16 ladr;	/* Low order address of packet */
14962306a36Sopenharmony_ci	volatile u8 hadr;	/* High order address */
15062306a36Sopenharmony_ci	volatile u8 bits;	/* Status and config */
15162306a36Sopenharmony_ci	volatile u16 bcnt;	/* 2s complement of buffer size in low 15 bits.
15262306a36Sopenharmony_ci				 * Receive terminal count interrupt enable in
15362306a36Sopenharmony_ci				 * top bit.
15462306a36Sopenharmony_ci				 */
15562306a36Sopenharmony_ci	volatile u16 mcnt;	/* Message byte count (15 bits) */
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/* Convert a length into the 15 bit 2's complement */
15962306a36Sopenharmony_ci/* #define cnv_bcnt(len)   (( ~(len) + 1 ) & 0x7FFF ) */
16062306a36Sopenharmony_ci/* Since we need to set the high bit to enable the completion interrupt this
16162306a36Sopenharmony_ci * can be made a lot simpler
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_ci#define cnv_bcnt(len)   (-(len))
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* Status and config bits for the above */
16662306a36Sopenharmony_ci#define DMA_OWN         0x80	/* SmartDMA owns the descriptor */
16762306a36Sopenharmony_ci#define TX_STP          0x02	/* Tx: start of packet */
16862306a36Sopenharmony_ci#define TX_ENP          0x01	/* Tx: end of packet */
16962306a36Sopenharmony_ci#define RX_ERR          0x40	/* Rx: error (OR of next 4 bits) */
17062306a36Sopenharmony_ci#define RX_FRAM         0x20	/* Rx: framing error */
17162306a36Sopenharmony_ci#define RX_OFLO         0x10	/* Rx: overflow error */
17262306a36Sopenharmony_ci#define RX_CRC          0x08	/* Rx: CRC error */
17362306a36Sopenharmony_ci#define RX_HBUF         0x04	/* Rx: buffer error */
17462306a36Sopenharmony_ci#define RX_STP          0x02	/* Rx: start of packet */
17562306a36Sopenharmony_ci#define RX_ENP          0x01	/* Rx: end of packet */
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* Interrupts from the card are caused by various events which are presented
17862306a36Sopenharmony_ci * in a circular buffer as several events may be processed on one physical int
17962306a36Sopenharmony_ci */
18062306a36Sopenharmony_ci#define MAX_CIRBUFF     32
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistruct cirbuff {
18362306a36Sopenharmony_ci	u8 rdindex;		/* read, then increment and wrap */
18462306a36Sopenharmony_ci	u8 wrindex;		/* write, then increment and wrap */
18562306a36Sopenharmony_ci	u8 evntbuff[MAX_CIRBUFF];
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/* Interrupt event codes.
18962306a36Sopenharmony_ci * Where appropriate the two low order bits indicate the port number
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_ci#define CTLA_CHG        0x18	/* Control signal changed */
19262306a36Sopenharmony_ci#define CTLB_CHG        0x19
19362306a36Sopenharmony_ci#define CTLC_CHG        0x1A
19462306a36Sopenharmony_ci#define CTLD_CHG        0x1B
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#define INIT_CPLT       0x20	/* Initialisation complete */
19762306a36Sopenharmony_ci#define INIT_FAIL       0x21	/* Initialisation failed */
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define ABTA_SENT       0x24	/* Abort sent */
20062306a36Sopenharmony_ci#define ABTB_SENT       0x25
20162306a36Sopenharmony_ci#define ABTC_SENT       0x26
20262306a36Sopenharmony_ci#define ABTD_SENT       0x27
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci#define TXA_UNDF        0x28	/* Transmission underflow */
20562306a36Sopenharmony_ci#define TXB_UNDF        0x29
20662306a36Sopenharmony_ci#define TXC_UNDF        0x2A
20762306a36Sopenharmony_ci#define TXD_UNDF        0x2B
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define F56_INT         0x2C
21062306a36Sopenharmony_ci#define M32_INT         0x2D
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci#define TE1_ALMA        0x30
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/* Port physical configuration. See farsync.h for field values */
21562306a36Sopenharmony_cistruct port_cfg {
21662306a36Sopenharmony_ci	u16 lineInterface;	/* Physical interface type */
21762306a36Sopenharmony_ci	u8 x25op;		/* Unused at present */
21862306a36Sopenharmony_ci	u8 internalClock;	/* 1 => internal clock, 0 => external */
21962306a36Sopenharmony_ci	u8 transparentMode;	/* 1 => on, 0 => off */
22062306a36Sopenharmony_ci	u8 invertClock;		/* 0 => normal, 1 => inverted */
22162306a36Sopenharmony_ci	u8 padBytes[6];		/* Padding */
22262306a36Sopenharmony_ci	u32 lineSpeed;		/* Speed in bps */
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* TE1 port physical configuration */
22662306a36Sopenharmony_cistruct su_config {
22762306a36Sopenharmony_ci	u32 dataRate;
22862306a36Sopenharmony_ci	u8 clocking;
22962306a36Sopenharmony_ci	u8 framing;
23062306a36Sopenharmony_ci	u8 structure;
23162306a36Sopenharmony_ci	u8 interface;
23262306a36Sopenharmony_ci	u8 coding;
23362306a36Sopenharmony_ci	u8 lineBuildOut;
23462306a36Sopenharmony_ci	u8 equalizer;
23562306a36Sopenharmony_ci	u8 transparentMode;
23662306a36Sopenharmony_ci	u8 loopMode;
23762306a36Sopenharmony_ci	u8 range;
23862306a36Sopenharmony_ci	u8 txBufferMode;
23962306a36Sopenharmony_ci	u8 rxBufferMode;
24062306a36Sopenharmony_ci	u8 startingSlot;
24162306a36Sopenharmony_ci	u8 losThreshold;
24262306a36Sopenharmony_ci	u8 enableIdleCode;
24362306a36Sopenharmony_ci	u8 idleCode;
24462306a36Sopenharmony_ci	u8 spare[44];
24562306a36Sopenharmony_ci};
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/* TE1 Status */
24862306a36Sopenharmony_cistruct su_status {
24962306a36Sopenharmony_ci	u32 receiveBufferDelay;
25062306a36Sopenharmony_ci	u32 framingErrorCount;
25162306a36Sopenharmony_ci	u32 codeViolationCount;
25262306a36Sopenharmony_ci	u32 crcErrorCount;
25362306a36Sopenharmony_ci	u32 lineAttenuation;
25462306a36Sopenharmony_ci	u8 portStarted;
25562306a36Sopenharmony_ci	u8 lossOfSignal;
25662306a36Sopenharmony_ci	u8 receiveRemoteAlarm;
25762306a36Sopenharmony_ci	u8 alarmIndicationSignal;
25862306a36Sopenharmony_ci	u8 spare[40];
25962306a36Sopenharmony_ci};
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* Finally sling all the above together into the shared memory structure.
26262306a36Sopenharmony_ci * Sorry it's a hodge podge of arrays, structures and unused bits, it's been
26362306a36Sopenharmony_ci * evolving under NT for some time so I guess we're stuck with it.
26462306a36Sopenharmony_ci * The structure starts at offset SMC_BASE.
26562306a36Sopenharmony_ci * See farsync.h for some field values.
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_cistruct fst_shared {
26862306a36Sopenharmony_ci	/* DMA descriptor rings */
26962306a36Sopenharmony_ci	struct rxdesc rxDescrRing[FST_MAX_PORTS][NUM_RX_BUFFER];
27062306a36Sopenharmony_ci	struct txdesc txDescrRing[FST_MAX_PORTS][NUM_TX_BUFFER];
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Obsolete small buffers */
27362306a36Sopenharmony_ci	u8 smallRxBuffer[FST_MAX_PORTS][NUM_RX_BUFFER][LEN_SMALL_RX_BUFFER];
27462306a36Sopenharmony_ci	u8 smallTxBuffer[FST_MAX_PORTS][NUM_TX_BUFFER][LEN_SMALL_TX_BUFFER];
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	u8 taskStatus;		/* 0x00 => initialising, 0x01 => running,
27762306a36Sopenharmony_ci				 * 0xFF => halted
27862306a36Sopenharmony_ci				 */
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	u8 interruptHandshake;	/* Set to 0x01 by adapter to signal interrupt,
28162306a36Sopenharmony_ci				 * set to 0xEE by host to acknowledge interrupt
28262306a36Sopenharmony_ci				 */
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	u16 smcVersion;		/* Must match SMC_VERSION */
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	u32 smcFirmwareVersion;	/* 0xIIVVRRBB where II = product ID, VV = major
28762306a36Sopenharmony_ci				 * version, RR = revision and BB = build
28862306a36Sopenharmony_ci				 */
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	u16 txa_done;		/* Obsolete completion flags */
29162306a36Sopenharmony_ci	u16 rxa_done;
29262306a36Sopenharmony_ci	u16 txb_done;
29362306a36Sopenharmony_ci	u16 rxb_done;
29462306a36Sopenharmony_ci	u16 txc_done;
29562306a36Sopenharmony_ci	u16 rxc_done;
29662306a36Sopenharmony_ci	u16 txd_done;
29762306a36Sopenharmony_ci	u16 rxd_done;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	u16 mailbox[4];		/* Diagnostics mailbox. Not used */
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	struct cirbuff interruptEvent;	/* interrupt causes */
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	u32 v24IpSts[FST_MAX_PORTS];	/* V.24 control input status */
30462306a36Sopenharmony_ci	u32 v24OpSts[FST_MAX_PORTS];	/* V.24 control output status */
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	struct port_cfg portConfig[FST_MAX_PORTS];
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	u16 clockStatus[FST_MAX_PORTS];	/* lsb: 0=> present, 1=> absent */
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	u16 cableStatus;	/* lsb: 0=> present, 1=> absent */
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	u16 txDescrIndex[FST_MAX_PORTS];	/* transmit descriptor ring index */
31362306a36Sopenharmony_ci	u16 rxDescrIndex[FST_MAX_PORTS];	/* receive descriptor ring index */
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	u16 portMailbox[FST_MAX_PORTS][2];	/* command, modifier */
31662306a36Sopenharmony_ci	u16 cardMailbox[4];	/* Not used */
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Number of times the card thinks the host has
31962306a36Sopenharmony_ci	 * missed an interrupt by not acknowledging
32062306a36Sopenharmony_ci	 * within 2mS (I guess NT has problems)
32162306a36Sopenharmony_ci	 */
32262306a36Sopenharmony_ci	u32 interruptRetryCount;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Driver private data used as an ID. We'll not
32562306a36Sopenharmony_ci	 * use this as I'd rather keep such things
32662306a36Sopenharmony_ci	 * in main memory rather than on the PCI bus
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	u32 portHandle[FST_MAX_PORTS];
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Count of Tx underflows for stats */
33162306a36Sopenharmony_ci	u32 transmitBufferUnderflow[FST_MAX_PORTS];
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Debounced V.24 control input status */
33462306a36Sopenharmony_ci	u32 v24DebouncedSts[FST_MAX_PORTS];
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/* Adapter debounce timers. Don't touch */
33762306a36Sopenharmony_ci	u32 ctsTimer[FST_MAX_PORTS];
33862306a36Sopenharmony_ci	u32 ctsTimerRun[FST_MAX_PORTS];
33962306a36Sopenharmony_ci	u32 dcdTimer[FST_MAX_PORTS];
34062306a36Sopenharmony_ci	u32 dcdTimerRun[FST_MAX_PORTS];
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	u32 numberOfPorts;	/* Number of ports detected at startup */
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	u16 _reserved[64];
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	u16 cardMode;		/* Bit-mask to enable features:
34762306a36Sopenharmony_ci				 * Bit 0: 1 enables LED identify mode
34862306a36Sopenharmony_ci				 */
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	u16 portScheduleOffset;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	struct su_config suConfig;	/* TE1 Bits */
35362306a36Sopenharmony_ci	struct su_status suStatus;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	u32 endOfSmcSignature;	/* endOfSmcSignature MUST be the last member of
35662306a36Sopenharmony_ci				 * the structure and marks the end of shared
35762306a36Sopenharmony_ci				 * memory. Adapter code initializes it as
35862306a36Sopenharmony_ci				 * END_SIG.
35962306a36Sopenharmony_ci				 */
36062306a36Sopenharmony_ci};
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/* endOfSmcSignature value */
36362306a36Sopenharmony_ci#define END_SIG                 0x12345678
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/* Mailbox values. (portMailbox) */
36662306a36Sopenharmony_ci#define NOP             0	/* No operation */
36762306a36Sopenharmony_ci#define ACK             1	/* Positive acknowledgement to PC driver */
36862306a36Sopenharmony_ci#define NAK             2	/* Negative acknowledgement to PC driver */
36962306a36Sopenharmony_ci#define STARTPORT       3	/* Start an HDLC port */
37062306a36Sopenharmony_ci#define STOPPORT        4	/* Stop an HDLC port */
37162306a36Sopenharmony_ci#define ABORTTX         5	/* Abort the transmitter for a port */
37262306a36Sopenharmony_ci#define SETV24O         6	/* Set V24 outputs */
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/* PLX Chip Register Offsets */
37562306a36Sopenharmony_ci#define CNTRL_9052      0x50	/* Control Register */
37662306a36Sopenharmony_ci#define CNTRL_9054      0x6c	/* Control Register */
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci#define INTCSR_9052     0x4c	/* Interrupt control/status register */
37962306a36Sopenharmony_ci#define INTCSR_9054     0x68	/* Interrupt control/status register */
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/* 9054 DMA Registers */
38262306a36Sopenharmony_ci/* Note that we will be using DMA Channel 0 for copying rx data
38362306a36Sopenharmony_ci * and Channel 1 for copying tx data
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_ci#define DMAMODE0        0x80
38662306a36Sopenharmony_ci#define DMAPADR0        0x84
38762306a36Sopenharmony_ci#define DMALADR0        0x88
38862306a36Sopenharmony_ci#define DMASIZ0         0x8c
38962306a36Sopenharmony_ci#define DMADPR0         0x90
39062306a36Sopenharmony_ci#define DMAMODE1        0x94
39162306a36Sopenharmony_ci#define DMAPADR1        0x98
39262306a36Sopenharmony_ci#define DMALADR1        0x9c
39362306a36Sopenharmony_ci#define DMASIZ1         0xa0
39462306a36Sopenharmony_ci#define DMADPR1         0xa4
39562306a36Sopenharmony_ci#define DMACSR0         0xa8
39662306a36Sopenharmony_ci#define DMACSR1         0xa9
39762306a36Sopenharmony_ci#define DMAARB          0xac
39862306a36Sopenharmony_ci#define DMATHR          0xb0
39962306a36Sopenharmony_ci#define DMADAC0         0xb4
40062306a36Sopenharmony_ci#define DMADAC1         0xb8
40162306a36Sopenharmony_ci#define DMAMARBR        0xac
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci#define FST_MIN_DMA_LEN 64
40462306a36Sopenharmony_ci#define FST_RX_DMA_INT  0x01
40562306a36Sopenharmony_ci#define FST_TX_DMA_INT  0x02
40662306a36Sopenharmony_ci#define FST_CARD_INT    0x04
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/* Larger buffers are positioned in memory at offset BFM_BASE */
40962306a36Sopenharmony_cistruct buf_window {
41062306a36Sopenharmony_ci	u8 txBuffer[FST_MAX_PORTS][NUM_TX_BUFFER][LEN_TX_BUFFER];
41162306a36Sopenharmony_ci	u8 rxBuffer[FST_MAX_PORTS][NUM_RX_BUFFER][LEN_RX_BUFFER];
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/* Calculate offset of a buffer object within the shared memory window */
41562306a36Sopenharmony_ci#define BUF_OFFSET(X)   (BFM_BASE + offsetof(struct buf_window, X))
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci#pragma pack()
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/*      Device driver private information
42062306a36Sopenharmony_ci *      =================================
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_ci/*      Per port (line or channel) information
42362306a36Sopenharmony_ci */
42462306a36Sopenharmony_cistruct fst_port_info {
42562306a36Sopenharmony_ci	struct net_device *dev; /* Device struct - must be first */
42662306a36Sopenharmony_ci	struct fst_card_info *card;	/* Card we're associated with */
42762306a36Sopenharmony_ci	int index;		/* Port index on the card */
42862306a36Sopenharmony_ci	int hwif;		/* Line hardware (lineInterface copy) */
42962306a36Sopenharmony_ci	int run;		/* Port is running */
43062306a36Sopenharmony_ci	int mode;		/* Normal or FarSync raw */
43162306a36Sopenharmony_ci	int rxpos;		/* Next Rx buffer to use */
43262306a36Sopenharmony_ci	int txpos;		/* Next Tx buffer to use */
43362306a36Sopenharmony_ci	int txipos;		/* Next Tx buffer to check for free */
43462306a36Sopenharmony_ci	int start;		/* Indication of start/stop to network */
43562306a36Sopenharmony_ci	/* A sixteen entry transmit queue
43662306a36Sopenharmony_ci	 */
43762306a36Sopenharmony_ci	int txqs;		/* index to get next buffer to tx */
43862306a36Sopenharmony_ci	int txqe;		/* index to queue next packet */
43962306a36Sopenharmony_ci	struct sk_buff *txq[FST_TXQ_DEPTH];	/* The queue */
44062306a36Sopenharmony_ci	int rxqdepth;
44162306a36Sopenharmony_ci};
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/*      Per card information
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_cistruct fst_card_info {
44662306a36Sopenharmony_ci	char __iomem *mem;	/* Card memory mapped to kernel space */
44762306a36Sopenharmony_ci	char __iomem *ctlmem;	/* Control memory for PCI cards */
44862306a36Sopenharmony_ci	unsigned int phys_mem;	/* Physical memory window address */
44962306a36Sopenharmony_ci	unsigned int phys_ctlmem;	/* Physical control memory address */
45062306a36Sopenharmony_ci	unsigned int irq;	/* Interrupt request line number */
45162306a36Sopenharmony_ci	unsigned int nports;	/* Number of serial ports */
45262306a36Sopenharmony_ci	unsigned int type;	/* Type index of card */
45362306a36Sopenharmony_ci	unsigned int state;	/* State of card */
45462306a36Sopenharmony_ci	spinlock_t card_lock;	/* Lock for SMP access */
45562306a36Sopenharmony_ci	unsigned short pci_conf;	/* PCI card config in I/O space */
45662306a36Sopenharmony_ci	/* Per port info */
45762306a36Sopenharmony_ci	struct fst_port_info ports[FST_MAX_PORTS];
45862306a36Sopenharmony_ci	struct pci_dev *device;	/* Information about the pci device */
45962306a36Sopenharmony_ci	int card_no;		/* Inst of the card on the system */
46062306a36Sopenharmony_ci	int family;		/* TxP or TxU */
46162306a36Sopenharmony_ci	int dmarx_in_progress;
46262306a36Sopenharmony_ci	int dmatx_in_progress;
46362306a36Sopenharmony_ci	unsigned long int_count;
46462306a36Sopenharmony_ci	unsigned long int_time_ave;
46562306a36Sopenharmony_ci	void *rx_dma_handle_host;
46662306a36Sopenharmony_ci	dma_addr_t rx_dma_handle_card;
46762306a36Sopenharmony_ci	void *tx_dma_handle_host;
46862306a36Sopenharmony_ci	dma_addr_t tx_dma_handle_card;
46962306a36Sopenharmony_ci	struct sk_buff *dma_skb_rx;
47062306a36Sopenharmony_ci	struct fst_port_info *dma_port_rx;
47162306a36Sopenharmony_ci	struct fst_port_info *dma_port_tx;
47262306a36Sopenharmony_ci	int dma_len_rx;
47362306a36Sopenharmony_ci	int dma_len_tx;
47462306a36Sopenharmony_ci	int dma_txpos;
47562306a36Sopenharmony_ci	int dma_rxpos;
47662306a36Sopenharmony_ci};
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/* Convert an HDLC device pointer into a port info pointer and similar */
47962306a36Sopenharmony_ci#define dev_to_port(D)  (dev_to_hdlc(D)->priv)
48062306a36Sopenharmony_ci#define port_to_dev(P)  ((P)->dev)
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/*      Shared memory window access macros
48362306a36Sopenharmony_ci *
48462306a36Sopenharmony_ci *      We have a nice memory based structure above, which could be directly
48562306a36Sopenharmony_ci *      mapped on i386 but might not work on other architectures unless we use
48662306a36Sopenharmony_ci *      the readb,w,l and writeb,w,l macros. Unfortunately these macros take
48762306a36Sopenharmony_ci *      physical offsets so we have to convert. The only saving grace is that
48862306a36Sopenharmony_ci *      this should all collapse back to a simple indirection eventually.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_ci#define WIN_OFFSET(X)   ((long)&(((struct fst_shared *)SMC_BASE)->X))
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci#define FST_RDB(C, E)    (readb((C)->mem + WIN_OFFSET(E)))
49362306a36Sopenharmony_ci#define FST_RDW(C, E)    (readw((C)->mem + WIN_OFFSET(E)))
49462306a36Sopenharmony_ci#define FST_RDL(C, E)    (readl((C)->mem + WIN_OFFSET(E)))
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci#define FST_WRB(C, E, B)  (writeb((B), (C)->mem + WIN_OFFSET(E)))
49762306a36Sopenharmony_ci#define FST_WRW(C, E, W)  (writew((W), (C)->mem + WIN_OFFSET(E)))
49862306a36Sopenharmony_ci#define FST_WRL(C, E, L)  (writel((L), (C)->mem + WIN_OFFSET(E)))
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/*      Debug support
50162306a36Sopenharmony_ci */
50262306a36Sopenharmony_ci#if FST_DEBUG
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int fst_debug_mask = { FST_DEBUG };
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/* Most common debug activity is to print something if the corresponding bit
50762306a36Sopenharmony_ci * is set in the debug mask. Note: this uses a non-ANSI extension in GCC to
50862306a36Sopenharmony_ci * support variable numbers of macro parameters. The inverted if prevents us
50962306a36Sopenharmony_ci * eating someone else's else clause.
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_ci#define dbg(F, fmt, args...)					\
51262306a36Sopenharmony_cido {								\
51362306a36Sopenharmony_ci	if (fst_debug_mask & (F))				\
51462306a36Sopenharmony_ci		printk(KERN_DEBUG pr_fmt(fmt), ##args);		\
51562306a36Sopenharmony_ci} while (0)
51662306a36Sopenharmony_ci#else
51762306a36Sopenharmony_ci#define dbg(F, fmt, args...)					\
51862306a36Sopenharmony_cido {								\
51962306a36Sopenharmony_ci	if (0)							\
52062306a36Sopenharmony_ci		printk(KERN_DEBUG pr_fmt(fmt), ##args);		\
52162306a36Sopenharmony_ci} while (0)
52262306a36Sopenharmony_ci#endif
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/*      PCI ID lookup table
52562306a36Sopenharmony_ci */
52662306a36Sopenharmony_cistatic const struct pci_device_id fst_pci_dev_id[] = {
52762306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID,
52862306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_T2P},
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4P, PCI_ANY_ID,
53162306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_T4P},
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T1U, PCI_ANY_ID,
53462306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_T1U},
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2U, PCI_ANY_ID,
53762306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_T2U},
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4U, PCI_ANY_ID,
54062306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_T4U},
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1, PCI_ANY_ID,
54362306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_TE1},
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1C, PCI_ANY_ID,
54662306a36Sopenharmony_ci	 PCI_ANY_ID, 0, 0, FST_TYPE_TE1},
54762306a36Sopenharmony_ci	{0,}			/* End */
54862306a36Sopenharmony_ci};
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, fst_pci_dev_id);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci/*      Device Driver Work Queues
55362306a36Sopenharmony_ci *
55462306a36Sopenharmony_ci *      So that we don't spend too much time processing events in the
55562306a36Sopenharmony_ci *      Interrupt Service routine, we will declare a work queue per Card
55662306a36Sopenharmony_ci *      and make the ISR schedule a task in the queue for later execution.
55762306a36Sopenharmony_ci *      In the 2.4 Kernel we used to use the immediate queue for BH's
55862306a36Sopenharmony_ci *      Now that they are gone, tasklets seem to be much better than work
55962306a36Sopenharmony_ci *      queues.
56062306a36Sopenharmony_ci */
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void do_bottom_half_tx(struct fst_card_info *card);
56362306a36Sopenharmony_cistatic void do_bottom_half_rx(struct fst_card_info *card);
56462306a36Sopenharmony_cistatic void fst_process_tx_work_q(struct tasklet_struct *unused);
56562306a36Sopenharmony_cistatic void fst_process_int_work_q(struct tasklet_struct *unused);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q);
56862306a36Sopenharmony_cistatic DECLARE_TASKLET(fst_int_task, fst_process_int_work_q);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic struct fst_card_info *fst_card_array[FST_MAX_CARDS];
57162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(fst_work_q_lock);
57262306a36Sopenharmony_cistatic u64 fst_work_txq;
57362306a36Sopenharmony_cistatic u64 fst_work_intq;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic void
57662306a36Sopenharmony_cifst_q_work_item(u64 *queue, int card_index)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	unsigned long flags;
57962306a36Sopenharmony_ci	u64 mask;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* Grab the queue exclusively
58262306a36Sopenharmony_ci	 */
58362306a36Sopenharmony_ci	spin_lock_irqsave(&fst_work_q_lock, flags);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Making an entry in the queue is simply a matter of setting
58662306a36Sopenharmony_ci	 * a bit for the card indicating that there is work to do in the
58762306a36Sopenharmony_ci	 * bottom half for the card.  Note the limitation of 64 cards.
58862306a36Sopenharmony_ci	 * That ought to be enough
58962306a36Sopenharmony_ci	 */
59062306a36Sopenharmony_ci	mask = (u64)1 << card_index;
59162306a36Sopenharmony_ci	*queue |= mask;
59262306a36Sopenharmony_ci	spin_unlock_irqrestore(&fst_work_q_lock, flags);
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void
59662306a36Sopenharmony_cifst_process_tx_work_q(struct tasklet_struct *unused)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	unsigned long flags;
59962306a36Sopenharmony_ci	u64 work_txq;
60062306a36Sopenharmony_ci	int i;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* Grab the queue exclusively
60362306a36Sopenharmony_ci	 */
60462306a36Sopenharmony_ci	dbg(DBG_TX, "fst_process_tx_work_q\n");
60562306a36Sopenharmony_ci	spin_lock_irqsave(&fst_work_q_lock, flags);
60662306a36Sopenharmony_ci	work_txq = fst_work_txq;
60762306a36Sopenharmony_ci	fst_work_txq = 0;
60862306a36Sopenharmony_ci	spin_unlock_irqrestore(&fst_work_q_lock, flags);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/* Call the bottom half for each card with work waiting
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci	for (i = 0; i < FST_MAX_CARDS; i++) {
61362306a36Sopenharmony_ci		if (work_txq & 0x01) {
61462306a36Sopenharmony_ci			if (fst_card_array[i]) {
61562306a36Sopenharmony_ci				dbg(DBG_TX, "Calling tx bh for card %d\n", i);
61662306a36Sopenharmony_ci				do_bottom_half_tx(fst_card_array[i]);
61762306a36Sopenharmony_ci			}
61862306a36Sopenharmony_ci		}
61962306a36Sopenharmony_ci		work_txq = work_txq >> 1;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic void
62462306a36Sopenharmony_cifst_process_int_work_q(struct tasklet_struct *unused)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	unsigned long flags;
62762306a36Sopenharmony_ci	u64 work_intq;
62862306a36Sopenharmony_ci	int i;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* Grab the queue exclusively
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	dbg(DBG_INTR, "fst_process_int_work_q\n");
63362306a36Sopenharmony_ci	spin_lock_irqsave(&fst_work_q_lock, flags);
63462306a36Sopenharmony_ci	work_intq = fst_work_intq;
63562306a36Sopenharmony_ci	fst_work_intq = 0;
63662306a36Sopenharmony_ci	spin_unlock_irqrestore(&fst_work_q_lock, flags);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* Call the bottom half for each card with work waiting
63962306a36Sopenharmony_ci	 */
64062306a36Sopenharmony_ci	for (i = 0; i < FST_MAX_CARDS; i++) {
64162306a36Sopenharmony_ci		if (work_intq & 0x01) {
64262306a36Sopenharmony_ci			if (fst_card_array[i]) {
64362306a36Sopenharmony_ci				dbg(DBG_INTR,
64462306a36Sopenharmony_ci				    "Calling rx & tx bh for card %d\n", i);
64562306a36Sopenharmony_ci				do_bottom_half_rx(fst_card_array[i]);
64662306a36Sopenharmony_ci				do_bottom_half_tx(fst_card_array[i]);
64762306a36Sopenharmony_ci			}
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci		work_intq = work_intq >> 1;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci/*      Card control functions
65462306a36Sopenharmony_ci *      ======================
65562306a36Sopenharmony_ci */
65662306a36Sopenharmony_ci/*      Place the processor in reset state
65762306a36Sopenharmony_ci *
65862306a36Sopenharmony_ci * Used to be a simple write to card control space but a glitch in the latest
65962306a36Sopenharmony_ci * AMD Am186CH processor means that we now have to do it by asserting and de-
66062306a36Sopenharmony_ci * asserting the PLX chip PCI Adapter Software Reset. Bit 30 in CNTRL register
66162306a36Sopenharmony_ci * at offset 9052_CNTRL.  Note the updates for the TXU.
66262306a36Sopenharmony_ci */
66362306a36Sopenharmony_cistatic inline void
66462306a36Sopenharmony_cifst_cpureset(struct fst_card_info *card)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	unsigned char interrupt_line_register;
66762306a36Sopenharmony_ci	unsigned int regval;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
67062306a36Sopenharmony_ci		if (pci_read_config_byte
67162306a36Sopenharmony_ci		    (card->device, PCI_INTERRUPT_LINE, &interrupt_line_register)) {
67262306a36Sopenharmony_ci			dbg(DBG_ASS,
67362306a36Sopenharmony_ci			    "Error in reading interrupt line register\n");
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci		/* Assert PLX software reset and Am186 hardware reset
67662306a36Sopenharmony_ci		 * and then deassert the PLX software reset but 186 still in reset
67762306a36Sopenharmony_ci		 */
67862306a36Sopenharmony_ci		outw(0x440f, card->pci_conf + CNTRL_9054 + 2);
67962306a36Sopenharmony_ci		outw(0x040f, card->pci_conf + CNTRL_9054 + 2);
68062306a36Sopenharmony_ci		/* We are delaying here to allow the 9054 to reset itself
68162306a36Sopenharmony_ci		 */
68262306a36Sopenharmony_ci		usleep_range(10, 20);
68362306a36Sopenharmony_ci		outw(0x240f, card->pci_conf + CNTRL_9054 + 2);
68462306a36Sopenharmony_ci		/* We are delaying here to allow the 9054 to reload its eeprom
68562306a36Sopenharmony_ci		 */
68662306a36Sopenharmony_ci		usleep_range(10, 20);
68762306a36Sopenharmony_ci		outw(0x040f, card->pci_conf + CNTRL_9054 + 2);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		if (pci_write_config_byte
69062306a36Sopenharmony_ci		    (card->device, PCI_INTERRUPT_LINE, interrupt_line_register)) {
69162306a36Sopenharmony_ci			dbg(DBG_ASS,
69262306a36Sopenharmony_ci			    "Error in writing interrupt line register\n");
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	} else {
69662306a36Sopenharmony_ci		regval = inl(card->pci_conf + CNTRL_9052);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		outl(regval | 0x40000000, card->pci_conf + CNTRL_9052);
69962306a36Sopenharmony_ci		outl(regval & ~0x40000000, card->pci_conf + CNTRL_9052);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/*      Release the processor from reset
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_cistatic inline void
70662306a36Sopenharmony_cifst_cpurelease(struct fst_card_info *card)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
70962306a36Sopenharmony_ci		/* Force posted writes to complete
71062306a36Sopenharmony_ci		 */
71162306a36Sopenharmony_ci		(void)readb(card->mem);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		/* Release LRESET DO = 1
71462306a36Sopenharmony_ci		 * Then release Local Hold, DO = 1
71562306a36Sopenharmony_ci		 */
71662306a36Sopenharmony_ci		outw(0x040e, card->pci_conf + CNTRL_9054 + 2);
71762306a36Sopenharmony_ci		outw(0x040f, card->pci_conf + CNTRL_9054 + 2);
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		(void)readb(card->ctlmem);
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci/*      Clear the cards interrupt flag
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_cistatic inline void
72662306a36Sopenharmony_cifst_clear_intr(struct fst_card_info *card)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
72962306a36Sopenharmony_ci		(void)readb(card->ctlmem);
73062306a36Sopenharmony_ci	} else {
73162306a36Sopenharmony_ci		/* Poke the appropriate PLX chip register (same as enabling interrupts)
73262306a36Sopenharmony_ci		 */
73362306a36Sopenharmony_ci		outw(0x0543, card->pci_conf + INTCSR_9052);
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci/*      Enable card interrupts
73862306a36Sopenharmony_ci */
73962306a36Sopenharmony_cistatic inline void
74062306a36Sopenharmony_cifst_enable_intr(struct fst_card_info *card)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU)
74362306a36Sopenharmony_ci		outl(0x0f0c0900, card->pci_conf + INTCSR_9054);
74462306a36Sopenharmony_ci	else
74562306a36Sopenharmony_ci		outw(0x0543, card->pci_conf + INTCSR_9052);
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/*      Disable card interrupts
74962306a36Sopenharmony_ci */
75062306a36Sopenharmony_cistatic inline void
75162306a36Sopenharmony_cifst_disable_intr(struct fst_card_info *card)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU)
75462306a36Sopenharmony_ci		outl(0x00000000, card->pci_conf + INTCSR_9054);
75562306a36Sopenharmony_ci	else
75662306a36Sopenharmony_ci		outw(0x0000, card->pci_conf + INTCSR_9052);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci/*      Process the result of trying to pass a received frame up the stack
76062306a36Sopenharmony_ci */
76162306a36Sopenharmony_cistatic void
76262306a36Sopenharmony_cifst_process_rx_status(int rx_status, char *name)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	switch (rx_status) {
76562306a36Sopenharmony_ci	case NET_RX_SUCCESS:
76662306a36Sopenharmony_ci		{
76762306a36Sopenharmony_ci			/* Nothing to do here
76862306a36Sopenharmony_ci			 */
76962306a36Sopenharmony_ci			break;
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci	case NET_RX_DROP:
77262306a36Sopenharmony_ci		{
77362306a36Sopenharmony_ci			dbg(DBG_ASS, "%s: Received packet dropped\n", name);
77462306a36Sopenharmony_ci			break;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci/*      Initilaise DMA for PLX 9054
78062306a36Sopenharmony_ci */
78162306a36Sopenharmony_cistatic inline void
78262306a36Sopenharmony_cifst_init_dma(struct fst_card_info *card)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	/* This is only required for the PLX 9054
78562306a36Sopenharmony_ci	 */
78662306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
78762306a36Sopenharmony_ci		pci_set_master(card->device);
78862306a36Sopenharmony_ci		outl(0x00020441, card->pci_conf + DMAMODE0);
78962306a36Sopenharmony_ci		outl(0x00020441, card->pci_conf + DMAMODE1);
79062306a36Sopenharmony_ci		outl(0x0, card->pci_conf + DMATHR);
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci/*      Tx dma complete interrupt
79562306a36Sopenharmony_ci */
79662306a36Sopenharmony_cistatic void
79762306a36Sopenharmony_cifst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
79862306a36Sopenharmony_ci		    int len, int txpos)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct net_device *dev = port_to_dev(port);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* Everything is now set, just tell the card to go
80362306a36Sopenharmony_ci	 */
80462306a36Sopenharmony_ci	dbg(DBG_TX, "fst_tx_dma_complete\n");
80562306a36Sopenharmony_ci	FST_WRB(card, txDescrRing[port->index][txpos].bits,
80662306a36Sopenharmony_ci		DMA_OWN | TX_STP | TX_ENP);
80762306a36Sopenharmony_ci	dev->stats.tx_packets++;
80862306a36Sopenharmony_ci	dev->stats.tx_bytes += len;
80962306a36Sopenharmony_ci	netif_trans_update(dev);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/* Mark it for our own raw sockets interface
81362306a36Sopenharmony_ci */
81462306a36Sopenharmony_cistatic __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	skb->dev = dev;
81762306a36Sopenharmony_ci	skb_reset_mac_header(skb);
81862306a36Sopenharmony_ci	skb->pkt_type = PACKET_HOST;
81962306a36Sopenharmony_ci	return htons(ETH_P_CUST);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci/*      Rx dma complete interrupt
82362306a36Sopenharmony_ci */
82462306a36Sopenharmony_cistatic void
82562306a36Sopenharmony_cifst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
82662306a36Sopenharmony_ci		    int len, struct sk_buff *skb, int rxp)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct net_device *dev = port_to_dev(port);
82962306a36Sopenharmony_ci	int pi;
83062306a36Sopenharmony_ci	int rx_status;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	dbg(DBG_TX, "fst_rx_dma_complete\n");
83362306a36Sopenharmony_ci	pi = port->index;
83462306a36Sopenharmony_ci	skb_put_data(skb, card->rx_dma_handle_host, len);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* Reset buffer descriptor */
83762306a36Sopenharmony_ci	FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/* Update stats */
84062306a36Sopenharmony_ci	dev->stats.rx_packets++;
84162306a36Sopenharmony_ci	dev->stats.rx_bytes += len;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	/* Push upstream */
84462306a36Sopenharmony_ci	dbg(DBG_RX, "Pushing the frame up the stack\n");
84562306a36Sopenharmony_ci	if (port->mode == FST_RAW)
84662306a36Sopenharmony_ci		skb->protocol = farsync_type_trans(skb, dev);
84762306a36Sopenharmony_ci	else
84862306a36Sopenharmony_ci		skb->protocol = hdlc_type_trans(skb, dev);
84962306a36Sopenharmony_ci	rx_status = netif_rx(skb);
85062306a36Sopenharmony_ci	fst_process_rx_status(rx_status, port_to_dev(port)->name);
85162306a36Sopenharmony_ci	if (rx_status == NET_RX_DROP)
85262306a36Sopenharmony_ci		dev->stats.rx_dropped++;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci/*      Receive a frame through the DMA
85662306a36Sopenharmony_ci */
85762306a36Sopenharmony_cistatic inline void
85862306a36Sopenharmony_cifst_rx_dma(struct fst_card_info *card, dma_addr_t dma, u32 mem, int len)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	/* This routine will setup the DMA and start it
86162306a36Sopenharmony_ci	 */
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	dbg(DBG_RX, "In fst_rx_dma %x %x %d\n", (u32)dma, mem, len);
86462306a36Sopenharmony_ci	if (card->dmarx_in_progress)
86562306a36Sopenharmony_ci		dbg(DBG_ASS, "In fst_rx_dma while dma in progress\n");
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	outl(dma, card->pci_conf + DMAPADR0);	/* Copy to here */
86862306a36Sopenharmony_ci	outl(mem, card->pci_conf + DMALADR0);	/* from here */
86962306a36Sopenharmony_ci	outl(len, card->pci_conf + DMASIZ0);	/* for this length */
87062306a36Sopenharmony_ci	outl(0x00000000c, card->pci_conf + DMADPR0);	/* In this direction */
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* We use the dmarx_in_progress flag to flag the channel as busy
87362306a36Sopenharmony_ci	 */
87462306a36Sopenharmony_ci	card->dmarx_in_progress = 1;
87562306a36Sopenharmony_ci	outb(0x03, card->pci_conf + DMACSR0);	/* Start the transfer */
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci/*      Send a frame through the DMA
87962306a36Sopenharmony_ci */
88062306a36Sopenharmony_cistatic inline void
88162306a36Sopenharmony_cifst_tx_dma(struct fst_card_info *card, dma_addr_t dma, u32 mem, int len)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	/* This routine will setup the DMA and start it.
88462306a36Sopenharmony_ci	 */
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	dbg(DBG_TX, "In fst_tx_dma %x %x %d\n", (u32)dma, mem, len);
88762306a36Sopenharmony_ci	if (card->dmatx_in_progress)
88862306a36Sopenharmony_ci		dbg(DBG_ASS, "In fst_tx_dma while dma in progress\n");
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	outl(dma, card->pci_conf + DMAPADR1);	/* Copy from here */
89162306a36Sopenharmony_ci	outl(mem, card->pci_conf + DMALADR1);	/* to here */
89262306a36Sopenharmony_ci	outl(len, card->pci_conf + DMASIZ1);	/* for this length */
89362306a36Sopenharmony_ci	outl(0x000000004, card->pci_conf + DMADPR1);	/* In this direction */
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* We use the dmatx_in_progress to flag the channel as busy
89662306a36Sopenharmony_ci	 */
89762306a36Sopenharmony_ci	card->dmatx_in_progress = 1;
89862306a36Sopenharmony_ci	outb(0x03, card->pci_conf + DMACSR1);	/* Start the transfer */
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci/*      Issue a Mailbox command for a port.
90262306a36Sopenharmony_ci *      Note we issue them on a fire and forget basis, not expecting to see an
90362306a36Sopenharmony_ci *      error and not waiting for completion.
90462306a36Sopenharmony_ci */
90562306a36Sopenharmony_cistatic void
90662306a36Sopenharmony_cifst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct fst_card_info *card;
90962306a36Sopenharmony_ci	unsigned short mbval;
91062306a36Sopenharmony_ci	unsigned long flags;
91162306a36Sopenharmony_ci	int safety;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	card = port->card;
91462306a36Sopenharmony_ci	spin_lock_irqsave(&card->card_lock, flags);
91562306a36Sopenharmony_ci	mbval = FST_RDW(card, portMailbox[port->index][0]);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	safety = 0;
91862306a36Sopenharmony_ci	/* Wait for any previous command to complete */
91962306a36Sopenharmony_ci	while (mbval > NAK) {
92062306a36Sopenharmony_ci		spin_unlock_irqrestore(&card->card_lock, flags);
92162306a36Sopenharmony_ci		schedule_timeout_uninterruptible(1);
92262306a36Sopenharmony_ci		spin_lock_irqsave(&card->card_lock, flags);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci		if (++safety > 2000) {
92562306a36Sopenharmony_ci			pr_err("Mailbox safety timeout\n");
92662306a36Sopenharmony_ci			break;
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		mbval = FST_RDW(card, portMailbox[port->index][0]);
93062306a36Sopenharmony_ci	}
93162306a36Sopenharmony_ci	if (safety > 0)
93262306a36Sopenharmony_ci		dbg(DBG_CMD, "Mailbox clear after %d jiffies\n", safety);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (mbval == NAK)
93562306a36Sopenharmony_ci		dbg(DBG_CMD, "issue_cmd: previous command was NAK'd\n");
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	FST_WRW(card, portMailbox[port->index][0], cmd);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (cmd == ABORTTX || cmd == STARTPORT) {
94062306a36Sopenharmony_ci		port->txpos = 0;
94162306a36Sopenharmony_ci		port->txipos = 0;
94262306a36Sopenharmony_ci		port->start = 0;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->card_lock, flags);
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci/*      Port output signals control
94962306a36Sopenharmony_ci */
95062306a36Sopenharmony_cistatic inline void
95162306a36Sopenharmony_cifst_op_raise(struct fst_port_info *port, unsigned int outputs)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	outputs |= FST_RDL(port->card, v24OpSts[port->index]);
95462306a36Sopenharmony_ci	FST_WRL(port->card, v24OpSts[port->index], outputs);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (port->run)
95762306a36Sopenharmony_ci		fst_issue_cmd(port, SETV24O);
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistatic inline void
96162306a36Sopenharmony_cifst_op_lower(struct fst_port_info *port, unsigned int outputs)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	outputs = ~outputs & FST_RDL(port->card, v24OpSts[port->index]);
96462306a36Sopenharmony_ci	FST_WRL(port->card, v24OpSts[port->index], outputs);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (port->run)
96762306a36Sopenharmony_ci		fst_issue_cmd(port, SETV24O);
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci/*      Setup port Rx buffers
97162306a36Sopenharmony_ci */
97262306a36Sopenharmony_cistatic void
97362306a36Sopenharmony_cifst_rx_config(struct fst_port_info *port)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	int i;
97662306a36Sopenharmony_ci	int pi;
97762306a36Sopenharmony_ci	unsigned int offset;
97862306a36Sopenharmony_ci	unsigned long flags;
97962306a36Sopenharmony_ci	struct fst_card_info *card;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	pi = port->index;
98262306a36Sopenharmony_ci	card = port->card;
98362306a36Sopenharmony_ci	spin_lock_irqsave(&card->card_lock, flags);
98462306a36Sopenharmony_ci	for (i = 0; i < NUM_RX_BUFFER; i++) {
98562306a36Sopenharmony_ci		offset = BUF_OFFSET(rxBuffer[pi][i][0]);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		FST_WRW(card, rxDescrRing[pi][i].ladr, (u16)offset);
98862306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][i].hadr, (u8)(offset >> 16));
98962306a36Sopenharmony_ci		FST_WRW(card, rxDescrRing[pi][i].bcnt, cnv_bcnt(LEN_RX_BUFFER));
99062306a36Sopenharmony_ci		FST_WRW(card, rxDescrRing[pi][i].mcnt, LEN_RX_BUFFER);
99162306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][i].bits, DMA_OWN);
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci	port->rxpos = 0;
99462306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->card_lock, flags);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci/*      Setup port Tx buffers
99862306a36Sopenharmony_ci */
99962306a36Sopenharmony_cistatic void
100062306a36Sopenharmony_cifst_tx_config(struct fst_port_info *port)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	int i;
100362306a36Sopenharmony_ci	int pi;
100462306a36Sopenharmony_ci	unsigned int offset;
100562306a36Sopenharmony_ci	unsigned long flags;
100662306a36Sopenharmony_ci	struct fst_card_info *card;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	pi = port->index;
100962306a36Sopenharmony_ci	card = port->card;
101062306a36Sopenharmony_ci	spin_lock_irqsave(&card->card_lock, flags);
101162306a36Sopenharmony_ci	for (i = 0; i < NUM_TX_BUFFER; i++) {
101262306a36Sopenharmony_ci		offset = BUF_OFFSET(txBuffer[pi][i][0]);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		FST_WRW(card, txDescrRing[pi][i].ladr, (u16)offset);
101562306a36Sopenharmony_ci		FST_WRB(card, txDescrRing[pi][i].hadr, (u8)(offset >> 16));
101662306a36Sopenharmony_ci		FST_WRW(card, txDescrRing[pi][i].bcnt, 0);
101762306a36Sopenharmony_ci		FST_WRB(card, txDescrRing[pi][i].bits, 0);
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci	port->txpos = 0;
102062306a36Sopenharmony_ci	port->txipos = 0;
102162306a36Sopenharmony_ci	port->start = 0;
102262306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->card_lock, flags);
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci/*      TE1 Alarm change interrupt event
102662306a36Sopenharmony_ci */
102762306a36Sopenharmony_cistatic void
102862306a36Sopenharmony_cifst_intr_te1_alarm(struct fst_card_info *card, struct fst_port_info *port)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	u8 los;
103162306a36Sopenharmony_ci	u8 rra;
103262306a36Sopenharmony_ci	u8 ais;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	los = FST_RDB(card, suStatus.lossOfSignal);
103562306a36Sopenharmony_ci	rra = FST_RDB(card, suStatus.receiveRemoteAlarm);
103662306a36Sopenharmony_ci	ais = FST_RDB(card, suStatus.alarmIndicationSignal);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (los) {
103962306a36Sopenharmony_ci		/* Lost the link
104062306a36Sopenharmony_ci		 */
104162306a36Sopenharmony_ci		if (netif_carrier_ok(port_to_dev(port))) {
104262306a36Sopenharmony_ci			dbg(DBG_INTR, "Net carrier off\n");
104362306a36Sopenharmony_ci			netif_carrier_off(port_to_dev(port));
104462306a36Sopenharmony_ci		}
104562306a36Sopenharmony_ci	} else {
104662306a36Sopenharmony_ci		/* Link available
104762306a36Sopenharmony_ci		 */
104862306a36Sopenharmony_ci		if (!netif_carrier_ok(port_to_dev(port))) {
104962306a36Sopenharmony_ci			dbg(DBG_INTR, "Net carrier on\n");
105062306a36Sopenharmony_ci			netif_carrier_on(port_to_dev(port));
105162306a36Sopenharmony_ci		}
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (los)
105562306a36Sopenharmony_ci		dbg(DBG_INTR, "Assert LOS Alarm\n");
105662306a36Sopenharmony_ci	else
105762306a36Sopenharmony_ci		dbg(DBG_INTR, "De-assert LOS Alarm\n");
105862306a36Sopenharmony_ci	if (rra)
105962306a36Sopenharmony_ci		dbg(DBG_INTR, "Assert RRA Alarm\n");
106062306a36Sopenharmony_ci	else
106162306a36Sopenharmony_ci		dbg(DBG_INTR, "De-assert RRA Alarm\n");
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (ais)
106462306a36Sopenharmony_ci		dbg(DBG_INTR, "Assert AIS Alarm\n");
106562306a36Sopenharmony_ci	else
106662306a36Sopenharmony_ci		dbg(DBG_INTR, "De-assert AIS Alarm\n");
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci/*      Control signal change interrupt event
107062306a36Sopenharmony_ci */
107162306a36Sopenharmony_cistatic void
107262306a36Sopenharmony_cifst_intr_ctlchg(struct fst_card_info *card, struct fst_port_info *port)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	int signals;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	signals = FST_RDL(card, v24DebouncedSts[port->index]);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	if (signals & ((port->hwif == X21 || port->hwif == X21D)
107962306a36Sopenharmony_ci		       ? IPSTS_INDICATE : IPSTS_DCD)) {
108062306a36Sopenharmony_ci		if (!netif_carrier_ok(port_to_dev(port))) {
108162306a36Sopenharmony_ci			dbg(DBG_INTR, "DCD active\n");
108262306a36Sopenharmony_ci			netif_carrier_on(port_to_dev(port));
108362306a36Sopenharmony_ci		}
108462306a36Sopenharmony_ci	} else {
108562306a36Sopenharmony_ci		if (netif_carrier_ok(port_to_dev(port))) {
108662306a36Sopenharmony_ci			dbg(DBG_INTR, "DCD lost\n");
108762306a36Sopenharmony_ci			netif_carrier_off(port_to_dev(port));
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci	}
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci/*      Log Rx Errors
109362306a36Sopenharmony_ci */
109462306a36Sopenharmony_cistatic void
109562306a36Sopenharmony_cifst_log_rx_error(struct fst_card_info *card, struct fst_port_info *port,
109662306a36Sopenharmony_ci		 unsigned char dmabits, int rxp, unsigned short len)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	struct net_device *dev = port_to_dev(port);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* Increment the appropriate error counter
110162306a36Sopenharmony_ci	 */
110262306a36Sopenharmony_ci	dev->stats.rx_errors++;
110362306a36Sopenharmony_ci	if (dmabits & RX_OFLO) {
110462306a36Sopenharmony_ci		dev->stats.rx_fifo_errors++;
110562306a36Sopenharmony_ci		dbg(DBG_ASS, "Rx fifo error on card %d port %d buffer %d\n",
110662306a36Sopenharmony_ci		    card->card_no, port->index, rxp);
110762306a36Sopenharmony_ci	}
110862306a36Sopenharmony_ci	if (dmabits & RX_CRC) {
110962306a36Sopenharmony_ci		dev->stats.rx_crc_errors++;
111062306a36Sopenharmony_ci		dbg(DBG_ASS, "Rx crc error on card %d port %d\n",
111162306a36Sopenharmony_ci		    card->card_no, port->index);
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci	if (dmabits & RX_FRAM) {
111462306a36Sopenharmony_ci		dev->stats.rx_frame_errors++;
111562306a36Sopenharmony_ci		dbg(DBG_ASS, "Rx frame error on card %d port %d\n",
111662306a36Sopenharmony_ci		    card->card_no, port->index);
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci	if (dmabits == (RX_STP | RX_ENP)) {
111962306a36Sopenharmony_ci		dev->stats.rx_length_errors++;
112062306a36Sopenharmony_ci		dbg(DBG_ASS, "Rx length error (%d) on card %d port %d\n",
112162306a36Sopenharmony_ci		    len, card->card_no, port->index);
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci/*      Rx Error Recovery
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_cistatic void
112862306a36Sopenharmony_cifst_recover_rx_error(struct fst_card_info *card, struct fst_port_info *port,
112962306a36Sopenharmony_ci		     unsigned char dmabits, int rxp, unsigned short len)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	int i;
113262306a36Sopenharmony_ci	int pi;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	pi = port->index;
113562306a36Sopenharmony_ci	/* Discard buffer descriptors until we see the start of the
113662306a36Sopenharmony_ci	 * next frame.  Note that for long frames this could be in
113762306a36Sopenharmony_ci	 * a subsequent interrupt.
113862306a36Sopenharmony_ci	 */
113962306a36Sopenharmony_ci	i = 0;
114062306a36Sopenharmony_ci	while ((dmabits & (DMA_OWN | RX_STP)) == 0) {
114162306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
114262306a36Sopenharmony_ci		rxp = (rxp + 1) % NUM_RX_BUFFER;
114362306a36Sopenharmony_ci		if (++i > NUM_RX_BUFFER) {
114462306a36Sopenharmony_ci			dbg(DBG_ASS, "intr_rx: Discarding more bufs"
114562306a36Sopenharmony_ci			    " than we have\n");
114662306a36Sopenharmony_ci			break;
114762306a36Sopenharmony_ci		}
114862306a36Sopenharmony_ci		dmabits = FST_RDB(card, rxDescrRing[pi][rxp].bits);
114962306a36Sopenharmony_ci		dbg(DBG_ASS, "DMA Bits of next buffer was %x\n", dmabits);
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci	dbg(DBG_ASS, "There were %d subsequent buffers in error\n", i);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* Discard the terminal buffer */
115462306a36Sopenharmony_ci	if (!(dmabits & DMA_OWN)) {
115562306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
115662306a36Sopenharmony_ci		rxp = (rxp + 1) % NUM_RX_BUFFER;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci	port->rxpos = rxp;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci/*      Rx complete interrupt
116262306a36Sopenharmony_ci */
116362306a36Sopenharmony_cistatic void
116462306a36Sopenharmony_cifst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	unsigned char dmabits;
116762306a36Sopenharmony_ci	int pi;
116862306a36Sopenharmony_ci	int rxp;
116962306a36Sopenharmony_ci	int rx_status;
117062306a36Sopenharmony_ci	unsigned short len;
117162306a36Sopenharmony_ci	struct sk_buff *skb;
117262306a36Sopenharmony_ci	struct net_device *dev = port_to_dev(port);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	/* Check we have a buffer to process */
117562306a36Sopenharmony_ci	pi = port->index;
117662306a36Sopenharmony_ci	rxp = port->rxpos;
117762306a36Sopenharmony_ci	dmabits = FST_RDB(card, rxDescrRing[pi][rxp].bits);
117862306a36Sopenharmony_ci	if (dmabits & DMA_OWN) {
117962306a36Sopenharmony_ci		dbg(DBG_RX | DBG_INTR, "intr_rx: No buffer port %d pos %d\n",
118062306a36Sopenharmony_ci		    pi, rxp);
118162306a36Sopenharmony_ci		return;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci	if (card->dmarx_in_progress)
118462306a36Sopenharmony_ci		return;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* Get buffer length */
118762306a36Sopenharmony_ci	len = FST_RDW(card, rxDescrRing[pi][rxp].mcnt);
118862306a36Sopenharmony_ci	/* Discard the CRC */
118962306a36Sopenharmony_ci	len -= 2;
119062306a36Sopenharmony_ci	if (len == 0) {
119162306a36Sopenharmony_ci		/* This seems to happen on the TE1 interface sometimes
119262306a36Sopenharmony_ci		 * so throw the frame away and log the event.
119362306a36Sopenharmony_ci		 */
119462306a36Sopenharmony_ci		pr_err("Frame received with 0 length. Card %d Port %d\n",
119562306a36Sopenharmony_ci		       card->card_no, port->index);
119662306a36Sopenharmony_ci		/* Return descriptor to card */
119762306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		rxp = (rxp + 1) % NUM_RX_BUFFER;
120062306a36Sopenharmony_ci		port->rxpos = rxp;
120162306a36Sopenharmony_ci		return;
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	/* Check buffer length and for other errors. We insist on one packet
120562306a36Sopenharmony_ci	 * in one buffer. This simplifies things greatly and since we've
120662306a36Sopenharmony_ci	 * allocated 8K it shouldn't be a real world limitation
120762306a36Sopenharmony_ci	 */
120862306a36Sopenharmony_ci	dbg(DBG_RX, "intr_rx: %d,%d: flags %x len %d\n", pi, rxp, dmabits, len);
120962306a36Sopenharmony_ci	if (dmabits != (RX_STP | RX_ENP) || len > LEN_RX_BUFFER - 2) {
121062306a36Sopenharmony_ci		fst_log_rx_error(card, port, dmabits, rxp, len);
121162306a36Sopenharmony_ci		fst_recover_rx_error(card, port, dmabits, rxp, len);
121262306a36Sopenharmony_ci		return;
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	/* Allocate SKB */
121662306a36Sopenharmony_ci	skb = dev_alloc_skb(len);
121762306a36Sopenharmony_ci	if (!skb) {
121862306a36Sopenharmony_ci		dbg(DBG_RX, "intr_rx: can't allocate buffer\n");
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci		dev->stats.rx_dropped++;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		/* Return descriptor to card */
122362306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		rxp = (rxp + 1) % NUM_RX_BUFFER;
122662306a36Sopenharmony_ci		port->rxpos = rxp;
122762306a36Sopenharmony_ci		return;
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	/* We know the length we need to receive, len.
123162306a36Sopenharmony_ci	 * It's not worth using the DMA for reads of less than
123262306a36Sopenharmony_ci	 * FST_MIN_DMA_LEN
123362306a36Sopenharmony_ci	 */
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (len < FST_MIN_DMA_LEN || card->family == FST_FAMILY_TXP) {
123662306a36Sopenharmony_ci		memcpy_fromio(skb_put(skb, len),
123762306a36Sopenharmony_ci			      card->mem + BUF_OFFSET(rxBuffer[pi][rxp][0]),
123862306a36Sopenharmony_ci			      len);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci		/* Reset buffer descriptor */
124162306a36Sopenharmony_ci		FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci		/* Update stats */
124462306a36Sopenharmony_ci		dev->stats.rx_packets++;
124562306a36Sopenharmony_ci		dev->stats.rx_bytes += len;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci		/* Push upstream */
124862306a36Sopenharmony_ci		dbg(DBG_RX, "Pushing frame up the stack\n");
124962306a36Sopenharmony_ci		if (port->mode == FST_RAW)
125062306a36Sopenharmony_ci			skb->protocol = farsync_type_trans(skb, dev);
125162306a36Sopenharmony_ci		else
125262306a36Sopenharmony_ci			skb->protocol = hdlc_type_trans(skb, dev);
125362306a36Sopenharmony_ci		rx_status = netif_rx(skb);
125462306a36Sopenharmony_ci		fst_process_rx_status(rx_status, port_to_dev(port)->name);
125562306a36Sopenharmony_ci		if (rx_status == NET_RX_DROP)
125662306a36Sopenharmony_ci			dev->stats.rx_dropped++;
125762306a36Sopenharmony_ci	} else {
125862306a36Sopenharmony_ci		card->dma_skb_rx = skb;
125962306a36Sopenharmony_ci		card->dma_port_rx = port;
126062306a36Sopenharmony_ci		card->dma_len_rx = len;
126162306a36Sopenharmony_ci		card->dma_rxpos = rxp;
126262306a36Sopenharmony_ci		fst_rx_dma(card, card->rx_dma_handle_card,
126362306a36Sopenharmony_ci			   BUF_OFFSET(rxBuffer[pi][rxp][0]), len);
126462306a36Sopenharmony_ci	}
126562306a36Sopenharmony_ci	if (rxp != port->rxpos) {
126662306a36Sopenharmony_ci		dbg(DBG_ASS, "About to increment rxpos by more than 1\n");
126762306a36Sopenharmony_ci		dbg(DBG_ASS, "rxp = %d rxpos = %d\n", rxp, port->rxpos);
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci	rxp = (rxp + 1) % NUM_RX_BUFFER;
127062306a36Sopenharmony_ci	port->rxpos = rxp;
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci/*      The bottom half to the ISR
127462306a36Sopenharmony_ci *
127562306a36Sopenharmony_ci */
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic void
127862306a36Sopenharmony_cido_bottom_half_tx(struct fst_card_info *card)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	struct fst_port_info *port;
128162306a36Sopenharmony_ci	int pi;
128262306a36Sopenharmony_ci	int txq_length;
128362306a36Sopenharmony_ci	struct sk_buff *skb;
128462306a36Sopenharmony_ci	unsigned long flags;
128562306a36Sopenharmony_ci	struct net_device *dev;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	/*  Find a free buffer for the transmit
128862306a36Sopenharmony_ci	 *  Step through each port on this card
128962306a36Sopenharmony_ci	 */
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	dbg(DBG_TX, "do_bottom_half_tx\n");
129262306a36Sopenharmony_ci	for (pi = 0, port = card->ports; pi < card->nports; pi++, port++) {
129362306a36Sopenharmony_ci		if (!port->run)
129462306a36Sopenharmony_ci			continue;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci		dev = port_to_dev(port);
129762306a36Sopenharmony_ci		while (!(FST_RDB(card, txDescrRing[pi][port->txpos].bits) &
129862306a36Sopenharmony_ci			 DMA_OWN) &&
129962306a36Sopenharmony_ci		       !(card->dmatx_in_progress)) {
130062306a36Sopenharmony_ci			/* There doesn't seem to be a txdone event per-se
130162306a36Sopenharmony_ci			 * We seem to have to deduce it, by checking the DMA_OWN
130262306a36Sopenharmony_ci			 * bit on the next buffer we think we can use
130362306a36Sopenharmony_ci			 */
130462306a36Sopenharmony_ci			spin_lock_irqsave(&card->card_lock, flags);
130562306a36Sopenharmony_ci			txq_length = port->txqe - port->txqs;
130662306a36Sopenharmony_ci			if (txq_length < 0) {
130762306a36Sopenharmony_ci				/* This is the case where one has wrapped and the
130862306a36Sopenharmony_ci				 * maths gives us a negative number
130962306a36Sopenharmony_ci				 */
131062306a36Sopenharmony_ci				txq_length = txq_length + FST_TXQ_DEPTH;
131162306a36Sopenharmony_ci			}
131262306a36Sopenharmony_ci			spin_unlock_irqrestore(&card->card_lock, flags);
131362306a36Sopenharmony_ci			if (txq_length > 0) {
131462306a36Sopenharmony_ci				/* There is something to send
131562306a36Sopenharmony_ci				 */
131662306a36Sopenharmony_ci				spin_lock_irqsave(&card->card_lock, flags);
131762306a36Sopenharmony_ci				skb = port->txq[port->txqs];
131862306a36Sopenharmony_ci				port->txqs++;
131962306a36Sopenharmony_ci				if (port->txqs == FST_TXQ_DEPTH)
132062306a36Sopenharmony_ci					port->txqs = 0;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci				spin_unlock_irqrestore(&card->card_lock, flags);
132362306a36Sopenharmony_ci				/* copy the data and set the required indicators on the
132462306a36Sopenharmony_ci				 * card.
132562306a36Sopenharmony_ci				 */
132662306a36Sopenharmony_ci				FST_WRW(card, txDescrRing[pi][port->txpos].bcnt,
132762306a36Sopenharmony_ci					cnv_bcnt(skb->len));
132862306a36Sopenharmony_ci				if (skb->len < FST_MIN_DMA_LEN ||
132962306a36Sopenharmony_ci				    card->family == FST_FAMILY_TXP) {
133062306a36Sopenharmony_ci					/* Enqueue the packet with normal io */
133162306a36Sopenharmony_ci					memcpy_toio(card->mem +
133262306a36Sopenharmony_ci						    BUF_OFFSET(txBuffer[pi]
133362306a36Sopenharmony_ci							       [port->
133462306a36Sopenharmony_ci								txpos][0]),
133562306a36Sopenharmony_ci						    skb->data, skb->len);
133662306a36Sopenharmony_ci					FST_WRB(card,
133762306a36Sopenharmony_ci						txDescrRing[pi][port->txpos].
133862306a36Sopenharmony_ci						bits,
133962306a36Sopenharmony_ci						DMA_OWN | TX_STP | TX_ENP);
134062306a36Sopenharmony_ci					dev->stats.tx_packets++;
134162306a36Sopenharmony_ci					dev->stats.tx_bytes += skb->len;
134262306a36Sopenharmony_ci					netif_trans_update(dev);
134362306a36Sopenharmony_ci				} else {
134462306a36Sopenharmony_ci					/* Or do it through dma */
134562306a36Sopenharmony_ci					memcpy(card->tx_dma_handle_host,
134662306a36Sopenharmony_ci					       skb->data, skb->len);
134762306a36Sopenharmony_ci					card->dma_port_tx = port;
134862306a36Sopenharmony_ci					card->dma_len_tx = skb->len;
134962306a36Sopenharmony_ci					card->dma_txpos = port->txpos;
135062306a36Sopenharmony_ci					fst_tx_dma(card,
135162306a36Sopenharmony_ci						   card->tx_dma_handle_card,
135262306a36Sopenharmony_ci						   BUF_OFFSET(txBuffer[pi]
135362306a36Sopenharmony_ci							      [port->txpos][0]),
135462306a36Sopenharmony_ci						   skb->len);
135562306a36Sopenharmony_ci				}
135662306a36Sopenharmony_ci				if (++port->txpos >= NUM_TX_BUFFER)
135762306a36Sopenharmony_ci					port->txpos = 0;
135862306a36Sopenharmony_ci				/* If we have flow control on, can we now release it?
135962306a36Sopenharmony_ci				 */
136062306a36Sopenharmony_ci				if (port->start) {
136162306a36Sopenharmony_ci					if (txq_length < fst_txq_low) {
136262306a36Sopenharmony_ci						netif_wake_queue(port_to_dev
136362306a36Sopenharmony_ci								 (port));
136462306a36Sopenharmony_ci						port->start = 0;
136562306a36Sopenharmony_ci					}
136662306a36Sopenharmony_ci				}
136762306a36Sopenharmony_ci				dev_kfree_skb(skb);
136862306a36Sopenharmony_ci			} else {
136962306a36Sopenharmony_ci				/* Nothing to send so break out of the while loop
137062306a36Sopenharmony_ci				 */
137162306a36Sopenharmony_ci				break;
137262306a36Sopenharmony_ci			}
137362306a36Sopenharmony_ci		}
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic void
137862306a36Sopenharmony_cido_bottom_half_rx(struct fst_card_info *card)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	struct fst_port_info *port;
138162306a36Sopenharmony_ci	int pi;
138262306a36Sopenharmony_ci	int rx_count = 0;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	/* Check for rx completions on all ports on this card */
138562306a36Sopenharmony_ci	dbg(DBG_RX, "do_bottom_half_rx\n");
138662306a36Sopenharmony_ci	for (pi = 0, port = card->ports; pi < card->nports; pi++, port++) {
138762306a36Sopenharmony_ci		if (!port->run)
138862306a36Sopenharmony_ci			continue;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci		while (!(FST_RDB(card, rxDescrRing[pi][port->rxpos].bits)
139162306a36Sopenharmony_ci			 & DMA_OWN) && !(card->dmarx_in_progress)) {
139262306a36Sopenharmony_ci			if (rx_count > fst_max_reads) {
139362306a36Sopenharmony_ci				/* Don't spend forever in receive processing
139462306a36Sopenharmony_ci				 * Schedule another event
139562306a36Sopenharmony_ci				 */
139662306a36Sopenharmony_ci				fst_q_work_item(&fst_work_intq, card->card_no);
139762306a36Sopenharmony_ci				tasklet_schedule(&fst_int_task);
139862306a36Sopenharmony_ci				break;	/* Leave the loop */
139962306a36Sopenharmony_ci			}
140062306a36Sopenharmony_ci			fst_intr_rx(card, port);
140162306a36Sopenharmony_ci			rx_count++;
140262306a36Sopenharmony_ci		}
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci/*      The interrupt service routine
140762306a36Sopenharmony_ci *      Dev_id is our fst_card_info pointer
140862306a36Sopenharmony_ci */
140962306a36Sopenharmony_cistatic irqreturn_t
141062306a36Sopenharmony_cifst_intr(int dummy, void *dev_id)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	struct fst_card_info *card = dev_id;
141362306a36Sopenharmony_ci	struct fst_port_info *port;
141462306a36Sopenharmony_ci	int rdidx;		/* Event buffer indices */
141562306a36Sopenharmony_ci	int wridx;
141662306a36Sopenharmony_ci	int event;		/* Actual event for processing */
141762306a36Sopenharmony_ci	unsigned int dma_intcsr = 0;
141862306a36Sopenharmony_ci	unsigned int do_card_interrupt;
141962306a36Sopenharmony_ci	unsigned int int_retry_count;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	/* Check to see if the interrupt was for this card
142262306a36Sopenharmony_ci	 * return if not
142362306a36Sopenharmony_ci	 * Note that the call to clear the interrupt is important
142462306a36Sopenharmony_ci	 */
142562306a36Sopenharmony_ci	dbg(DBG_INTR, "intr: %d %p\n", card->irq, card);
142662306a36Sopenharmony_ci	if (card->state != FST_RUNNING) {
142762306a36Sopenharmony_ci		pr_err("Interrupt received for card %d in a non running state (%d)\n",
142862306a36Sopenharmony_ci		       card->card_no, card->state);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		/* It is possible to really be running, i.e. we have re-loaded
143162306a36Sopenharmony_ci		 * a running card
143262306a36Sopenharmony_ci		 * Clear and reprime the interrupt source
143362306a36Sopenharmony_ci		 */
143462306a36Sopenharmony_ci		fst_clear_intr(card);
143562306a36Sopenharmony_ci		return IRQ_HANDLED;
143662306a36Sopenharmony_ci	}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	/* Clear and reprime the interrupt source */
143962306a36Sopenharmony_ci	fst_clear_intr(card);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	/* Is the interrupt for this card (handshake == 1)
144262306a36Sopenharmony_ci	 */
144362306a36Sopenharmony_ci	do_card_interrupt = 0;
144462306a36Sopenharmony_ci	if (FST_RDB(card, interruptHandshake) == 1) {
144562306a36Sopenharmony_ci		do_card_interrupt += FST_CARD_INT;
144662306a36Sopenharmony_ci		/* Set the software acknowledge */
144762306a36Sopenharmony_ci		FST_WRB(card, interruptHandshake, 0xEE);
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
145062306a36Sopenharmony_ci		/* Is it a DMA Interrupt
145162306a36Sopenharmony_ci		 */
145262306a36Sopenharmony_ci		dma_intcsr = inl(card->pci_conf + INTCSR_9054);
145362306a36Sopenharmony_ci		if (dma_intcsr & 0x00200000) {
145462306a36Sopenharmony_ci			/* DMA Channel 0 (Rx transfer complete)
145562306a36Sopenharmony_ci			 */
145662306a36Sopenharmony_ci			dbg(DBG_RX, "DMA Rx xfer complete\n");
145762306a36Sopenharmony_ci			outb(0x8, card->pci_conf + DMACSR0);
145862306a36Sopenharmony_ci			fst_rx_dma_complete(card, card->dma_port_rx,
145962306a36Sopenharmony_ci					    card->dma_len_rx, card->dma_skb_rx,
146062306a36Sopenharmony_ci					    card->dma_rxpos);
146162306a36Sopenharmony_ci			card->dmarx_in_progress = 0;
146262306a36Sopenharmony_ci			do_card_interrupt += FST_RX_DMA_INT;
146362306a36Sopenharmony_ci		}
146462306a36Sopenharmony_ci		if (dma_intcsr & 0x00400000) {
146562306a36Sopenharmony_ci			/* DMA Channel 1 (Tx transfer complete)
146662306a36Sopenharmony_ci			 */
146762306a36Sopenharmony_ci			dbg(DBG_TX, "DMA Tx xfer complete\n");
146862306a36Sopenharmony_ci			outb(0x8, card->pci_conf + DMACSR1);
146962306a36Sopenharmony_ci			fst_tx_dma_complete(card, card->dma_port_tx,
147062306a36Sopenharmony_ci					    card->dma_len_tx, card->dma_txpos);
147162306a36Sopenharmony_ci			card->dmatx_in_progress = 0;
147262306a36Sopenharmony_ci			do_card_interrupt += FST_TX_DMA_INT;
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	/* Have we been missing Interrupts
147762306a36Sopenharmony_ci	 */
147862306a36Sopenharmony_ci	int_retry_count = FST_RDL(card, interruptRetryCount);
147962306a36Sopenharmony_ci	if (int_retry_count) {
148062306a36Sopenharmony_ci		dbg(DBG_ASS, "Card %d int_retry_count is  %d\n",
148162306a36Sopenharmony_ci		    card->card_no, int_retry_count);
148262306a36Sopenharmony_ci		FST_WRL(card, interruptRetryCount, 0);
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (!do_card_interrupt)
148662306a36Sopenharmony_ci		return IRQ_HANDLED;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/* Scehdule the bottom half of the ISR */
148962306a36Sopenharmony_ci	fst_q_work_item(&fst_work_intq, card->card_no);
149062306a36Sopenharmony_ci	tasklet_schedule(&fst_int_task);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	/* Drain the event queue */
149362306a36Sopenharmony_ci	rdidx = FST_RDB(card, interruptEvent.rdindex) & 0x1f;
149462306a36Sopenharmony_ci	wridx = FST_RDB(card, interruptEvent.wrindex) & 0x1f;
149562306a36Sopenharmony_ci	while (rdidx != wridx) {
149662306a36Sopenharmony_ci		event = FST_RDB(card, interruptEvent.evntbuff[rdidx]);
149762306a36Sopenharmony_ci		port = &card->ports[event & 0x03];
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci		dbg(DBG_INTR, "Processing Interrupt event: %x\n", event);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci		switch (event) {
150262306a36Sopenharmony_ci		case TE1_ALMA:
150362306a36Sopenharmony_ci			dbg(DBG_INTR, "TE1 Alarm intr\n");
150462306a36Sopenharmony_ci			if (port->run)
150562306a36Sopenharmony_ci				fst_intr_te1_alarm(card, port);
150662306a36Sopenharmony_ci			break;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci		case CTLA_CHG:
150962306a36Sopenharmony_ci		case CTLB_CHG:
151062306a36Sopenharmony_ci		case CTLC_CHG:
151162306a36Sopenharmony_ci		case CTLD_CHG:
151262306a36Sopenharmony_ci			if (port->run)
151362306a36Sopenharmony_ci				fst_intr_ctlchg(card, port);
151462306a36Sopenharmony_ci			break;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		case ABTA_SENT:
151762306a36Sopenharmony_ci		case ABTB_SENT:
151862306a36Sopenharmony_ci		case ABTC_SENT:
151962306a36Sopenharmony_ci		case ABTD_SENT:
152062306a36Sopenharmony_ci			dbg(DBG_TX, "Abort complete port %d\n", port->index);
152162306a36Sopenharmony_ci			break;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci		case TXA_UNDF:
152462306a36Sopenharmony_ci		case TXB_UNDF:
152562306a36Sopenharmony_ci		case TXC_UNDF:
152662306a36Sopenharmony_ci		case TXD_UNDF:
152762306a36Sopenharmony_ci			/* Difficult to see how we'd get this given that we
152862306a36Sopenharmony_ci			 * always load up the entire packet for DMA.
152962306a36Sopenharmony_ci			 */
153062306a36Sopenharmony_ci			dbg(DBG_TX, "Tx underflow port %d\n", port->index);
153162306a36Sopenharmony_ci			port_to_dev(port)->stats.tx_errors++;
153262306a36Sopenharmony_ci			port_to_dev(port)->stats.tx_fifo_errors++;
153362306a36Sopenharmony_ci			dbg(DBG_ASS, "Tx underflow on card %d port %d\n",
153462306a36Sopenharmony_ci			    card->card_no, port->index);
153562306a36Sopenharmony_ci			break;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		case INIT_CPLT:
153862306a36Sopenharmony_ci			dbg(DBG_INIT, "Card init OK intr\n");
153962306a36Sopenharmony_ci			break;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci		case INIT_FAIL:
154262306a36Sopenharmony_ci			dbg(DBG_INIT, "Card init FAILED intr\n");
154362306a36Sopenharmony_ci			card->state = FST_IFAILED;
154462306a36Sopenharmony_ci			break;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci		default:
154762306a36Sopenharmony_ci			pr_err("intr: unknown card event %d. ignored\n", event);
154862306a36Sopenharmony_ci			break;
154962306a36Sopenharmony_ci		}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci		/* Bump and wrap the index */
155262306a36Sopenharmony_ci		if (++rdidx >= MAX_CIRBUFF)
155362306a36Sopenharmony_ci			rdidx = 0;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci	FST_WRB(card, interruptEvent.rdindex, rdidx);
155662306a36Sopenharmony_ci	return IRQ_HANDLED;
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci/*      Check that the shared memory configuration is one that we can handle
156062306a36Sopenharmony_ci *      and that some basic parameters are correct
156162306a36Sopenharmony_ci */
156262306a36Sopenharmony_cistatic void
156362306a36Sopenharmony_cicheck_started_ok(struct fst_card_info *card)
156462306a36Sopenharmony_ci{
156562306a36Sopenharmony_ci	int i;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	/* Check structure version and end marker */
156862306a36Sopenharmony_ci	if (FST_RDW(card, smcVersion) != SMC_VERSION) {
156962306a36Sopenharmony_ci		pr_err("Bad shared memory version %d expected %d\n",
157062306a36Sopenharmony_ci		       FST_RDW(card, smcVersion), SMC_VERSION);
157162306a36Sopenharmony_ci		card->state = FST_BADVERSION;
157262306a36Sopenharmony_ci		return;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci	if (FST_RDL(card, endOfSmcSignature) != END_SIG) {
157562306a36Sopenharmony_ci		pr_err("Missing shared memory signature\n");
157662306a36Sopenharmony_ci		card->state = FST_BADVERSION;
157762306a36Sopenharmony_ci		return;
157862306a36Sopenharmony_ci	}
157962306a36Sopenharmony_ci	/* Firmware status flag, 0x00 = initialising, 0x01 = OK, 0xFF = fail */
158062306a36Sopenharmony_ci	i = FST_RDB(card, taskStatus);
158162306a36Sopenharmony_ci	if (i == 0x01) {
158262306a36Sopenharmony_ci		card->state = FST_RUNNING;
158362306a36Sopenharmony_ci	} else if (i == 0xFF) {
158462306a36Sopenharmony_ci		pr_err("Firmware initialisation failed. Card halted\n");
158562306a36Sopenharmony_ci		card->state = FST_HALTED;
158662306a36Sopenharmony_ci		return;
158762306a36Sopenharmony_ci	} else if (i != 0x00) {
158862306a36Sopenharmony_ci		pr_err("Unknown firmware status 0x%x\n", i);
158962306a36Sopenharmony_ci		card->state = FST_HALTED;
159062306a36Sopenharmony_ci		return;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	/* Finally check the number of ports reported by firmware against the
159462306a36Sopenharmony_ci	 * number we assumed at card detection. Should never happen with
159562306a36Sopenharmony_ci	 * existing firmware etc so we just report it for the moment.
159662306a36Sopenharmony_ci	 */
159762306a36Sopenharmony_ci	if (FST_RDL(card, numberOfPorts) != card->nports) {
159862306a36Sopenharmony_ci		pr_warn("Port count mismatch on card %d.  Firmware thinks %d we say %d\n",
159962306a36Sopenharmony_ci			card->card_no,
160062306a36Sopenharmony_ci			FST_RDL(card, numberOfPorts), card->nports);
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_cistatic int
160562306a36Sopenharmony_ciset_conf_from_info(struct fst_card_info *card, struct fst_port_info *port,
160662306a36Sopenharmony_ci		   struct fstioc_info *info)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	int err;
160962306a36Sopenharmony_ci	unsigned char my_framing;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/* Set things according to the user set valid flags
161262306a36Sopenharmony_ci	 * Several of the old options have been invalidated/replaced by the
161362306a36Sopenharmony_ci	 * generic hdlc package.
161462306a36Sopenharmony_ci	 */
161562306a36Sopenharmony_ci	err = 0;
161662306a36Sopenharmony_ci	if (info->valid & FSTVAL_PROTO) {
161762306a36Sopenharmony_ci		if (info->proto == FST_RAW)
161862306a36Sopenharmony_ci			port->mode = FST_RAW;
161962306a36Sopenharmony_ci		else
162062306a36Sopenharmony_ci			port->mode = FST_GEN_HDLC;
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	if (info->valid & FSTVAL_CABLE)
162462306a36Sopenharmony_ci		err = -EINVAL;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	if (info->valid & FSTVAL_SPEED)
162762306a36Sopenharmony_ci		err = -EINVAL;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	if (info->valid & FSTVAL_PHASE)
163062306a36Sopenharmony_ci		FST_WRB(card, portConfig[port->index].invertClock,
163162306a36Sopenharmony_ci			info->invertClock);
163262306a36Sopenharmony_ci	if (info->valid & FSTVAL_MODE)
163362306a36Sopenharmony_ci		FST_WRW(card, cardMode, info->cardMode);
163462306a36Sopenharmony_ci	if (info->valid & FSTVAL_TE1) {
163562306a36Sopenharmony_ci		FST_WRL(card, suConfig.dataRate, info->lineSpeed);
163662306a36Sopenharmony_ci		FST_WRB(card, suConfig.clocking, info->clockSource);
163762306a36Sopenharmony_ci		my_framing = FRAMING_E1;
163862306a36Sopenharmony_ci		if (info->framing == E1)
163962306a36Sopenharmony_ci			my_framing = FRAMING_E1;
164062306a36Sopenharmony_ci		if (info->framing == T1)
164162306a36Sopenharmony_ci			my_framing = FRAMING_T1;
164262306a36Sopenharmony_ci		if (info->framing == J1)
164362306a36Sopenharmony_ci			my_framing = FRAMING_J1;
164462306a36Sopenharmony_ci		FST_WRB(card, suConfig.framing, my_framing);
164562306a36Sopenharmony_ci		FST_WRB(card, suConfig.structure, info->structure);
164662306a36Sopenharmony_ci		FST_WRB(card, suConfig.interface, info->interface);
164762306a36Sopenharmony_ci		FST_WRB(card, suConfig.coding, info->coding);
164862306a36Sopenharmony_ci		FST_WRB(card, suConfig.lineBuildOut, info->lineBuildOut);
164962306a36Sopenharmony_ci		FST_WRB(card, suConfig.equalizer, info->equalizer);
165062306a36Sopenharmony_ci		FST_WRB(card, suConfig.transparentMode, info->transparentMode);
165162306a36Sopenharmony_ci		FST_WRB(card, suConfig.loopMode, info->loopMode);
165262306a36Sopenharmony_ci		FST_WRB(card, suConfig.range, info->range);
165362306a36Sopenharmony_ci		FST_WRB(card, suConfig.txBufferMode, info->txBufferMode);
165462306a36Sopenharmony_ci		FST_WRB(card, suConfig.rxBufferMode, info->rxBufferMode);
165562306a36Sopenharmony_ci		FST_WRB(card, suConfig.startingSlot, info->startingSlot);
165662306a36Sopenharmony_ci		FST_WRB(card, suConfig.losThreshold, info->losThreshold);
165762306a36Sopenharmony_ci		if (info->idleCode)
165862306a36Sopenharmony_ci			FST_WRB(card, suConfig.enableIdleCode, 1);
165962306a36Sopenharmony_ci		else
166062306a36Sopenharmony_ci			FST_WRB(card, suConfig.enableIdleCode, 0);
166162306a36Sopenharmony_ci		FST_WRB(card, suConfig.idleCode, info->idleCode);
166262306a36Sopenharmony_ci#if FST_DEBUG
166362306a36Sopenharmony_ci		if (info->valid & FSTVAL_TE1) {
166462306a36Sopenharmony_ci			printk("Setting TE1 data\n");
166562306a36Sopenharmony_ci			printk("Line Speed = %d\n", info->lineSpeed);
166662306a36Sopenharmony_ci			printk("Start slot = %d\n", info->startingSlot);
166762306a36Sopenharmony_ci			printk("Clock source = %d\n", info->clockSource);
166862306a36Sopenharmony_ci			printk("Framing = %d\n", my_framing);
166962306a36Sopenharmony_ci			printk("Structure = %d\n", info->structure);
167062306a36Sopenharmony_ci			printk("interface = %d\n", info->interface);
167162306a36Sopenharmony_ci			printk("Coding = %d\n", info->coding);
167262306a36Sopenharmony_ci			printk("Line build out = %d\n", info->lineBuildOut);
167362306a36Sopenharmony_ci			printk("Equaliser = %d\n", info->equalizer);
167462306a36Sopenharmony_ci			printk("Transparent mode = %d\n",
167562306a36Sopenharmony_ci			       info->transparentMode);
167662306a36Sopenharmony_ci			printk("Loop mode = %d\n", info->loopMode);
167762306a36Sopenharmony_ci			printk("Range = %d\n", info->range);
167862306a36Sopenharmony_ci			printk("Tx Buffer mode = %d\n", info->txBufferMode);
167962306a36Sopenharmony_ci			printk("Rx Buffer mode = %d\n", info->rxBufferMode);
168062306a36Sopenharmony_ci			printk("LOS Threshold = %d\n", info->losThreshold);
168162306a36Sopenharmony_ci			printk("Idle Code = %d\n", info->idleCode);
168262306a36Sopenharmony_ci		}
168362306a36Sopenharmony_ci#endif
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci#if FST_DEBUG
168662306a36Sopenharmony_ci	if (info->valid & FSTVAL_DEBUG)
168762306a36Sopenharmony_ci		fst_debug_mask = info->debug;
168862306a36Sopenharmony_ci#endif
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	return err;
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_cistatic void
169462306a36Sopenharmony_cigather_conf_info(struct fst_card_info *card, struct fst_port_info *port,
169562306a36Sopenharmony_ci		 struct fstioc_info *info)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	int i;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	memset(info, 0, sizeof(struct fstioc_info));
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	i = port->index;
170262306a36Sopenharmony_ci	info->kernelVersion = LINUX_VERSION_CODE;
170362306a36Sopenharmony_ci	info->nports = card->nports;
170462306a36Sopenharmony_ci	info->type = card->type;
170562306a36Sopenharmony_ci	info->state = card->state;
170662306a36Sopenharmony_ci	info->proto = FST_GEN_HDLC;
170762306a36Sopenharmony_ci	info->index = i;
170862306a36Sopenharmony_ci#if FST_DEBUG
170962306a36Sopenharmony_ci	info->debug = fst_debug_mask;
171062306a36Sopenharmony_ci#endif
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	/* Only mark information as valid if card is running.
171362306a36Sopenharmony_ci	 * Copy the data anyway in case it is useful for diagnostics
171462306a36Sopenharmony_ci	 */
171562306a36Sopenharmony_ci	info->valid = ((card->state == FST_RUNNING) ? FSTVAL_ALL : FSTVAL_CARD)
171662306a36Sopenharmony_ci#if FST_DEBUG
171762306a36Sopenharmony_ci	    | FSTVAL_DEBUG
171862306a36Sopenharmony_ci#endif
171962306a36Sopenharmony_ci	    ;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	info->lineInterface = FST_RDW(card, portConfig[i].lineInterface);
172262306a36Sopenharmony_ci	info->internalClock = FST_RDB(card, portConfig[i].internalClock);
172362306a36Sopenharmony_ci	info->lineSpeed = FST_RDL(card, portConfig[i].lineSpeed);
172462306a36Sopenharmony_ci	info->invertClock = FST_RDB(card, portConfig[i].invertClock);
172562306a36Sopenharmony_ci	info->v24IpSts = FST_RDL(card, v24IpSts[i]);
172662306a36Sopenharmony_ci	info->v24OpSts = FST_RDL(card, v24OpSts[i]);
172762306a36Sopenharmony_ci	info->clockStatus = FST_RDW(card, clockStatus[i]);
172862306a36Sopenharmony_ci	info->cableStatus = FST_RDW(card, cableStatus);
172962306a36Sopenharmony_ci	info->cardMode = FST_RDW(card, cardMode);
173062306a36Sopenharmony_ci	info->smcFirmwareVersion = FST_RDL(card, smcFirmwareVersion);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/* The T2U can report cable presence for both A or B
173362306a36Sopenharmony_ci	 * in bits 0 and 1 of cableStatus.  See which port we are and
173462306a36Sopenharmony_ci	 * do the mapping.
173562306a36Sopenharmony_ci	 */
173662306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
173762306a36Sopenharmony_ci		if (port->index == 0) {
173862306a36Sopenharmony_ci			/* Port A
173962306a36Sopenharmony_ci			 */
174062306a36Sopenharmony_ci			info->cableStatus = info->cableStatus & 1;
174162306a36Sopenharmony_ci		} else {
174262306a36Sopenharmony_ci			/* Port B
174362306a36Sopenharmony_ci			 */
174462306a36Sopenharmony_ci			info->cableStatus = info->cableStatus >> 1;
174562306a36Sopenharmony_ci			info->cableStatus = info->cableStatus & 1;
174662306a36Sopenharmony_ci		}
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci	/* Some additional bits if we are TE1
174962306a36Sopenharmony_ci	 */
175062306a36Sopenharmony_ci	if (card->type == FST_TYPE_TE1) {
175162306a36Sopenharmony_ci		info->lineSpeed = FST_RDL(card, suConfig.dataRate);
175262306a36Sopenharmony_ci		info->clockSource = FST_RDB(card, suConfig.clocking);
175362306a36Sopenharmony_ci		info->framing = FST_RDB(card, suConfig.framing);
175462306a36Sopenharmony_ci		info->structure = FST_RDB(card, suConfig.structure);
175562306a36Sopenharmony_ci		info->interface = FST_RDB(card, suConfig.interface);
175662306a36Sopenharmony_ci		info->coding = FST_RDB(card, suConfig.coding);
175762306a36Sopenharmony_ci		info->lineBuildOut = FST_RDB(card, suConfig.lineBuildOut);
175862306a36Sopenharmony_ci		info->equalizer = FST_RDB(card, suConfig.equalizer);
175962306a36Sopenharmony_ci		info->loopMode = FST_RDB(card, suConfig.loopMode);
176062306a36Sopenharmony_ci		info->range = FST_RDB(card, suConfig.range);
176162306a36Sopenharmony_ci		info->txBufferMode = FST_RDB(card, suConfig.txBufferMode);
176262306a36Sopenharmony_ci		info->rxBufferMode = FST_RDB(card, suConfig.rxBufferMode);
176362306a36Sopenharmony_ci		info->startingSlot = FST_RDB(card, suConfig.startingSlot);
176462306a36Sopenharmony_ci		info->losThreshold = FST_RDB(card, suConfig.losThreshold);
176562306a36Sopenharmony_ci		if (FST_RDB(card, suConfig.enableIdleCode))
176662306a36Sopenharmony_ci			info->idleCode = FST_RDB(card, suConfig.idleCode);
176762306a36Sopenharmony_ci		else
176862306a36Sopenharmony_ci			info->idleCode = 0;
176962306a36Sopenharmony_ci		info->receiveBufferDelay =
177062306a36Sopenharmony_ci		    FST_RDL(card, suStatus.receiveBufferDelay);
177162306a36Sopenharmony_ci		info->framingErrorCount =
177262306a36Sopenharmony_ci		    FST_RDL(card, suStatus.framingErrorCount);
177362306a36Sopenharmony_ci		info->codeViolationCount =
177462306a36Sopenharmony_ci		    FST_RDL(card, suStatus.codeViolationCount);
177562306a36Sopenharmony_ci		info->crcErrorCount = FST_RDL(card, suStatus.crcErrorCount);
177662306a36Sopenharmony_ci		info->lineAttenuation = FST_RDL(card, suStatus.lineAttenuation);
177762306a36Sopenharmony_ci		info->lossOfSignal = FST_RDB(card, suStatus.lossOfSignal);
177862306a36Sopenharmony_ci		info->receiveRemoteAlarm =
177962306a36Sopenharmony_ci		    FST_RDB(card, suStatus.receiveRemoteAlarm);
178062306a36Sopenharmony_ci		info->alarmIndicationSignal =
178162306a36Sopenharmony_ci		    FST_RDB(card, suStatus.alarmIndicationSignal);
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_cistatic int
178662306a36Sopenharmony_cifst_set_iface(struct fst_card_info *card, struct fst_port_info *port,
178762306a36Sopenharmony_ci	      struct if_settings *ifs)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	sync_serial_settings sync;
179062306a36Sopenharmony_ci	int i;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (ifs->size != sizeof(sync))
179362306a36Sopenharmony_ci		return -ENOMEM;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	if (copy_from_user(&sync, ifs->ifs_ifsu.sync, sizeof(sync)))
179662306a36Sopenharmony_ci		return -EFAULT;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	if (sync.loopback)
179962306a36Sopenharmony_ci		return -EINVAL;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	i = port->index;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	switch (ifs->type) {
180462306a36Sopenharmony_ci	case IF_IFACE_V35:
180562306a36Sopenharmony_ci		FST_WRW(card, portConfig[i].lineInterface, V35);
180662306a36Sopenharmony_ci		port->hwif = V35;
180762306a36Sopenharmony_ci		break;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	case IF_IFACE_V24:
181062306a36Sopenharmony_ci		FST_WRW(card, portConfig[i].lineInterface, V24);
181162306a36Sopenharmony_ci		port->hwif = V24;
181262306a36Sopenharmony_ci		break;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	case IF_IFACE_X21:
181562306a36Sopenharmony_ci		FST_WRW(card, portConfig[i].lineInterface, X21);
181662306a36Sopenharmony_ci		port->hwif = X21;
181762306a36Sopenharmony_ci		break;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	case IF_IFACE_X21D:
182062306a36Sopenharmony_ci		FST_WRW(card, portConfig[i].lineInterface, X21D);
182162306a36Sopenharmony_ci		port->hwif = X21D;
182262306a36Sopenharmony_ci		break;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	case IF_IFACE_T1:
182562306a36Sopenharmony_ci		FST_WRW(card, portConfig[i].lineInterface, T1);
182662306a36Sopenharmony_ci		port->hwif = T1;
182762306a36Sopenharmony_ci		break;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	case IF_IFACE_E1:
183062306a36Sopenharmony_ci		FST_WRW(card, portConfig[i].lineInterface, E1);
183162306a36Sopenharmony_ci		port->hwif = E1;
183262306a36Sopenharmony_ci		break;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	case IF_IFACE_SYNC_SERIAL:
183562306a36Sopenharmony_ci		break;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	default:
183862306a36Sopenharmony_ci		return -EINVAL;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	switch (sync.clock_type) {
184262306a36Sopenharmony_ci	case CLOCK_EXT:
184362306a36Sopenharmony_ci		FST_WRB(card, portConfig[i].internalClock, EXTCLK);
184462306a36Sopenharmony_ci		break;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	case CLOCK_INT:
184762306a36Sopenharmony_ci		FST_WRB(card, portConfig[i].internalClock, INTCLK);
184862306a36Sopenharmony_ci		break;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	default:
185162306a36Sopenharmony_ci		return -EINVAL;
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci	FST_WRL(card, portConfig[i].lineSpeed, sync.clock_rate);
185462306a36Sopenharmony_ci	return 0;
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_cistatic int
185862306a36Sopenharmony_cifst_get_iface(struct fst_card_info *card, struct fst_port_info *port,
185962306a36Sopenharmony_ci	      struct if_settings *ifs)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	sync_serial_settings sync;
186262306a36Sopenharmony_ci	int i;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	/* First check what line type is set, we'll default to reporting X.21
186562306a36Sopenharmony_ci	 * if nothing is set as IF_IFACE_SYNC_SERIAL implies it can't be
186662306a36Sopenharmony_ci	 * changed
186762306a36Sopenharmony_ci	 */
186862306a36Sopenharmony_ci	switch (port->hwif) {
186962306a36Sopenharmony_ci	case E1:
187062306a36Sopenharmony_ci		ifs->type = IF_IFACE_E1;
187162306a36Sopenharmony_ci		break;
187262306a36Sopenharmony_ci	case T1:
187362306a36Sopenharmony_ci		ifs->type = IF_IFACE_T1;
187462306a36Sopenharmony_ci		break;
187562306a36Sopenharmony_ci	case V35:
187662306a36Sopenharmony_ci		ifs->type = IF_IFACE_V35;
187762306a36Sopenharmony_ci		break;
187862306a36Sopenharmony_ci	case V24:
187962306a36Sopenharmony_ci		ifs->type = IF_IFACE_V24;
188062306a36Sopenharmony_ci		break;
188162306a36Sopenharmony_ci	case X21D:
188262306a36Sopenharmony_ci		ifs->type = IF_IFACE_X21D;
188362306a36Sopenharmony_ci		break;
188462306a36Sopenharmony_ci	case X21:
188562306a36Sopenharmony_ci	default:
188662306a36Sopenharmony_ci		ifs->type = IF_IFACE_X21;
188762306a36Sopenharmony_ci		break;
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci	if (!ifs->size)
189062306a36Sopenharmony_ci		return 0;	/* only type requested */
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	if (ifs->size < sizeof(sync))
189362306a36Sopenharmony_ci		return -ENOMEM;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	i = port->index;
189662306a36Sopenharmony_ci	memset(&sync, 0, sizeof(sync));
189762306a36Sopenharmony_ci	sync.clock_rate = FST_RDL(card, portConfig[i].lineSpeed);
189862306a36Sopenharmony_ci	/* Lucky card and linux use same encoding here */
189962306a36Sopenharmony_ci	sync.clock_type = FST_RDB(card, portConfig[i].internalClock) ==
190062306a36Sopenharmony_ci	    INTCLK ? CLOCK_INT : CLOCK_EXT;
190162306a36Sopenharmony_ci	sync.loopback = 0;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	if (copy_to_user(ifs->ifs_ifsu.sync, &sync, sizeof(sync)))
190462306a36Sopenharmony_ci		return -EFAULT;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	ifs->size = sizeof(sync);
190762306a36Sopenharmony_ci	return 0;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_cistatic int
191162306a36Sopenharmony_cifst_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __user *data, int cmd)
191262306a36Sopenharmony_ci{
191362306a36Sopenharmony_ci	struct fst_card_info *card;
191462306a36Sopenharmony_ci	struct fst_port_info *port;
191562306a36Sopenharmony_ci	struct fstioc_write wrthdr;
191662306a36Sopenharmony_ci	struct fstioc_info info;
191762306a36Sopenharmony_ci	unsigned long flags;
191862306a36Sopenharmony_ci	void *buf;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	dbg(DBG_IOCTL, "ioctl: %x, %p\n", cmd, data);
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	port = dev_to_port(dev);
192362306a36Sopenharmony_ci	card = port->card;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	if (!capable(CAP_NET_ADMIN))
192662306a36Sopenharmony_ci		return -EPERM;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	switch (cmd) {
192962306a36Sopenharmony_ci	case FSTCPURESET:
193062306a36Sopenharmony_ci		fst_cpureset(card);
193162306a36Sopenharmony_ci		card->state = FST_RESET;
193262306a36Sopenharmony_ci		return 0;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	case FSTCPURELEASE:
193562306a36Sopenharmony_ci		fst_cpurelease(card);
193662306a36Sopenharmony_ci		card->state = FST_STARTING;
193762306a36Sopenharmony_ci		return 0;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	case FSTWRITE:		/* Code write (download) */
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci		/* First copy in the header with the length and offset of data
194262306a36Sopenharmony_ci		 * to write
194362306a36Sopenharmony_ci		 */
194462306a36Sopenharmony_ci		if (!data)
194562306a36Sopenharmony_ci			return -EINVAL;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		if (copy_from_user(&wrthdr, data, sizeof(struct fstioc_write)))
194862306a36Sopenharmony_ci			return -EFAULT;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci		/* Sanity check the parameters. We don't support partial writes
195162306a36Sopenharmony_ci		 * when going over the top
195262306a36Sopenharmony_ci		 */
195362306a36Sopenharmony_ci		if (wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE ||
195462306a36Sopenharmony_ci		    wrthdr.size + wrthdr.offset > FST_MEMSIZE)
195562306a36Sopenharmony_ci			return -ENXIO;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		/* Now copy the data to the card. */
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci		buf = memdup_user(data + sizeof(struct fstioc_write),
196062306a36Sopenharmony_ci				  wrthdr.size);
196162306a36Sopenharmony_ci		if (IS_ERR(buf))
196262306a36Sopenharmony_ci			return PTR_ERR(buf);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		memcpy_toio(card->mem + wrthdr.offset, buf, wrthdr.size);
196562306a36Sopenharmony_ci		kfree(buf);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci		/* Writes to the memory of a card in the reset state constitute
196862306a36Sopenharmony_ci		 * a download
196962306a36Sopenharmony_ci		 */
197062306a36Sopenharmony_ci		if (card->state == FST_RESET)
197162306a36Sopenharmony_ci			card->state = FST_DOWNLOAD;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		return 0;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	case FSTGETCONF:
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci		/* If card has just been started check the shared memory config
197862306a36Sopenharmony_ci		 * version and marker
197962306a36Sopenharmony_ci		 */
198062306a36Sopenharmony_ci		if (card->state == FST_STARTING) {
198162306a36Sopenharmony_ci			check_started_ok(card);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci			/* If everything checked out enable card interrupts */
198462306a36Sopenharmony_ci			if (card->state == FST_RUNNING) {
198562306a36Sopenharmony_ci				spin_lock_irqsave(&card->card_lock, flags);
198662306a36Sopenharmony_ci				fst_enable_intr(card);
198762306a36Sopenharmony_ci				FST_WRB(card, interruptHandshake, 0xEE);
198862306a36Sopenharmony_ci				spin_unlock_irqrestore(&card->card_lock, flags);
198962306a36Sopenharmony_ci			}
199062306a36Sopenharmony_ci		}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci		if (!data)
199362306a36Sopenharmony_ci			return -EINVAL;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci		gather_conf_info(card, port, &info);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci		if (copy_to_user(data, &info, sizeof(info)))
199862306a36Sopenharmony_ci			return -EFAULT;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci		return 0;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	case FSTSETCONF:
200362306a36Sopenharmony_ci		/* Most of the settings have been moved to the generic ioctls
200462306a36Sopenharmony_ci		 * this just covers debug and board ident now
200562306a36Sopenharmony_ci		 */
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		if (card->state != FST_RUNNING) {
200862306a36Sopenharmony_ci			pr_err("Attempt to configure card %d in non-running state (%d)\n",
200962306a36Sopenharmony_ci			       card->card_no, card->state);
201062306a36Sopenharmony_ci			return -EIO;
201162306a36Sopenharmony_ci		}
201262306a36Sopenharmony_ci		if (copy_from_user(&info, data, sizeof(info)))
201362306a36Sopenharmony_ci			return -EFAULT;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci		return set_conf_from_info(card, port, &info);
201662306a36Sopenharmony_ci	default:
201762306a36Sopenharmony_ci		return -EINVAL;
201862306a36Sopenharmony_ci	}
201962306a36Sopenharmony_ci}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cistatic int
202262306a36Sopenharmony_cifst_ioctl(struct net_device *dev, struct if_settings *ifs)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	struct fst_card_info *card;
202562306a36Sopenharmony_ci	struct fst_port_info *port;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	dbg(DBG_IOCTL, "SIOCDEVPRIVATE, %x\n", ifs->type);
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	port = dev_to_port(dev);
203062306a36Sopenharmony_ci	card = port->card;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	if (!capable(CAP_NET_ADMIN))
203362306a36Sopenharmony_ci		return -EPERM;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	switch (ifs->type) {
203662306a36Sopenharmony_ci	case IF_GET_IFACE:
203762306a36Sopenharmony_ci		return fst_get_iface(card, port, ifs);
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	case IF_IFACE_SYNC_SERIAL:
204062306a36Sopenharmony_ci	case IF_IFACE_V35:
204162306a36Sopenharmony_ci	case IF_IFACE_V24:
204262306a36Sopenharmony_ci	case IF_IFACE_X21:
204362306a36Sopenharmony_ci	case IF_IFACE_X21D:
204462306a36Sopenharmony_ci	case IF_IFACE_T1:
204562306a36Sopenharmony_ci	case IF_IFACE_E1:
204662306a36Sopenharmony_ci		return fst_set_iface(card, port, ifs);
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	case IF_PROTO_RAW:
204962306a36Sopenharmony_ci		port->mode = FST_RAW;
205062306a36Sopenharmony_ci		return 0;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	case IF_GET_PROTO:
205362306a36Sopenharmony_ci		if (port->mode == FST_RAW) {
205462306a36Sopenharmony_ci			ifs->type = IF_PROTO_RAW;
205562306a36Sopenharmony_ci			return 0;
205662306a36Sopenharmony_ci		}
205762306a36Sopenharmony_ci		return hdlc_ioctl(dev, ifs);
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	default:
206062306a36Sopenharmony_ci		port->mode = FST_GEN_HDLC;
206162306a36Sopenharmony_ci		dbg(DBG_IOCTL, "Passing this type to hdlc %x\n",
206262306a36Sopenharmony_ci		    ifs->type);
206362306a36Sopenharmony_ci		return hdlc_ioctl(dev, ifs);
206462306a36Sopenharmony_ci	}
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_cistatic void
206862306a36Sopenharmony_cifst_openport(struct fst_port_info *port)
206962306a36Sopenharmony_ci{
207062306a36Sopenharmony_ci	int signals;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	/* Only init things if card is actually running. This allows open to
207362306a36Sopenharmony_ci	 * succeed for downloads etc.
207462306a36Sopenharmony_ci	 */
207562306a36Sopenharmony_ci	if (port->card->state == FST_RUNNING) {
207662306a36Sopenharmony_ci		if (port->run) {
207762306a36Sopenharmony_ci			dbg(DBG_OPEN, "open: found port already running\n");
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci			fst_issue_cmd(port, STOPPORT);
208062306a36Sopenharmony_ci			port->run = 0;
208162306a36Sopenharmony_ci		}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci		fst_rx_config(port);
208462306a36Sopenharmony_ci		fst_tx_config(port);
208562306a36Sopenharmony_ci		fst_op_raise(port, OPSTS_RTS | OPSTS_DTR);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		fst_issue_cmd(port, STARTPORT);
208862306a36Sopenharmony_ci		port->run = 1;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci		signals = FST_RDL(port->card, v24DebouncedSts[port->index]);
209162306a36Sopenharmony_ci		if (signals & ((port->hwif == X21 || port->hwif == X21D)
209262306a36Sopenharmony_ci			       ? IPSTS_INDICATE : IPSTS_DCD))
209362306a36Sopenharmony_ci			netif_carrier_on(port_to_dev(port));
209462306a36Sopenharmony_ci		else
209562306a36Sopenharmony_ci			netif_carrier_off(port_to_dev(port));
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci		port->txqe = 0;
209862306a36Sopenharmony_ci		port->txqs = 0;
209962306a36Sopenharmony_ci	}
210062306a36Sopenharmony_ci}
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_cistatic void
210362306a36Sopenharmony_cifst_closeport(struct fst_port_info *port)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	if (port->card->state == FST_RUNNING) {
210662306a36Sopenharmony_ci		if (port->run) {
210762306a36Sopenharmony_ci			port->run = 0;
210862306a36Sopenharmony_ci			fst_op_lower(port, OPSTS_RTS | OPSTS_DTR);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci			fst_issue_cmd(port, STOPPORT);
211162306a36Sopenharmony_ci		} else {
211262306a36Sopenharmony_ci			dbg(DBG_OPEN, "close: port not running\n");
211362306a36Sopenharmony_ci		}
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_cistatic int
211862306a36Sopenharmony_cifst_open(struct net_device *dev)
211962306a36Sopenharmony_ci{
212062306a36Sopenharmony_ci	int err;
212162306a36Sopenharmony_ci	struct fst_port_info *port;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	port = dev_to_port(dev);
212462306a36Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
212562306a36Sopenharmony_ci		return -EBUSY;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (port->mode != FST_RAW) {
212862306a36Sopenharmony_ci		err = hdlc_open(dev);
212962306a36Sopenharmony_ci		if (err) {
213062306a36Sopenharmony_ci			module_put(THIS_MODULE);
213162306a36Sopenharmony_ci			return err;
213262306a36Sopenharmony_ci		}
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	fst_openport(port);
213662306a36Sopenharmony_ci	netif_wake_queue(dev);
213762306a36Sopenharmony_ci	return 0;
213862306a36Sopenharmony_ci}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_cistatic int
214162306a36Sopenharmony_cifst_close(struct net_device *dev)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	struct fst_port_info *port;
214462306a36Sopenharmony_ci	struct fst_card_info *card;
214562306a36Sopenharmony_ci	unsigned char tx_dma_done;
214662306a36Sopenharmony_ci	unsigned char rx_dma_done;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	port = dev_to_port(dev);
214962306a36Sopenharmony_ci	card = port->card;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	tx_dma_done = inb(card->pci_conf + DMACSR1);
215262306a36Sopenharmony_ci	rx_dma_done = inb(card->pci_conf + DMACSR0);
215362306a36Sopenharmony_ci	dbg(DBG_OPEN,
215462306a36Sopenharmony_ci	    "Port Close: tx_dma_in_progress = %d (%x) rx_dma_in_progress = %d (%x)\n",
215562306a36Sopenharmony_ci	    card->dmatx_in_progress, tx_dma_done, card->dmarx_in_progress,
215662306a36Sopenharmony_ci	    rx_dma_done);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	netif_stop_queue(dev);
215962306a36Sopenharmony_ci	fst_closeport(dev_to_port(dev));
216062306a36Sopenharmony_ci	if (port->mode != FST_RAW)
216162306a36Sopenharmony_ci		hdlc_close(dev);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	module_put(THIS_MODULE);
216462306a36Sopenharmony_ci	return 0;
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_cistatic int
216862306a36Sopenharmony_cifst_attach(struct net_device *dev, unsigned short encoding, unsigned short parity)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	/* Setting currently fixed in FarSync card so we check and forget
217162306a36Sopenharmony_ci	 */
217262306a36Sopenharmony_ci	if (encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT)
217362306a36Sopenharmony_ci		return -EINVAL;
217462306a36Sopenharmony_ci	return 0;
217562306a36Sopenharmony_ci}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_cistatic void
217862306a36Sopenharmony_cifst_tx_timeout(struct net_device *dev, unsigned int txqueue)
217962306a36Sopenharmony_ci{
218062306a36Sopenharmony_ci	struct fst_port_info *port;
218162306a36Sopenharmony_ci	struct fst_card_info *card;
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	port = dev_to_port(dev);
218462306a36Sopenharmony_ci	card = port->card;
218562306a36Sopenharmony_ci	dev->stats.tx_errors++;
218662306a36Sopenharmony_ci	dev->stats.tx_aborted_errors++;
218762306a36Sopenharmony_ci	dbg(DBG_ASS, "Tx timeout card %d port %d\n",
218862306a36Sopenharmony_ci	    card->card_no, port->index);
218962306a36Sopenharmony_ci	fst_issue_cmd(port, ABORTTX);
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	netif_trans_update(dev);
219262306a36Sopenharmony_ci	netif_wake_queue(dev);
219362306a36Sopenharmony_ci	port->start = 0;
219462306a36Sopenharmony_ci}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_cistatic netdev_tx_t
219762306a36Sopenharmony_cifst_start_xmit(struct sk_buff *skb, struct net_device *dev)
219862306a36Sopenharmony_ci{
219962306a36Sopenharmony_ci	struct fst_card_info *card;
220062306a36Sopenharmony_ci	struct fst_port_info *port;
220162306a36Sopenharmony_ci	unsigned long flags;
220262306a36Sopenharmony_ci	int txq_length;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	port = dev_to_port(dev);
220562306a36Sopenharmony_ci	card = port->card;
220662306a36Sopenharmony_ci	dbg(DBG_TX, "fst_start_xmit: length = %d\n", skb->len);
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	/* Drop packet with error if we don't have carrier */
220962306a36Sopenharmony_ci	if (!netif_carrier_ok(dev)) {
221062306a36Sopenharmony_ci		dev_kfree_skb(skb);
221162306a36Sopenharmony_ci		dev->stats.tx_errors++;
221262306a36Sopenharmony_ci		dev->stats.tx_carrier_errors++;
221362306a36Sopenharmony_ci		dbg(DBG_ASS,
221462306a36Sopenharmony_ci		    "Tried to transmit but no carrier on card %d port %d\n",
221562306a36Sopenharmony_ci		    card->card_no, port->index);
221662306a36Sopenharmony_ci		return NETDEV_TX_OK;
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* Drop it if it's too big! MTU failure ? */
222062306a36Sopenharmony_ci	if (skb->len > LEN_TX_BUFFER) {
222162306a36Sopenharmony_ci		dbg(DBG_ASS, "Packet too large %d vs %d\n", skb->len,
222262306a36Sopenharmony_ci		    LEN_TX_BUFFER);
222362306a36Sopenharmony_ci		dev_kfree_skb(skb);
222462306a36Sopenharmony_ci		dev->stats.tx_errors++;
222562306a36Sopenharmony_ci		return NETDEV_TX_OK;
222662306a36Sopenharmony_ci	}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	/* We are always going to queue the packet
222962306a36Sopenharmony_ci	 * so that the bottom half is the only place we tx from
223062306a36Sopenharmony_ci	 * Check there is room in the port txq
223162306a36Sopenharmony_ci	 */
223262306a36Sopenharmony_ci	spin_lock_irqsave(&card->card_lock, flags);
223362306a36Sopenharmony_ci	txq_length = port->txqe - port->txqs;
223462306a36Sopenharmony_ci	if (txq_length < 0) {
223562306a36Sopenharmony_ci		/* This is the case where the next free has wrapped but the
223662306a36Sopenharmony_ci		 * last used hasn't
223762306a36Sopenharmony_ci		 */
223862306a36Sopenharmony_ci		txq_length = txq_length + FST_TXQ_DEPTH;
223962306a36Sopenharmony_ci	}
224062306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->card_lock, flags);
224162306a36Sopenharmony_ci	if (txq_length > fst_txq_high) {
224262306a36Sopenharmony_ci		/* We have got enough buffers in the pipeline.  Ask the network
224362306a36Sopenharmony_ci		 * layer to stop sending frames down
224462306a36Sopenharmony_ci		 */
224562306a36Sopenharmony_ci		netif_stop_queue(dev);
224662306a36Sopenharmony_ci		port->start = 1;	/* I'm using this to signal stop sent up */
224762306a36Sopenharmony_ci	}
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	if (txq_length == FST_TXQ_DEPTH - 1) {
225062306a36Sopenharmony_ci		/* This shouldn't have happened but such is life
225162306a36Sopenharmony_ci		 */
225262306a36Sopenharmony_ci		dev_kfree_skb(skb);
225362306a36Sopenharmony_ci		dev->stats.tx_errors++;
225462306a36Sopenharmony_ci		dbg(DBG_ASS, "Tx queue overflow card %d port %d\n",
225562306a36Sopenharmony_ci		    card->card_no, port->index);
225662306a36Sopenharmony_ci		return NETDEV_TX_OK;
225762306a36Sopenharmony_ci	}
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	/* queue the buffer
226062306a36Sopenharmony_ci	 */
226162306a36Sopenharmony_ci	spin_lock_irqsave(&card->card_lock, flags);
226262306a36Sopenharmony_ci	port->txq[port->txqe] = skb;
226362306a36Sopenharmony_ci	port->txqe++;
226462306a36Sopenharmony_ci	if (port->txqe == FST_TXQ_DEPTH)
226562306a36Sopenharmony_ci		port->txqe = 0;
226662306a36Sopenharmony_ci	spin_unlock_irqrestore(&card->card_lock, flags);
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	/* Scehdule the bottom half which now does transmit processing */
226962306a36Sopenharmony_ci	fst_q_work_item(&fst_work_txq, card->card_no);
227062306a36Sopenharmony_ci	tasklet_schedule(&fst_tx_task);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	return NETDEV_TX_OK;
227362306a36Sopenharmony_ci}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci/*      Card setup having checked hardware resources.
227662306a36Sopenharmony_ci *      Should be pretty bizarre if we get an error here (kernel memory
227762306a36Sopenharmony_ci *      exhaustion is one possibility). If we do see a problem we report it
227862306a36Sopenharmony_ci *      via a printk and leave the corresponding interface and all that follow
227962306a36Sopenharmony_ci *      disabled.
228062306a36Sopenharmony_ci */
228162306a36Sopenharmony_cistatic char *type_strings[] = {
228262306a36Sopenharmony_ci	"no hardware",		/* Should never be seen */
228362306a36Sopenharmony_ci	"FarSync T2P",
228462306a36Sopenharmony_ci	"FarSync T4P",
228562306a36Sopenharmony_ci	"FarSync T1U",
228662306a36Sopenharmony_ci	"FarSync T2U",
228762306a36Sopenharmony_ci	"FarSync T4U",
228862306a36Sopenharmony_ci	"FarSync TE1"
228962306a36Sopenharmony_ci};
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_cistatic int
229262306a36Sopenharmony_cifst_init_card(struct fst_card_info *card)
229362306a36Sopenharmony_ci{
229462306a36Sopenharmony_ci	int i;
229562306a36Sopenharmony_ci	int err;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	/* We're working on a number of ports based on the card ID. If the
229862306a36Sopenharmony_ci	 * firmware detects something different later (should never happen)
229962306a36Sopenharmony_ci	 * we'll have to revise it in some way then.
230062306a36Sopenharmony_ci	 */
230162306a36Sopenharmony_ci	for (i = 0; i < card->nports; i++) {
230262306a36Sopenharmony_ci		err = register_hdlc_device(card->ports[i].dev);
230362306a36Sopenharmony_ci		if (err < 0) {
230462306a36Sopenharmony_ci			pr_err("Cannot register HDLC device for port %d (errno %d)\n",
230562306a36Sopenharmony_ci			       i, -err);
230662306a36Sopenharmony_ci			while (i--)
230762306a36Sopenharmony_ci				unregister_hdlc_device(card->ports[i].dev);
230862306a36Sopenharmony_ci			return err;
230962306a36Sopenharmony_ci		}
231062306a36Sopenharmony_ci	}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	pr_info("%s-%s: %s IRQ%d, %d ports\n",
231362306a36Sopenharmony_ci		port_to_dev(&card->ports[0])->name,
231462306a36Sopenharmony_ci		port_to_dev(&card->ports[card->nports - 1])->name,
231562306a36Sopenharmony_ci		type_strings[card->type], card->irq, card->nports);
231662306a36Sopenharmony_ci	return 0;
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic const struct net_device_ops fst_ops = {
232062306a36Sopenharmony_ci	.ndo_open       = fst_open,
232162306a36Sopenharmony_ci	.ndo_stop       = fst_close,
232262306a36Sopenharmony_ci	.ndo_start_xmit = hdlc_start_xmit,
232362306a36Sopenharmony_ci	.ndo_siocwandev	= fst_ioctl,
232462306a36Sopenharmony_ci	.ndo_siocdevprivate = fst_siocdevprivate,
232562306a36Sopenharmony_ci	.ndo_tx_timeout = fst_tx_timeout,
232662306a36Sopenharmony_ci};
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci/*      Initialise card when detected.
232962306a36Sopenharmony_ci *      Returns 0 to indicate success, or errno otherwise.
233062306a36Sopenharmony_ci */
233162306a36Sopenharmony_cistatic int
233262306a36Sopenharmony_cifst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
233362306a36Sopenharmony_ci{
233462306a36Sopenharmony_ci	static int no_of_cards_added;
233562306a36Sopenharmony_ci	struct fst_card_info *card;
233662306a36Sopenharmony_ci	int err = 0;
233762306a36Sopenharmony_ci	int i;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	printk_once(KERN_INFO
234062306a36Sopenharmony_ci		    pr_fmt("FarSync WAN driver " FST_USER_VERSION
234162306a36Sopenharmony_ci			   " (c) 2001-2004 FarSite Communications Ltd.\n"));
234262306a36Sopenharmony_ci#if FST_DEBUG
234362306a36Sopenharmony_ci	dbg(DBG_ASS, "The value of debug mask is %x\n", fst_debug_mask);
234462306a36Sopenharmony_ci#endif
234562306a36Sopenharmony_ci	/* We are going to be clever and allow certain cards not to be
234662306a36Sopenharmony_ci	 * configured.  An exclude list can be provided in /etc/modules.conf
234762306a36Sopenharmony_ci	 */
234862306a36Sopenharmony_ci	if (fst_excluded_cards != 0) {
234962306a36Sopenharmony_ci		/* There are cards to exclude
235062306a36Sopenharmony_ci		 *
235162306a36Sopenharmony_ci		 */
235262306a36Sopenharmony_ci		for (i = 0; i < fst_excluded_cards; i++) {
235362306a36Sopenharmony_ci			if (pdev->devfn >> 3 == fst_excluded_list[i]) {
235462306a36Sopenharmony_ci				pr_info("FarSync PCI device %d not assigned\n",
235562306a36Sopenharmony_ci					(pdev->devfn) >> 3);
235662306a36Sopenharmony_ci				return -EBUSY;
235762306a36Sopenharmony_ci			}
235862306a36Sopenharmony_ci		}
235962306a36Sopenharmony_ci	}
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	/* Allocate driver private data */
236262306a36Sopenharmony_ci	card = kzalloc(sizeof(struct fst_card_info), GFP_KERNEL);
236362306a36Sopenharmony_ci	if (!card)
236462306a36Sopenharmony_ci		return -ENOMEM;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	/* Try to enable the device */
236762306a36Sopenharmony_ci	err = pci_enable_device(pdev);
236862306a36Sopenharmony_ci	if (err) {
236962306a36Sopenharmony_ci		pr_err("Failed to enable card. Err %d\n", -err);
237062306a36Sopenharmony_ci		goto enable_fail;
237162306a36Sopenharmony_ci	}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	err = pci_request_regions(pdev, "FarSync");
237462306a36Sopenharmony_ci	if (err) {
237562306a36Sopenharmony_ci		pr_err("Failed to allocate regions. Err %d\n", -err);
237662306a36Sopenharmony_ci		goto regions_fail;
237762306a36Sopenharmony_ci	}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	/* Get virtual addresses of memory regions */
238062306a36Sopenharmony_ci	card->pci_conf = pci_resource_start(pdev, 1);
238162306a36Sopenharmony_ci	card->phys_mem = pci_resource_start(pdev, 2);
238262306a36Sopenharmony_ci	card->phys_ctlmem = pci_resource_start(pdev, 3);
238362306a36Sopenharmony_ci	card->mem = ioremap(card->phys_mem, FST_MEMSIZE);
238462306a36Sopenharmony_ci	if (!card->mem) {
238562306a36Sopenharmony_ci		pr_err("Physical memory remap failed\n");
238662306a36Sopenharmony_ci		err = -ENODEV;
238762306a36Sopenharmony_ci		goto ioremap_physmem_fail;
238862306a36Sopenharmony_ci	}
238962306a36Sopenharmony_ci	card->ctlmem = ioremap(card->phys_ctlmem, 0x10);
239062306a36Sopenharmony_ci	if (!card->ctlmem) {
239162306a36Sopenharmony_ci		pr_err("Control memory remap failed\n");
239262306a36Sopenharmony_ci		err = -ENODEV;
239362306a36Sopenharmony_ci		goto ioremap_ctlmem_fail;
239462306a36Sopenharmony_ci	}
239562306a36Sopenharmony_ci	dbg(DBG_PCI, "kernel mem %p, ctlmem %p\n", card->mem, card->ctlmem);
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	/* Register the interrupt handler */
239862306a36Sopenharmony_ci	if (request_irq(pdev->irq, fst_intr, IRQF_SHARED, FST_DEV_NAME, card)) {
239962306a36Sopenharmony_ci		pr_err("Unable to register interrupt %d\n", card->irq);
240062306a36Sopenharmony_ci		err = -ENODEV;
240162306a36Sopenharmony_ci		goto irq_fail;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/* Record info we need */
240562306a36Sopenharmony_ci	card->irq = pdev->irq;
240662306a36Sopenharmony_ci	card->type = ent->driver_data;
240762306a36Sopenharmony_ci	card->family = ((ent->driver_data == FST_TYPE_T2P) ||
240862306a36Sopenharmony_ci			(ent->driver_data == FST_TYPE_T4P))
240962306a36Sopenharmony_ci	    ? FST_FAMILY_TXP : FST_FAMILY_TXU;
241062306a36Sopenharmony_ci	if (ent->driver_data == FST_TYPE_T1U ||
241162306a36Sopenharmony_ci	    ent->driver_data == FST_TYPE_TE1)
241262306a36Sopenharmony_ci		card->nports = 1;
241362306a36Sopenharmony_ci	else
241462306a36Sopenharmony_ci		card->nports = ((ent->driver_data == FST_TYPE_T2P) ||
241562306a36Sopenharmony_ci				(ent->driver_data == FST_TYPE_T2U)) ? 2 : 4;
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	card->state = FST_UNINIT;
241862306a36Sopenharmony_ci	spin_lock_init(&card->card_lock);
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	for (i = 0; i < card->nports; i++) {
242162306a36Sopenharmony_ci		struct net_device *dev = alloc_hdlcdev(&card->ports[i]);
242262306a36Sopenharmony_ci		hdlc_device *hdlc;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci		if (!dev) {
242562306a36Sopenharmony_ci			while (i--)
242662306a36Sopenharmony_ci				free_netdev(card->ports[i].dev);
242762306a36Sopenharmony_ci			pr_err("FarSync: out of memory\n");
242862306a36Sopenharmony_ci			err = -ENOMEM;
242962306a36Sopenharmony_ci			goto hdlcdev_fail;
243062306a36Sopenharmony_ci		}
243162306a36Sopenharmony_ci		card->ports[i].dev    = dev;
243262306a36Sopenharmony_ci		card->ports[i].card   = card;
243362306a36Sopenharmony_ci		card->ports[i].index  = i;
243462306a36Sopenharmony_ci		card->ports[i].run    = 0;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci		hdlc = dev_to_hdlc(dev);
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci		/* Fill in the net device info */
243962306a36Sopenharmony_ci		/* Since this is a PCI setup this is purely
244062306a36Sopenharmony_ci		 * informational. Give them the buffer addresses
244162306a36Sopenharmony_ci		 * and basic card I/O.
244262306a36Sopenharmony_ci		 */
244362306a36Sopenharmony_ci		dev->mem_start   = card->phys_mem
244462306a36Sopenharmony_ci				+ BUF_OFFSET(txBuffer[i][0][0]);
244562306a36Sopenharmony_ci		dev->mem_end     = card->phys_mem
244662306a36Sopenharmony_ci				+ BUF_OFFSET(txBuffer[i][NUM_TX_BUFFER - 1][LEN_RX_BUFFER - 1]);
244762306a36Sopenharmony_ci		dev->base_addr   = card->pci_conf;
244862306a36Sopenharmony_ci		dev->irq         = card->irq;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci		dev->netdev_ops = &fst_ops;
245162306a36Sopenharmony_ci		dev->tx_queue_len = FST_TX_QUEUE_LEN;
245262306a36Sopenharmony_ci		dev->watchdog_timeo = FST_TX_TIMEOUT;
245362306a36Sopenharmony_ci		hdlc->attach = fst_attach;
245462306a36Sopenharmony_ci		hdlc->xmit   = fst_start_xmit;
245562306a36Sopenharmony_ci	}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	card->device = pdev;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	dbg(DBG_PCI, "type %d nports %d irq %d\n", card->type,
246062306a36Sopenharmony_ci	    card->nports, card->irq);
246162306a36Sopenharmony_ci	dbg(DBG_PCI, "conf %04x mem %08x ctlmem %08x\n",
246262306a36Sopenharmony_ci	    card->pci_conf, card->phys_mem, card->phys_ctlmem);
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	/* Reset the card's processor */
246562306a36Sopenharmony_ci	fst_cpureset(card);
246662306a36Sopenharmony_ci	card->state = FST_RESET;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	/* Initialise DMA (if required) */
246962306a36Sopenharmony_ci	fst_init_dma(card);
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	/* Record driver data for later use */
247262306a36Sopenharmony_ci	pci_set_drvdata(pdev, card);
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	/* Remainder of card setup */
247562306a36Sopenharmony_ci	if (no_of_cards_added >= FST_MAX_CARDS) {
247662306a36Sopenharmony_ci		pr_err("FarSync: too many cards\n");
247762306a36Sopenharmony_ci		err = -ENOMEM;
247862306a36Sopenharmony_ci		goto card_array_fail;
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_ci	fst_card_array[no_of_cards_added] = card;
248162306a36Sopenharmony_ci	card->card_no = no_of_cards_added++;	/* Record instance and bump it */
248262306a36Sopenharmony_ci	err = fst_init_card(card);
248362306a36Sopenharmony_ci	if (err)
248462306a36Sopenharmony_ci		goto init_card_fail;
248562306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
248662306a36Sopenharmony_ci		/* Allocate a dma buffer for transmit and receives
248762306a36Sopenharmony_ci		 */
248862306a36Sopenharmony_ci		card->rx_dma_handle_host =
248962306a36Sopenharmony_ci		    dma_alloc_coherent(&card->device->dev, FST_MAX_MTU,
249062306a36Sopenharmony_ci				       &card->rx_dma_handle_card, GFP_KERNEL);
249162306a36Sopenharmony_ci		if (!card->rx_dma_handle_host) {
249262306a36Sopenharmony_ci			pr_err("Could not allocate rx dma buffer\n");
249362306a36Sopenharmony_ci			err = -ENOMEM;
249462306a36Sopenharmony_ci			goto rx_dma_fail;
249562306a36Sopenharmony_ci		}
249662306a36Sopenharmony_ci		card->tx_dma_handle_host =
249762306a36Sopenharmony_ci		    dma_alloc_coherent(&card->device->dev, FST_MAX_MTU,
249862306a36Sopenharmony_ci				       &card->tx_dma_handle_card, GFP_KERNEL);
249962306a36Sopenharmony_ci		if (!card->tx_dma_handle_host) {
250062306a36Sopenharmony_ci			pr_err("Could not allocate tx dma buffer\n");
250162306a36Sopenharmony_ci			err = -ENOMEM;
250262306a36Sopenharmony_ci			goto tx_dma_fail;
250362306a36Sopenharmony_ci		}
250462306a36Sopenharmony_ci	}
250562306a36Sopenharmony_ci	return 0;		/* Success */
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_citx_dma_fail:
250862306a36Sopenharmony_ci	dma_free_coherent(&card->device->dev, FST_MAX_MTU,
250962306a36Sopenharmony_ci			  card->rx_dma_handle_host, card->rx_dma_handle_card);
251062306a36Sopenharmony_cirx_dma_fail:
251162306a36Sopenharmony_ci	fst_disable_intr(card);
251262306a36Sopenharmony_ci	for (i = 0 ; i < card->nports ; i++)
251362306a36Sopenharmony_ci		unregister_hdlc_device(card->ports[i].dev);
251462306a36Sopenharmony_ciinit_card_fail:
251562306a36Sopenharmony_ci	fst_card_array[card->card_no] = NULL;
251662306a36Sopenharmony_cicard_array_fail:
251762306a36Sopenharmony_ci	for (i = 0 ; i < card->nports ; i++)
251862306a36Sopenharmony_ci		free_netdev(card->ports[i].dev);
251962306a36Sopenharmony_cihdlcdev_fail:
252062306a36Sopenharmony_ci	free_irq(card->irq, card);
252162306a36Sopenharmony_ciirq_fail:
252262306a36Sopenharmony_ci	iounmap(card->ctlmem);
252362306a36Sopenharmony_ciioremap_ctlmem_fail:
252462306a36Sopenharmony_ci	iounmap(card->mem);
252562306a36Sopenharmony_ciioremap_physmem_fail:
252662306a36Sopenharmony_ci	pci_release_regions(pdev);
252762306a36Sopenharmony_ciregions_fail:
252862306a36Sopenharmony_ci	pci_disable_device(pdev);
252962306a36Sopenharmony_cienable_fail:
253062306a36Sopenharmony_ci	kfree(card);
253162306a36Sopenharmony_ci	return err;
253262306a36Sopenharmony_ci}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci/*      Cleanup and close down a card
253562306a36Sopenharmony_ci */
253662306a36Sopenharmony_cistatic void
253762306a36Sopenharmony_cifst_remove_one(struct pci_dev *pdev)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	struct fst_card_info *card;
254062306a36Sopenharmony_ci	int i;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	card = pci_get_drvdata(pdev);
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	for (i = 0; i < card->nports; i++) {
254562306a36Sopenharmony_ci		struct net_device *dev = port_to_dev(&card->ports[i]);
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci		unregister_hdlc_device(dev);
254862306a36Sopenharmony_ci		free_netdev(dev);
254962306a36Sopenharmony_ci	}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	fst_disable_intr(card);
255262306a36Sopenharmony_ci	free_irq(card->irq, card);
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	iounmap(card->ctlmem);
255562306a36Sopenharmony_ci	iounmap(card->mem);
255662306a36Sopenharmony_ci	pci_release_regions(pdev);
255762306a36Sopenharmony_ci	if (card->family == FST_FAMILY_TXU) {
255862306a36Sopenharmony_ci		/* Free dma buffers
255962306a36Sopenharmony_ci		 */
256062306a36Sopenharmony_ci		dma_free_coherent(&card->device->dev, FST_MAX_MTU,
256162306a36Sopenharmony_ci				  card->rx_dma_handle_host,
256262306a36Sopenharmony_ci				  card->rx_dma_handle_card);
256362306a36Sopenharmony_ci		dma_free_coherent(&card->device->dev, FST_MAX_MTU,
256462306a36Sopenharmony_ci				  card->tx_dma_handle_host,
256562306a36Sopenharmony_ci				  card->tx_dma_handle_card);
256662306a36Sopenharmony_ci	}
256762306a36Sopenharmony_ci	fst_card_array[card->card_no] = NULL;
256862306a36Sopenharmony_ci	kfree(card);
256962306a36Sopenharmony_ci}
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_cistatic struct pci_driver fst_driver = {
257262306a36Sopenharmony_ci	.name		= FST_NAME,
257362306a36Sopenharmony_ci	.id_table	= fst_pci_dev_id,
257462306a36Sopenharmony_ci	.probe		= fst_add_one,
257562306a36Sopenharmony_ci	.remove		= fst_remove_one,
257662306a36Sopenharmony_ci};
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_cistatic int __init
257962306a36Sopenharmony_cifst_init(void)
258062306a36Sopenharmony_ci{
258162306a36Sopenharmony_ci	int i;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	for (i = 0; i < FST_MAX_CARDS; i++)
258462306a36Sopenharmony_ci		fst_card_array[i] = NULL;
258562306a36Sopenharmony_ci	return pci_register_driver(&fst_driver);
258662306a36Sopenharmony_ci}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_cistatic void __exit
258962306a36Sopenharmony_cifst_cleanup_module(void)
259062306a36Sopenharmony_ci{
259162306a36Sopenharmony_ci	pr_info("FarSync WAN driver unloading\n");
259262306a36Sopenharmony_ci	pci_unregister_driver(&fst_driver);
259362306a36Sopenharmony_ci}
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_cimodule_init(fst_init);
259662306a36Sopenharmony_cimodule_exit(fst_cleanup_module);
2597