patch-2.2.18 linux/drivers/net/xpds/xpds.c
Next file: linux/drivers/net/xpds/xpds.h
Previous file: linux/drivers/net/xpds/xpds-softnet.h
Back to the patch index
Back to the overall index
- Lines: 4024
- Date:
Tue Nov 7 13:19:46 2000
- Orig file:
v2.2.17/drivers/net/xpds/xpds.c
- Orig date:
Thu Jan 1 01:00:00 1970
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds.c linux/drivers/net/xpds/xpds.c
@@ -0,0 +1,4023 @@
+/*
+ * Copyright 1998, 1999, 2000 Xpeed, Inc.
+ * xpds.c, $Revision: 1.33 $
+ * License to copy and distribute is GNU General Public License, version 2.
+ */
+#ifndef VERSION_STRING
+#define VERSION_STRING "release-20001009k"
+#endif
+
+#define LT_IND_AI 0xc
+#define NT_IND_AI 0xc
+
+#ifndef __KERNEL__
+#define __KERNEL__ 1
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>
+#include <linux/ctype.h>
+
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#include <linux/tqueue.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#if ! defined (CONFIG_PCI)
+#error "CONFIG_PCI is not defined"
+#endif
+
+#include "xpds-softnet.h"
+#include "xpds-reg.h"
+#include "xpds-fsm.h"
+#include <linux/xpds-ioctl.h>
+#include "xpds-sdsl.h"
+#include "xpds-encap-fr.h"
+#include "xpds.h"
+
+MODULE_AUTHOR("Timothy J. Lee <linux@xpeed.com>");
+MODULE_DESCRIPTION("Xpeed 200 IDSL and 300 SDSL NIC driver (frame relay)");
+
+/*
+ * Debugging stuff.
+ */
+#define DEBUG_MAIN 1
+#define DEBUG_FSM 2
+#define DEBUG_PACKET 64
+#define DEBUG_DETAILED 128
+int xpds_debug_level = 0 /* DEBUG_MAIN | DEBUG_FSM */;
+MODULE_PARM(xpds_debug_level, "i");
+
+#ifdef DEBUG
+#define dprintk if (xpds_debug_level & DEBUG_MAIN) printk
+#define dpprintk if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_PACKET)) == (DEBUG_MAIN | DEBUG_PACKET)) printk
+#define ddprintk if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_DETAILED)) == (DEBUG_MAIN | DEBUG_DETAILED)) printk
+#else
+#define dprintk if (0) printk
+#define dpprintk if (0) printk
+#define ddprintk if (0) printk
+#endif
+
+#define nrprintk if (net_ratelimit()) printk
+
+/*
+ * If we are loaded module for flashing, ignore error in detection.
+ */
+int xpds_load_for_flash = 0;
+MODULE_PARM(xpds_load_for_flash, "i");
+
+/*
+ * For loopback testing only.
+ */
+int xpds_asic_loopback = 0;
+MODULE_PARM(xpds_asic_loopback, "i");
+int xpds_external_loopback = 0;
+MODULE_PARM(xpds_external_loopback, "i");
+
+/* some motherboards have 6 PCI slots... */
+#define XPDS_DEFAULT_MAX 6
+int xpds_max_cards = XPDS_DEFAULT_MAX;
+MODULE_PARM(xpds_max_cards, "i");
+
+/* time to wait for SDSL physical layer to come up */
+#define XPDS_SDSL_TIMEOUT 300
+int xpds_sdsl_timeout = XPDS_SDSL_TIMEOUT;
+MODULE_PARM(xpds_sdsl_timeout, "i");
+
+int xpds_default_dlci = XPDS_DEFAULT_DLCI;
+MODULE_PARM(xpds_default_dlci, "i");
+
+int xpds_default_dlci_cr = XPDS_DEFAULT_DLCI_CR;
+MODULE_PARM(xpds_default_dlci_cr, "i");
+
+int xpds_default_dlci_lmi = XPDS_DLCI_LMI_LT_OR_NT;
+MODULE_PARM(xpds_default_dlci_lmi, "i");
+
+int xpds_default_bridged = 0;
+MODULE_PARM(xpds_default_bridged, "i");
+
+static char *xpds_dev_name = "dsl";
+MODULE_PARM(xpds_dev_name, "s");
+
+/*
+ * At rates below 400 Kbps, the SDSL TX DMA does not work on some
+ * computers.
+ */
+#define LOW_BIT_RATE 404
+#define TX_DMA_LOW_RATE_BUG(card_num) \
+ (xpds_data[card_num].is_sdsl && \
+ xpds_data[card_num].has_tx_dma_low_rate_bug && \
+ xpds_data[card_num].sdsl_speed < LOW_BIT_RATE)
+#define RX_DMA_LOW_RATE_BUG(card_num) \
+ (xpds_data[card_num].is_sdsl && \
+ xpds_data[card_num].has_rx_dma_low_rate_bug && \
+ xpds_data[card_num].sdsl_speed < LOW_BIT_RATE)
+
+#define PCI_VENDOR_ID_XPDS 0x14b3
+#define PCI_DEVICE_ID_XPDS_1 0x0000
+
+#define ALLOW_OLD_PCI_VENDOR_ID 0
+#define PCI_VENDOR_ID_XPDS_OLD 0xeeee
+
+/*
+ * Set xpds_mode by insmod.
+ */
+#define XPDS_MODE_B1 1
+#define XPDS_MODE_B2 2
+#define XPDS_MODE_D 4
+#define XPDS_MODE_DEFAULT 7
+
+int xpds_mode = XPDS_MODE_DEFAULT;
+MODULE_PARM(xpds_mode, "i");
+
+/*
+ * Guard time for the state machines.
+ */
+#define DEFAULT_GUARD_TIME 15
+int xpds_guard_time = DEFAULT_GUARD_TIME;
+MODULE_PARM(xpds_guard_time, "i");
+
+#define RXTX_BUFFER_SIZE 2048
+
+/*
+ * Maximum packet length that is put into a hardware register.
+ * Packets received by the hardware are dropped if they are
+ * equal to or greater in length.
+ */
+#define DEFAULT_MAX_PACKET_LENGTH 0x600
+u16 xpds_max_packet_length = DEFAULT_MAX_PACKET_LENGTH;
+MODULE_PARM(xpds_max_packet_length, "i");
+
+#define RXTX_CONTROL__SWGO 0x80000000
+#define RXTX_CONTROL__HWGO 0x40000000
+#define RXTX_CONTROL__NEXT_VALID 0x20000000
+#define RXTX_CONTROL__PACKET_TAG_OFFSET 16
+#define RXTX_CONTROL__PACKET_TAG_MASK 0xf
+#define RXTX_CONTROL__PACKET_LENGTH_MASK 0xffff
+
+#define NUM_MAIN_CONTROL_REGISTERS 16
+#define NUM_FIFO_CONTROL_REGISTERS 16
+#define NUM_DMA_CONTROL_REGISTERS 48
+#define NUM_FIFO_DATA_REGISTERS 32
+#define NUM_AUX_REGISTERS 4
+
+#define NUM_FIFO 4
+#define FIFO_SIZE (NUM_FIFO_DATA_REGISTERS / NUM_FIFO)
+
+xpds_data_t *xpds_data = NULL;
+static int num_xpds_found = 0;
+
+#define XPDS_MAIN 0
+#define XPDS_RX_FIFO 2
+#define XPDS_TX_FIFO 3
+#define XPDS_RX_DMA 4
+#define XPDS_TX_DMA 5
+#define XPDS_RX_FIFO_DATA 6
+#define XPDS_TX_FIFO_DATA 7
+#define XPDS_AUX 8
+
+#define MAIN XPDS_MAIN
+#define RX_FIFO XPDS_RX_FIFO
+#define TX_FIFO XPDS_TX_FIFO
+#define RX_DMA XPDS_RX_DMA
+#define TX_DMA XPDS_TX_DMA
+#define RX_FIFO_DATA XPDS_RX_FIFO_DATA
+#define TX_FIFO_DATA XPDS_TX_FIFO_DATA
+#define AUX XPDS_AUX
+
+#define NAME_SIZE 16
+
+#define NUM_DESC 14
+
+static int xpds_init (struct net_device *dev);
+
+static char *xpds_names = NULL;
+struct net_device *xpds_devs = NULL;
+
+__inline__ static int
+xpds_read_control_register_internal (int xpds_num, int register_number,
+ u32 *value, int which, int verbose)
+{
+ register_number >>= 2;
+
+ if (verbose) dprintk (KERN_DEBUG "%s: ", xpds_devs[xpds_num].name);
+ switch (which) {
+ case MAIN:
+ if (register_number > NUM_MAIN_CONTROL_REGISTERS ||
+ xpds_data[xpds_num].main_control_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].main_control_registers[register_number];
+ if (verbose) {
+ dprintk ("main_ctl[%02x]->%08x ",
+ register_number, *value);
+ }
+ break;
+ case RX_FIFO:
+ if (register_number > NUM_FIFO_CONTROL_REGISTERS ||
+ xpds_data[xpds_num].rx_fifo_control_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].rx_fifo_control_registers[register_number];
+ if (verbose) dprintk ("rx_fifo_ctl[%02x]->%08x ",
+ register_number, *value);
+ break;
+ case TX_FIFO:
+ if (register_number > NUM_FIFO_CONTROL_REGISTERS ||
+ xpds_data[xpds_num].tx_fifo_control_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].tx_fifo_control_registers[register_number];
+ if (verbose) dprintk ("tx_fifo_ctl[%02x]->%08x ",
+ register_number, *value);
+ break;
+ case RX_DMA:
+ if (register_number > NUM_DMA_CONTROL_REGISTERS ||
+ xpds_data[xpds_num].rx_dma_control_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].rx_dma_control_registers[register_number];
+ if (verbose) dprintk ("rx_dma_ctl[%02x]->%08x ",
+ register_number, *value);
+ break;
+ case TX_DMA:
+ if (register_number > NUM_DMA_CONTROL_REGISTERS ||
+ xpds_data[xpds_num].tx_dma_control_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].tx_dma_control_registers[register_number];
+ if (verbose) dprintk ("tx_dma_ctl[%02x]->%08x ",
+ register_number, *value);
+ break;
+ case RX_FIFO_DATA:
+ if (register_number > NUM_FIFO_DATA_REGISTERS ||
+ xpds_data[xpds_num].rx_fifo_data_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].rx_fifo_data_registers[register_number];
+ if (verbose) dprintk ("rx_fifo_data[%02x]->%08x ",
+ register_number, *value);
+ break;
+ case TX_FIFO_DATA:
+ if (register_number > NUM_FIFO_DATA_REGISTERS ||
+ xpds_data[xpds_num].tx_fifo_data_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].tx_fifo_data_registers[register_number];
+ if (verbose) dprintk ("tx_fifo_data[%02x]->%08x ",
+ register_number, *value);
+ break;
+ case AUX:
+ if (register_number > NUM_AUX_REGISTERS ||
+ xpds_data[xpds_num].aux_registers == NULL) {
+ return 4;
+ }
+ *value = xpds_data[xpds_num].aux_registers[register_number];
+ if (verbose) dprintk ("aux[%02x]->%08x ",
+ register_number, *value);
+ break;
+ default:
+ if (verbose) dprintk ("\n");
+ return 4;
+ }
+ if (verbose) dprintk ("\n");
+ return 0;
+}
+
+__inline__ int
+xpds_read_control_register (int xpds_num, int register_number,
+ u32 *value, int which)
+{
+ return xpds_read_control_register_internal (xpds_num, register_number,
+ value, which, 0);
+}
+
+__inline__ int
+xpds_read_control_register_verbose (int xpds_num, int register_number,
+ u32 *value, int which)
+{
+ return xpds_read_control_register_internal (xpds_num, register_number,
+ value, which, 1);
+}
+
+__inline__ int
+xpds_read_control_register_quiet (int xpds_num, int register_number,
+ u32 *value, int which)
+{
+ return xpds_read_control_register_internal (xpds_num, register_number,
+ value, which, 0);
+}
+
+__inline__ static int
+xpds_write_control_register_internal (int xpds_num, int register_number,
+ u32 value, int which, int verbose)
+{
+ register_number >>= 2;
+
+ if (verbose) dprintk (KERN_DEBUG "%s: ", xpds_devs[xpds_num].name);
+
+ switch (which) {
+ case MAIN:
+ if (register_number > NUM_MAIN_CONTROL_REGISTERS) {
+ return 4;
+ }
+ xpds_data[xpds_num].main_control_registers[register_number] = value;
+ if (verbose) {
+ dprintk ("%08x->main_ctl[%02x] ",
+ value, register_number);
+ }
+ break;
+ case RX_FIFO:
+ if (register_number > NUM_FIFO_CONTROL_REGISTERS) {
+ return 4;
+ }
+ xpds_data[xpds_num].rx_fifo_control_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->rx_fifo_ctl[%02x] ",
+ value, register_number);
+ break;
+ case TX_FIFO:
+ if (register_number > NUM_FIFO_CONTROL_REGISTERS) {
+ return 4;
+ }
+ xpds_data[xpds_num].tx_fifo_control_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->tx_fifo_ctl[%02x] ",
+ value, register_number);
+ break;
+ case RX_DMA:
+ if (register_number > NUM_DMA_CONTROL_REGISTERS) {
+ return 4;
+ }
+ xpds_data[xpds_num].rx_dma_control_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->rx_dma_ctl[%02x] ",
+ value, register_number);
+ break;
+ case TX_DMA:
+ if (register_number > NUM_DMA_CONTROL_REGISTERS) {
+ return 4;
+ }
+ xpds_data[xpds_num].tx_dma_control_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->tx_dma_ctl[%02x] ",
+ value, register_number);
+ break;
+ case RX_FIFO_DATA:
+ if (register_number > NUM_FIFO_DATA_REGISTERS) {
+ return 4;
+ }
+ xpds_data[xpds_num].rx_fifo_data_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->rx_fifo_data[%02x] ",
+ value, register_number);
+ break;
+ case TX_FIFO_DATA:
+ if (register_number > NUM_FIFO_DATA_REGISTERS) {
+ if (verbose) dprintk ("\n");
+ return 4;
+ }
+ xpds_data[xpds_num].tx_fifo_data_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->tx_fifo_data[%02x] ",
+ value, register_number);
+ break;
+ case AUX:
+ if (register_number > NUM_AUX_REGISTERS) {
+ if (verbose) dprintk ("\n");
+ return 4;
+ }
+ xpds_data[xpds_num].aux_registers[register_number] = value;
+ if (verbose) dprintk ("%08x->aux[%02x] ",
+ value, register_number);
+ break;
+ default:
+ if (verbose) dprintk ("\n");
+ return 4;
+ }
+ if (verbose) dprintk ("\n");
+ return 0;
+}
+
+__inline__ int
+xpds_write_control_register (int xpds_num, int register_number,
+ u32 value, int which)
+{
+ return xpds_write_control_register_internal (xpds_num, register_number,
+ value, which, 0);
+}
+
+__inline__ int
+xpds_write_control_register_verbose (int xpds_num, int register_number,
+ u32 value, int which)
+{
+ return xpds_write_control_register_internal (xpds_num, register_number,
+ value, which, 1);
+}
+
+__inline__ int
+xpds_write_control_register_quiet (int xpds_num, int register_number,
+ u32 value, int which)
+{
+ return xpds_write_control_register_internal (xpds_num, register_number,
+ value, which, 0);
+}
+
+/*
+ * Return 1 if the hardware version is >= major.minor, unless
+ * the hardware version is the uninitialized 0xff.0xff value,
+ * which is assumed to be the lowest revision. Return 0 otherwise.
+ */
+static int
+xpds_is_hardware_version (int card_num, int major, int minor)
+{
+ if (xpds_data[card_num].serial_data.hardware_version[0] == 0xff &&
+ xpds_data[card_num].serial_data.hardware_version[1] == 0xff) {
+ return 0;
+ }
+ if (xpds_data[card_num].serial_data.hardware_version[0] > major) {
+ return 1;
+ }
+ if (xpds_data[card_num].serial_data.hardware_version[0] == major &&
+ xpds_data[card_num].serial_data.hardware_version[1] >= minor) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+xpds_init_descriptors (int card_num)
+{
+ u32 bus_addr;
+
+ dprintk (KERN_DEBUG "xpds_init_descriptors (%d)\n", card_num);
+ /*
+ * lock?
+ */
+
+ /*
+ * Set maximum packet length
+ */
+ dprintk (KERN_DEBUG "setting maximum packet length to %u (0x%x)\n",
+ xpds_max_packet_length, xpds_max_packet_length);
+ xpds_write_control_register (card_num, XPDS_MCR_PACKH,
+ (xpds_max_packet_length >> 8) & 0xff, MAIN);
+ xpds_write_control_register (card_num, XPDS_MCR_PACKL,
+ xpds_max_packet_length & 0xff, MAIN);
+
+ /*
+ * Initialize descriptor
+ */
+ {
+ volatile xpds_rxtx_list_t *rx_ptr, *tx_ptr;
+ int i;
+
+ rx_ptr = xpds_data[card_num].rx_dma_list;
+ tx_ptr = xpds_data[card_num].tx_dma_list;
+ for (i = 0; i < NUM_DESC; i ++) {
+ rx_ptr->control =
+ RXTX_CONTROL__NEXT_VALID | RXTX_CONTROL__HWGO;
+ rx_ptr = rx_ptr->next;
+ tx_ptr->control =
+ RXTX_CONTROL__NEXT_VALID;
+ tx_ptr = tx_ptr->next;
+ }
+ }
+
+ /*
+ * Initialize pointers to receive and transmit buffers
+ * that were allocated on module initialization (by
+ * allocate_rxtx_buffers() ).
+ */
+ bus_addr = virt_to_bus (xpds_data[card_num].rx_dma_list);
+ dprintk (KERN_DEBUG "%s: writing RX DMA status address %p (bus address %08x)\n", xpds_devs[card_num].name, xpds_data[card_num].rx_dma_list, bus_addr);
+ xpds_write_control_register (card_num, XPDS_DMA_STAT_ADDR,
+ bus_addr, RX_DMA);
+ bus_addr = virt_to_bus (xpds_data[card_num].tx_dma_list);
+ dprintk (KERN_DEBUG "%s: writing TX DMA status address %p (bus address %08x)\n", xpds_devs[card_num].name, xpds_data[card_num].tx_dma_list, bus_addr);
+ xpds_write_control_register (card_num, XPDS_DMA_STAT_ADDR,
+ bus_addr, TX_DMA);
+ xpds_data[card_num].current_rx_dma = xpds_data[card_num].rx_dma_list;
+ xpds_data[card_num].current_tx_dma = xpds_data[card_num].tx_dma_list;
+ xpds_data[card_num].current_hw_tx_dma = xpds_data[card_num].tx_dma_list;
+ xpds_data[card_num].current_hw_rx_dma = xpds_data[card_num].rx_dma_list;
+
+ /*
+ * release lock?
+ */
+
+ return 0;
+}
+
+static int
+xpds_dma_enable (int card_num)
+{
+ u32 value;
+
+ dprintk (KERN_DEBUG "xpds_dma_enable (%d)\n", card_num);
+
+ /*
+ * Check SDSL speed. If speed mode had been set to 0
+ * (autonegotiation mode), then the speed needs to be
+ * read before the DMA is enabled, in order to determine
+ * DMA low rate bug is applicable.
+ */
+ if (xpds_data[card_num].is_sdsl) {
+ u32 waituntil = jiffies + 90 * HZ;
+
+ do {
+ u32 sdsl_mode, speed_mode;
+ int rc;
+
+ rc = xpds_get_sdsl_mode (card_num, &sdsl_mode);
+ dprintk ("%s: SDSL mode is %08x\n",
+ xpds_devs[card_num].name, sdsl_mode);
+ speed_mode = sdsl_mode & XPDS_SDSL_MODE__SPEED_MASK;
+ dprintk ("%s: SDSL speed is %d\n",
+ xpds_devs[card_num].name, speed_mode << 3);
+ xpds_data[card_num].sdsl_speed = speed_mode << 3;
+ schedule_if_no_interrupt (card_num);
+ } while (xpds_data[card_num].sdsl_speed == 0 &&
+ jiffies < waituntil);
+ printk ("%s: SDSL speed is %d kbps.\n",
+ xpds_devs[card_num].name,
+ xpds_data[card_num].sdsl_speed);
+ }
+
+ /*
+ * Disable all interrupts
+ */
+ xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK,
+ XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW |
+ XPDS_DMA_MASK__LONG | XPDS_DMA_MASK__ABORT |
+ XPDS_DMA_MASK__CRC, RX_DMA);
+ xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK,
+ XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW |
+ XPDS_DMA_MASK__LONG | XPDS_DMA_MASK__ABORT |
+ XPDS_DMA_MASK__CRC, TX_DMA);
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR,
+ 0xff /* XPDS_MCR_MASK__RX_FIFO | XPDS_MCR_MASK__TX_FIFO */, MAIN);
+
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ 0xff, MAIN);
+
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", xpds_devs[card_num].name, value);
+
+ /*
+ * Enable receive and transmit DMAs. The transmit DMA is only
+ * enabled if we do not encounter the low bit rate bug.
+ */
+ if (! RX_DMA_LOW_RATE_BUG (card_num) ) {
+ if (! xpds_data[card_num].has_rx_dma_burst_bug) {
+ dprintk (KERN_INFO "%s: enabling burst on RX DMA\n",
+ xpds_devs[card_num].name);
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG,
+ XPDS_DMA_CONFIG__BURST_ENABLE | XPDS_DMA_CONFIG__ENABLE,
+ RX_DMA);
+ } else {
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG,
+ XPDS_DMA_CONFIG__ENABLE, RX_DMA);
+ }
+ }
+ if (! TX_DMA_LOW_RATE_BUG (card_num) ) {
+ if (! xpds_data[card_num].has_tx_dma_burst_bug) {
+ dprintk (KERN_INFO "%s: enabling burst on TX DMA\n",
+ xpds_devs[card_num].name);
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG,
+ XPDS_DMA_CONFIG__BURST_ENABLE | XPDS_DMA_CONFIG__ENABLE,
+ TX_DMA);
+ } else {
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG,
+ XPDS_DMA_CONFIG__ENABLE, TX_DMA);
+ }
+ }
+
+ /*
+ * Enable DMA interrupts. The transmit DMA interrupt is only
+ * enabled if the low bit rate bug is not encountered.
+ */
+ if (! RX_DMA_LOW_RATE_BUG (card_num) ) {
+ xpds_write_control_register (card_num, XPDS_DMA_SET_MASK,
+ XPDS_DMA_MASK__DONE, RX_DMA);
+ xpds_read_control_register (card_num, XPDS_DMA_SET_STAT,
+ &value, RX_DMA);
+ dprintk (KERN_DEBUG "%s: RX DMA status is %02x\n",
+ xpds_devs[card_num].name, value);
+ }
+
+ if (! TX_DMA_LOW_RATE_BUG (card_num) ) {
+ xpds_write_control_register (card_num, XPDS_DMA_SET_MASK,
+ XPDS_DMA_MASK__DONE, TX_DMA);
+ xpds_read_control_register (card_num, XPDS_DMA_SET_STAT,
+ &value, TX_DMA);
+ dprintk (KERN_DEBUG "%s: TX DMA status is %02x\n",
+ xpds_devs[card_num].name, value);
+ }
+
+ if (xpds_data[card_num].is_sdsl) {
+ u32 mask;
+
+ mask = XPDS_MCR_MASK__EXT;
+ if (! TX_DMA_LOW_RATE_BUG (card_num)) {
+ mask |= XPDS_MCR_MASK__TX_DMA;
+ }
+ if (! RX_DMA_LOW_RATE_BUG (card_num)) {
+ mask |= XPDS_MCR_MASK__RX_DMA;
+ } else {
+ mask |= XPDS_MCR_MASK__RX_FIFO;
+ }
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_SET, mask, MAIN);
+ } else {
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_SET,
+ XPDS_MCR_MASK__RX_DMA | XPDS_MCR_MASK__TX_DMA |
+ XPDS_MCR_MASK__RXCI, MAIN);
+ }
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+#if DEBUG
+ dprintk (KERN_DEBUG "%s: interrupt mask is %02x", xpds_devs[card_num].name, value);
+ if (value & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO");
+ if (value & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO");
+ if (value & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA");
+ if (value & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA");
+ if (value & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR");
+ if (value & XPDS_MCR_MASK__EXT) dprintk (" EXT");
+ if (value & XPDS_MCR_MASK__RXCI) dprintk (" RXCI");
+ dprintk ("\n");
+#endif
+
+ /*
+ * Let the RX DMA begin (write to hunt bit).
+ * If RX DMA bug, reset and unreset the RX FIFO instead.
+ */
+ if (RX_DMA_LOW_RATE_BUG (card_num)) {
+ xpds_data[card_num].current_rx_fifo = 0;
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, RX_FIFO);
+ udelay (20);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ 0, RX_FIFO);
+ } else {
+ xpds_write_control_register (card_num, XPDS_DMA_GO,
+ XPDS_DMA_GO__HUNT, RX_DMA);
+ }
+
+ /*
+ * Reset and unreset to enable TX FIFO mode instead of
+ * TX DMA to work around the TX DMA bug at < 400 Kbps.
+ */
+ if (TX_DMA_LOW_RATE_BUG (card_num)) {
+ xpds_data[card_num].current_tx_fifo = 0;
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, TX_FIFO);
+ udelay (20);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ 0, TX_FIFO);
+ }
+
+ return 0;
+}
+
+static int
+xpds_dma_disable (int card_num)
+{
+ u32 value;
+
+ dprintk (KERN_DEBUG "xpds_dma_disable (%d)\n", card_num);
+
+ /*
+ * Reset the DMAs
+ */
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG,
+ XPDS_DMA_CONFIG__RESET, RX_DMA);
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG,
+ XPDS_DMA_CONFIG__RESET, TX_DMA);
+
+ /*
+ * Disable the DMAs
+ */
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG, 0x0, RX_DMA);
+ xpds_write_control_register (card_num, XPDS_DMA_CONFIG, 0x0, TX_DMA);
+ /*
+ * Disable the DMA interrupts
+ */
+ xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK,
+ XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW, RX_DMA);
+ xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK,
+ XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW, TX_DMA);
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR,
+ XPDS_MCR_MASK__RX_DMA | XPDS_MCR_MASK__TX_DMA, MAIN);
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", xpds_devs[card_num].name, value);
+
+ return 0;
+}
+
+#define LED_OFF 0
+#define LED_ON 1
+/*
+ * Turn on/off the TX or activity LED
+ */
+__inline__ static void
+xpds_tx_led (int card_num, int on)
+{
+ if (xpds_data[card_num].is_fpga) {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_FPGA_TX_LED, MAIN );
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_FPGA_TX_LED, MAIN );
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_FPGA_TX_LED |
+ XPDS_MCR_GPIO__OE_FPGA_TX_LED, MAIN );
+ }
+ } else if (xpds_data[card_num].is_sdsl) {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN);
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_SDSL_ACT_LED, MAIN);
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_SDSL_ACT_LED |
+ XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN);
+ }
+ } else {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN);
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_ASIC_ACT_LED, MAIN);
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_ASIC_ACT_LED |
+ XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN);
+ }
+ }
+}
+
+/*
+ * Turn on/off the RX or activity LED
+ */
+__inline__ static void
+xpds_rx_led (int card_num, int on)
+{
+ if (xpds_data[card_num].is_fpga) {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_FPGA_RX_LED, MAIN );
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_FPGA_RX_LED, MAIN );
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_FPGA_RX_LED |
+ XPDS_MCR_GPIO__OE_FPGA_RX_LED, MAIN );
+ }
+ } else if (xpds_data[card_num].is_sdsl) {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN);
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_SDSL_ACT_LED, MAIN);
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_SDSL_ACT_LED |
+ XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN);
+ }
+ } else {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN);
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_ASIC_ACT_LED, MAIN);
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_ASIC_ACT_LED |
+ XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN);
+ }
+ }
+}
+
+
+/*
+ * Turn on the link LED
+ */
+__inline__ static void
+xpds_link_led (int card_num, int on)
+{
+ if (! xpds_data[card_num].is_fpga) {
+ if (on) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_ASIC_LINK_LED, MAIN);
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_ASIC_LINK_LED, MAIN);
+ } else {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_ASIC_LINK_LED |
+ XPDS_MCR_GPIO__OE_ASIC_LINK_LED, MAIN);
+ }
+ }
+}
+
+/*
+ * Resets the XPDS card, including running the PEB 2091 state machine
+ * into transparent mode by calling xpds_fsm().
+ */
+static int
+xpds_reset (int card_num)
+{
+ int rc;
+ int i;
+ int speed_mode;
+ u32 mode;
+ u32 value;
+
+ dprintk (KERN_DEBUG "%s: xpds_reset\n", xpds_devs[card_num].name);
+
+ rc = xpds_dma_disable (card_num);
+ if (rc != 0) return rc;
+
+ /*
+ * Reset the TX FIFO, then unreset it.
+ */
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, TX_FIFO);
+
+ /*
+ * For each FIFO, zero the status.
+ */
+ for (i = 0; i < NUM_FIFO; i ++ ) {
+ xpds_write_control_register (card_num, XPDS_FCR_STAT,
+ 0, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, TX_FIFO);
+ }
+
+ /*
+ * Reset the TX FIFO, then unreset it.
+ */
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, TX_FIFO);
+
+ /*
+ * Reset the RX FIFO, then unreset it.
+ */
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, RX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, RX_FIFO);
+
+ /*
+ * For each FIFO, zero the status.
+ */
+ for (i = 0; i < NUM_FIFO; i ++ ) {
+ xpds_write_control_register (card_num, XPDS_FCR_STAT,
+ 0, RX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, RX_FIFO);
+ }
+
+ /*
+ * Reset the RX FIFO, then unreset it.
+ */
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, RX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, RX_FIFO);
+
+ /*
+ * Enable TX and RX HDLC
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_TXCFG,
+ XPDS_MCR_TXCFG__ENABLE, MAIN);
+ if (xpds_data[card_num].has_last_byte_bug) {
+ xpds_write_control_register (card_num, XPDS_MCR_RXCFG,
+ (xpds_data[card_num].is_fpga ?
+ XPDS_MCR_RXCFG__ENABLE :
+ XPDS_MCR_RXCFG__ENABLE | XPDS_MCR_RXCFG__NO_CRC),
+ MAIN);
+ } else {
+ xpds_write_control_register (card_num, XPDS_MCR_RXCFG,
+ XPDS_MCR_RXCFG__ENABLE, MAIN);
+ }
+
+ /*
+ * Set mode register to normal mode.
+ */
+ if (xpds_asic_loopback) {
+ dprintk (KERN_INFO "%s: setting ASIC loopback\n", xpds_devs[card_num].name);
+ xpds_write_control_register (card_num, XPDS_MCR_CONFIG,
+ XPDS_MCR_CONFIG__MODE_LOOPBACK, MAIN);
+ } else {
+ xpds_write_control_register (card_num, XPDS_MCR_CONFIG,
+ XPDS_MCR_CONFIG__MODE_NORMAL, MAIN);
+ }
+
+ /*
+ * Turn on activation LED
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_TEST, 1, MAIN);
+
+ /*
+ * Clear all bits in GPIO
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_GPIO_CLR, 0xff, MAIN);
+
+ /*
+ * Enable GPIO outputs
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_MASK, MAIN);
+
+ /*
+ * Enable NT or LT mode
+ */
+ if (xpds_data[card_num].is_fpga) {
+ xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET,
+ (xpds_data[card_num].is_lt ?
+ XPDS_MCR_GPIO__GP_FPGA_LT :
+ XPDS_MCR_GPIO__GP_FPGA_NT) |
+ XPDS_MCR_GPIO__OE_MASK,
+ MAIN);
+ }
+
+ /*
+ * Turn off the LEDs
+ */
+ if (xpds_data[card_num].is_fpga) {
+ xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_FPGA_TX_LED |
+ XPDS_MCR_GPIO__GP_FPGA_RX_LED |
+ XPDS_MCR_GPIO__OE_FPGA_TX_LED |
+ XPDS_MCR_GPIO__OE_FPGA_RX_LED, MAIN);
+ } else {
+ xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__GP_ASIC_ACT_LED |
+ XPDS_MCR_GPIO__GP_ASIC_LINK_LED |
+ XPDS_MCR_GPIO__OE_ASIC_ACT_LED |
+ XPDS_MCR_GPIO__OE_ASIC_LINK_LED, MAIN);
+ }
+
+ /*
+ * Enable interrupt which notifies a change in the indication
+ * code of the PEB 2091 (RXCI) or the interrupt which indicates
+ * a change in the status of the SDSL (EXT).
+ */
+ if (xpds_data[card_num].is_sdsl) {
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_SET,
+ XPDS_MCR_MASK__EXT, MAIN);
+ } else {
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_SET,
+ XPDS_MCR_MASK__RXCI, MAIN);
+ }
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_SET,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt mask is %02x\n",
+ xpds_devs[card_num].name, value);
+
+ rc = xpds_init_descriptors (card_num);
+ if (rc != 0) return rc;
+
+ mode = 0;
+ if (xpds_data[card_num].is_sdsl) {
+ u32 sdsl_mode;
+
+ /*
+ * Reset and unreset the SDSL, then get the SDSL mode.
+ */
+ rc = xpds_reset_sdsl (card_num);
+ if (rc != 0) return rc;
+ rc = xpds_start_sdsl (card_num);
+ if (rc != 0) return rc;
+
+ rc = xpds_get_sdsl_mode (card_num, &sdsl_mode);
+ dprintk ("%s: SDSL mode is %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ speed_mode = sdsl_mode & XPDS_SDSL_MODE__SPEED_MASK;
+ dprintk ("%s: SDSL speed is %d\n", xpds_devs[card_num].name, speed_mode << 3);
+ xpds_data[card_num].sdsl_speed = speed_mode << 3;
+ } else {
+ /*
+ * Take the PEB 2091 out of reset (B1, B2, and D channels for
+ * 144k operation). Only for IDSL card.
+ */
+ speed_mode = xpds_data[card_num].speed_mode;
+ if (speed_mode & XPDS_MODE_B1) {
+ if (speed_mode & XPDS_MODE_B2) {
+ if (speed_mode & XPDS_MODE_D) {
+ dprintk ("%s: selecting B1B2D (144k)\n", xpds_devs[card_num].name);
+ mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1B2D;
+ } else {
+ dprintk ("%s: selecting B1B2 (128k)\n", xpds_devs[card_num].name);
+ mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1B2;
+ }
+ } else {
+ dprintk ("%s: selecting B1 (64k)\n", xpds_devs[card_num].name);
+ mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1;
+ }
+ } else if (speed_mode & XPDS_MODE_B2) {
+ dprintk ("%s: selecting B2 (64k)\n", xpds_devs[card_num].name);
+ mode |= XPDS_MCR_TXCI__PMD_CONFIG_B2;
+ } else {
+ dprintk (KERN_ERR "%s: invalid mode %d\n", xpds_devs[card_num].name, speed_mode);
+ dprintk ("%s: selecting B1B2D (144k)\n", xpds_devs[card_num].name);
+ mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1B2D;
+ }
+ xpds_write_control_register (card_num, XPDS_MCR_TXCI, mode, MAIN);
+ }
+
+ /*
+ * Set the PMD enable bit.
+ */
+ if (! xpds_data[card_num].is_sdsl) {
+ xpds_read_control_register (card_num, XPDS_MCR_TXCI, &mode, MAIN);
+ }
+ mode |= XPDS_MCR_TXCI__PMD_ENABLE | XPDS_MCR_TXCI__PMD_RESQ;
+ xpds_write_control_register (card_num, XPDS_MCR_TXCI, mode, MAIN);
+
+ if (xpds_data[card_num].is_sdsl) {
+ rc = xpds_mailbox_write (card_num, XPDS_MBX_START_BITPUMP, 0);
+ DELAY_HZ (3 * HZ / 2, card_num);
+ if (xpds_external_loopback) {
+ xpds_sdsl_loopback (card_num);
+ DELAY (2, card_num);
+ }
+ } else {
+ /*
+ * need to control state machine for non-SDSL cards
+ */
+ if (xpds_data[card_num].is_lt) {
+ rc = xpds_fsm_lt (card_num, mode, xpds_guard_time);
+ } else {
+ rc = xpds_fsm_nt (card_num, mode, xpds_guard_time);
+ }
+ if (rc != 0) return rc;
+ }
+
+ /*
+ * Turn on the link LED
+ */
+ if (! xpds_data[card_num].is_sdsl) xpds_link_led (card_num, 1);
+
+ /*
+ * Reset the FIFOs.
+ */
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG,
+ XPDS_FCR_CONFIG__RESET, RX_FIFO);
+
+ DELAY_HZ (1, card_num);
+
+ /*
+ * For each FIFO, zero the status.
+ */
+ for (i = 0; i < NUM_FIFO; i ++ ) {
+ xpds_write_control_register (card_num, XPDS_FCR_STAT,
+ 0, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_STAT,
+ 0, RX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, RX_FIFO);
+ }
+
+ /*
+ * Unreset the FIFOs.
+ */
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, RX_FIFO);
+
+ xpds_read_control_register (card_num, XPDS_FCR_CONFIG, &value, RX_FIFO);
+ dprintk (KERN_DEBUG "%s: RX FIFO config register is %08x\n",
+ xpds_devs[card_num].name, value);
+
+ /*
+ * For IDSL, physical layer is up.
+ * For SDSL, wait until interrupt occurs to let us know.
+ */
+ if (! xpds_data[card_num].is_sdsl) {
+ struct net_device *dev;
+
+ printk ("%s: physical link came up\n", xpds_devs[card_num].name);
+ xpds_data[card_num].physical_up = 1;
+ rc = xpds_dma_enable (card_num);
+ dev = &(xpds_devs[card_num]);
+ netif_start_queue(dev);
+ if (rc != 0) return rc;
+ }
+
+ return 0;
+}
+
+/*
+ * Called from interrupt handler to receive a packet.
+ */
+static void
+xpds_rx (struct net_device *dev, int len, volatile u8 *buf)
+{
+ struct sk_buff *skb;
+ int card_num;
+ struct frad_local *fp;
+ short dlci;
+ xpds_data_t *data_ptr;
+ int i;
+
+ card_num = dev - xpds_devs;
+ dprintk (KERN_DEBUG "xpds_rx (%p (%d), %d, %p)\n",
+ dev, card_num, len, buf);
+ xpds_rx_led (card_num, LED_ON);
+
+ data_ptr = dev->priv;
+ fp = &(data_ptr->frad_data);
+ dlci = data_ptr->dlci;
+
+ ddprintk (KERN_DEBUG "data_ptr = %p, fp = %p\n", data_ptr, fp);
+
+#if DEBUG
+ {
+ int i, debuglen;
+
+ debuglen = len;
+ if (debuglen > sizeof (struct frhdr)) {
+ debuglen = sizeof (struct frhdr);
+ }
+ dpprintk (KERN_DEBUG "frame header (%p) received:", buf);
+ for (i = 0; i < debuglen; i ++) {
+ dpprintk (" %02x", buf[i]);
+ }
+ dpprintk ("\n");
+ }
+ {
+ int i, debuglen;
+
+ debuglen = len;
+ if (debuglen > 256) debuglen = 256;
+ dpprintk (KERN_DEBUG "data (%p) received:",
+ buf + sizeof (struct frhdr));
+ for (i = sizeof (struct frhdr); i < debuglen ; i ++) {
+ dpprintk (" %02x", buf[i]);
+ }
+ if (len > debuglen) dpprintk (" ...");
+ dpprintk ("\n");
+ }
+#endif
+
+ if (dlci == 0) {
+ data_ptr->stats.rx_errors ++;
+ nrprintk (KERN_ERR "xpds_rx failed -- DLCI 0???\n");
+ xpds_rx_led (card_num, LED_OFF);
+ return;
+ }
+
+ for (i = 0; i < CONFIG_DLCI_MAX; i ++) {
+ if (fp->dlci[i] == dlci) break;
+ }
+ if (i == CONFIG_DLCI_MAX) {
+ data_ptr->stats.rx_errors ++;
+ nrprintk (KERN_ERR "xpds_rx failed -- invalid DLCI %d\n", dlci);
+ xpds_rx_led (card_num, LED_OFF);
+ return;
+ }
+ ddprintk (KERN_DEBUG "dlci = %d, i = %d\n", dlci, i);
+
+ skb = dev_alloc_skb (len);
+ if (skb == NULL) {
+ printk (KERN_ERR "%s: unable to allocate skb for packet reception\n", dev->name);
+ return;
+ }
+ memcpy (skb_put (skb, len), (void *)buf, len);
+ skb->dev = dev;
+ /* skb->protocol = eth_type_trans (skb, dev); */
+ skb->ip_summed = CHECKSUM_NONE; /* software will do checksum */
+ xpds_dlci_receive (skb, dev);
+ /* netif_rx (skb); */
+
+ data_ptr->stats.rx_packets ++;
+ data_ptr->stats.rx_bytes ++;
+
+ dprintk (KERN_DEBUG "xpds_rx done\n");
+
+ dev->last_rx = jiffies;
+ xpds_rx_led (card_num, LED_OFF);
+}
+
+static struct tq_struct *xpds_reset_bh_tasks;
+
+/*
+ * A bottom half function that is meant to be put on a task queue
+ * if the link goes down (i.e. PEB 2091 falls out of transparent mode)
+ * and either a transmit is attempted or an RXCI interrupt (indicating
+ * that the other side may be back up) is received.
+ */
+static void
+xpds_reset_bh (void *p)
+{
+ int rc;
+ int card_num;
+ struct net_device *dev;
+
+ dev = (struct net_device *)p;
+
+ card_num = dev - xpds_devs;
+
+ dprintk (KERN_DEBUG "%s: retrying physical link / state machine, calling xpds_reset\n", xpds_devs[card_num].name);
+
+ /*
+ * The guard times should be different on LT vs. NT
+ * when retrying. Should the guard times change every
+ * retry?
+ */
+ xpds_guard_time = xpds_data[card_num].is_lt ? 3 : 2;
+ rc = xpds_reset (card_num);
+ if (rc == 0) {
+ printk ("%s: physical link is up\n", xpds_devs[card_num].name);
+ if (! xpds_data[card_num].is_sdsl) xpds_link_led (card_num, 1);
+ netif_start_queue(dev);
+ }
+ xpds_data[card_num].physical_retrying = 0;
+}
+
+#if DEBUG
+static void
+xpds_print_interrupt_type (int card_num, u32 interrupt)
+{
+ u32 value;
+
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt mask is %02x", xpds_devs[card_num].name, value);
+ if (value & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO");
+ if (value & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO");
+ if (value & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA");
+ if (value & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA");
+ if (value & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR");
+ if (value & XPDS_MCR_MASK__EXT) dprintk (" EXT");
+ if (value & XPDS_MCR_MASK__RXCI) dprintk (" RXCI");
+ dprintk ("\n");
+ dprintk (KERN_DEBUG "%s: received interrupt %02x",
+ xpds_devs[card_num].name, interrupt);
+ if (interrupt & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO");
+ if (interrupt & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO");
+ if (interrupt & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA");
+ if (interrupt & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA");
+ if (interrupt & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR");
+ if (interrupt & XPDS_MCR_MASK__EXT) dprintk (" EXT");
+ if (interrupt & XPDS_MCR_MASK__RXCI) dprintk (" RXCI");
+ dprintk ("\n");
+ xpds_read_control_register (card_num, XPDS_DMA_SET_MASK,
+ &value, RX_DMA);
+ dprintk (KERN_DEBUG "%s: RX DMA mask is %02x\n", xpds_devs[card_num].name, value);
+ xpds_read_control_register (card_num, XPDS_DMA_SET_MASK,
+ &value, TX_DMA);
+ dprintk (KERN_DEBUG "%s: TX DMA mask is %02x\n", xpds_devs[card_num].name, value);
+}
+
+static void
+xpds_print_fifo_data (int card_num, u32 interrupt)
+{
+ u32 value;
+
+ if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_DETAILED)) != (DEBUG_MAIN | DEBUG_DETAILED)) return;
+
+ if (interrupt & XPDS_MCR_INT__RX_FIFO) {
+ int i, rc;
+ u8 *vptr;
+ const volatile xpds_rxtx_list_t *rxtx;
+
+ ddprintk (KERN_DEBUG "RX FIFO control registers:");
+ for (i = 0; i < NUM_FIFO_CONTROL_REGISTERS; i += 4) {
+ if (i % 16 == 0) {
+ ddprintk ("\n");
+ ddprintk (KERN_DEBUG "%08x:", i);
+ }
+ rc = xpds_read_control_register (card_num, i, &value, RX_FIFO);
+ if (rc > 0) {
+ ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc);
+ } else {
+ vptr = (u8 *) &value;
+ ddprintk (" %02x %02x %02x %02x",
+ vptr[0], vptr[1], vptr[2], vptr[3]);
+ }
+ }
+ ddprintk ("\n");
+
+ ddprintk (KERN_DEBUG "RX FIFO data registers:");
+ for (i = 0; i < NUM_FIFO_DATA_REGISTERS; i += 4) {
+ if (i % 16 == 0) {
+ ddprintk ("\n");
+ ddprintk (KERN_DEBUG "%08x:", i);
+ }
+ rc = xpds_read_control_register (card_num, i, &value, RX_FIFO_DATA);
+ if (rc > 0) {
+ ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc);
+ } else {
+ vptr = (u8 *) &value;
+ ddprintk (" %02x %02x %02x %02x",
+ vptr[0], vptr[1], vptr[2], vptr[3]);
+ }
+ }
+ ddprintk ("\n");
+
+ ddprintk (KERN_DEBUG "TX FIFO control registers:");
+ for (i = 0; i < NUM_FIFO_CONTROL_REGISTERS; i += 4) {
+ if (i % 16 == 0) {
+ ddprintk ("\n");
+ ddprintk (KERN_DEBUG "%08x:", i);
+ }
+ rc = xpds_read_control_register (card_num, i, &value, TX_FIFO);
+ if (rc > 0) {
+ ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc);
+ } else {
+ vptr = (u8 *) &value;
+ ddprintk (" %02x %02x %02x %02x",
+ vptr[0], vptr[1], vptr[2], vptr[3]);
+ }
+ }
+ ddprintk ("\n");
+
+ ddprintk (KERN_DEBUG "TX FIFO data registers:");
+ for (i = 0; i < NUM_FIFO_DATA_REGISTERS; i += 4) {
+ if (i % 16 == 0) {
+ ddprintk ("\n");
+ ddprintk (KERN_DEBUG "%08x:", i);
+ }
+ rc = xpds_read_control_register (card_num, i, &value, TX_FIFO_DATA);
+ if (rc > 0) {
+ ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc);
+ } else {
+ vptr = (u8 *) &value;
+ ddprintk (" %02x %02x %02x %02x",
+ vptr[0], vptr[1], vptr[2], vptr[3]);
+ }
+ }
+ ddprintk ("\n");
+
+ ddprintk (KERN_DEBUG "RX DMA control registers:");
+ for (i = 0; i < NUM_DMA_CONTROL_REGISTERS; i += 4) {
+ if (i % 16 == 0) {
+ ddprintk ("\n");
+ ddprintk (KERN_DEBUG "%08x:", i);
+ }
+ rc = xpds_read_control_register (card_num, i, &value, RX_DMA);
+ if (rc > 0) {
+ ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc);
+ } else {
+ vptr = (u8 *) &value;
+ ddprintk (" %02x %02x %02x %02x",
+ vptr[0], vptr[1], vptr[2], vptr[3]);
+ }
+ }
+ ddprintk ("\n");
+
+ ddprintk (KERN_DEBUG "TX DMA control registers:");
+ for (i = 0; i < NUM_DMA_CONTROL_REGISTERS; i += 4) {
+ if (i % 16 == 0) {
+ ddprintk ("\n");
+ ddprintk (KERN_DEBUG "%08x:", i);
+ }
+ rc = xpds_read_control_register (card_num, i, &value, TX_DMA);
+ if (rc > 0) {
+ ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc);
+ } else {
+ vptr = (u8 *) &value;
+ ddprintk (" %02x %02x %02x %02x",
+ vptr[0], vptr[1], vptr[2], vptr[3]);
+ }
+ }
+ ddprintk ("\n");
+
+ for (i = 0, rxtx = xpds_data[card_num].current_rx_dma;
+ i < NUM_DESC;
+ i ++, rxtx = rxtx->next) {
+ ddprintk (KERN_DEBUG "rx[%d](%p)->control = %08x",
+ i, rxtx, rxtx->control);
+ if (rxtx->control & RXTX_CONTROL__SWGO) {
+ ddprintk (" SWGO");
+ }
+ if (rxtx->control & RXTX_CONTROL__HWGO) {
+ ddprintk (" HWGO");
+ }
+ if (rxtx->control & RXTX_CONTROL__NEXT_VALID) {
+ ddprintk (" NEXT_VALID");
+ }
+ ddprintk ("\n");
+ if (! (rxtx->control & RXTX_CONTROL__NEXT_VALID)) {
+ break;
+ }
+ }
+ for (i = 0, rxtx = xpds_data[card_num].current_tx_dma;
+ i < NUM_DESC;
+ i ++, rxtx = rxtx->next) {
+ ddprintk (KERN_DEBUG "tx[%d](%p)->control = %08x",
+ i, rxtx, rxtx->control);
+ if (rxtx->control & RXTX_CONTROL__SWGO) {
+ ddprintk (" SWGO");
+ }
+ if (rxtx->control & RXTX_CONTROL__HWGO) {
+ ddprintk (" HWGO");
+ }
+ if (rxtx->control & RXTX_CONTROL__NEXT_VALID) {
+ ddprintk (" NEXT_VALID");
+ }
+ ddprintk ("\n");
+ if (! (rxtx->control & RXTX_CONTROL__NEXT_VALID)) {
+ break;
+ }
+ }
+ }
+ xpds_read_control_register (card_num, XPDS_MCR_RXCFG, &value, MAIN);
+ ddprintk ("%s: RX HDLC config is %08x\n", xpds_devs[card_num].name, value);
+ xpds_read_control_register (card_num, XPDS_MCR_TXCFG, &value, MAIN);
+ ddprintk ("%s: TX HDLC config is %08x\n", xpds_devs[card_num].name, value);
+}
+#endif
+
+/*
+ * For SDSL cards with the TX DMA low rate bug, do the transfer from the
+ * TX DMA descriptor to the TX FIFO. The TX FIFO interrupt indicates that
+ * the TX FIFO is ready to receive up to 32 bytes of data; this function
+ * simulates the hardware's method of copying data from the TX DMA to the
+ * TX FIFO.
+ *
+ * Note that this function keep stuffing the TX FIFO as long as it is
+ * ready (i.e. the TX FIFO interrupt bit shows 1), since if there is
+ * too long a delay for the next piece of the packet to be put in the
+ * TX FIFO, the packet will be aborted.
+ */
+#define TX_FIFO_DO_MORE 1
+#define TX_FIFO_DONE 2
+__inline__ static int
+xpds_tx_fifo_interrupt (int card_num)
+{
+ volatile u32 *tx_fifo_data_pointer;
+ volatile u8 *data;
+ int tx_len, copy_len, i;
+ u32 control, length, offset;
+ u32 value;
+ struct timeval tv1, tv2;
+ int tvdiff;
+
+ /*
+ * If there is no data in TX DMA (i.e. no more packets to
+ * send), disallow the TX FIFO interrupt (which will be
+ * enabled the next time a packet is transmitted by
+ * xpds_hw_tx() ) and be done.
+ */
+ control = xpds_data[card_num].current_hw_tx_dma->control;
+ if (! (control & RXTX_CONTROL__HWGO) ) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_CLR, XPDS_MCR_INT__TX_FIFO, MAIN);
+ return TX_FIFO_DONE;
+ }
+
+ /*
+ * Check TX FIFO interrupt to see if hardware is
+ * ready for the next TX FIFO to be filled.
+ * If not, allow TX FIFO interrupts (so that when the
+ * TX FIFO is ready, we come back here) and be done.
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ XPDS_MCR_INT__TX_FIFO, MAIN);
+ xpds_read_control_register (card_num, XPDS_MCR_INT_CLR,
+ &value, MAIN);
+ if (! (value & XPDS_MCR_INT__TX_FIFO)) {
+ dprintk (KERN_DEBUG "%s: TX FIFO interrupt not asserted\n", xpds_devs[card_num].name);
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_SET, XPDS_MCR_INT__TX_FIFO, MAIN);
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ XPDS_MCR_INT__TX_FIFO, MAIN);
+ return TX_FIFO_DONE;
+ }
+ do_gettimeofday (&tv1);
+
+ /*
+ * Get needed information about the length, offset,
+ * and data pointer in the TX DMA descriptor. Note
+ * that the length in the control field is one less
+ * than the actual length; we add 1 here to get the
+ * true length.
+ */
+ length = (control & RXTX_CONTROL__PACKET_LENGTH_MASK) + 1;
+ offset = xpds_data[card_num].current_hw_tx_dma->offset;
+ data = xpds_data[card_num].current_hw_tx_dma->buffer + offset;
+
+#if DEBUG
+ xpds_read_control_register (card_num, XPDS_FCR_CONFIG,
+ &value, TX_FIFO);
+ dprintk (KERN_DEBUG "%s: TX FIFO config is %02x\n",
+ xpds_devs[card_num].name, value);
+#endif
+
+ /*
+ * Put data in the appropriate TX FIFO. Data must be
+ * set / copied into the TX FIFO data registers in 32
+ * bit chunks, not 8 bit chunks.
+ */
+ tx_fifo_data_pointer = (volatile u32 *) (xpds_data[card_num].tx_fifo_data_registers + FIFO_SIZE * xpds_data[card_num].current_tx_fifo);
+ dprintk (KERN_DEBUG "%s: current_tx_fifo=%d, tx_fifo_data_pointer=%p\n", xpds_devs[card_num].name, xpds_data[card_num].current_tx_fifo, tx_fifo_data_pointer);
+
+ if (length - offset > FIFO_SIZE * sizeof (u32)) {
+ tx_len = FIFO_SIZE * sizeof (u32);
+ } else {
+ tx_len = length - offset;
+ }
+
+ copy_len = tx_len % 4 == 0 ? tx_len : (tx_len + 4) / 4 * 4;
+ for (i = 0; i < copy_len / 4; i ++) {
+ tx_fifo_data_pointer[i] = *((u32 *)data + i);
+ }
+
+ dprintk (KERN_DEBUG "%s: transmitting %d bytes through FIFO (%d left)\n", xpds_devs[card_num].name, tx_len, length - offset);
+#if DEBUG
+ dprintk (KERN_DEBUG "TX FIFO data (%p):", tx_fifo_data_pointer);
+ for (i = 0; i < tx_len; i ++) {
+ dprintk (" %02x", ((volatile u8 *)tx_fifo_data_pointer)[i]);
+ }
+ dprintk ("\n");
+#endif
+
+ /*
+ * Increment the current TX FIFO number and data pointer.
+ * Decrement the length.
+ */
+ xpds_data[card_num].current_tx_fifo ++;
+ xpds_data[card_num].current_tx_fifo %= NUM_FIFO;
+ offset += tx_len;
+ xpds_data[card_num].current_hw_tx_dma->offset = offset;
+
+ /*
+ * Tell the hardware that the data is ready. Note that
+ * the length is reduced by 1 for the hardware.
+ */
+ tx_len -= 1;
+ if (length - offset <= 0) {
+ tx_len |= XPDS_FCR_STAT__LAST;
+ xpds_data[card_num].current_hw_tx_dma->control &=
+ ~ RXTX_CONTROL__HWGO;
+ xpds_data[card_num].current_hw_tx_dma->control |=
+ RXTX_CONTROL__SWGO;
+ xpds_data[card_num].current_hw_tx_dma->offset = 0;
+ xpds_data[card_num].current_hw_tx_dma =
+ xpds_data[card_num].current_hw_tx_dma->next;
+ }
+
+ /*
+ * Note that due to the bug, we cannot use the FIFO registers
+ * until at least 10 microseconds after the FIFO ready (interrupt)
+ * is set.
+ */
+ do_gettimeofday (&tv2);
+ tvdiff = tv2.tv_usec - tv1.tv_usec +
+ (tv2.tv_sec - tv1.tv_sec) * 1000000;
+ if (tvdiff >= 0 && tvdiff < 10) {
+ udelay (10 - tvdiff);
+ }
+
+ dprintk (KERN_DEBUG "%s: writing %02x to FIFO stat\n",
+ xpds_devs[card_num].name, tx_len);
+ xpds_write_control_register (card_num, XPDS_FCR_STAT,
+ tx_len, TX_FIFO);
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, TX_FIFO);
+
+#if DEBUG
+ xpds_read_control_register (card_num, XPDS_FCR_CONFIG,
+ &value, TX_FIFO);
+ dprintk (KERN_DEBUG "%s: TX FIFO config is %02x after FCR_INC\n", xpds_devs[card_num].name, value);
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ XPDS_MCR_INT__TX_FIFO, MAIN);
+ xpds_read_control_register (card_num, XPDS_MCR_INT_CLR,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt value is %02x\n",
+ xpds_devs[card_num].name, value);
+#endif
+ return TX_FIFO_DO_MORE;
+}
+
+/*
+ * For SDSL cards with the RX DMA low rate bug, do the transfer from the
+ * RX FIFO descriptor to the RX DMA. The RX FIFO interrupt indicates that
+ * there is data in the RX FIFO that should be copied to the RX DMA.
+ *
+ * Note that this function keep taking from the RX FIFO as long as it is
+ * ready (i.e. the RX FIFO interrupt bit shows 1), since if there is
+ * too long a delay, pieces of the packet may be lost.
+ */
+#define RX_FIFO_DO_MORE 1
+#define RX_FIFO_DONE 2
+__inline__ static int
+xpds_rx_fifo_interrupt (int card_num)
+{
+ volatile u32 *rx_fifo_data_pointer;
+ volatile u8 *data;
+ int rx_len, rx_last, copy_len, i;
+ u32 control, length, offset;
+ u32 value;
+ struct timeval tv1, tv2;
+ int tvdiff;
+
+ /*
+ * If the RX DMA buffer is not ready for the hardware,
+ * stop. The packet is likely to drop in this case...
+ */
+ control = xpds_data[card_num].current_hw_rx_dma->control;
+ if (! (control & RXTX_CONTROL__HWGO) ) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_CLR, XPDS_MCR_INT__RX_FIFO, MAIN);
+ return RX_FIFO_DONE;
+ }
+
+ /*
+ * Check RX FIFO interrupt to see if hardware hass
+ * filled the next RX FIFO.
+ * If not, allow RX FIFO interrupts (so that when the
+ * RX FIFO is ready, we come back here) and be done.
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ XPDS_MCR_INT__RX_FIFO, MAIN);
+ xpds_read_control_register (card_num, XPDS_MCR_INT_CLR,
+ &value, MAIN);
+ if (! (value & XPDS_MCR_INT__RX_FIFO)) {
+ dprintk (KERN_DEBUG "%s: RX FIFO interrupt not asserted\n", xpds_devs[card_num].name);
+ /*
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_SET, XPDS_MCR_INT__RX_FIFO, MAIN);
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ XPDS_MCR_INT__RX_FIFO, MAIN);
+ */
+ return RX_FIFO_DONE;
+ }
+
+ do_gettimeofday (&tv1);
+
+ /*
+ * Get needed information about the length, offset,
+ * and data pointer in the RX DMA descriptor. Note
+ * that the length in the control field is one less
+ * than the actual length; we add 1 here to get the
+ * true length.
+ */
+ length = (control & RXTX_CONTROL__PACKET_LENGTH_MASK);
+ offset = xpds_data[card_num].current_hw_rx_dma->offset;
+ data = xpds_data[card_num].current_hw_rx_dma->buffer + offset;
+
+ dprintk (KERN_DEBUG "%s: current RX DMA buffer = %p\n",
+ xpds_devs[card_num].name,
+ xpds_data[card_num].current_hw_rx_dma->buffer);
+ dprintk (KERN_DEBUG "%s: current RX DMA length = %d\n",
+ xpds_devs[card_num].name, length);
+ dprintk (KERN_DEBUG "%s: current RX DMA offset = %d\n",
+ xpds_devs[card_num].name, offset);
+ dprintk (KERN_DEBUG "%s: current RX DMA data pointer = %p\n",
+ xpds_devs[card_num].name, data);
+
+ /*
+ * Copy data from the RX FIFO into the DMA buffer. Data
+ * must be set / copied in 32 bit chunks, not 8 bit chunks.
+ */
+ rx_fifo_data_pointer = (volatile u32 *) (xpds_data[card_num].rx_fifo_data_registers + FIFO_SIZE * xpds_data[card_num].current_rx_fifo);
+ dprintk (KERN_DEBUG "%s: current_rx_fifo=%d, rx_fifo_data_pointer=%p\n", xpds_devs[card_num].name, xpds_data[card_num].current_rx_fifo, rx_fifo_data_pointer);
+
+ /*
+ * Note that due to the bug, we cannot read the FIFO registers
+ * until at least 10 microseconds after the FIFO ready (interrupt)
+ * is set.
+ */
+ do_gettimeofday (&tv2);
+ tvdiff = tv2.tv_usec - tv1.tv_usec +
+ (tv2.tv_sec - tv1.tv_sec) * 1000000;
+ if (tvdiff >= 0 && tvdiff < 10) {
+ udelay (10 - tvdiff);
+ }
+
+ xpds_read_control_register (card_num, XPDS_FCR_STAT,
+ &value, RX_FIFO);
+ rx_len = value & XPDS_FCR_STAT__SIZE_MASK;
+ rx_len += 1;
+ rx_last = value & XPDS_FCR_STAT__LAST;
+
+ if (length + rx_len > RXTX_BUFFER_SIZE) {
+ dprintk (KERN_ERR "%s: packet too long (length = %d, rx_len = %d)\n", xpds_devs[card_num].name, length, rx_len);
+ if (rx_last) {
+ control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK;
+ control |= (length - 1);
+ control &= ~ RXTX_CONTROL__HWGO;
+ control |= RXTX_CONTROL__SWGO;
+ control &= ~ XPDS_DMA_DESC__PACKET_TAG_MASK;
+ control |= XPDS_DMA_DESC__PACKET_TAG_LONG;
+ xpds_data[card_num].current_hw_rx_dma->control = control;
+ xpds_data[card_num].current_hw_rx_dma->offset = 0;
+ }
+ xpds_data[card_num].current_rx_fifo ++;
+ xpds_data[card_num].current_rx_fifo %= NUM_FIFO;
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, RX_FIFO);
+ return RX_FIFO_DO_MORE;
+ }
+ dprintk (KERN_DEBUG "%s: receiving %d bytes through FIFO (rx_last=%x)\n", xpds_devs[card_num].name, rx_len, rx_last);
+#if DEBUG
+ dprintk (KERN_DEBUG "RX FIFO data (%p):", rx_fifo_data_pointer);
+ for (i = 0; i < rx_len; i ++) {
+ dprintk (" %02x", ((volatile u8 *)rx_fifo_data_pointer)[i]);
+ }
+ dprintk ("\n");
+#endif
+
+ copy_len = (rx_len % 4 == 0) ? rx_len : (rx_len + 4) / 4 * 4;
+ dprintk (KERN_DEBUG "%s: RX DMA offset = %d, data = %p, copy_len = %d\n", xpds_devs[card_num].name, offset, data, copy_len);
+ for (i = 0; i < copy_len / 4; i ++) {
+ *((u32 *)data + i) = rx_fifo_data_pointer[i];
+ }
+
+ /*
+ * Increment the RX FIFO number and data pointer.
+ */
+ xpds_data[card_num].current_rx_fifo ++;
+ xpds_data[card_num].current_rx_fifo %= NUM_FIFO;
+ xpds_write_control_register (card_num, XPDS_FCR_INC,
+ XPDS_FCR_INC__NEXT, RX_FIFO);
+
+ /*
+ * Increment the length and offset in the RX DMA buffer.
+ * If this is the last piece of the packet, turn on
+ * SW_GO and turn off HW_GO in the descriptor.
+ */
+ length += rx_len;
+ if (rx_last) {
+ u32 tag;
+ offset = 0;
+ /*
+ * Check for tags.
+ */
+ xpds_read_control_register (card_num, XPDS_FCR_TAG,
+ &value, RX_FIFO);
+ tag = value & XPDS_FCR_TAG__MASK;
+ if (tag) {
+ dprintk (KERN_DEBUG "%s: RX FIFO received tag %x\n",
+ xpds_devs[card_num].name, tag);
+ }
+
+ control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK;
+ control |= (length - 1);
+ control &= ~ RXTX_CONTROL__HWGO;
+ control |= RXTX_CONTROL__SWGO;
+ control &= ~ XPDS_DMA_DESC__PACKET_TAG_MASK;
+ control |= ((tag << 16) & XPDS_DMA_DESC__PACKET_TAG_MASK);
+ dprintk (KERN_DEBUG "%s: packet length is %d\n",
+ xpds_devs[card_num].name, length);
+ } else {
+ control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK;
+ control |= length;
+ offset += rx_len;
+ }
+ xpds_data[card_num].current_hw_rx_dma->control = control;
+ xpds_data[card_num].current_hw_rx_dma->offset = offset;
+
+ if (rx_last) {
+ xpds_data[card_num].current_hw_rx_dma = xpds_data[card_num].current_hw_rx_dma->next;
+ if (! (control & RXTX_CONTROL__NEXT_VALID)) {
+ dprintk (KERN_ERR "%s: RX DMA next valid is not set\n", xpds_devs[card_num].name);
+ }
+ }
+ return RX_FIFO_DO_MORE;
+}
+
+/*
+ * If the RX or TX low rate bugs exist and the
+ * RX or TX FIFOs are ready, do the FIFO manipulations.
+ */
+__inline__ static void
+xpds_fifo_interrupts (int card_num, u32 interrupt)
+{
+ int rx_rc = RX_FIFO_DONE, tx_rc = TX_FIFO_DONE, do_more;
+
+ dprintk (KERN_DEBUG "%s: xpds_fifo_interrupts(%d,%02x) called\n",
+ xpds_devs[card_num].name, card_num, interrupt);
+ if ((interrupt & XPDS_MCR_INT__RX_FIFO) &&
+ RX_DMA_LOW_RATE_BUG (card_num)) {
+ rx_rc = xpds_rx_fifo_interrupt (card_num);
+ }
+ if ((interrupt & XPDS_MCR_INT__TX_FIFO) &&
+ TX_DMA_LOW_RATE_BUG (card_num)) {
+ tx_rc = xpds_tx_fifo_interrupt (card_num);
+ }
+ do_more = rx_rc == RX_FIFO_DO_MORE || tx_rc == TX_FIFO_DO_MORE;
+ while (do_more) {
+ int i, rc;
+
+ do_more = 0;
+ for (i = 0; i < xpds_max_cards; i ++) {
+ if (xpds_data[i].rxtx_mem_allocated == NULL) continue;
+ if (RX_DMA_LOW_RATE_BUG (i)) {
+ rc = xpds_rx_fifo_interrupt (i);
+ if (rc == RX_FIFO_DO_MORE) do_more = 1;
+ }
+ if (TX_DMA_LOW_RATE_BUG (i)) {
+ rc = xpds_tx_fifo_interrupt (i);
+ if (rc == TX_FIFO_DO_MORE) do_more = 1;
+ }
+ }
+ }
+}
+
+/*
+ * Handle RXCI interrupt for IDSL, indicating possible physical
+ * layer state change.
+ */
+__inline__ static void
+xpds_rxci_interrupt (int card_num, struct net_device *dev)
+{
+ int ind_ai;
+ u32 value;
+
+ /*
+ * Get correct IND_AI to look for.
+ */
+ ind_ai = xpds_data[card_num].is_lt ? LT_IND_AI : NT_IND_AI;
+
+ xpds_data[card_num].rxci_interrupt_received = 1;
+ xpds_read_control_register (card_num, XPDS_MCR_RXCI,
+ &value, MAIN);
+
+ /*
+ * If network interface is up, check to see if PEB 2091
+ * fell out of transparent mode.
+ */
+ if (xpds_if_busy(dev) && (value & XPDS_MCR_RXCI__MASK) != ind_ai) {
+ dprintk (KERN_DEBUG "%s: RXCI status change to 0x%02x\n", xpds_devs[card_num].name, value);
+ printk (KERN_NOTICE "%s: physical link went down\n", xpds_devs[card_num].name);
+ if (! xpds_data[card_num].is_sdsl) xpds_link_led (card_num, 0);
+ netif_stop_queue(dev);
+ xpds_if_down(dev);
+ xpds_data[card_num].physical_up = 0;
+ xpds_data[card_num].physical_retrying = 0;
+ memset (xpds_data[card_num].frad_data.pvc_active, 0,
+ sizeof (xpds_data[card_num].frad_data.pvc_active));
+ memset (xpds_data[card_num].frad_data.pvc_new, 0,
+ sizeof (xpds_data[card_num].frad_data.pvc_new));
+ } else {
+ dprintk (KERN_DEBUG "%s: RXCI status change to 0x%02x\n", xpds_devs[card_num].name, value);
+ }
+}
+
+/*
+ * Handle external interrupt for SDSL, indicating possible physical
+ * layer state change.
+ */
+__inline__ static void
+xpds_ext_interrupt (int card_num, struct net_device *dev)
+{
+ u8 irq_type;
+ int rc;
+
+ /* unmask external interrupt */
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_SET,
+ XPDS_MCR_INT__EXT, MAIN);
+
+ /* get IRQ type */
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_WRITE_IRQTYPE,
+ &irq_type);
+ if (rc > 0) {
+ printk (KERN_ERR "%s: mailbox read (WRITE_IRQTYPE) failed (%d)\n", xpds_devs[card_num].name, rc);
+ } else if (irq_type == XPDS_SDSL_IRQTYPE_STATE_CHANGE) {
+ u8 state;
+
+ rc = xpds_mailbox_read (card_num,
+ XPDS_MBX_READ_PHYS_STATE, &state);
+ if (rc > 0) {
+ printk (KERN_ERR "%s: mailbox read (READ_PHYS_STATE) failed (%d)\n", xpds_devs[card_num].name, rc);
+ } else {
+ if (state & XPDS_SDSL_STATE_LINKUP) {
+ int rc;
+
+ printk (KERN_NOTICE "%s: physical link came up (state=%02x)\n", xpds_devs[card_num].name, state);
+ netif_start_queue(dev);
+ if (! xpds_data[card_num].physical_up) {
+ xpds_data[card_num].physical_up = 1;
+ xpds_data[card_num].physical_retrying = 0;
+
+ /*
+ * Need to re-enable the DMA which was
+ * disabled when the link went down.
+ */
+ rc = xpds_init_descriptors (card_num);
+ if (rc) printk (KERN_ERR "%s: xpds_init_descriptors(%d) failed\n", xpds_devs[card_num].name, card_num);
+ rc = xpds_dma_enable (card_num);
+ if (rc) printk (KERN_ERR "%s: xpds_dma_enable(%d) failed\n", xpds_devs[card_num].name, card_num);
+ }
+
+ } else {
+ printk (KERN_NOTICE "%s: physical link went down (state=%02x)\n", xpds_devs[card_num].name, state);
+ netif_stop_queue(dev);
+ xpds_if_down(dev);
+ if (xpds_data[card_num].physical_up) {
+ u32 sdsl_mode, speed_mode;
+ int rc;
+
+ xpds_data[card_num].physical_up = 0;
+ xpds_data[card_num].physical_retrying = 1;
+
+ /*
+ * DMA can get jammed up with junk
+ * packets when link goes down and
+ * up. Need to disable the DMA here
+ * to get the ASIC unstuck.
+ */
+ rc = xpds_dma_disable (card_num);
+ if (rc) printk (KERN_ERR "%s: xpds_dma_disable(%d) failed\n", xpds_devs[card_num].name, card_num);
+
+ /*
+ * Reset speed mode (in case it is 0,
+ * need it set that way for mailbox
+ * timeouts).
+ */
+ rc = xpds_get_sdsl_mode (card_num,
+ &sdsl_mode);
+ speed_mode = sdsl_mode & XPDS_SDSL_MODE__SPEED_MASK;
+ xpds_data[card_num].sdsl_speed =
+ speed_mode << 3;
+
+ }
+ }
+ }
+ }
+}
+
+#define PACKET_READ 0
+#define RX_DMA_NOT_READY 1
+
+/*
+ * Handle an RX DMA interrupt. Return PACKET_READ if a packet was
+ * read (erroneous or otherwise), and RX_DMA_NOT_READY if SW_GO is
+ * not set in the next descriptor.
+ */
+__inline__ static int
+xpds_rx_dma_interrupt (struct net_device *dev, int card_num)
+{
+ volatile xpds_rxtx_list_t *current_rx;
+ int len;
+ int packet_good;
+#if DEBUG
+ u32 value;
+#endif
+
+ current_rx = xpds_data[card_num].current_rx_dma;
+
+ dprintk (KERN_DEBUG "%s: xpds_rx_dma_interrupt() called\n", xpds_devs[card_num].name);
+ dprintk (KERN_DEBUG "%s: current_rx = %p\n", xpds_devs[card_num].name, current_rx);
+ dprintk (KERN_DEBUG "%s: current_rx->control = %08x\n", xpds_devs[card_num].name, current_rx->control);
+ dprintk (KERN_DEBUG "%s: current_rx->buffer = %p\n", xpds_devs[card_num].name, current_rx->buffer);
+ dprintk (KERN_DEBUG "%s: current_rx->next = %p\n", xpds_devs[card_num].name, current_rx->next);
+ dprintk (KERN_DEBUG "%s: current_rx->prev = %p\n", xpds_devs[card_num].name, current_rx->prev);
+ {
+ volatile xpds_rxtx_list_t *rx;
+
+ for (rx = current_rx->next; rx != current_rx; rx = rx->next) {
+ ddprintk (KERN_DEBUG "rx = %p\n", rx);
+ ddprintk (KERN_DEBUG "rx->control = %08x\n", rx->control);
+ ddprintk (KERN_DEBUG "rx->buffer = %p\n", rx->buffer);
+ ddprintk (KERN_DEBUG "rx->next = %p\n", rx->next);
+ ddprintk (KERN_DEBUG "rx->prev = %p\n", rx->prev);
+ }
+ }
+
+#if DEBUG
+ xpds_read_control_register (card_num, XPDS_DMA_CLR_STAT,
+ &value, RX_DMA);
+ ddprintk (KERN_DEBUG "%s: RX DMA status is %02x\n",
+ xpds_devs[card_num].name, value);
+#endif
+
+#if DEBUG
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+ ddprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", xpds_devs[card_num].name, value);
+ xpds_read_control_register (card_num, XPDS_MCR_INT_CLR,
+ &value, MAIN);
+ ddprintk (KERN_DEBUG "%s: interrupt is %02x\n", xpds_devs[card_num].name, value);
+#endif
+
+ /*
+ * Hardware should have set the software-go bit.
+ */
+ if (! (current_rx->control & RXTX_CONTROL__SWGO) ) {
+ dprintk (KERN_DEBUG "%s: xpds_rx_dma_interrupt() done, not ready\n", xpds_devs[card_num].name);
+ return RX_DMA_NOT_READY;
+ }
+
+ /*
+ * Packet is good unless proven otherwise...
+ */
+ packet_good = 1;
+
+ /*
+ * Check the packet tag. If not OK, mark the packet as not good.
+ */
+ {
+ u32 packet_tag;
+ const char *tag_str;
+
+ packet_tag = current_rx->control & XPDS_DMA_DESC__PACKET_TAG_MASK;
+ if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_CRC) {
+ tag_str = "CRC error";
+ } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_BOUNDARY_VIOLATION) {
+ tag_str = "boundary violation";
+ } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_LONG) {
+ tag_str = "long frame";
+ } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_ABORT) {
+ tag_str = "abort received";
+ } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_OK) {
+ tag_str = "OK";
+ } else if (packet_tag & 0x80000) {
+ tag_str = "overflow/underflow";
+ } else {
+ tag_str = "unlisted error";
+ }
+ if (packet_tag != XPDS_DMA_DESC__PACKET_TAG_OK) {
+ len = current_rx->control &
+ RXTX_CONTROL__PACKET_LENGTH_MASK;
+ len ++;
+ dprintk (KERN_ERR "%s: received packet of length %d with tag %05x (%s)\n", xpds_devs[card_num].name, len, packet_tag, tag_str);
+ packet_good = 0;
+ }
+ }
+
+ /*
+ * Get and check length of packet.
+ */
+ len = current_rx->control & RXTX_CONTROL__PACKET_LENGTH_MASK;
+ len ++;
+ /* buggy ASIC has packet length 2 too large */
+ if (xpds_data[card_num].has_last_byte_bug) {
+ len -= 2;
+ if (len < 0) len = 0;
+ }
+ if (len > RXTX_BUFFER_SIZE) {
+ dprintk (KERN_ERR "%s: receiving packet of length %d -- too large\n", xpds_devs[card_num].name, len);
+ packet_good = 0;
+ } else if (len < 1) {
+ dprintk (KERN_ERR "%s: receiving packet of length %d -- too small\n", xpds_devs[card_num].name, len);
+ packet_good = 0;
+ } else {
+ dprintk (KERN_DEBUG "%s: receiving packet of length %d\n",
+ xpds_devs[card_num].name, len);
+ }
+
+ /*
+ * Receive the packet (i.e. copy it to where the kernel
+ * deals with it) if the packet is ok.
+ */
+ if (packet_good) {
+ xpds_rx (dev, len, current_rx->buffer);
+ }
+
+ /*
+ * Zero the packet length.
+ */
+ ddprintk (KERN_DEBUG "%s: zeroing packet length\n", xpds_devs[card_num].name);
+ current_rx->control &= ~ (RXTX_CONTROL__PACKET_LENGTH_MASK | (RXTX_CONTROL__PACKET_TAG_MASK << RXTX_CONTROL__PACKET_TAG_OFFSET));
+
+ /*
+ * Turn off software-go, then turn on hardware-go to let the
+ * hardware know that it is ok to reuse the buffer.
+ */
+ current_rx->control &= ~ RXTX_CONTROL__SWGO;
+ current_rx->control |= RXTX_CONTROL__HWGO;
+
+ /*
+ * Advance the current to the next descriptor.
+ */
+ xpds_data[card_num].current_rx_dma = current_rx->next;
+
+ /*
+ * Increment the counters.
+ */
+ if (packet_good) {
+ xpds_data[card_num].stats.rx_packets ++;
+ } else {
+ xpds_data[card_num].stats.rx_errors ++;
+ }
+
+ dprintk (KERN_DEBUG "%s: xpds_rx_dma_interrupt() done, packet read\n", xpds_devs[card_num].name);
+
+ return PACKET_READ;
+}
+
+typedef struct {
+ struct net_device *dev;
+ u32 interrupt;
+} interrupt_bh_data_t;
+
+static struct tq_struct *xpds_interrupt_bh_tasks;
+
+static void xpds_interrupt_bh (void *p);
+
+/*
+ * The interrupt handler for the card. Interrupts may happen due
+ * to receiving a packet, or due to an RXCI status change (which
+ * occurs while the state machines on the LT and NT sides are
+ * negotiating each other into transparent mode).
+ */
+static void
+xpds_interrupt (int irq __attribute__((unused)), void *dev_instance,
+ struct pt_regs *regs __attribute__((unused)))
+{
+ struct net_device *dev;
+ int card_num;
+ u32 interrupt, bh_interrupts;
+
+ dprintk (KERN_DEBUG "xpds_interrupt (%d, %p, %p)\n", irq, dev_instance, regs);
+
+ dev = (struct net_device *)dev_instance;
+
+ if (dev == NULL) return;
+
+ /*
+ * Lock.
+ */
+#ifdef __SMP__
+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+ dprintk (KERN_DEBUG "%s: Duplicate entry of the interrupt handler by processor %d.\n",
+ dev->name, hard_smp_processor_id());
+ dev->interrupt = 0;
+ return;
+ }
+#else
+/* if (dev->interrupt) {
+ dprintk (KERN_DEBUG "%s: Re-entering the interrupt handler.\n", dev->name);
+ return;
+ }
+ dev->interrupt = 1; */
+#endif
+
+ card_num = dev - xpds_devs;
+
+ /*
+ * Get the interrupt type.
+ */
+ xpds_read_control_register (card_num, XPDS_MCR_INT_SET,
+ &interrupt, MAIN);
+#if DEBUG
+ xpds_print_interrupt_type (card_num, interrupt);
+#endif
+
+ if (RX_DMA_LOW_RATE_BUG (card_num)) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_CLR, XPDS_MCR_INT__RX_FIFO, MAIN);
+ }
+ if (TX_DMA_LOW_RATE_BUG (card_num)) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_CLR, XPDS_MCR_INT__TX_FIFO, MAIN);
+ }
+
+ /*
+ * Tell the hardware to stop generating this interrupt.
+ * For SDSL, clear the physical layer interrupt first.
+ * For all cards, clear the interrupt in the MCR.
+ */
+ if ((interrupt & XPDS_MCR_INT__EXT) && xpds_data[card_num].is_sdsl) {
+ int rc;
+
+ rc = xpds_mailbox_write (card_num, XPDS_MBX_CLEAR_IRQ, 0);
+ if (rc > 0) printk (KERN_ERR "%s: mailbox write (CLEAR_IRQ, 0) failed\n", xpds_devs[card_num].name);
+
+ /* mask external interrupt */
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR,
+ XPDS_MCR_INT__EXT, MAIN);
+ }
+
+ if (interrupt & XPDS_MCR_INT__RX_DMA) {
+ xpds_write_control_register (card_num, XPDS_DMA_CLR_STAT,
+ 0xff /* XPDS_DMA_STAT__DONE */, RX_DMA);
+ }
+
+ /* clear the interrupt in the MCR */
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ 0xff, MAIN);
+
+ /* read the interrupt in the MCR */
+ if (xpds_debug_level) {
+ u32 value;
+ xpds_read_control_register (card_num, XPDS_MCR_INT_SET,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt register is %02x after clearing\n", xpds_devs[card_num].name, value);
+ }
+
+ /*
+ * If the RX or TX low rate bugs exist and the
+ * RX or TX FIFOs are ready, do the FIFO manipulations.
+ */
+ xpds_fifo_interrupts (card_num, interrupt);
+
+#if DEBUG
+ xpds_print_fifo_data (card_num, interrupt);
+#endif
+
+ /*
+ * If it is a TX DMA interrupt, clear the HW_GO and SW_GO bits
+ * in any descriptors where both are set, and clear the interrupt.
+ */
+ if (interrupt & XPDS_MCR_INT__TX_DMA) {
+ volatile xpds_rxtx_list_t *tx_desc;
+ int i;
+
+ tx_desc = xpds_data[card_num].current_tx_dma;
+ for (i = 0; i < NUM_DESC; i ++) {
+ if ((tx_desc->control & (XPDS_DMA_DESC__HW_GO | XPDS_DMA_DESC__SW_GO)) == (XPDS_DMA_DESC__HW_GO | XPDS_DMA_DESC__SW_GO)) {
+ tx_desc->control &= ~ (XPDS_DMA_DESC__HW_GO | XPDS_DMA_DESC__SW_GO);
+ }
+ tx_desc = tx_desc->next;
+ }
+
+ ddprintk (KERN_DEBUG "%s: clearing TX DMA interrupt\n", xpds_devs[card_num].name);
+ xpds_write_control_register (card_num,
+ XPDS_DMA_CLR_STAT,
+ 0xff /* XPDS_DMA_STAT__DONE */, TX_DMA);
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ XPDS_MCR_INT__TX_DMA, MAIN);
+
+ xpds_tx_led (card_num, LED_OFF);
+ }
+
+ /*
+ * Check to see if the hardware has caught up with the
+ * software. If it has the software-go bit set, then
+ * reset and start the DMA again.
+ */
+ if (xpds_data[card_num].current_rx_dma->prev->control & RXTX_CONTROL__SWGO) {
+ if (! RX_DMA_LOW_RATE_BUG (card_num)) {
+ printk (KERN_INFO "%s: RX DMA overrun -- restarting RX DMA\n", xpds_devs[card_num].name);
+ xpds_dma_disable (card_num);
+ xpds_init_descriptors (card_num);
+ xpds_dma_enable (card_num);
+ }
+ }
+
+ mark_bh (NET_BH);
+
+ bh_interrupts = XPDS_MCR_INT__EXT | XPDS_MCR_INT__RXCI | XPDS_MCR_INT__RX_DMA;
+ if (RX_DMA_LOW_RATE_BUG (card_num) || TX_DMA_LOW_RATE_BUG (card_num)) {
+ bh_interrupts |= XPDS_MCR_INT__RX_FIFO | XPDS_MCR_INT__TX_FIFO;
+ }
+
+ if (interrupt & bh_interrupts) {
+ dprintk (KERN_DEBUG "queuing a bottom half task (dev = %p (%d), interrupt = %02x)\n", dev, card_num, interrupt);
+ ((interrupt_bh_data_t *)(xpds_interrupt_bh_tasks[card_num].data))->dev = dev;
+ ((interrupt_bh_data_t *)(xpds_interrupt_bh_tasks[card_num].data))->interrupt = interrupt;
+ queue_task (&(xpds_interrupt_bh_tasks[card_num]), &tq_immediate);
+ mark_bh (IMMEDIATE_BH);
+ }
+#if defined(__i386__)
+/* clear_bit(0, (void*)&dev->interrupt); */
+#else
+/* dev->interrupt = 0; */
+#endif
+}
+
+static void
+xpds_interrupt_bh (void *p)
+{
+ interrupt_bh_data_t *data;
+ struct net_device *dev;
+ int card_num;
+ u32 interrupt;
+
+ dprintk (KERN_DEBUG "xpds_interrupt_bh(%p) started\n", p);
+
+ data = p;
+ dev = data->dev;
+ card_num = dev - xpds_devs;
+ interrupt = data->interrupt;
+
+ dprintk (KERN_DEBUG "card_num = %d, interrupt = %02x\n",
+ card_num, interrupt);
+
+ /*
+ * If it is an RX DMA interrupt, need to get the packet
+ * from the buffer that hardware wrote into. Keep doing
+ * this until there are no more descriptors to read,
+ * because there may be multiple descriptors filled
+ * during one interrupt.
+ *
+ * Note that if we have the TX DMA low bit rate bug, we
+ * need to check see if we can push more data into the TX
+ * FIFO each time we receive a packet; if this isn't done,
+ * the TX FIFOs may get starved.
+ */
+ if ((interrupt & XPDS_MCR_INT__RX_DMA) ||
+ ((interrupt & XPDS_MCR_INT__RX_FIFO) &&
+ RX_DMA_LOW_RATE_BUG (card_num)) ) {
+ int rc;
+ do {
+ xpds_fifo_interrupts (card_num, interrupt);
+ rc = xpds_rx_dma_interrupt (dev, card_num);
+ } while (rc == PACKET_READ);
+ }
+
+ /*
+ * Turn on RX FIFO interrupts if necessary.
+ */
+ if (RX_DMA_LOW_RATE_BUG (card_num)) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_SET, XPDS_MCR_INT__RX_FIFO, MAIN);
+ }
+
+ /*
+ * If it is an RXCI interrupt, clear it, handle it, and go on.
+ * The RXCI interrupt is only used for IDSL cards.
+ */
+ if ((interrupt & XPDS_MCR_INT__RXCI) && ! xpds_data[card_num].is_sdsl) {
+ xpds_rxci_interrupt (card_num, dev);
+ }
+
+ /*
+ * If it is an external interrupt, clear it, handle it, and go on.
+ * The external interrupt is only used for SDSL cards.
+ */
+ if ((interrupt & XPDS_MCR_INT__EXT) && xpds_data[card_num].is_sdsl) {
+ xpds_ext_interrupt (card_num, dev);
+ }
+
+ dprintk (KERN_DEBUG "xpds_interrupt_bh() finished\n");
+}
+
+
+/*
+ * Called when "ifconfig xpds0 up" or some such is done.
+ * Tries to bring up and reset the device. Needs to have
+ * the other side also trying to get to transparent mode.
+ */
+static int
+xpds_open (struct net_device *dev)
+{
+ int card_num, rc, flags;
+ u32 value;
+
+ dprintk (KERN_DEBUG "xpds_open (%p (%d))\n", dev, dev - xpds_devs);
+
+ card_num = dev - xpds_devs;
+
+ /*
+ * Disable all interrupts.
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR,
+ 0xff, MAIN);
+ xpds_write_control_register (card_num, XPDS_MCR_INT_CLR,
+ 0xff, MAIN);
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt mask is %08x\n", xpds_devs[card_num].name, value);
+
+ /*
+ * Request the IRQ.
+ */
+ dev->irq = xpds_data[card_num].pci_dev->irq;
+
+ flags = SA_SHIRQ;
+
+ dprintk (KERN_DEBUG "%s: request_irq (%d, %p, %08x, %s, %p)\n",
+ dev->name, dev->irq, xpds_interrupt, flags, dev->name, dev);
+ /* DELAY (2, card_num); */
+ rc = request_irq (dev->irq, &xpds_interrupt, flags, dev->name, dev);
+ if (rc != 0) {
+ dprintk (KERN_DEBUG "%s: unable to get IRQ %d (rc=%d)\n",
+ dev->name, dev->irq, rc);
+ free_irq (dev->irq, dev);
+ return -EAGAIN;
+ }
+
+ dprintk (KERN_DEBUG "%s: %s got interrupt %d\n", dev->name, dev->name, dev->irq);
+
+ /* dev->dev_addr = ??? ; */
+
+ rc = xpds_reset (card_num);
+
+ xpds_dlci_install_lmi_timer (0, dev);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+/*
+ * Called when "ifconfig xpds0 down" or some such is done.
+ * Brings down the device.
+ */
+static int
+xpds_stop (struct net_device *dev)
+{
+ int card_num;
+ int rc;
+ u32 value;
+
+ card_num = dev - xpds_devs;
+
+ dprintk (KERN_DEBUG "%s: xpds_stop(%p)\n", xpds_devs[card_num].name, dev);
+ printk (KERN_DEBUG "%s: going down\n", xpds_devs[card_num].name);
+
+ xpds_dlci_remove_lmi_timer (0, dev);
+
+ rc = xpds_dma_disable (card_num);
+ if (rc != 0) return rc;
+
+ /*
+ * Turn off link LED, or put the SDSL in reset.
+ */
+ if (! xpds_data[card_num].is_sdsl) {
+ xpds_link_led (card_num, 0);
+ } else {
+ xpds_reset_sdsl (card_num);
+ }
+
+ /*
+ * Bring physical layer down.
+ */
+ if (xpds_data[card_num].is_sdsl) {
+ xpds_reset_sdsl (card_num);
+ } else {
+ xpds_read_control_register (card_num, XPDS_MCR_TXCI, &value,
+ MAIN);
+ value &= (XPDS_MCR_TXCI__MASK | XPDS_MCR_TXCI__PMD_CONFIG_B1B2D);
+ xpds_write_control_register (card_num, XPDS_MCR_TXCI, value,
+ MAIN);
+ }
+ xpds_data[card_num].physical_up = 0;
+ xpds_data[card_num].physical_retrying = 0;
+
+ /*
+ * Disable interrupts
+ */
+ xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR, 0xff, MAIN);
+
+ /*
+ * Mark the device as off and busy.
+ */
+ netif_stop_queue(dev);
+ xpds_if_down(dev);
+
+ MOD_DEC_USE_COUNT;
+
+ free_irq (dev->irq, dev);
+
+ return 0;
+}
+
+/*
+ * Does the hardware control part of the packet transmission.
+ */
+static int
+xpds_hw_tx (char *data, int len, struct net_device *dev)
+{
+ int card_num;
+ volatile xpds_rxtx_list_t *current_tx;
+ u32 control;
+
+ card_num = dev - xpds_devs;
+#if DEBUG
+ {
+ u32 value;
+
+ xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR,
+ &value, MAIN);
+ dprintk (KERN_DEBUG "%s: interrupt mask is %02x", xpds_devs[card_num].name, value);
+ if (value & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO");
+ if (value & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO");
+ if (value & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA");
+ if (value & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA");
+ if (value & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR");
+ if (value & XPDS_MCR_MASK__EXT) dprintk (" EXT");
+ if (value & XPDS_MCR_MASK__RXCI) dprintk (" RXCI");
+ dprintk ("\n");
+ }
+#endif
+
+ dprintk (KERN_DEBUG "%s: transmitting packet of length %d\n",
+ xpds_devs[card_num].name, len);
+
+ /*
+ * Make sure data is not too big. We are assuming that the
+ * other end has the same maximum packet length limitation.
+ * Is this necessarily correct?
+ */
+ if (len > xpds_max_packet_length) {
+ xpds_data[card_num].stats.tx_errors ++;
+ printk (KERN_ERR "packet size %d is too large (maximum %d)\n",
+ len, xpds_max_packet_length);
+ return -E2BIG;
+ }
+
+ /*
+ * Get control information for the descriptor.
+ */
+ control = xpds_data[card_num].current_tx_dma->control;
+
+ /*
+ * Check current descriptor to see if it is available.
+ * If software-go flag is not set, then the buffer is still
+ * waiting for the hardware to empty it.
+ */
+ if (! (control & RXTX_CONTROL__SWGO) && (control & RXTX_CONTROL__HWGO) ) {
+ dprintk (KERN_DEBUG "%s: unable to transmit (SWGO == 0 && HWGO == 1)\n", xpds_devs[card_num].name);
+ /* xpds_data[card_num].stats.tx_errors ++; */
+ return -EBUSY;
+ }
+
+ /*
+ * Indicate the time a transmission started.
+ */
+ dev->trans_start = jiffies;
+
+ /*
+ * Fill in current transmit buffer.
+ */
+ ddprintk (KERN_DEBUG "%s: filling current transmit buffer\n", xpds_devs[card_num].name);
+ memcpy ((void *)(xpds_data[card_num].current_tx_dma->buffer), data, len);
+
+ /*
+ * Set up the length in the current descriptor.
+ */
+ ddprintk (KERN_DEBUG "%s: setting length in descriptor\n", xpds_devs[card_num].name);
+ control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK;
+ control |= ((len - 1) & RXTX_CONTROL__PACKET_LENGTH_MASK);
+
+ /*
+ * Clear the software-go flag and set the hardware-go flag
+ * in the current descriptor.
+ */
+ ddprintk (KERN_DEBUG "%s: clearing SWGO and setting HWGO\n", xpds_devs[card_num].name);
+ control &= ~ RXTX_CONTROL__SWGO;
+ control |= RXTX_CONTROL__HWGO;
+
+ /*
+ * Put changed control back in the TX descriptor.
+ */
+ xpds_data[card_num].current_tx_dma->control = control;
+
+ /*
+ * Print out the current TX descriptor.
+ */
+ current_tx = xpds_data[card_num].current_tx_dma;
+
+ /*
+ * Write a 1 to the hunt bit of the DMA go register for
+ * the transmit DMA to cause it to fetch the next descriptor.
+ */
+ ddprintk (KERN_DEBUG "%s: setting hunt bit\n", xpds_devs[card_num].name);
+ xpds_write_control_register (card_num, XPDS_DMA_GO,
+ XPDS_DMA_GO__HUNT, TX_DMA);
+
+ /*
+ * Set current transmit buffer to the next one in the
+ * circular list, after setting the offset to 0 in case
+ * of the TX DMA bug.
+ */
+ xpds_data[card_num].current_tx_dma->offset = 0;
+ ddprintk (KERN_DEBUG "%s: setting current transmit buffer to next\n", xpds_devs[card_num].name);
+ xpds_data[card_num].current_tx_dma =
+ xpds_data[card_num].current_tx_dma->next;
+
+ /*
+ * Increment the counters.
+ */
+ xpds_data[card_num].stats.tx_packets ++;
+ xpds_data[card_num].stats.tx_bytes += len;
+
+ dprintk (KERN_DEBUG "%s: transmitted packet %ld\n",
+ xpds_devs[card_num].name, (long) (xpds_data[card_num].stats.tx_packets));
+
+ /*
+ * If we have the TX DMA bug we need to enable the TX FIFO
+ * interrupt so that when the TX FIFO is ready, we can simulate
+ * the hardware DMA->FIFO transfer in the driver.
+ */
+ if (TX_DMA_LOW_RATE_BUG (card_num)) {
+ xpds_write_control_register (card_num,
+ XPDS_MCR_MASK_SET, XPDS_MCR_INT__TX_FIFO, MAIN);
+ }
+
+ dprintk (KERN_DEBUG "%s: xpds_hw_tx () done\n", xpds_devs[card_num].name);
+
+ return 0;
+}
+
+/*
+ * Called whenever a packet needs to be transmitted.
+ * Note that if the physical link is down (not in transparent
+ * mode), a bottom half to reset the device is placed on the
+ * scheduler queue.
+ */
+int
+xpds_tx (u8 *data, unsigned int len, struct net_device *dev)
+{
+ int card_num;
+ int rc;
+ u32 control;
+
+ card_num = dev - xpds_devs;
+
+ xpds_tx_led (card_num, LED_ON);
+
+ dprintk (KERN_DEBUG "%s: xpds_tx (%p, %u, %p)\n", xpds_devs[card_num].name,
+ data, len, dev);
+
+#if DEBUG
+ {
+ int i, debuglen;
+
+ debuglen = len;
+ if (debuglen > sizeof (struct frhdr)) {
+ debuglen = sizeof (struct frhdr);
+ }
+ dpprintk (KERN_DEBUG "frame header sent:");
+ for (i = 0; i < sizeof (struct frhdr); i ++) {
+ dpprintk (" %02x", data[i]);
+ }
+ dpprintk ("\n");
+ }
+ {
+ int i, debuglen;
+
+ /* debuglen = ETH_ZLEN < len ? len : ETH_ZLEN; */
+ debuglen = len;
+ if (debuglen > 256) debuglen = 256;
+ dpprintk (KERN_DEBUG "data sent:");
+ for (i = sizeof (struct frhdr); i < debuglen ; i ++) {
+ dpprintk (" %02x", data[i]);
+ }
+ if (len > debuglen) dpprintk (" ...");
+ dpprintk ("\n");
+ }
+#endif
+ if (! xpds_data[card_num].physical_up) {
+ dprintk (KERN_DEBUG "%s: physical link is down\n", xpds_devs[card_num].name);
+ if (xpds_data[card_num].is_sdsl) {
+ return -EBUSY;
+ }
+ if (! xpds_data[card_num].physical_retrying) {
+ xpds_data[card_num].physical_retrying = 1;
+
+ xpds_reset_bh_tasks[card_num].next = NULL;
+ xpds_reset_bh_tasks[card_num].sync = 0;
+ xpds_reset_bh_tasks[card_num].routine = xpds_reset_bh;
+ xpds_reset_bh_tasks[card_num].data = dev;
+
+ queue_task (&(xpds_reset_bh_tasks[card_num]),
+ &tq_scheduler);
+ }
+ xpds_tx_led (card_num, LED_OFF);
+ return -EBUSY;
+ }
+
+ /*
+ * Atomically test and set (bit 0 of) the busy flag.
+ * If busy, return BUSY.
+ */
+ if (xpds_if_busy(dev)) {
+ dprintk (KERN_DEBUG "%s: busy\n", xpds_devs[card_num].name);
+ xpds_tx_led (card_num, LED_OFF);
+ /* xpds_data[card_num].stats.tx_errors ++; */
+
+ return -EBUSY;
+ }
+ netif_stop_queue(dev);
+
+ /* len = ETH_ZLEN < len ? len : ETH_ZLEN; */
+ dev->trans_start = jiffies;
+
+ rc = xpds_hw_tx (data, len, dev);
+
+ if (rc == 0) {
+ /* dev_kfree_skb (skb, FREE_WRITE); */
+ } else {
+ xpds_tx_led (card_num, LED_OFF);
+ }
+
+ /*
+ * Get control information for the descriptor (after
+ * the one that we just wrote into).
+ */
+ control = xpds_data[card_num].current_tx_dma->control;
+
+ /*
+ * Atomically clear the busy bit.
+ */
+/* if (test_and_clear_bit (0, (void *)&(dev->tbusy)) == 0) {
+ printk (KERN_ERR "%s: test_and_clear_bit(0, &(dev->tbusy)) in xpds_tx() found bit already clear\n", xpds_devs[card_num].name);
+ } */
+ netif_wake_queue(dev);
+
+ /*
+ * Return OK if xpds_tx returned 0 (OK), BUSY if -EBUSY,
+ * ERR otherwise.
+ */
+ return rc;
+}
+
+struct net_device_stats *
+xpds_get_stats (struct net_device *dev)
+{
+ xpds_data_t *data_ptr;
+
+ data_ptr = dev->priv;
+ return &(data_ptr->stats);
+}
+
+static int
+xpds_set_config (struct net_device *dev,
+ struct ifmap *map __attribute__ ((unused)) )
+{
+ dprintk (KERN_DEBUG "%s: xpds_set_config() called\n",
+ dev->name);
+
+ if (dev->flags & IFF_UP) return -EBUSY;
+
+ /* nothing */
+
+ return 0;
+}
+
+static void
+xpds_reboot_sdsl_physical_layer (int card_num)
+{
+ if (xpds_data[card_num].physical_up ||
+ xpds_data[card_num].physical_retrying) {
+ xpds_reset_sdsl (card_num);
+ xpds_start_sdsl (card_num);
+ }
+}
+
+static int xpds_init_frad_data (struct frad_local *fp, short dlci);
+
+static int
+xpds_ioctl (struct net_device *dev, struct ifreq *rq,
+ int cmd)
+{
+ xpds_data_t *data_ptr;
+ int val, card_num, rc = 0;
+
+ if (! suser ()) return -EACCES;
+
+ data_ptr = dev->priv;
+ card_num = data_ptr - xpds_data;
+ val = (int)(rq->ifr_data);
+ if (cmd == XPDS_IOCTL_SET_DEBUG) {
+#if DEBUG
+ int i;
+
+ printk ("XPDS driver debug level set to %d\n", val);
+ xpds_debug_level = val;
+ for (i = 0; i < xpds_max_cards; i ++) {
+ xpds_devs[i].flags &= ~ IFF_DEBUG;
+ xpds_devs[i].flags |= val ? IFF_DEBUG : 0;
+ }
+#else
+ printk (KERN_ERR "This version of the XPDS driver does not have debug capability.\n");
+#endif
+ } else if (cmd == XPDS_IOCTL_SET_LT) {
+ printk ("%s: set to %s\n",
+ xpds_devs[card_num].name,
+ val ? "LT (line termination)" :
+ "NT (network termination)");
+ val = (val != 0);
+ data_ptr->is_lt = val;
+ data_ptr->frad_data.no_initiate_lmi = val;
+ if (data_ptr->is_sdsl) {
+ u32 sdsl_mode;
+ u8 byte;
+
+ xpds_get_flash_sdsl_mode (card_num, &sdsl_mode);
+ printk (KERN_DEBUG "%s: sdsl_mode = %08x\n",
+ xpds_devs[card_num].name, sdsl_mode);
+ sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED;
+ sdsl_mode &= ~ XPDS_SDSL_MODE__NT;
+ sdsl_mode |= data_ptr->is_lt ? 0 : XPDS_SDSL_MODE__NT;
+ printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ rc = xpds_set_sdsl_mode (card_num, sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ rc = xpds_get_sdsl_exit_code (card_num, &byte);
+ if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) {
+ printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte);
+ rc = -EBUSY;
+ }
+ }
+ } else if (cmd == XPDS_IOCTL_SET_IDSL_MODE) {
+ if (! data_ptr->is_sdsl) {
+ printk ("%s: set to mode %d\n", xpds_devs[card_num].name, val);
+ data_ptr->speed_mode = val;
+ } else {
+ printk (KERN_ERR "Setting the IDSL mode is only applicable to IDSL.\n");
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_SET_SDSL_SPEED) {
+ if (data_ptr->is_sdsl) {
+ u32 sdsl_mode;
+ u8 byte;
+
+ printk ("%s: SDSL speed set to %d\n",
+ xpds_devs[card_num].name,
+ ((val >> 3) & XPDS_SDSL_MODE__SPEED_MASK) << 3);
+ rc = xpds_get_flash_sdsl_mode (card_num, &sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_get_flash_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ printk (KERN_DEBUG "%s: sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED;
+ sdsl_mode &= ~ XPDS_SDSL_MODE__SPEED_MASK;
+ sdsl_mode |= (val >> 3) & XPDS_SDSL_MODE__SPEED_MASK;
+ printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ rc = xpds_set_sdsl_mode (card_num, sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ rc = xpds_get_sdsl_exit_code (card_num, &byte);
+ if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) {
+ printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte);
+ rc = -EBUSY;
+ }
+
+ xpds_reboot_sdsl_physical_layer (card_num);
+
+ if ((xpds_data[card_num].has_tx_dma_low_rate_bug ||
+ xpds_data[card_num].has_rx_dma_low_rate_bug) &&
+ xpds_data[card_num].physical_up) {
+ if ((xpds_data[card_num].sdsl_speed < LOW_BIT_RATE && val >= LOW_BIT_RATE) || (xpds_data[card_num].sdsl_speed >= LOW_BIT_RATE && val < LOW_BIT_RATE)) {
+ /*
+ * If card has the low bit rate bug,
+ * and the speed change moved across
+ * the value that triggers the bug,
+ * need to reset the DMA / FIFO.
+ */
+ xpds_dma_disable (card_num);
+ xpds_dma_enable (card_num);
+ }
+ }
+ xpds_data[card_num].sdsl_speed = val;
+ } else {
+ printk (KERN_ERR "Setting the SDSL speed is only applicable to SDSL.\n");
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_SET_SDSL_INVERT) {
+ if (data_ptr->is_sdsl) {
+ u32 sdsl_mode;
+ u8 byte;
+
+ printk ("%s: SDSL invert set to %d\n",
+ xpds_devs[card_num].name, val ? 1 : 0);
+ rc = xpds_get_flash_sdsl_mode (card_num, &sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_get_flash_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ printk (KERN_DEBUG "%s: sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED;
+ sdsl_mode &= ~ XPDS_SDSL_MODE__INVERT;
+ sdsl_mode |= (val ? XPDS_SDSL_MODE__INVERT : 0);
+ printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ xpds_set_sdsl_mode (card_num, sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ rc = xpds_get_sdsl_exit_code (card_num, &byte);
+ if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) {
+ printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte);
+ rc = -EBUSY;
+ }
+ xpds_reboot_sdsl_physical_layer (card_num);
+ } else {
+ printk (KERN_ERR "Setting the invert is only applicable to SDSL.\n");
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_SET_SDSL_SWAP) {
+ if (data_ptr->is_sdsl) {
+ u32 sdsl_mode;
+ u8 byte;
+
+ printk ("%s: SDSL swap set to %d\n",
+ xpds_devs[card_num].name, val ? 1 : 0);
+ rc = xpds_get_flash_sdsl_mode (card_num, &sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_get_flash_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ printk (KERN_DEBUG "%s: sdsl_mode = %08x\n",
+ xpds_devs[card_num].name, sdsl_mode);
+ sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED;
+ sdsl_mode &= ~ XPDS_SDSL_MODE__SWAP;
+ sdsl_mode |= (val ? XPDS_SDSL_MODE__SWAP : 0);
+ printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode);
+ rc = xpds_set_sdsl_mode (card_num, sdsl_mode);
+ if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name);
+ rc = xpds_get_sdsl_exit_code (card_num, &byte);
+ if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) {
+ printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte);
+ rc = -EBUSY;
+ }
+ xpds_reboot_sdsl_physical_layer (card_num);
+ } else {
+ printk (KERN_ERR "Setting the swap is only applicable to SDSL.\n");
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_INSTALL_FLASH) {
+ rc = xpds_install_flash_image (card_num,
+ (xpds_flash_image_t *)(rq->ifr_data));
+ if (rc > 0) rc = -EBUSY;
+ } else if (cmd == XPDS_IOCTL_GET_SDSL_INFO) {
+ if (data_ptr->is_sdsl) {
+ printk ("%s: getting SDSL serial info for user process\n", xpds_devs[card_num].name);
+ copy_to_user ((void *)(rq->ifr_data),
+ &(data_ptr->serial_data),
+ sizeof (data_ptr->serial_data));
+ } else {
+ printk (KERN_ERR "%s: cannot get SDSL info on IDSL card\n", xpds_devs[card_num].name);
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_SET_SDSL_INFO) {
+ if (data_ptr->is_sdsl) {
+ printk ("%s: setting SDSL serial info from user process\n", xpds_devs[card_num].name);
+ copy_from_user (&(data_ptr->serial_data),
+ (void *)(rq->ifr_data),
+ sizeof (data_ptr->serial_data));
+ rc = xpds_set_sdsl_info (card_num);
+ if (rc > 0) {
+ printk (KERN_ERR "%s: unable to set SDSL info\n", xpds_devs[card_num].name);
+ rc = -EBUSY;
+ }
+ } else {
+ printk (KERN_ERR "%s: cannot set SDSL info on IDSL card\n", xpds_devs[card_num].name);
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_GET_SDSL_STATE) {
+ if (data_ptr->is_sdsl) {
+ u8 state;
+ rc = xpds_sdsl_get_state (card_num, &state);
+ if (rc != 0) {
+ printk (KERN_ERR "%s: get SDSL state failed, rc = %d\n", xpds_devs[card_num].name, rc);
+ state = -1;
+ rc = -EBUSY;
+ } else {
+ printk (KERN_NOTICE "%s: SDSL state is 0x%02x\n", xpds_devs[card_num].name, state);
+ }
+ copy_to_user (rq->ifr_data, &state, 1);
+ } else {
+ printk (KERN_ERR "%s: cannot set SDSL state on IDSL card\n", xpds_devs[card_num].name);
+ rc = -EINVAL;
+ }
+ } else if (cmd == XPDS_IOCTL_SET_LOOPBACK) {
+ xpds_loopback_parameters_t loopback_params;
+ copy_from_user (&loopback_params,
+ (void *)(rq->ifr_data),
+ sizeof (loopback_params));
+ if (loopback_params.loopback_type == XPDS_ASIC_LOOPBACK) {
+ if (loopback_params.on) {
+ printk (KERN_NOTICE "%s: setting ASIC loopback\n", xpds_devs[card_num].name);
+ xpds_write_control_register (card_num, XPDS_MCR_CONFIG,
+ XPDS_MCR_CONFIG__MODE_LOOPBACK, MAIN);
+ netif_start_queue(dev);
+ xpds_data[card_num].physical_up = 1;
+ } else {
+ printk (KERN_NOTICE "%s: unsetting ASIC loopback\n", xpds_devs[card_num].name);
+ xpds_write_control_register (card_num, XPDS_MCR_CONFIG,
+ XPDS_MCR_CONFIG__MODE_NORMAL, MAIN);
+ netif_stop_queue(dev);
+ xpds_if_down(dev);
+ xpds_data[card_num].physical_up = 0;
+ }
+ } else if (loopback_params.loopback_type == XPDS_SDSL_LOOPBACK) {
+ if (data_ptr->is_sdsl) {
+ printk (KERN_NOTICE "%s: setting SDSL external loopback\n", xpds_devs[card_num].name);
+ rc = xpds_sdsl_loopback (card_num);
+ if (rc != 0) {
+ printk (KERN_ERR "%s: setting SDSL external loopback failed, rc = %d\n", xpds_devs[card_num].name, rc);
+ rc = -EBUSY;
+ }
+ } else {
+ printk (KERN_ERR "%s: cannot set SDSL external loopback on IDSL card\n", xpds_devs[card_num].name);
+ rc = -EINVAL;
+ }
+ } else {
+ printk (KERN_ERR "%s: invalid loopback type %d\n",
+ xpds_devs[card_num].name, loopback_params.loopback_type);
+ }
+ } else if (cmd == XPDS_IOCTL_SET_BRIDGED_ETHERNET) {
+ /*
+ * 1 for bridged ethernet mode, 0 otherwise.
+ */
+ printk ("%s: bridged ethernet set to %d (%s)\n", xpds_devs[card_num].name,
+ val, val ? "on" : "off");
+ xpds_data[card_num].bridged_ethernet = val;
+ } else if (cmd == XPDS_IOCTL_SET_DLCI_CR) {
+ /*
+ * Should be 2, except for buggy Ascends which need 0.
+ */
+ printk ("%s: DLCI CR set to %d\n", xpds_devs[card_num].name, val);
+ xpds_data[card_num].dlci_cr = val;
+ } else if (cmd == XPDS_IOCTL_SET_DLCI_LMI) {
+ /*
+ * 0 LMI off
+ * 1 LMI in LT mode (responds to LMI messages)
+ * 2 LMI in NT mode (generates LMI messages)
+ * 3 LMI in NT bidirectional mode (generates and
+ * responds to LMI messages)
+ */
+ printk ("%s: DLCI LMI set to %d\n", xpds_devs[card_num].name, val);
+ xpds_data[card_num].dlci_lmi = val;
+ } else if (cmd == XPDS_IOCTL_SET_DLCI) {
+ printk ("%s: DLCI set to %d\n", xpds_devs[card_num].name, val);
+ xpds_data[card_num].dlci = val;
+ xpds_init_frad_data (&(xpds_data[card_num].frad_data), val);
+ } else {
+ printk (KERN_ERR "%s: received cmd = %d, data = %d\n",
+ xpds_devs[card_num].name, cmd, val);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int
+xpds_init_frad_data (struct frad_local *fp, short dlci)
+{
+ memset (&(fp->dlci), 0, sizeof (fp->dlci));
+ fp->dlci[0] = dlci;
+
+ return 0;
+}
+
+static int
+xpds_init (struct net_device *dev)
+{
+ xpds_data_t *data_ptr;
+ int card_num;
+
+ card_num = dev - xpds_devs;
+
+ dprintk (KERN_DEBUG "xpds_init (%p (%d))\n", dev, card_num);
+
+ netif_stop_queue(dev);
+ xpds_if_down(dev);
+
+ ether_setup (dev);
+ dev->open = xpds_open;
+ dev->stop = xpds_stop;
+ dev->hard_start_xmit = /* xpds_tx */ xpds_dlci_transmit;
+ dev->get_stats = xpds_get_stats;
+ dev->set_config = xpds_set_config;
+ /* dev->set_mac_address = xpds_set_mac_addr; */
+ /* dev->rebuild_header = xpds_rebuild_header; */
+ dev->do_ioctl = xpds_ioctl;
+ /* dev->change_mtu = xpds_change_mtu; */
+ dev->priv = &(xpds_data[card_num]);
+#if DEBUG
+ if (xpds_debug_level) dev->flags |= IFF_DEBUG;
+#endif
+ dev->flags &= ~ (IFF_BROADCAST | IFF_MULTICAST);
+
+ data_ptr = dev->priv;
+ memset (&(data_ptr->stats), 0, sizeof (data_ptr->stats));
+
+ /* memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); */
+ memcpy(dev->dev_addr,
+ xpds_data[dev - xpds_devs].serial_data.mac_address,
+ sizeof(dev->dev_addr));
+ /* dev->hard_header_len = sizeof (struct frhdr); */
+
+ /*
+ * Make sure that the payload cannot be equal to or
+ * greater than the maximum packet length minus headers.
+ * For some reason, it must be 2 less, not 1 less???
+ * If dev->mtu from ether_setup() is already smaller,
+ * leave it alone.
+ */
+ if (dev->mtu > xpds_max_packet_length - sizeof (struct frhdr) - 2) {
+ dev->mtu = xpds_max_packet_length - sizeof (struct frhdr) - 2;
+ dprintk (KERN_DEBUG "dev->mtu set to %d\n", dev->mtu);
+ }
+
+ xpds_init_frad_data (&(xpds_data[card_num].frad_data),
+ xpds_default_dlci);
+
+ /*
+ * Should be set by ioctls...
+ */
+ xpds_data[card_num].bridged_ethernet = xpds_default_bridged;
+ xpds_data[card_num].dlci = xpds_default_dlci;
+ /* dlci_cr needs to be 0 for buggy Ascends */
+ xpds_data[card_num].dlci_cr = xpds_default_dlci_cr;
+ if (xpds_default_dlci_lmi == XPDS_DLCI_LMI_LT_OR_NT) {
+ if (xpds_data[card_num].is_lt) {
+ xpds_data[card_num].dlci_lmi = XPDS_DLCI_LMI_LT;
+ } else {
+ xpds_data[card_num].dlci_lmi = XPDS_DLCI_LMI_NT;
+ }
+ } else {
+ xpds_data[card_num].dlci_lmi = xpds_default_dlci_lmi;
+ }
+
+ dprintk (KERN_INFO "%s: bridged ethernet mode is %d (%s)\n",
+ xpds_devs[card_num].name, xpds_data[card_num].bridged_ethernet,
+ xpds_data[card_num].bridged_ethernet ? "on" : "off");
+ dprintk (KERN_INFO "%s: DLCI = %d\n",
+ xpds_devs[card_num].name, xpds_data[card_num].dlci);
+ dprintk (KERN_INFO "%s: DLCI CR = %d\n",
+ xpds_devs[card_num].name, xpds_data[card_num].dlci_cr);
+ dprintk (KERN_INFO "%s: DLCI LMI = %d\n",
+ xpds_devs[card_num].name, xpds_data[card_num].dlci_lmi);
+
+ dprintk (KERN_DEBUG "xpds_init done\n");
+
+ return 0;
+}
+
+#define SEPROM_SIZE 17
+
+#define SEPROM_WRITE_OPCODE 0x5
+#define SEPROM_READ_OPCODE 0x6
+#define SEPROM_ERASE_OPCODE 0x7
+
+#define SEPROM_READ_OPERAND_LEN 9
+#define SEPROM_READ_DATA_LEN 17
+
+/*
+ * Read the given address out of the serial EPROM from an IDSL card.
+ */
+static u16
+read_seprom_data (int card_num, int address)
+{
+ int i;
+ u16 value = 0;
+ int opcode;
+
+ if (address < 0 || address >= SEPROM_SIZE) {
+ printk (KERN_ERR "%s: read_seprom_data (%d (invalid))\n",
+ xpds_devs[card_num].name, address);
+ return 0;
+ }
+
+ opcode = (SEPROM_READ_OPCODE << 6) | address;
+
+ /*
+ * Clear the GPIO.
+ */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR, 0xff, MAIN );
+
+ /*
+ * Enable the SK, DI, and CS bits in the GPIO,
+ * and set the CS.
+ */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET,
+ XPDS_MCR_GPIO__OE_SEPROM_SK |
+ XPDS_MCR_GPIO__OE_SEPROM_DI |
+ XPDS_MCR_GPIO__GP_SEPROM_CS |
+ XPDS_MCR_GPIO__OE_SEPROM_CS,
+ MAIN );
+ /*
+ * Give the address to the serial SEPROM.
+ */
+ for (i = 0; i < SEPROM_READ_OPERAND_LEN; i ++) {
+ int bit;
+
+ bit = opcode >> ((SEPROM_READ_OPERAND_LEN - 1) - i);
+ bit &= 0x1;
+ bit = bit ? XPDS_MCR_GPIO__GP_SEPROM_DI : 0;
+ /* 0 -> SK, DI */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR,
+ XPDS_MCR_GPIO__GP_SEPROM_SK |
+ XPDS_MCR_GPIO__GP_SEPROM_DI,
+ MAIN);
+ udelay (3);
+ /* bit -> DI */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET, bit, MAIN);
+ /* setup time */
+ udelay (3);
+ /* 1 -> SK */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET, XPDS_MCR_GPIO__GP_SEPROM_SK, MAIN);
+ /* hold time */
+ udelay (3);
+ }
+ /*
+ * Get the data from the serial SEPROM.
+ */
+ for (i = 0; i < SEPROM_READ_DATA_LEN; i ++) {
+ u32 bit;
+
+ /* 0 -> SK */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_CLR, XPDS_MCR_GPIO__GP_SEPROM_SK, MAIN);
+ /* setup time */
+ udelay (3);
+ /* 1 -> SK */
+ xpds_write_control_register (card_num,
+ XPDS_MCR_GPIO_SET, XPDS_MCR_GPIO__GP_SEPROM_SK, MAIN);
+ /* hold time */
+ udelay (3);
+
+ /* read bit */
+ xpds_read_control_register (card_num, XPDS_MCR_GPIO_SET,
+ &bit, MAIN);
+ bit &= XPDS_MCR_GPIO__GP_SEPROM_DO;
+ bit = bit ? 1 : 0;
+ value <<= 1;
+ value |= bit;
+ }
+ value >>= 1;
+
+ /*
+ dprintk (KERN_DEBUG "%s: read_seprom (%d) -> %x\n",
+ xpds_devs[card_num].name, address, value);
+ */
+
+ return value;
+}
+
+#define SEPROM_REVISION 0
+#define SEPROM_HARDWARE_VERSION 1
+#define SEPROM_SOFTWARE_VERSION 2
+#define SEPROM_FIRMWARE_VERSION 2
+#define SEPROM_MFG_DATE_HI 4
+#define SEPROM_MFG_DATE_LO 5
+#define SEPROM_MAC_ADDR_0_1 6
+#define SEPROM_MAC_ADDR_2_3 7
+#define SEPROM_MAC_ADDR_4_5 8
+#define SEPROM_SERIAL_0 9
+#define SEPROM_SERIAL_1 10
+#define SEPROM_SERIAL_2 11
+#define SEPROM_SERIAL_3 12
+#define SEPROM_SERIAL_4 13
+#define SEPROM_SERIAL_5 14
+#define SEPROM_SERIAL_6 15
+#define SEPROM_SERIAL_7 16
+
+/*
+ * Determine if the card is an IDSL or SDSL card. Only the IDSL
+ * card has the serial EPROM, so garbage indicates an SDSL card.
+ * Note: an FPGA card will have is_sdsl set to 1; read_sdsl_info()
+ * will set is_sdsl back to 0 if it appears to be an IDSL FPGA card.
+ * If IDSL, determine if it has the last byte bug.
+ */
+static void
+read_seprom_info (int card_num)
+{
+ u16 value1, value2, value3, value4;
+ xpds_serial_data_t *sdata;
+
+ if (xpds_data[card_num].is_fpga) {
+ /*
+ * FPGA card may be SDSL, so set is_sdsl so that
+ * read_sdsl_info() is called. read_sdsl_info()
+ * will unset if unable to get SDSL information.
+ */
+ xpds_data[card_num].is_sdsl = 1;
+ dprintk (KERN_INFO "No serial EPROM for FPGA device.\n");
+ return;
+ }
+
+ sdata = &(xpds_data[card_num].serial_data);
+
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_0);
+ value2 = read_seprom_data (card_num, SEPROM_SERIAL_1);
+ value3 = read_seprom_data (card_num, SEPROM_SERIAL_2);
+ value4 = read_seprom_data (card_num, SEPROM_SERIAL_3);
+ if (value1 != 0x5854 /* 'XT' */ || value2 != 0x414e /* 'AN' */ ||
+ value3 != 0x3230 /* '20' */ || (value4 >> 8) != '0') {
+ dprintk (KERN_DEBUG "Serial EPROM serial number does not begin with XTAN200; not an IDSL card.\n");
+ xpds_data[card_num].is_sdsl = 1;
+ return;
+ }
+
+ value1 = read_seprom_data (card_num, SEPROM_REVISION);
+ dprintk (KERN_DEBUG "Serial EPROM revision %d\n", value1);
+ sdata->seprom_revision = value1;
+
+ value1 = read_seprom_data (card_num, SEPROM_HARDWARE_VERSION);
+ dprintk (KERN_DEBUG "Hardware version %d.%d\n",
+ value1 >> 8, value1 & 0xff);
+ sdata->hardware_version[0] = value1 >> 8;
+ sdata->hardware_version[1] = value1 & 0xff;
+
+ value1 = read_seprom_data (card_num, SEPROM_SOFTWARE_VERSION);
+ dprintk (KERN_DEBUG "Software version %d.%d\n",
+ value1 >> 8, value1 & 0xff);
+ sdata->software_version[0] = value1 >> 8;
+ sdata->software_version[1] = value1 & 0xff;
+
+ value1 = read_seprom_data (card_num, SEPROM_FIRMWARE_VERSION);
+ dprintk (KERN_DEBUG "Firmware version %d.%d\n",
+ value1 >> 8, value1 & 0xff);
+ sdata->firmware_version[0] = value1 >> 8;
+ sdata->firmware_version[1] = value1 & 0xff;
+
+ value1 = read_seprom_data (card_num, SEPROM_MFG_DATE_HI);
+ value2 = read_seprom_data (card_num, SEPROM_MFG_DATE_LO);
+ dprintk (KERN_DEBUG "Manufacturing date %d.%d.%d\n",
+ value1, value2 >> 8, value2 & 0xff);
+ sdata->mfg_date[0] = value1 >> 8;
+ sdata->mfg_date[1] = value1 & 0xff;
+ sdata->mfg_date[2] = value2 >> 8;
+ sdata->mfg_date[3] = value2 & 0xff;
+
+ value1 = read_seprom_data (card_num, SEPROM_MAC_ADDR_0_1);
+ value2 = read_seprom_data (card_num, SEPROM_MAC_ADDR_2_3);
+ value3 = read_seprom_data (card_num, SEPROM_MAC_ADDR_4_5);
+ dprintk (KERN_DEBUG "MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ value1 >> 8, value1 & 0xff, value2 >> 8, value2 & 0xff,
+ value3 >> 8, value3 & 0xff);
+ sdata->mac_address[0] = value1 >> 8;
+ sdata->mac_address[1] = value1 & 0xff;
+ sdata->mac_address[2] = value2 >> 8;
+ sdata->mac_address[3] = value2 & 0xff;
+ sdata->mac_address[4] = value3 >> 8;
+ sdata->mac_address[5] = value3 & 0xff;
+
+ dprintk (KERN_DEBUG "Serial number ");
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_0);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[0] = value1 >> 8;
+ sdata->serial_number[1] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_1);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[2] = value1 >> 8;
+ sdata->serial_number[3] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_2);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[4] = value1 >> 8;
+ sdata->serial_number[5] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_3);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[6] = value1 >> 8;
+ sdata->serial_number[7] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_4);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[8] = value1 >> 8;
+ sdata->serial_number[9] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_5);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[10] = value1 >> 8;
+ sdata->serial_number[11] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_6);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[12] = value1 >> 8;
+ sdata->serial_number[13] = value1 & 0xff;
+ value1 = read_seprom_data (card_num, SEPROM_SERIAL_7);
+ dprintk ("%c%c", value1 >> 8, value1 & 0xff);
+ sdata->serial_number[14] = value1 >> 8;
+ sdata->serial_number[15] = value1 & 0xff;
+ dprintk ("\n");
+}
+
+/*
+ * Read information from the SDSL card (previously identified
+ * because the serial EPROM did not exist).
+ * Note that if the mailbox reads fail, it is probably an IDSL
+ * FPGA card.
+ */
+static int
+read_sdsl_info (int card_num)
+{
+ u8 byte, byte1, byte2;
+ int i, rc, rval = 0;
+ xpds_serial_data_t *sdata;
+
+ if (! xpds_data[card_num].is_sdsl) return 1;
+
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_HWVER, &byte1);
+ if (rc) rval = 1;
+
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_HWVER, &byte2);
+ if (rc) rval = 1;
+
+ if (rval) {
+ /* IDSL FPGA card */
+ xpds_data[card_num].is_sdsl = 0;
+ return rval;
+ }
+
+ sdata = &(xpds_data[card_num].serial_data);
+
+ dprintk (KERN_INFO "Hardware version ");
+ dprintk ("%d.", byte1);
+ dprintk ("%d\n", byte2);
+
+ sdata->hardware_version[0] = byte1;
+ sdata->hardware_version[1] = byte2;
+
+ dprintk (KERN_INFO "Firmware version ");
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_FWVER, &byte);
+ dprintk ("%d.", byte);
+ if (rc) rval = 1;
+ sdata->firmware_version[0] = byte;
+
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_FWVER, &byte);
+ dprintk ("%d\n", byte);
+ if (rc) rval = 1;
+ sdata->firmware_version[1] = byte;
+
+ if (rval) return rval;
+
+ dprintk (KERN_INFO "Manufacturing date ");
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte1);
+ if (rc) rval = 1;
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte2);
+ if (rc) rval = 1;
+ dprintk ("%d.", (byte1 << 8) + byte2);
+ sdata->mfg_date[0] = byte1;
+ sdata->mfg_date[1] = byte2;
+
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte);
+ if (rc) rval = 1;
+ dprintk ("%d.", byte);
+ sdata->mfg_date[2] = byte;
+
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte);
+ if (rc) rval = 1;
+ dprintk ("%d\n", byte);
+ sdata->mfg_date[3] = byte;
+
+ if (rval) return rval;
+
+ dprintk (KERN_INFO "MAC address ");
+ for (i = 0; i < 6; i ++) {
+ if (i != 0) dprintk (":");
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MACADDR, &byte);
+ dprintk ("%02x", byte);
+ if (rc) rval = 1;
+ sdata->mac_address[i] = byte;
+ }
+ dprintk ("\n");
+
+ if (rval) return rval;
+
+ dprintk (KERN_INFO "Serial number ");
+ for (i = 0; i < 16; i ++) {
+ rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_SERIALNUMBER, &byte);
+ dprintk ("%c", byte);
+ if (rc) rval = 1;
+ sdata->serial_number[i] = byte;
+ }
+ dprintk ("\n");
+
+ return rval;
+}
+
+static int
+get_pci_config (struct pci_dev *dev, volatile void **config_mem)
+{
+ u32 value;
+ int rc;
+
+ rc = pci_read_config_dword (dev, PCI_BASE_ADDRESS_0, &value);
+
+ if (rc != PCIBIOS_SUCCESSFUL) {
+ printk (KERN_ERR "unable to read PCI configuration register 4, error = %d\n", rc);
+ return -EIO;
+ }
+
+ dprintk (KERN_DEBUG "PCI config register 4 value=%08x\n", value);
+
+ value &= PCI_BASE_ADDRESS_IO_MASK;
+
+ *config_mem = ioremap (value, 32768);
+
+ dprintk (KERN_DEBUG "remapped hw_config_mem=%08x\n", (u32) *config_mem);
+#if (LINUX_VERSION_CODE < 0x02030d)
+ dprintk (KERN_DEBUG "dev->base_address[0]=%08x\n", (u32) dev->base_address[0]);
+ dprintk (KERN_DEBUG "dev->base_address[1]=%08x\n", (u32) dev->base_address[1]);
+ dprintk (KERN_DEBUG "dev->base_address[2]=%08x\n", (u32) dev->base_address[2]);
+ dprintk (KERN_DEBUG "dev->base_address[3]=%08x\n", (u32) dev->base_address[3]);
+ dprintk (KERN_DEBUG "dev->base_address[4]=%08x\n", (u32) dev->base_address[4]);
+ dprintk (KERN_DEBUG "dev->base_address[5]=%08x\n", (u32) dev->base_address[5]);
+#else
+ dprintk (KERN_DEBUG "dev->base_address[0]=%08x\n", (u32) dev->resource[0].start);
+ dprintk (KERN_DEBUG "dev->base_address[1]=%08x\n", (u32) dev->resource[1].start);
+ dprintk (KERN_DEBUG "dev->base_address[2]=%08x\n", (u32) dev->resource[2].start);
+ dprintk (KERN_DEBUG "dev->base_address[3]=%08x\n", (u32) dev->resource[3].start);
+ dprintk (KERN_DEBUG "dev->base_address[4]=%08x\n", (u32) dev->resource[4].start);
+ dprintk (KERN_DEBUG "dev->base_address[5]=%08x\n", (u32) dev->resource[5].start);
+#endif
+
+ return config_mem == NULL ? -ENOMEM : 0;
+}
+
+#define TRIES 8
+
+static int
+allocate_rxtx_buffers (int xpds_num, int num_rxtx, volatile void **rxtx_mem,
+ volatile xpds_rxtx_list_t **rx_list,
+ volatile xpds_rxtx_list_t **tx_list)
+{
+ int size, i, j;
+ volatile u8 *rx_buffer, *tx_buffer;
+ volatile xpds_rxtx_list_t *rx_ptr, *tx_ptr;
+ volatile void *old_mem[TRIES];
+
+ size = (num_rxtx + num_rxtx) * sizeof (xpds_rxtx_list_t) +
+ (num_rxtx + num_rxtx) * RXTX_BUFFER_SIZE;
+
+ /*
+ * Prevent RX/TX memory from crossing a 16 bit page (64k
+ * byte) boundary. This is due to a hardware limitation.
+ */
+ memset (old_mem, 0, sizeof (old_mem));
+ for (i = 0; i < TRIES; i ++) {
+ u32 start, end;
+
+ *rxtx_mem = kmalloc (size + 16, GFP_KERNEL /* | GFP_DMA */);
+ if (*rxtx_mem == NULL) break;
+
+ start = virt_to_bus (*rxtx_mem);
+ end = start + size + 16;
+
+ start &= 0xffff;
+ end &= 0xffff;
+
+ if (start < end) break;
+
+ printk (KERN_DEBUG "%s: RX/TX buffer allocation crossed 16 bit boundary, reallocating.\n", xpds_devs[xpds_num].name);
+ old_mem[i] = *rxtx_mem;
+ }
+ for (j = 0; j < i; j ++) {
+ if (old_mem[j] != NULL) kfree ((void *)(old_mem[j]));
+ }
+ if (i == TRIES || *rxtx_mem == NULL) return -ENOMEM;
+
+ xpds_data[xpds_num].rxtx_mem_allocated = *rxtx_mem;
+
+ if ((u32)*rxtx_mem & 0xf) {
+ *rxtx_mem = (volatile void *) (((u32) *rxtx_mem + 16) & 0xfffffff0);
+ }
+
+ *rx_list = (volatile xpds_rxtx_list_t *) *rxtx_mem;
+ *tx_list = (volatile xpds_rxtx_list_t *) ((u32) *rxtx_mem +
+ sizeof (xpds_rxtx_list_t) * num_rxtx);
+
+ rx_buffer = (volatile u8 *) ((u32) *tx_list +
+ sizeof (xpds_rxtx_list_t) * num_rxtx);
+ tx_buffer = (volatile u8 *) ((u32) rx_buffer +
+ RXTX_BUFFER_SIZE * num_rxtx);
+
+ rx_ptr = *rx_list;
+ tx_ptr = *tx_list;
+
+ for (i = 0; i < num_rxtx; i ++) {
+ rx_ptr->control = RXTX_CONTROL__NEXT_VALID | RXTX_CONTROL__HWGO;
+ rx_ptr->buffer = rx_buffer + i * RXTX_BUFFER_SIZE;
+ rx_ptr->buffer_bus_addr = virt_to_bus (rx_ptr->buffer);
+ rx_ptr->next = (i == num_rxtx - 1) ?
+ *rx_list :
+ (volatile xpds_rxtx_list_t *) ((u32) rx_ptr +
+ sizeof (xpds_rxtx_list_t));
+ rx_ptr->next_bus_addr = virt_to_bus (rx_ptr->next);
+ rx_ptr->unused1 = 0;
+ rx_ptr->prev = (i == 0) ?
+ (volatile xpds_rxtx_list_t *) ((u32) *rx_list +
+ sizeof (xpds_rxtx_list_t) * (num_rxtx - 1)) :
+ (volatile xpds_rxtx_list_t *) ((u32) rx_ptr -
+ sizeof (xpds_rxtx_list_t));
+ rx_ptr->offset = 0;
+ rx_ptr = rx_ptr->next;
+
+ tx_ptr->control = RXTX_CONTROL__NEXT_VALID;
+ tx_ptr->buffer = tx_buffer + i * RXTX_BUFFER_SIZE;
+ tx_ptr->buffer_bus_addr = virt_to_bus (tx_ptr->buffer);
+ tx_ptr->next = (i == num_rxtx - 1) ?
+ *tx_list :
+ (volatile xpds_rxtx_list_t *) ((u32) tx_ptr +
+ sizeof (xpds_rxtx_list_t));
+ tx_ptr->next_bus_addr = virt_to_bus (tx_ptr->next);
+ tx_ptr->unused1 = 0;
+ tx_ptr->prev = (i == 0) ?
+ (volatile xpds_rxtx_list_t *) ((u32) *tx_list +
+ sizeof (xpds_rxtx_list_t) * (num_rxtx - 1)) :
+ (volatile xpds_rxtx_list_t *) ((u32) tx_ptr -
+ sizeof (xpds_rxtx_list_t));
+ tx_ptr->offset = 0;
+ tx_ptr = tx_ptr->next;
+ }
+
+ dprintk (KERN_DEBUG "rxtx_mem = %08x, rx_list = %08x, tx_list = %08x,\n",
+ (u32) *rxtx_mem, (u32) *rx_list, (u32) *tx_list);
+ dprintk (KERN_DEBUG "rx_buffer = %08x, tx_buffer = %08x\n",
+ (u32) rx_buffer, (u32) tx_buffer);
+ return 0;
+}
+
+/*
+ * Given a pointer to memory, set the control register pointers.
+ */
+static int
+set_control_register_pointers (int xpds_num, volatile void *mem,
+ volatile xpds_rxtx_list_t *rx_list, volatile xpds_rxtx_list_t *tx_list)
+{
+ int rc;
+
+ dprintk (KERN_DEBUG "setting %s: control register pointers\n", xpds_devs[xpds_num].name);
+ xpds_data[xpds_num].main_control_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x0000 );
+ xpds_data[xpds_num].rx_fifo_control_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x0050 );
+ xpds_data[xpds_num].tx_fifo_control_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x0040 );
+ xpds_data[xpds_num].rx_dma_control_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x00c0 );
+ xpds_data[xpds_num].tx_dma_control_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x0080 );
+ xpds_data[xpds_num].rx_fifo_data_registers =
+ (volatile u32 *) ( (volatile u8 *) mem +
+ (xpds_data[xpds_num].is_fpga ? 0x0600 : 0x0500) );
+ xpds_data[xpds_num].tx_fifo_data_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x0400 );
+ xpds_data[xpds_num].aux_registers =
+ (volatile u32 *) ( (volatile u8 *) mem + 0x0060 );
+ dprintk (KERN_DEBUG "memory=%08x\n", (u32)mem);
+ dprintk (KERN_DEBUG "main_control_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].main_control_registers));
+ dprintk (KERN_DEBUG "rx_fifo_control_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].rx_fifo_control_registers));
+ dprintk (KERN_DEBUG "tx_fifo_control_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].tx_fifo_control_registers));
+ dprintk (KERN_DEBUG "rx_dma_control_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].rx_dma_control_registers));
+ dprintk (KERN_DEBUG "tx_dma_control_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].tx_dma_control_registers));
+ dprintk (KERN_DEBUG "rx_fifo_data_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].rx_fifo_data_registers));
+ dprintk (KERN_DEBUG "tx_fifo_data_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].tx_fifo_data_registers));
+ dprintk (KERN_DEBUG "aux_registers=%08x\n",
+ (u32)(xpds_data[xpds_num].aux_registers));
+
+ /*
+ * Install the buffer lists for RX and TX DMA.
+ */
+ xpds_data[xpds_num].rx_dma_list = rx_list;
+ dprintk (KERN_DEBUG "initializing %s: RX DMA Status Address:\n", xpds_devs[xpds_num].name);
+ rc = xpds_write_control_register (xpds_num, XPDS_DMA_STAT_ADDR,
+ (u32) rx_list, RX_DMA);
+ if (rc != 0) return rc;
+ dprintk ("\n");
+ xpds_data[xpds_num].tx_dma_list = tx_list;
+ dprintk (KERN_DEBUG "initializing %s: TX DMA Status Address:\n", xpds_devs[xpds_num].name);
+ rc = xpds_write_control_register (xpds_num, XPDS_DMA_STAT_ADDR,
+ (u32) tx_list, TX_DMA);
+ dprintk ("\n");
+ if (rc != 0) return rc;
+
+ return 0;
+}
+
+static int
+xpds_alloc_data (void)
+{
+ int rc;
+
+ if (xpds_data == NULL) {
+ xpds_data = kmalloc (sizeof (*xpds_data) * xpds_max_cards, GFP_KERNEL);
+ if (xpds_data == NULL) return -ENOMEM;
+ memset (xpds_data, 0, sizeof (*xpds_data) * xpds_max_cards);
+ }
+ if (xpds_names == NULL) {
+ xpds_names = kmalloc (NAME_SIZE * xpds_max_cards, GFP_KERNEL);
+ if (xpds_names == NULL) return -ENOMEM;
+ memset (xpds_names, 0, NAME_SIZE * xpds_max_cards);
+ }
+ if (xpds_reset_bh_tasks == NULL) {
+ xpds_reset_bh_tasks = kmalloc (sizeof (*xpds_reset_bh_tasks) * xpds_max_cards, GFP_KERNEL);
+ if (xpds_reset_bh_tasks == NULL) return -ENOMEM;
+ memset (xpds_reset_bh_tasks, 0, sizeof (*xpds_reset_bh_tasks) * xpds_max_cards);
+ }
+ if (xpds_interrupt_bh_tasks == NULL) {
+ int i;
+ xpds_interrupt_bh_tasks = kmalloc (sizeof (*xpds_interrupt_bh_tasks) * xpds_max_cards, GFP_KERNEL);
+ if (xpds_interrupt_bh_tasks == NULL) return -ENOMEM;
+ memset (xpds_interrupt_bh_tasks, 0, sizeof (*xpds_interrupt_bh_tasks) * xpds_max_cards);
+ for (i = 0; i < xpds_max_cards; i ++) {
+ xpds_interrupt_bh_tasks[i].data = kmalloc (sizeof (interrupt_bh_data_t), GFP_KERNEL);
+ xpds_interrupt_bh_tasks[i].next = NULL;
+ xpds_interrupt_bh_tasks[i].sync = 0;
+ xpds_interrupt_bh_tasks[i].routine = xpds_interrupt_bh;
+ }
+ }
+ if (xpds_devs == NULL) {
+ int i;
+ xpds_devs = kmalloc (sizeof (*xpds_devs) * xpds_max_cards, GFP_KERNEL);
+ if (xpds_devs == NULL) return -ENOMEM;
+ memset (xpds_devs, 0, sizeof (*xpds_devs) * xpds_max_cards);
+
+ for (i = 0; i < xpds_max_cards; i ++) {
+#if (LINUX_VERSION_CODE < HAS_SOFT_NET)
+ xpds_devs[i].name = xpds_names + NAME_SIZE * i;
+#endif
+ xpds_devs[i].init = xpds_init;
+ }
+ }
+ rc = xpds_sdsl_allocate ();
+ if (rc) return rc;
+ return 0;
+}
+
+static void
+xpds_free_data (void)
+{
+ if (xpds_data != NULL) kfree (xpds_data);
+ if (xpds_names != NULL) kfree (xpds_names);
+ if (xpds_reset_bh_tasks != NULL) kfree (xpds_reset_bh_tasks);
+ if (xpds_devs != NULL) kfree (xpds_devs);
+ xpds_sdsl_cleanup ();
+}
+
+#ifdef MODULE
+int init_module (void)
+#else
+int xpdsl_init(void)
+#endif
+{
+ int i;
+ int rc;
+ volatile xpds_rxtx_list_t *rx_list, *tx_list;
+ volatile void *rxtx_mem;
+ int found_sdsl = 0;
+ struct pci_dev *dev = NULL;
+#if ALLOW_OLD_PCI_VENDOR_ID
+ int old_offset = -1;
+#endif
+
+ printk (KERN_NOTICE "xpds.c: Xpeed XPDS frame relay driver %s, linux@xpeed.com, Copyright 1999, 2000 Xpeed, Inc.\n", VERSION_STRING);
+ rc = xpds_alloc_data ();
+ if (rc != 0) {
+ printk (KERN_ERR "Unable to allocate memory for XPDS data.\n");
+ xpds_free_data ();
+ return rc;
+ }
+
+ dprintk (KERN_DEBUG "xpds_data = %p, &(xpds_data[0].rxci_interrupt_received) = %p\n", xpds_data, &(xpds_data[0].rxci_interrupt_received));
+
+ /*
+ * Make sure that there is a PCI present, and the
+ * desired device is there.
+ */
+ if ( ! pci_present ()) {
+ printk (KERN_ERR "No PCI present.\n");
+ xpds_free_data ();
+ return -ENODEV;
+ }
+
+ for (i = 0; i < xpds_max_cards; i ++) {
+ char devname[NAME_SIZE], name[NAME_SIZE];
+ int n;
+
+ sprintf (devname, "%.*s%%d", NAME_SIZE - 4, xpds_dev_name);
+ n = dev_alloc_name (&(xpds_devs[i]), devname);
+ if (n < 0) {
+ printk(KERN_ERR "%s: dev_alloc_name failed (%d)\n", xpds_dev_name, n);
+ xpds_free_data ();
+ return -ENODEV;
+ }
+ sprintf (name, "%.*s%d", NAME_SIZE - 4, xpds_dev_name, n);
+ strcpy (xpds_devs[i].name, name);
+ }
+
+ for (i = 0; i < xpds_max_cards; i ++) {
+ memset (&(xpds_data[i]), 0, sizeof (xpds_data[i]));
+ xpds_data[i].speed_mode = xpds_mode;
+
+#if ALLOW_OLD_PCI_VENDOR_ID
+ if (old_offset < 0) {
+ dev = pci_find_device (PCI_VENDOR_ID_XPDS,
+ PCI_DEVICE_ID_XPDS_1, dev);
+ if (dev == NULL) {
+ old_offset = i;
+ dev = pci_find_device (PCI_VENDOR_ID_XPDS_OLD,
+ PCI_DEVICE_ID_XPDS_1, dev);
+ }
+ } else {
+ dev = pci_find_device (PCI_VENDOR_ID_XPDS_OLD,
+ PCI_DEVICE_ID_XPDS_1, dev);
+ }
+#else
+ dev = pci_find_device (PCI_VENDOR_ID_XPDS,
+ PCI_DEVICE_ID_XPDS_1, dev);
+#endif
+ if (dev == NULL) break;
+ dprintk (KERN_DEBUG "dev = %p\n", dev);
+
+ xpds_data[i].pci_dev = dev;
+
+ pci_set_master (dev);
+
+#if ALLOW_OLD_PCI_VENDOR_ID
+ if (old_offset >= 0) {
+ dprintk (KERN_DEBUG "XPDS FPGA device %d at pci_bus=0x%02x, pci_dev_fn=0x%02x, pci_irq_line=0x%02x.\n",
+ i,
+ xpds_data[i].pci_dev->bus->number,
+ xpds_data[i].pci_dev->devfn,
+ xpds_data[i].pci_dev->irq);
+ xpds_data[i].is_fpga = 1;
+ } else {
+ dprintk (KERN_DEBUG "XPDS device %d found at pci_bus=0x%02x, pci_dev_fn=0x%02x, pci_irq_line=0x%02x.\n",
+ i,
+ xpds_data[i].pci_dev->bus->number,
+ xpds_data[i].pci_dev->devfn,
+ xpds_data[i].pci_dev->irq);
+ xpds_data[i].is_fpga = 0;
+ }
+#else
+ dprintk (KERN_DEBUG "XPDS device %d found at pci_bus=0x%02x, pci_dev_fn=0x%02x, pci_irq_line=0x%02x.\n",
+ i,
+ xpds_data[i].pci_dev->bus->number,
+ xpds_data[i].pci_dev->devfn,
+ xpds_data[i].pci_dev->irq);
+ xpds_data[i].is_fpga = 0;
+#endif
+
+ /*
+ * Get the 32k of memory from hardware.
+ */
+ dprintk (KERN_DEBUG "%s: setting up PCI configuration\n", xpds_devs[i].name);
+ rc = get_pci_config (xpds_data[i].pci_dev,
+ &(xpds_data[i].config_mem_remapped));
+ if (rc != 0) {
+ xpds_free_data ();
+ return rc;
+ }
+
+ /*
+ * Allocate the RX and TX lists and buffers.
+ */
+ dprintk (KERN_DEBUG "%s: allocating RX/TX buffers\n", xpds_devs[i].name);
+ rc = allocate_rxtx_buffers (i, NUM_DESC, &rxtx_mem,
+ &rx_list, &tx_list);
+ if (rc != 0) {
+ xpds_free_data ();
+ return rc;
+ }
+
+ /*
+ * Set up the control register pointers to the RX/TX buffers.
+ */
+ rc = set_control_register_pointers (i,
+ xpds_data[i].config_mem_remapped, rx_list, tx_list);
+ if (rc != 0) {
+ xpds_free_data ();
+ return rc;
+ }
+
+ /*
+ * Read the serial EPROM for some more information
+ * about the device. May set xpds_data[i].is_sdsl or
+ * xpds_data[i].has_last_byte_bug .
+ */
+ read_seprom_info (i);
+
+ /*
+ * If the serial EPROM read failed, then it should be
+ * an SDSL device. Read the information from the SDSL
+ * device. If an error, then something is wrong...
+ */
+ if (xpds_data[i].is_sdsl) {
+ xpds_reset_sdsl (i);
+ xpds_start_sdsl (i);
+ DELAY_HZ (3 * HZ / 2, i);
+ rc = read_sdsl_info (i);
+ if (rc != 0) {
+ if (xpds_data[i].is_sdsl) {
+ printk (KERN_ERR "%s: Unable to determine if %s is an IDSL or SDSL card.\n", xpds_devs[i].name, xpds_devs[i].name);
+ printk (KERN_ERR "%s: %s may be defective\n", xpds_devs[i].name, xpds_devs[i].name);
+ if (! xpds_load_for_flash) {
+ xpds_free_data ();
+ return -ENODEV;
+ }
+ } else {
+ /* FPGA IDSL board */
+ printk (KERN_DEBUG "%s: %s has no SDSL infomation.\n", xpds_devs[i].name, xpds_devs[i].name);
+ printk (KERN_DEBUG "%s: is assumed to be an FPGA IDSL card.\n", xpds_devs[i].name);
+ }
+ }
+ }
+
+ /*
+ * Hardware bugs:
+ * ASIC < 1.1: last byte corruption bug
+ * hardware < 1.1: RX DMA burst bug
+ * hardware < 1.2: TX DMA burst bug
+ */
+ if (! xpds_data[i].is_fpga && ! xpds_is_hardware_version (i, 1, 1)) {
+ dprintk (KERN_DEBUG "Has last byte bug, using workaround.\n");
+ xpds_data[i].has_last_byte_bug = 1;
+ }
+
+ if (! xpds_is_hardware_version (i, 1, 1)) {
+ dprintk (KERN_DEBUG "Has RX DMA burst bug, not using RX DMA burst mode.\n");
+ xpds_data[i].has_rx_dma_burst_bug = 1;
+ }
+
+ if (! xpds_is_hardware_version (i, 1, 2)) {
+ dprintk (KERN_DEBUG "Has TX DMA burst bug, not using TX DMA burst mode.\n");
+ xpds_data[i].has_tx_dma_burst_bug = 1;
+ dprintk (KERN_DEBUG "Has TX DMA low rate (<%d Kbps) bug.\n", LOW_BIT_RATE);
+ xpds_data[i].has_tx_dma_low_rate_bug = 1;
+ }
+
+ printk (KERN_DEBUG "%s: Xpeed %c00 %cDSL NIC, %02X %02X %02X %02X %02X %02X, IRQ %d.\n",
+ xpds_devs[i].name,
+ xpds_data[i].is_sdsl ? '3' : '2',
+ xpds_data[i].is_sdsl ? 'S' : 'I',
+ xpds_data[i].serial_data.mac_address[0],
+ xpds_data[i].serial_data.mac_address[1],
+ xpds_data[i].serial_data.mac_address[2],
+ xpds_data[i].serial_data.mac_address[3],
+ xpds_data[i].serial_data.mac_address[4],
+ xpds_data[i].serial_data.mac_address[5],
+ xpds_data[i].pci_dev->irq);
+
+ if (xpds_data[i].is_sdsl) {
+ int rc;
+ u32 mode, speed, swap, invert, nt;
+
+ rc = xpds_get_flash_sdsl_mode (i, &mode);
+
+ if (rc) {
+ printk (KERN_ERR "%s: unable to get speed, swap, and invert\n", xpds_devs[i].name);
+ } else {
+ speed = (mode & XPDS_SDSL_MODE__SPEED_MASK) << 3;
+ nt = (mode & XPDS_SDSL_MODE__NT);
+ swap = (mode & XPDS_SDSL_MODE__SWAP);
+ invert = (mode & XPDS_SDSL_MODE__INVERT);
+ printk (KERN_DEBUG "%s: speed = %d%s, swap %s, invert %s, %s mode\n", xpds_devs[i].name, speed, (speed == 0) ? " (CM auto)" : "", swap ? "on" : "off", invert ? "on" : "off", nt ? "NT" : "LT");
+ }
+ }
+
+ if (xpds_data[i].is_sdsl) found_sdsl = 1;
+
+ /*
+ * Register network device.
+ */
+ rc = register_netdev (&(xpds_devs[i]));
+ if (rc != 0) {
+ xpds_free_data ();
+ return rc;
+ }
+ }
+
+ num_xpds_found = i;
+
+ if (num_xpds_found < 1) {
+ printk (KERN_ERR "PCI error: XPDS device not found.\n");
+ xpds_free_data ();
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void cleanup_module (void)
+{
+ int i;
+
+ for (i = 0; i < num_xpds_found; i ++) {
+ if (xpds_data[i].rxtx_mem_allocated != NULL) {
+ kfree ((void *)(xpds_data[i].rxtx_mem_allocated));
+ }
+ if (xpds_data[i].config_mem_remapped != NULL) {
+ iounmap ((void *)(xpds_data[i].config_mem_remapped));
+ }
+ dprintk (KERN_DEBUG "unregistering XPDS network device %d\n", i);
+ unregister_netdev (&(xpds_devs[i]));
+ }
+ xpds_free_data ();
+ dprintk (KERN_DEBUG "removing Xpeed XPDS frame relay driver\n");
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)