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