diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /drivers/net/sdla_fr.c | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'drivers/net/sdla_fr.c')
-rw-r--r-- | drivers/net/sdla_fr.c | 1725 |
1 files changed, 1391 insertions, 334 deletions
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c index fd7173b45..e30bede48 100644 --- a/drivers/net/sdla_fr.c +++ b/drivers/net/sdla_fr.c @@ -1,7 +1,8 @@ -/***************************************************************************** +/**************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * -* Author: Gene Kozin <genek@compuserve.com> +* Author(s): Gene Kozin +* Jaspreet Singh <jaspreet@sangoma.com> * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -10,26 +11,52 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* -* Jun 29, 1997 Alan Cox o Hacked up vendor source 1.0.3 to remove -* C++ style comments, and a massive security -* hole (the UDP management junk). -* +* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards +* o Added Cli() to protect enabling of interrupts +* while polling is called. +* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts +* when they have been disabled by another +* interface or routine (eg. wpf_poll). +* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling +* routine disable interrupts during interrupt +* testing. +* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. +* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow +* control by avoiding RACE conditions. The +* cli() and restore_flags() are taken out. +* The fr_channel structure is appended for +* Driver Statistics. +* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX +* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() +* o Abstracted the UDP management stuff +* o Now use tbusy and critical more intelligently +* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 +* through router.conf. +* o Protected calls to sdla_peek() by adDing +* save_flags(), cli() and restore_flags(). +* o Added error message for Inactive DLCIs in +* fr_event() and update_chan_state(). +* o Fixed freeing up of buffers using kfree() +* when packets are received. +* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets +* o Added ability to discard multicast and +* broadcast source addressed packets +* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities +* New case (0x44) statement in if_send routine * Added a global variable rCount to keep track +* of FT1 status enabled on the board. * May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem * With multiple boards a problem was seen where * the second board always stopped transmitting * packet after running for a while. The code * got into a stage where the interrupts were * disabled and dev->tbusy was set to 1. -* This caused the If_send() routine to get into -* the if clause for set_bit(0,dev->tbusy) +* This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy) * forever. * The code got into this stage due to an * interrupt occuring within the if clause for * set_bit(0,dev->tbusy). Since an interrupt * disables furhter transmit interrupt and -* makes dev->tbusy = 0, this effect was undone -* by making dev->tbusy = 1 in the if clause. +* makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause. * The Fix checks to see if Transmit interrupts * are disabled then do not make dev->tbusy = 1 * Introduced a global variable: int_occur and @@ -51,7 +78,7 @@ * Jan 30, 1997 Gene Kozin Version 3.1.0 * o implemented exec() entry point * o fixed a bug causing driver configured as -* a FR switch to be stuck in WAN_DISCONNECTED +* a FR switch to be stuck in WAN_ * mode * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -60,115 +87,237 @@ #error This code MUST be compiled as a kernel module! #endif +#include <linux/config.h> /* OS configuration options */ #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ #include <linux/malloc.h> /* kmalloc(), kfree() */ +#include <linux/init.h> /* __initfunc */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <linux/init.h> /* __initfunc et al. */ #include <asm/byteorder.h> /* htons(), etc. */ #include <asm/io.h> /* for inb(), outb(), etc. */ #include <asm/uaccess.h> +#include <linux/time.h> /* for do_gettimeofday */ #define _GNUC_ #include <linux/sdla_fr.h> /* frame relay firmware API definitions */ - /****** Defines & Macros ****************************************************/ -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ /* Q.922 frame types */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* ??? */ + +/* DLCI configured or not */ +#define DLCI_NOT_CONFIGURED 0x00 +#define DLCI_CONFIG_PENDING 0x01 +#define DLCI_CONFIGURED 0x02 + +/* CIR enabled or not */ +#define CIR_ENABLED 0x00 +#define CIR_DISABLED 0x01 + +/* Interrupt mode for DLCI = 0 */ +#define BUFFER_INTR_MODE 0x00 +#define DLCI_LIST_INTR_MODE 0x01 +/* Transmit Interrupt Status */ +#define DISABLED 0x00 +#define WAITING_TO_BE_ENABLED 0x01 + +/* For handle_IPXWAN() */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + /****** Data Structures *****************************************************/ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of channel-specific data. */ -typedef struct fr_channel { - char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - char state; /* channel state */ +typedef struct fr_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci_configured ; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ + unsigned short pkt_length; /* Packet Length */ + unsigned long router_start_time;/* Router start time in seconds */ + unsigned long tick_counter; /* counter for transmit time out */ + char dev_pending_devtint; /* interface pending dev_tint() */ + char state; /* channel state */ + void* dlci_int_interface; /* pointer to the DLCI Interface */ + unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ - sdla_t *card; /* -> owner */ - struct enet_statistics ifstats; /* interface statistics */ + sdla_t* card; /* -> owner */ + struct enet_statistics ifstats; /* interface statistics */ + + unsigned long if_send_entry; + unsigned long if_send_skb_null; + unsigned long if_send_broadcast; + unsigned long if_send_multicast; + unsigned long if_send_critical_ISR; + unsigned long if_send_critical_non_ISR; + unsigned long if_send_busy; + unsigned long if_send_busy_timeout; + unsigned long if_send_FPIPE_request; + unsigned long if_send_DRVSTATS_request; + unsigned long if_send_wan_disconnected; + unsigned long if_send_dlci_disconnected; + unsigned long if_send_no_bfrs; + unsigned long if_send_adptr_bfrs_full; + unsigned long if_send_bfrs_passed_to_adptr; + + unsigned long rx_intr_no_socket; + unsigned long rx_intr_dev_not_started; + unsigned long rx_intr_FPIPE_request; + unsigned long rx_intr_DRVSTATS_request; + unsigned long rx_intr_bfr_not_passed_to_stack; + unsigned long rx_intr_bfr_passed_to_stack; + + unsigned long UDP_FPIPE_mgmt_kmalloc_err; + unsigned long UDP_FPIPE_mgmt_direction_err; + unsigned long UDP_FPIPE_mgmt_adptr_type_err; + unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK; + unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout; + unsigned long UDP_FPIPE_mgmt_adptr_send_passed; + unsigned long UDP_FPIPE_mgmt_adptr_send_failed; + unsigned long UDP_FPIPE_mgmt_not_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_no_socket; + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed; + unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed; + unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; + unsigned long UDP_DRVSTATS_mgmt_no_socket; + unsigned long router_up_time; } fr_channel_t; -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; } dlci_status_t; +typedef struct dlci_IB_mapping +{ + unsigned short dlci PACKED; + unsigned long addr_value PACKED; +} dlci_IB_mapping_t; + +/* This structure is used for DLCI list Tx interrupt mode. It is used to + enable interrupt bit and set the packet length for transmission + */ +typedef struct fr_dlci_interface +{ + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; + +static unsigned short num_frames; +static unsigned long curr_trace_addr; +static unsigned long start_trace_addr; +static unsigned short available_buffer_space; static char TracingEnabled; -/* variable for checking interrupts within the ISR routine */ -static int int_occur = 0; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* variable for keeping track of number of interrupts generated during + * interrupt test routine + */ +static int Intr_test_counter; + /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); /* WANPIPE-specific entry points */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data); /* Network device interface */ -static int if_init(struct device *dev); -static int if_open(struct device *dev); -static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct device *dev); -static struct enet_statistics *if_stats(struct device *dev); +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (struct sk_buff* skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); /* Interrupt handlers */ -static void fr502_isr(sdla_t * card); -static void fr508_isr(sdla_t * card); -static void fr502_rx_intr(sdla_t * card); -static void fr508_rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -static void spur_intr(sdla_t * card); +static void fr502_isr (sdla_t* card); +static void fr508_isr (sdla_t* card); +static void fr502_rx_intr (sdla_t* card); +static void fr508_rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); +static void spur_intr (sdla_t* card); /* Background polling routines */ -static void wpf_poll(sdla_t * card); +static void wpf_poll (sdla_t* card); /* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t * card, char *str); -static int fr_configure(sdla_t * card, fr_conf_t * conf); -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); -static int fr_comm_enable(sdla_t * card); -static int fr_comm_disable(sdla_t * card); -static int fr_get_err_stats(sdla_t * card); -static int fr_get_stats(sdla_t * card); -static int fr_add_dlci(sdla_t * card, int dlci, int num); -static int fr_activate_dlci(sdla_t * card, int dlci, int num); -static int fr_issue_isf(sdla_t * card, int isf); -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); +static int fr_read_version (sdla_t* card, char* str); +static int fr_configure (sdla_t* card, fr_conf_t *conf); +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci); +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu); +static int fr_comm_enable (sdla_t* card); +static int fr_comm_disable (sdla_t* card); +static int fr_get_err_stats (sdla_t* card); +static int fr_get_stats (sdla_t* card); +static int fr_add_dlci (sdla_t* card, int dlci, int num); +static int fr_activate_dlci (sdla_t* card, int dlci, int num); +static int fr_issue_isf (sdla_t* card, int isf); +static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf); +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf); /* Firmware asynchronous event handlers */ -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); +static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox); +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox); +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox); /* Miscellaneous functions */ -static int update_chan_state(struct device *dev); -static void set_chan_state(struct device *dev, int state); -static struct device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card); -static unsigned int dec_to_uint(unsigned char *str, int len); +static int update_chan_state (struct device* dev); +static void set_chan_state (struct device* dev, int state); +static struct device* find_channel (sdla_t* card, unsigned dlci); +static int is_tx_ready (sdla_t* card, fr_channel_t* chan); +static unsigned int dec_to_uint (unsigned char* str, int len); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); + +static int intr_test( sdla_t* card ); +static void init_chan_statistics( fr_channel_t* chan ); +static void init_global_statistics( sdla_t* card ); +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); + +/* Udp management functions */ +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan); +static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan); +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ); + +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); /****** Public Functions ****************************************************/ @@ -198,22 +347,23 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf)) return -EINVAL; } /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) { - case SFID_FR502: - card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); - card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); - card->isr = &fr502_isr; - break; + switch (card->hw.fwid) + { + case SFID_FR502: + card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); + card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); + card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); + card->isr = &fr502_isr; + break; - case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); - card->isr = &fr508_isr; - break; + case SFID_FR508: + card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); + card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); + card->isr = &fr508_isr; + break; - default: - return -EINVAL; + default: + return -EINVAL; } /* Read firmware version. Note that when adapter initializes, it @@ -243,21 +393,28 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf)) u.cfg.cir_fwd = 16; u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd; u.cfg.options = 0x0081; /* direct Rx, no CIR check */ - switch (conf->u.fr.signalling) { - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; + + switch (conf->u.fr.signalling) + { + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; + break; + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; + break; } - if (conf->station == WANOPT_CPE) { + + if (conf->station == WANOPT_CPE) + { u.cfg.options |= 0x8000; /* auto config DLCI */ - } else { + } + else + { u.cfg.station = 1; /* switch emulation mode */ card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16; card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); } + if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001 ; @@ -279,7 +436,8 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf)) return -EIO ; - if (card->hw.fwid == SFID_FR508) { + if (card->hw.fwid == SFID_FR508) + { fr_buf_info_t *buf_info = (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); @@ -392,6 +550,32 @@ static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf kfree(chan); return err; } + + /* place cir,be,bc and other channel specific information into the + * chan structure + */ + if (conf->cir) + { + chan->cir = max( 1, min( conf->cir, 512 ) ); + chan->cir_status = CIR_ENABLED; + + if (conf->bc) + chan->bc = max( 1, min( conf->bc, 512 ) ); + if (conf->be) + chan->be = max( 0, min( conf->be, 511) ); + + } + else + chan->cir_status = CIR_DISABLED; + + chan->mc = conf->mc; + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + chan->tx_int_status = DISABLED; + + init_chan_statistics( chan ); + /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; @@ -489,9 +673,8 @@ static int if_init(struct device *dev) /* Set transmit buffer queue length */ dev->tx_queue_len = 30; - /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]); + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -503,34 +686,146 @@ static int if_init(struct device *dev) * * Return 0 if O.k. or errno. */ + static int if_open(struct device *dev) { fr_channel_t *chan = dev->priv; sdla_t *card = chan->card; + struct device *dev2; int err = 0; - + fr508_flags_t *flags = card->flags; + struct timeval tv; + if (dev->start) - return -EBUSY /* only one open is allowed */ - ; + return -EBUSY; /* only one open is allowed */ + if (test_and_set_bit(0, (void *) &card->wandev.critical)) return -EAGAIN; - ; - if (!card->open_cnt) { - if ((fr_comm_enable(card)) || - (fr_set_intr_mode(card, 0x03, card->wandev.mtu))) { + + if (!card->open_cnt) + { + Intr_test_counter = 0; + card->intr_mode = INTR_TEST_MODE; + err = intr_test( card ); + + if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) { + printk(KERN_INFO + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); err = -EIO; - goto done; + card->wandev.critical = 0; + return err; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" + ,card->devname, Intr_test_counter); + + /* The following allocates and intializes a circular + * link list of interfaces per card. + */ + + card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); + if (card->devs_struct == NULL) + return -ENOMEM; + card->dev_to_devtint_next = card->devs_struct; + + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + (card->devs_struct)->dev_ptr = dev2; + if(dev2->slave == NULL) + (card->devs_struct)->next = card->dev_to_devtint_next; + else { + (card->devs_struct)->next = kmalloc( + sizeof(load_sharing_t), GFP_KERNEL); + if ((card->devs_struct)->next == NULL) + return -ENOMEM; + card->devs_struct = (card->devs_struct)->next; + } + } + + card->devs_struct = card->dev_to_devtint_next; + + card->intr_mode = BUFFER_INTR_MODE; + + /* + check all the interfaces for the device to see if CIR has + been enabled for any DLCI(s). If so then use the DLCI list + Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode + */ + + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + + if( ((fr_channel_t *)dev2->priv)->cir_status + == CIR_ENABLED) { + card->intr_mode = DLCI_LIST_INTR_MODE; + break; + } + } + + /* + * If you enable comms and then set ints, you get a Tx int as you + * perform the SET_INT_TRIGGERS command. So, we only set int + * triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. + */ + if (card->intr_mode == BUFFER_INTR_MODE) + { + if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) + { + err = -EIO; + card->wandev.critical = 0; + return err; + } + + printk( KERN_INFO + "%s: Global Buffering Tx Interrupt Mode\n" + , card->devname); + + } + else if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) + { + err = -EIO; + card->wandev.critical = 0; + return err; + } + + printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n", + card->devname); + } + + flags->imask &= ~0x02; + + if (fr_comm_enable(card)) + { + err = -EIO; + card->wandev.critical = 0; + return err; + } + wanpipe_set_state(card, WAN_CONNECTED); - if (card->wandev.station == WANOPT_CPE) { + if (card->wandev.station == WANOPT_CPE) + { /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); - } else { /* FR switch: activate DLCI(s) */ - fr_add_dlci(card, - card->u.f.node_dlci, card->u.f.dlci_num); - fr_activate_dlci(card, - card->u.f.node_dlci, card->u.f.dlci_num); + } + else + { /* FR switch: activate DLCI(s) */ + + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + + fr_add_dlci(card, card->u.f.node_dlci[0], card->u.f.dlci_num); + fr_activate_dlci(card, card->u.f.node_dlci, card->u.f.dlci_num); } } dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); @@ -540,7 +835,8 @@ static int if_open(struct device *dev) wanpipe_open(card); update_chan_state(dev); - done: + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; card->wandev.critical = 0; return err; } @@ -636,69 +932,257 @@ static int if_send(struct sk_buff *skb, struct device *dev) sdla_t *card = chan->card; int retry = 0, err; struct device *dev2; + fr508_flags_t* adptr_flags = card->flags; + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + unsigned long host_cpu_flags; + int send_data = 0; + ++chan->if_send_entry; + + if (dev->tbusy) + { + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + */ + + ++chan->if_send_busy; + ++chan->ifstats.collisions; + + if ((jiffies - chan->tick_counter) < (5*HZ)) + return 1; + + printk(KERN_INFO "%s: Transmit timed out\n", chan->name); + + ++chan->if_send_busy_timeout; + + /* unbusy all the interfaces on the card */ + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + dev2->tbusy = 0; + } if (test_and_set_bit(0, (void *) &card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", card->devname); #endif - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } - if (test_and_set_bit(0, (void *) &dev->tbusy)) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s: Tx collision on interface %s!\n", - card->devname, dev->name); -#endif - ++chan->ifstats.collisions; - ++card->wandev.stats.collisions; - - retry = 1; - if (card->wandev.tx_int_enabled) { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - dev2->tbusy = 1; + disable_irq(card->hw.irq); + ++card->irq_dis_if_send_count; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + if (card->wandev.critical == CRITICAL_IN_ISR) + { + ++chan->if_send_critical_ISR; + + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + /* The enable_tx_int flag is set here so that if + * the critical flag is set due to an interrupt + * then we want to enable transmit interrupts + * again. + */ + + card->wandev.enable_tx_int = 1; + + /* Setting this flag to WAITING_TO_BE_ENABLED + * specifies that interrupt bit has to be + * enabled for that particular interface. + * (delayed interrupt) + */ + + chan->tx_int_status = WAITING_TO_BE_ENABLED; + + /* This is used for enabling dynamic calculation + * of CIRs relative to the packet length. + */ + + chan->pkt_length = skb->len; + dev->tbusy = 1; + chan->tick_counter = jiffies; } + else + { + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + chan->tick_counter = jiffies; + } + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 1; } - } else if (card->wandev.state != WAN_CONNECTED) { + + ++chan->if_send_critical_non_ISR; + ++chan->ifstats.tx_dropped; + dev_kfree_skb(skb); + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 0; + } + + card->wandev.critical = 0x21; + + if (card->wandev.state != WAN_CONNECTED) + { + ++chan->if_send_wan_disconnected; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } else if (chan->state != WAN_CONNECTED) { + } + else if (chan->state != WAN_CONNECTED) + { + ++chan->if_send_dlci_disconnected; update_chan_state(dev); ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } else if (!is_tx_ready(card)) { + } + else if (!is_tx_ready(card, chan)) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE ) + { + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = skb->len; + } + dev->tbusy = 1; + chan->tick_counter = jiffies; + + adptr_flags->imask |= 0x02; + + ++ chan->if_send_no_bfrs; retry = 1; - if (card->wandev.tx_int_enabled) { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - dev2->tbusy = 1; + } + else + { + send_data = 1; + /* If it's an IPX packet */ + if( sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) + { + if( card->wandev.enable_IPX ) + { + switch_net_numbers(sendpacket, + card->wandev.network_number, 0); + } + else + { + /* increment some statistic here! */ + send_data = 0; } } - } else { - err = (card->hw.fwid == SFID_FR508) ? - fr508_send(card, chan->dlci, 0, skb->len, skb->data) : - fr502_send(card, chan->dlci, 0, skb->len, skb->data); - if (err) { - ++chan->ifstats.tx_errors; - ++card->wandev.stats.tx_errors; - } else { - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; + + if (send_data) + { + err = (card->hw.fwid == SFID_FR508) ? + fr508_send(card, chan->dlci, 0, skb->len, skb->data) : + fr502_send(card, chan->dlci, 0, skb->len, skb->data); + + if (err) + { + if (card->intr_mode == DLCI_LIST_INTR_MODE) + { + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = skb->len; + } + dev->tbusy = 1; + chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; + retry = 1; + ++ chan->if_send_adptr_bfrs_full; + ++ chan->ifstats.tx_errors; + ++ card->wandev.stats.tx_errors; + } + else + { + ++ chan->if_send_bfrs_passed_to_adptr; + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + } } } - if (!retry) { - dev_kfree_skb(skb, FREE_WRITE); - dev->tbusy = 0; - } + + if (!retry) + dev_kfree_skb(skb); + card->wandev.critical = 0; + save_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); return retry; } +/* + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + * + */ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[14] << 24) + + (sendpacket[15] << 16) + (sendpacket[16] << 8) + + sendpacket[17]); + + if (!incoming) { + if( pnetwork_number == network_number) { + sendpacket[14] = sendpacket[15] = sendpacket[16] = + sendpacket[17] = 0x00; + } + } else { + if( pnetwork_number == 0) { + sendpacket[14] = (unsigned char)(network_number >> 24); + sendpacket[15] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[16] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[17] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[26] << 24) + + (sendpacket[27] << 16) + (sendpacket[28] << 8) + + sendpacket[29]); + + if( !incoming ) { + if( pnetwork_number == network_number) { + sendpacket[26] = sendpacket[27] = sendpacket[28] = + sendpacket[29] = 0x00; + } + } else { + if( pnetwork_number == 0 ) { + sendpacket[26] = (unsigned char)(network_number >> 24); + sendpacket[27] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[28] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[29] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + /*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ -static struct enet_statistics *if_stats(struct device *dev) +static struct net_device_stats *if_stats(struct device *dev) { fr_channel_t *chan = dev->priv; @@ -714,18 +1198,19 @@ static void fr502_isr(sdla_t * card) { fr502_flags_t *flags = card->flags; - switch (flags->iflag) { - case 0x01: /* receive interrupt */ - fr502_rx_intr(card); - break; + switch (flags->iflag) + { + case 0x01: /* receive interrupt */ + fr502_rx_intr(card); + break; - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; + case 0x02: /* transmit interrupt */ + flags->imask &= ~0x02; + tx_intr(card); + break; - default: - spur_intr(card); + default: + spur_intr(card); } flags->iflag = 0; } @@ -737,36 +1222,186 @@ static void fr508_isr(sdla_t * card) { fr508_flags_t *flags = card->flags; fr_buf_ctl_t *bctl; + char *ptr = &flags->iflag; + struct device* dev = card->wandev.dev; + struct device* dev2; + int i; + unsigned long host_cpu_flags; + unsigned disable_tx_intr =1; + fr_channel_t* chan; + fr_dlci_interface_t* dlci_interface; - if (int_occur) { -#ifdef _DEBUG_ - printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n", card->devname); -#endif + /* This flag prevents nesting of interrupts. See sdla_isr() routine + * in sdlamain.c. + */ + card->in_isr = 1; + + ++card->statistics.isr_entry; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + { + printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); + ++card->statistics.isr_already_critical; + card->in_isr = 0; return; } int_occur = 1; + + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + + card->dlci_int_mode_unbusy = 0; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) { - case 0x01: /* receive interrupt */ - fr508_rx_intr(card); - break; + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + fr508_rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); + bctl->flag = 0xA0; + + if (card->intr_mode == DLCI_LIST_INTR_MODE ) + { + /* Find the structure and make it unbusy */ + dev = find_channel( card, flags->dlci); + dev->tbusy = 0; + + /* This is used to perform devtint at the + * end of the isr + */ + card->dlci_int_mode_unbusy = 1; + + /* check to see if any other interfaces are + * busy. If so then do not disable the tx + * interrupts + */ + for (dev2 = card->wandev.dev; dev2; + dev2 = dev2->slave) + { + if ( dev2->tbusy == 1) + { + disable_tx_intr = 0; + break; + } + } + if (disable_tx_intr) + flags->imask &= ~0x02; + + } + else if (card->intr_mode == BUFFER_INTR_MODE) + { + for (dev2 = card->wandev.dev; dev2; + dev2 = dev2->slave) + { + if ( !dev2 || !dev2->start ) + { + ++card->statistics. + tx_intr_dev_not_started; + continue; + } + if(dev2->tbusy) + { + card->buff_int_mode_unbusy = 1; + ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 1; + dev2->tbusy = 0; + } else + ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 0; + } + flags->imask &= ~0x02; + } + break; + + case 0x08: + Intr_test_counter++; + ++card->statistics.isr_intr_test; + break; + + default: + ++card->statistics.isr_spurious; + spur_intr(card); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, flags->iflag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + + break; + } + + card->wandev.critical = CRITICAL_INTR_HANDLED; + if (card->wandev.enable_tx_int) + { + if( card->intr_mode == DLCI_LIST_INTR_MODE ) + { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + chan = dev2->priv; + if ( chan->tx_int_status == + WAITING_TO_BE_ENABLED ) + { + dlci_interface = + chan->dlci_int_interface; + dlci_interface->gen_interrupt |= 0x40; + dlci_interface->packet_length = + chan->pkt_length; + chan->tx_int_status = DISABLED; + } + } + } + card->wandev.enable_tx_int = 0; + flags->imask |= 0x02; + ++card->statistics.isr_enable_tx_int; + } + save_flags(host_cpu_flags); + cli(); + card->in_isr = 0; + card->wandev.critical = 0xD1; + flags->iflag = 0; + card->wandev.critical = 0; + restore_flags(host_cpu_flags); - case 0x02: /* transmit interrupt */ - bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - bctl->flag = 0x90; /* disable further Tx interrupts */ - tx_intr(card); - break; + /* + * Device is now ready to send. The instant this is executed the If_Send + * routine is called. That is why this is put at the bottom of the ISR + * to prevent a endless loop condition caused by repeated Interrupts and + * enable_tx_int flag. + */ - default: - spur_intr(card); + if(card->dlci_int_mode_unbusy) + dev_tint(dev); + + if(card->buff_int_mode_unbusy) + { + for (;;) + { + if (((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1){ + + ((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint=0; + dev_tint((card->devs_struct)->dev_ptr); + } + if ((card->devs_struct)->next == card->dev_to_devtint_next) + break; + card->devs_struct = (card->devs_struct)->next; + } + card->devs_struct = (card->dev_to_devtint_next)->next; + card->dev_to_devtint_next = card->devs_struct; } - int_occur = 0; - flags->iflag = 0; } /*============================================================================ * Receive interrupt handler. */ + static void fr502_rx_intr(sdla_t * card) { fr_mbox_t *mbox = card->rxmb; @@ -787,12 +1422,12 @@ static void fr502_rx_intr(sdla_t * card) /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", card->devname, dlci); - goto rx_done; + sdla_mapmem(&card->hw, FR_MB_VECTOR); } chan = dev->priv; if (!dev->start) { ++chan->ifstats.rx_dropped; - goto rx_done; + sdla_mapmem(&card->hw, FR_MB_VECTOR); } /* Allocate socket buffer */ skb = dev_alloc_skb(len); @@ -800,7 +1435,7 @@ static void fr502_rx_intr(sdla_t * card) printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++chan->ifstats.rx_dropped; - goto rx_done; + sdla_mapmem(&card->hw, FR_MB_VECTOR); } /* Copy data to the socket buffer */ buf = skb_put(skb, len); @@ -812,7 +1447,7 @@ static void fr502_rx_intr(sdla_t * card) buf = skb_pull(skb, 1); /* remove hardware header */ if (!wan_type_trans(skb, dev)) { /* can't decapsulate packet */ - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); ++chan->ifstats.rx_errors; ++card->wandev.stats.rx_errors; } else { @@ -820,7 +1455,6 @@ static void fr502_rx_intr(sdla_t * card) ++chan->ifstats.rx_packets; ++card->wandev.stats.rx_packets; } - rx_done: sdla_mapmem(&card->hw, FR_MB_VECTOR); } @@ -835,68 +1469,133 @@ static void fr508_rx_intr(sdla_t * card) fr_channel_t *chan; unsigned dlci, len, offs; void *buf; + unsigned rx_count = 0; + fr508_flags_t* flags = card->flags; + char *ptr = &flags->iflag; + int i, err; if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", card->devname, (unsigned) frbuf); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + + ++card->statistics.rx_intr_corrupt_rx_bfr; return; } - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (dev == NULL) { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci); - goto rx_done; - } - chan = dev->priv; - if (!dev->start) { - ++chan->ifstats.rx_dropped; - goto rx_done; - } - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++chan->ifstats.rx_dropped; - goto rx_done; - } - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; + do + { + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + chan = dev->priv; + + if (dev == NULL) + { + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" + , card->devname, dlci); + ++card->statistics.rx_intr_on_orphaned_DLCI; + } + else + { + skb = dev_alloc_skb(len); + if (!dev->start || (skb == NULL)) + { + ++chan->ifstats.rx_dropped; + if(dev->start) + { + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + ++chan->rx_intr_no_socket; + + } + else + ++ chan->rx_intr_dev_not_started; + } + else + { + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) + { + unsigned tmp = card->u.f.rx_top - + offs + 1; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); +#ifdef CONFIG_SANGOMA_MANAGER + if (management_check(skb,card)) + { + ++chan->rx_intr_DRVSTATS_request; + } + else +#endif + if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number)) + { + if (card->wandev.enable_IPX) + { + fr508_send(card, dlci, 0, skb->len, skb->data); + } else { + /* increment some statistic! */ + } + } + else + { + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wan_type_trans(skb, dev)) + { + /* can't decapsulate packet */ + dev_kfree_skb(skb); + ++chan->rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + } + else + { + netif_rx(skb); + ++ chan->rx_intr_bfr_passed_to_stack; + ++ chan->ifstats.rx_packets; + ++ card->wandev.stats.rx_packets; + } + } + } + } + + /* Release buffer element and calculate a pointer to the next + one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + + if ((void*)frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base; + + /* The loop put in is temporary, that is why the break is + * placed here. (?????) + */ + break; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - /* Decapsulate packet and pass it up the protocol stack */ - skb->dev = dev; - buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wan_type_trans(skb, dev)) { - /* can't decapsulate packet */ - dev_kfree_skb(skb, FREE_READ); - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - } else { - netif_rx(skb); - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - } - rx_done: - /* Release buffer element and calculate a pointer to the next one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void *) frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base - ; + frbuf = card->rxmb; + + } while (frbuf->flag && ((++ rx_count) < 4)); } /*============================================================================ @@ -908,20 +1607,26 @@ static void fr508_rx_intr(sdla_t * card) static void tx_intr(sdla_t * card) { struct device *dev = card->wandev.dev; - int v = 0; - for (; dev; dev = dev->slave) { - if (!dev || !dev->start) - continue; - v += dev->tbusy; + if (card->intr_mode == BUFFER_INTR_MODE) + { + for (; dev; dev = dev->slave) + { + if ( !dev || !dev->start ) + { + ++ card->statistics.tx_intr_dev_not_started; + continue; + } + + dev->tbusy = 0; + dev_tint(dev); + } + } + else + { dev->tbusy = 0; + dev_tint(dev); } - card->wandev.tx_int_enabled = 0; - if (v) - mark_bh(NET_BH); -/* - printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); - */ } /*============================================================================ @@ -935,6 +1640,105 @@ static void spur_intr(sdla_t * card) printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } +/* + Return 0 for non-IPXWAN packet + 1 for IPXWAN packet or IPX is not enabled! + +*/ + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) +{ + int i; + + if( sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) { + + if(!enable_IPX) { + return 1; + } + } else { + return 0; + } + + if( sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) + { + if( sendpacket[10] == 0x02 && + sendpacket[42] == 0x00) + { + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + for(i = 49; sendpacket[i] == 0x00; i += 5) + { + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + sendpacket[42] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[42] == 0x02 ) + { + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + sendpacket[42] = 0x03; + + sendpacket[59] = 'F'; + sendpacket[60] = 'P'; + sendpacket[61] = 'I'; + sendpacket[62] = 'P'; + sendpacket[63] = 'E'; + sendpacket[64] = '-'; + sendpacket[65] = CVHexToAscii(network_number >> 28); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); + for(i = 73; i < 107; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + sendpacket[43] = (unsigned char)(network_number >> 24); + sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } + + switch_net_numbers(sendpacket, network_number ,1); + return 0; +} + + /****** Background Polling Routines ****************************************/ /*============================================================================ @@ -948,18 +1752,40 @@ static void spur_intr(sdla_t * card) * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ + static void wpf_poll(sdla_t * card) { - static unsigned long last_poll; - fr502_flags_t *flags; + fr508_flags_t *flags; + unsigned long host_cpu_flags; - if ((jiffies - last_poll) < HZ) - return - ; + ++card->statistics.poll_entry; + + if (((jiffies - card->state_tick) < HZ) || + (card->intr_mode == INTR_TEST_MODE)) + return; + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (test_and_set_bit(0, (void *)&card->wandev.critical)) + { + ++ card->statistics.poll_already_critical; + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && + (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + return; + } + + card->wandev.critical = 0x11; + + ++ card->statistics.poll_processed; - flags = card->flags; if (flags->event) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int err; memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); @@ -968,9 +1794,19 @@ static void wpf_poll(sdla_t * card) if (err) fr_event(card, err, mbox); } - last_poll = jiffies; + + card->wandev.critical = 0; + + save_flags(host_cpu_flags); + cli(); + if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + + card->state_tick = jiffies; } + /****** Frame Relay Firmware-Specific Functions *****************************/ /*============================================================================ @@ -1005,17 +1841,17 @@ static int fr_configure(sdla_t * card, fr_conf_t * conf) { fr_mbox_t *mbox = card->mbox; int retry = MAX_CMD_RETRY; - int dlci = card->u.f.node_dlci; int dlci_num = card->u.f.dlci_num; int err, i; do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_conf_t)); - if (dlci_num) - for (i = 0; i < dlci_num; ++i) - ((fr_conf_t *) mbox->data)->dlci[i] = dlci + i - ; + + if (dlci_num) for (i = 0; i < dlci_num; ++i) + ((fr_conf_t*)mbox->data)->dlci[i] = + card->u.f.node_dlci[i]; + mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = sizeof(fr_conf_t) + dlci_num * sizeof(short); @@ -1026,6 +1862,30 @@ static int fr_configure(sdla_t * card, fr_conf_t * conf) } /*============================================================================ + * Set DLCI configuration. + */ +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); + mbox->cmd.dlci = (unsigned short) dlci; + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.length = 0x0E; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + } while (err && retry--); + + return err; +} + +/*============================================================================ * Set interrupt mode. */ static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) @@ -1112,12 +1972,12 @@ static int fr_get_err_stats(sdla_t * card) while (err && retry-- && fr_event(card, err, mbox)); if (!err) { - fr_comm_stat_t *stats = (void *) mbox->data; + fr_comm_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; card->wandev.stats.tx_aborted_errors = stats->tx_aborts; } return err; @@ -1153,6 +2013,7 @@ static int fr_get_stats(sdla_t * card) /*============================================================================ * Add DLCI(s) (Access Node only!). */ + static int fr_add_dlci(sdla_t * card, int dlci, int num) { fr_mbox_t *mbox = card->mbox; @@ -1164,8 +2025,8 @@ static int fr_add_dlci(sdla_t * card, int dlci, int num) memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); for (i = 0; i < num; ++i) - dlci_list[i] = dlci + i - ; + dlci_list[i] = card->u.f.node_dlci[i]; + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ADD_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1188,8 +2049,8 @@ static int fr_activate_dlci(sdla_t * card, int dlci, int num) memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); for (i = 0; i < num; ++i) - dlci_list[i] = dlci + i - ; + dlci_list[i] = card->u.f.node_dlci[i]; + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ACTIVATE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1262,13 +2123,8 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) if (!err) { fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - FR_MB_VECTOR + card->hw.dpmbase); - unsigned long flags; - - save_flags(flags); - cli(); sdla_poke(&card->hw, frbuf->offset, buf, len); frbuf->flag = 0x01; - restore_flags(flags); } return err; } @@ -1284,33 +2140,51 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) */ static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) { - switch (event) { - case FRRES_MODEM_FAILURE: - return fr_modem_failure(card, mbox); + fr508_flags_t* flags = card->flags; + char *ptr = &flags->iflag; + int i; - case FRRES_CHANNEL_DOWN: - wanpipe_set_state(card, WAN_DISCONNECTED); - return 1; + switch (event) + { + case FRRES_MODEM_FAILURE: + return fr_modem_failure(card, mbox); - case FRRES_CHANNEL_UP: - wanpipe_set_state(card, WAN_CONNECTED); - return 1; + case FRRES_CHANNEL_DOWN: + wanpipe_set_state(card, WAN_DISCONNECTED); + return 1; - case FRRES_DLCI_CHANGE: - return fr_dlci_change(card, mbox); + case FRRES_CHANNEL_UP: + wanpipe_set_state(card, WAN_CONNECTED); + return 1; - case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname); - return 1; + case FRRES_DLCI_CHANGE: + return fr_dlci_change(card, mbox); - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - break; + case FRRES_DLCI_MISMATCH: + printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname); + return 1; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, mbox->cmd.command, event); + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, mbox->cmd.command); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); + break; + + case FRRES_DLCI_INACTIVE: + printk(KERN_ERR "%s: DLCI %u is inactive!\n", + card->devname, mbox->cmd.dlci); + break; + + case FRRES_CIR_OVERFLOW: + break; + case FRRES_BUFFER_OVERFLOW: + break; + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, mbox->cmd.command, event); } return 0; } @@ -1324,10 +2198,11 @@ static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) { printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", card->devname, mbox->data[0]); - switch (mbox->cmd.command) { - case FR_WRITE: - case FR_READ: - return 0; + switch (mbox->cmd.command) + { + case FR_WRITE: + case FR_READ: + return 0; } return 1; } @@ -1341,25 +2216,91 @@ static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox) { dlci_status_t *status = (void *) mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); - + fr_dlc_conf_t cfg; + fr_channel_t *chan; + struct device* dev2; + for (; cnt; --cnt, ++status) { unsigned short dlci = status->dlci; struct device *dev = find_channel(card, dlci); - if (status->state & 0x01) { - printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); - if (dev && dev->start) - set_chan_state(dev, WAN_DISCONNECTED); - } else if (status->state & 0x02) { - printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci); - if (dev && dev->start) - set_chan_state(dev, WAN_CONNECTED); + if (dev == NULL) + { + printk(KERN_INFO "%s: CPE contains unconfigured DLCI= %d\n", + card->devname, dlci); + } + else + { + if (status->state & 0x01) + { + printk(KERN_INFO + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + if (dev && dev->start) + set_chan_state(dev, WAN_DISCONNECTED); + } + else if (status->state & 0x02) + { + printk(KERN_INFO + "%s: DLCI %u becomes active!\n", + card->devname, dlci); + chan = dev->priv; + /* This flag is used for configuring specific + DLCI(s) when they become active. + */ + chan->dlci_configured = DLCI_CONFIG_PENDING; + + if (dev && dev->start) + set_chan_state(dev, WAN_CONNECTED); + } } } + + for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave) + { + chan = dev2->priv; + + if (chan->dlci_configured == DLCI_CONFIG_PENDING) + { + memset(&cfg, 0, sizeof(cfg)); + + if ( chan->cir_status == CIR_DISABLED) + { + cfg.cir_fwd = cfg.cir_bwd = 16; + cfg.bc_fwd = cfg.bc_bwd = 16; + cfg.conf_flags = 0x0001; + printk(KERN_INFO "%s: CIR Disabled for %s\n", + card->devname, chan->name); + } + else if (chan->cir_status == CIR_ENABLED) + { + cfg.cir_fwd = cfg.cir_bwd = chan->cir; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.conf_flags = 0x0000; + printk(KERN_INFO "%s: CIR Enabled for %s\n", + card->devname, chan->name); + + } + + if (fr_dlci_configure( card, &cfg , chan->dlci)) + { + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; + } + + chan->dlci_configured = DLCI_CONFIGURED; + + /* + * Read the interface byte mapping into the channel + * structure. + */ + if (card->intr_mode == DLCI_LIST_INTR_MODE) + read_DLCI_IB_mapping( card, chan ); + } + } return 1; } @@ -1375,6 +2316,7 @@ static int update_chan_state(struct device *dev) fr_mbox_t *mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + int dlci_found = 0; do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); @@ -1387,12 +2329,19 @@ static int update_chan_state(struct device *dev) unsigned short *list = (void *) mbox->data; int cnt = mbox->cmd.length / sizeof(short); - for (; cnt; --cnt, ++list) { - if (*list == chan->dlci) { + for (; cnt; --cnt, ++list) + { + if (*list == chan->dlci) + { + dlci_found = 1; set_chan_state(dev, WAN_CONNECTED); break; } } + + if(!dlci_found) + printk(KERN_INFO "%s: DLCI %u is inactive\n", + card->devname, chan->dlci); } return err; } @@ -1408,22 +2357,25 @@ static void set_chan_state(struct device *dev, int state) save_flags(flags); cli(); - if (chan->state != state) { - switch (state) { - case WAN_CONNECTED: - printk(KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); - break; - - case WAN_CONNECTING: - printk(KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); - break; - case WAN_DISCONNECTED: - printk(KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - break; + if (chan->state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk(KERN_INFO "%s: interface %s connected!\n" + , card->devname, dev->name); + break; + case WAN_CONNECTING: + printk(KERN_INFO + "%s: interface %s connecting...\n", + card->devname, dev->name); + break; + case WAN_DISCONNECTED: + printk (KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); + break; } chan->state = state; } @@ -1452,20 +2404,19 @@ static struct device *find_channel(sdla_t * card, unsigned dlci) * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ + static int is_tx_ready(sdla_t * card) { - if (card->hw.fwid == SFID_FR508) { - fr508_flags_t *flags = card->flags; + if (card->hw.fwid == SFID_FR508) + { unsigned char sb = inb(card->hw.port); if (sb & 0x02) return 1; - flags->imask |= 0x02; - card->wandev.tx_int_enabled = 1; } else { - fr502_flags_t *flags = card->flags; + fr502_flags_t* flags = card->flags; - if (flags->tx_ready) + if (flags->tx_ready) return 1; flags->imask |= 0x02; } @@ -1487,4 +2438,110 @@ static unsigned int dec_to_uint(unsigned char *str, int len) return val; } +/*============================================================================== + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ + * TEST_COUNTER times. + */ +static int intr_test( sdla_t* card ) +{ + fr_mbox_t* mb = card->mbox; + int err,i; + + /* + * The critical flag is unset here because we want to get into the + * ISR without the flag already set. The If_open sets the flag. + */ + + card->wandev.critical = 0; + + err = fr_set_intr_mode( card, 0x08, card->wandev.mtu ); + + if (err == CMD_OK) + { + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) + { + /* Run command READ_CODE_VERSION */ + memset(&mb->cmd, 0, sizeof(fr_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = 0x40; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + fr_event(card, err, mb); + } + } + else + return err; + + err = fr_set_intr_mode( card, 0, card->wandev.mtu ); + + if( err != CMD_OK ) + return err; + + card->wandev.critical = 1; + return 0; +} + +/*============================================================================== + * Initializes the Statistics values in the Sdla_t structure. + */ + +void init_global_statistics( sdla_t* card ) +{ + /* Intialize global statistics for a card */ + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.rx_intr_on_orphaned_DLCI = 0; + card->statistics.tx_intr_dev_not_started = 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; +} + +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t* result; + int err, counter, found; + + do { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + } while (err && retry-- && fr_event(card, err, mbox)); + + if( mbox->cmd.result != 0) + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", + chan->name); + + counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); + result = (void *)mbox->data; + + found = 0; + for (; counter; --counter, ++result) { + if ( result->dlci == chan->dlci ) { + printk( KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" + ,card->devname,result->dlci, result->addr_value + ,chan->name); + chan->IB_addr = result->addr_value; + chan->dlci_int_interface = (void*)(card->hw.dpmbase + + ( chan->IB_addr & 0x00001FFF)); + found = 1; + break; + } + } + if (!found) + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); +} + /****** End *****************************************************************/ |