diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-07-20 14:56:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-07-20 14:56:40 +0000 |
commit | e308faf24f68e262d92d294a01ddca7a17e76762 (patch) | |
tree | 22c47cb315811834861f013067878ff664e95abd /drivers/net/sdla_fr.c | |
parent | 30c6397ce63178fcb3e7963ac247f0a03132aca9 (diff) |
Sync with Linux 2.1.46.
Diffstat (limited to 'drivers/net/sdla_fr.c')
-rw-r--r-- | drivers/net/sdla_fr.c | 339 |
1 files changed, 272 insertions, 67 deletions
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c index d2dc0eb90..95f1ae739 100644 --- a/drivers/net/sdla_fr.c +++ b/drivers/net/sdla_fr.c @@ -10,6 +10,49 @@ * 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). +* +* 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) +* 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. +* The Fix checks to see if Transmit interrupts +* are disabled then do not make dev->tbusy = 1 +* Introduced a global variable: int_occur and +* added tx_int_enabled in the wan_device +* structure. +* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple +* boards. +* +* Apr 25, 1997 Farhan Thawar o added UDP Management stuff +* o fixed bug in if_send() and tx_intr() to +* sleep and wakeup all devices +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o fixed (+1) bug in fr508_rx_intr() +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* o added tx_intr() routine +* 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 +* mode * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -22,12 +65,13 @@ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ #include <linux/malloc.h> /* kmalloc(), kfree() */ -#include <linux/router.h> /* WAN router definitions */ +#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> #define _GNUC_ #include <linux/sdla_fr.h> /* frame relay firmware API definitions */ @@ -67,6 +111,9 @@ typedef struct dlci_status unsigned char state PACKED; } dlci_status_t; +static char TracingEnabled; +/* variable for checking interrupts within the ISR routine */ +static int int_occur = 0; /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ @@ -75,14 +122,16 @@ 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); + /* 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 (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb); +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); @@ -103,6 +152,8 @@ 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); @@ -120,7 +171,6 @@ 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 unsigned int hex_to_uint (unsigned char* str, int len); /****** Public Functions ****************************************************/ @@ -198,7 +248,7 @@ __initfunc(int wpf_init (sdla_t* card, wandev_conf_t* conf)) u.cfg.n392 = 3; u.cfg.n393 = 4; u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = max(min(u.cfg.kbps, 512), 1); + 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) @@ -214,7 +264,7 @@ __initfunc(int wpf_init (sdla_t* card, wandev_conf_t* conf)) { 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 = max(min(conf->u.fr.dlci_num, 1), 100); + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); } if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001 @@ -270,11 +320,14 @@ __initfunc(int wpf_init (sdla_t* card, wandev_conf_t* conf)) card->wandev.clocking = conf->clocking; card->wandev.station = conf->station; card->poll = &wpf_poll; + card->exec = &wpf_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; card->wandev.state = WAN_DISCONNECTED; - return 0; + card->wandev.udp_port = conf->udp_port; + TracingEnabled = '0'; + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -284,9 +337,22 @@ __initfunc(int wpf_init (sdla_t* card, wandev_conf_t* conf)) */ static int update (wan_device_t* wandev) { -/* - sdla_t* card = wandev->private; -*/ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT + ; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV + ; + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN + ; + card = wandev->private; + fr_get_err_stats(card); + fr_get_stats(card); + wandev->critical = 0; return 0; } @@ -377,6 +443,43 @@ static int del_if (wan_device_t* wandev, struct device* dev) return 0; } +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, len; + fr_cmd_t cmd; + + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + if (cmd.length) + if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) + return -EFAULT; + if (sdla_exec(mbox)) + err = mbox->cmd.result; + else + return -EIO; + } + while (err && retry-- && fr_event(card, err, mbox)); + + /* return result */ + if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) + return -EFAULT; + return 0; +} + /****** Network Device Interface ********************************************/ /*============================================================================ @@ -416,6 +519,9 @@ static int if_init (struct device* dev) dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; + /* 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]) @@ -451,12 +557,14 @@ static int if_open (struct device* dev) err = -EIO; goto done; } + wanpipe_set_state(card, WAN_CONNECTED); + if (card->wandev.station == WANOPT_CPE) { /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); } - else /* Switch: activate DLCI(s) */ + else /* FR switch: activate DLCI(s) */ { fr_add_dlci(card, card->u.f.node_dlci, card->u.f.dlci_num) @@ -465,7 +573,6 @@ static int if_open (struct device* dev) card->u.f.node_dlci, card->u.f.dlci_num) ; } - wanpipe_set_state(card, WAN_CONNECTED); } dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); dev->interrupt = 0; @@ -538,14 +645,13 @@ static int if_header (struct sk_buff* skb, struct device* dev, * Return: 1 physical address resolved. * 0 physical address not resolved */ -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - fr_channel_t* chan = dev->priv; + fr_channel_t* chan = skb->dev->priv; sdla_t* card = chan->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name) + card->devname, skb->dev->name) ; return 1; } @@ -570,10 +676,11 @@ static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, */ static int if_send (struct sk_buff* skb, struct device* dev) { - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int retry = 0; - + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + int retry=0, err; + struct device *dev2; + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ @@ -581,7 +688,8 @@ static int if_send (struct sk_buff* skb, struct device* dev) card->devname) ; #endif - return 1; + dev_kfree_skb(skb, FREE_WRITE); + return 0; } if (test_and_set_bit(0, (void*)&dev->tbusy)) @@ -592,23 +700,55 @@ static int if_send (struct sk_buff* skb, struct device* dev) ; #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; + } + } + } + else if (card->wandev.state != WAN_CONNECTED) + { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + else if (chan->state != WAN_CONNECTED) + { + update_chan_state(dev); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + else if (!is_tx_ready(card)) + { + retry = 1; + if(card->wandev.tx_int_enabled) + { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + dev2->tbusy = 1; + } + } } - else if ((card->wandev.state != WAN_CONNECTED) || - (chan->state != WAN_CONNECTED)) - ++chan->ifstats.tx_dropped - ; - else if (!is_tx_ready(card)) - retry = 1 - ; else { - int err = (card->hw.fwid == SFID_FR508) ? + 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; - else ++chan->ifstats.tx_packets; + if (err) + { + ++chan->ifstats.tx_errors; + ++card->wandev.stats.tx_errors; + } + else + { + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + } } if (!retry) { @@ -619,6 +759,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) return retry; } + /*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. @@ -663,7 +804,14 @@ static void fr508_isr (sdla_t* card) { fr508_flags_t* flags = card->flags; fr_buf_ctl_t* bctl; - + + if(int_occur){ +#ifdef _DEBUG_ + printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n",card->devname); +#endif + return; + } + int_occur=1; switch (flags->iflag) { case 0x01: /* receive interrupt */ @@ -681,6 +829,7 @@ static void fr508_isr (sdla_t* card) default: spur_intr(card); } + int_occur = 0; flags->iflag = 0; } @@ -690,13 +839,14 @@ static void fr508_isr (sdla_t* card) static void fr502_rx_intr (sdla_t* card) { fr_mbox_t* mbox = card->rxmb; - struct sk_buff* skb; - struct device* dev; - fr_channel_t* chan; + struct sk_buff *skb; + struct device *dev; + fr_channel_t *chan; unsigned dlci, len; void* buf; - + sdla_mapmem(&card->hw, FR502_RX_VECTOR); + dlci = mbox->cmd.dlci; len = mbox->cmd.length; @@ -741,13 +891,14 @@ static void fr502_rx_intr (sdla_t* card) /* 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: sdla_mapmem(&card->hw, FR_MB_VECTOR); } @@ -763,7 +914,7 @@ static void fr508_rx_intr (sdla_t* card) fr_channel_t* chan; unsigned dlci, len, offs; void* buf; - + if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", @@ -804,9 +955,9 @@ static void fr508_rx_intr (sdla_t* card) } /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top) + if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs; + unsigned tmp = card->u.f.rx_top - offs + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, offs, buf, tmp); @@ -814,8 +965,7 @@ static void fr508_rx_intr (sdla_t* card) len -= tmp; } buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, 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 */ @@ -824,13 +974,14 @@ static void fr508_rx_intr (sdla_t* card) /* 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; @@ -848,7 +999,17 @@ rx_done: */ static void tx_intr (sdla_t* card) { + struct device* dev = card->wandev.dev; + + for (; dev; dev = dev->slave) { + if( !dev || !dev->start ) continue; + dev->tbusy = 0; + dev_tint(dev); + } + card->wandev.tx_int_enabled = 0; +/* printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); +*/ } /*============================================================================ @@ -877,8 +1038,14 @@ static void spur_intr (sdla_t* card) */ static void wpf_poll (sdla_t* card) { - fr502_flags_t* flags = card->flags; + static unsigned long last_poll; + fr502_flags_t* flags; + if ((jiffies - last_poll) < HZ) + return + ; + + flags = card->flags; if (flags->event) { fr_mbox_t* mbox = card->mbox; @@ -889,6 +1056,7 @@ static void wpf_poll (sdla_t* card) err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; if (err) fr_event(card, err, mbox); } + last_poll = jiffies; } /****** Frame Relay Firmware-Specific Functions *****************************/ @@ -1025,6 +1193,65 @@ static int fr_comm_disable (sdla_t* card) } /*============================================================================ + * Get communications error statistics. + */ +static int fr_get_err_stats (sdla_t* card) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_ERROR_STATS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + 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.tx_aborted_errors = stats->tx_aborts; + } + return err; +} + +/*============================================================================ + * Get statistics. + */ +static int fr_get_stats (sdla_t* card) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATISTICS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_link_stat_t* stats = (void*)mbox->data; + + card->wandev.stats.rx_frame_errors = stats->rx_bad_format; + card->wandev.stats.rx_dropped = + stats->rx_dropped + stats->rx_dropped2 + ; + } + return err; +} + +/*============================================================================ * Add DLCI(s) (Access Node only!). */ static int fr_add_dlci (sdla_t* card, int dlci, int num) @@ -1363,6 +1590,7 @@ static int is_tx_ready (sdla_t* card) if (sb & 0x02) return 1; flags->imask |= 0x02; + card->wandev.tx_int_enabled = 1; } else { @@ -1389,27 +1617,4 @@ static unsigned int dec_to_uint (unsigned char* str, int len) return val; } -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. - */ -static unsigned int hex_to_uint (unsigned char* str, int len) -{ - unsigned val, ch; - - if (!len) len = strlen(str); - for (val = 0; len; ++str, --len) - { - ch = *str; - if (is_digit(ch)) - val = (val << 4) + (ch - (unsigned)'0') - ; - else if (is_hex_digit(ch)) - val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10) - ; - else break; - } - return val; -} - /****** End *****************************************************************/ |