diff options
| author | Krzysztof Halasa <khc@pm.waw.pl> | 2003-07-25 01:24:04 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-07-25 01:24:04 -0700 |
| commit | 314635e1132bddd57d293550f34dca8f3c19d20a (patch) | |
| tree | 14ce835b4533cc6b6df7bd2da135c22fd4767de3 | |
| parent | 9c8b55a99e9e9ecfb98d674adabfe2c375cf3c61 (diff) | |
[PATCH] HDLC update
This updates generic HDLC from 1.14 to 1.15.
- fix a kernel panic caused by a recent change to unregister_netdevice()
(struct net_device * can't be kfreed before rtnl_unlock())
- adds carrier_* support - hw drivers report DCD status and higher level
protocols use that info, and do netif_carrier_{on,off}() according to
DCD and (Cisco and FR) link management status.
- moves Frame-Relay constants etc. from include/linux/hdlc.h to hdlc_fr.c.
They are internal FR things and are not needed in the global header.
- protocol hooks are slighty changed to allow zeroing (memset).
- removes CONFIG_HDLC_DEBUG_* variables. Users tend to make very wrong
use of them. Now setting them requires changing .c #define. Anyway they
are development-only things.
- misc style corrections etc.
| -rw-r--r-- | drivers/net/wan/Kconfig | 31 | ||||
| -rw-r--r-- | drivers/net/wan/c101.c | 64 | ||||
| -rw-r--r-- | drivers/net/wan/hd64570.h | 3 | ||||
| -rw-r--r-- | drivers/net/wan/hd6457x.c | 90 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_cisco.c | 29 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_fr.c | 287 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_generic.c | 119 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_ppp.c | 11 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_raw.c | 9 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_raw_eth.c | 9 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_x25.c | 12 | ||||
| -rw-r--r-- | drivers/net/wan/n2.c | 13 | ||||
| -rw-r--r-- | include/linux/hdlc.h | 151 |
13 files changed, 515 insertions, 313 deletions
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 77f5ace58eaa..929ca4813194 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -401,37 +401,6 @@ config FARSYNC should add "alias hdlcX farsync" to /etc/modules.conf for each interface, where X is 0, 1, 2, ... -config HDLC_DEBUG_PKT - bool "Debug received/transmitted packets" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_HARD_HEADER - bool "Debug hard_header routines" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_ECN - bool "Debug FECN/BECN conditions" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_RINGS - bool "Debug RX/TX packet rings" - depends on HDLC - help - If you answer Y here you will be able to get a diagnostic dump of - port's TX and RX packet rings, using "sethdlc hdlcX private" - command. It does not affect normal operations. - - If unsure, say Y here. - config DLCI tristate "Frame relay DLCI support" depends on WAN diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 0854ade71ca9..f47cd918ea56 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -14,7 +14,6 @@ * Moxa C101 User's Manual */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -31,9 +30,12 @@ #include "hd64570.h" -static const char* version = "Moxa C101 driver version: 1.14"; +static const char* version = "Moxa C101 driver version: 1.15"; static const char* devname = "C101"; +#undef DEBUG_PKT +#define DEBUG_RINGS + #define C101_PAGE 0x1D00 #define C101_DTR 0x1E00 #define C101_SCA 0x1F00 @@ -95,7 +97,8 @@ static card_t **new_card = &first_card; #define winsize(card) (C101_WINDOW_SIZE) #define win0base(card) ((card)->win0base) #define winbase(card) ((card)->win0base + 0x2000) -#define get_port(card, port) ((port) == 0 ? (card) : NULL) +#define get_port(card, port) (card) +static void sca_msci_intr(port_t *port); static inline u8 sca_get_page(card_t *card) @@ -116,9 +119,30 @@ static inline void openwin(card_t *card, u8 page) #include "hd6457x.c" +static void sca_msci_intr(port_t *port) +{ + card_t* card = port_to_card(port); + u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */ + + /* Reset MSCI TX underrun status bit */ + sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card); + + if (stat & ST1_UDRN) { + port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ + port->hdlc.stats.tx_fifo_errors++; + } + + /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ + sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, card); + + if (stat & ST1_CDCD) + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), + &port->hdlc); +} + + static void c101_set_iface(port_t *port) { - u8 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; @@ -145,8 +169,8 @@ static void c101_set_iface(port_t *port) port->rxs = rxs; port->txs = txs; - sca_out(rxs, msci + RXS, port); - sca_out(txs, msci + TXS, port); + sca_out(rxs, MSCI1_OFFSET + RXS, port); + sca_out(txs, MSCI1_OFFSET + TXS, port); sca_set_port(port); } @@ -164,6 +188,17 @@ static int c101_open(struct net_device *dev) writeb(1, port->win0base + C101_DTR); sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ sca_open(hdlc); + /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ + sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); + sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); + + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), hdlc); + printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port)); + + /* enable MSCI1 CDCD interrupt */ + sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port); + sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port); + sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */ c101_set_iface(port); return 0; } @@ -189,9 +224,14 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(hdlc); + printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", + sca_in(MSCI1_OFFSET + ST0, port), + sca_in(MSCI1_OFFSET + ST1, port), + sca_in(MSCI1_OFFSET + ST2, port), + sca_in(MSCI1_OFFSET + ST3, port)); return 0; } #endif @@ -298,9 +338,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) card->tx_ring_buffers = TX_RING_BUFFERS; card->rx_ring_buffers = RX_RING_BUFFERS; - printk(KERN_DEBUG "c101: using %u TX + %u RX packets rings\n", - card->tx_ring_buffers, card->rx_ring_buffers); - card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ readb(card->win0base + C101_PAGE); /* Resets SCA? */ @@ -333,6 +370,13 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) } sca_init_sync_port(card); /* Set up C101 memory */ + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), + &card->hdlc); + + printk(KERN_INFO "%s: Moxa C101 on IRQ%u," + " using %u TX + %u RX packets rings\n", + hdlc_to_name(&card->hdlc), card->irq, + card->tx_ring_buffers, card->rx_ring_buffers); *new_card = card; new_card = &card->next_card; diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h index cd3fcf86d6cf..3839662ff201 100644 --- a/drivers/net/wan/hd64570.h +++ b/drivers/net/wan/hd64570.h @@ -217,12 +217,15 @@ typedef struct { #define ST0_RXRDY 0x01 /* RX ready */ #define ST1_UDRN 0x80 /* MSCI TX underrun */ +#define ST1_CDCD 0x04 /* DCD level changed */ #define ST3_CTS 0x08 /* modem input - /CTS */ #define ST3_DCD 0x04 /* modem input - /DCD */ #define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */ +#define IE0_RXINTA 0x40 /* RX INT A MSCI interrupt enable */ #define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */ +#define IE1_CDCD 0x04 /* DCD level changed */ #define DCR_ABORT 0x01 /* Software abort command */ #define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */ diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c index f85ae029f419..561216c1a4eb 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd6457x.c @@ -35,7 +35,6 @@ #include <linux/interrupt.h> #include <linux/in.h> #include <linux/string.h> -#include <linux/timer.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/ioport.h> @@ -244,10 +243,14 @@ static void sca_init_sync_port(port_t *port) sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card); } } + + hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD), + &port->hdlc); } +#ifdef NEED_SCA_MSCI_INTR /* MSCI interrupt service */ static inline void sca_msci_intr(port_t *port) { @@ -255,17 +258,19 @@ static inline void sca_msci_intr(port_t *port) card_t* card = port_to_card(port); u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */ - /* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n", - stat, sca_in(ILAR, card)); */ - - /* Reset MSCI TX underrun status bit */ - sca_out(stat & ST1_UDRN, msci + ST1, card); + /* Reset MSCI TX underrun and CDCD status bit */ + sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card); if (stat & ST1_UDRN) { port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ port->hdlc.stats.tx_fifo_errors++; } + + if (stat & ST1_CDCD) + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), + &port->hdlc); } +#endif @@ -307,7 +312,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin) openwin(card, 0); #endif skb_put(skb, len); -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); debug_frame(skb); #endif @@ -560,25 +565,28 @@ static void sca_open(hdlc_device *hdlc) #endif /* We're using the following interrupts: - - TXINT (DMAC completed all transmisions, underflow or CTS change) + - TXINT (DMAC completed all transmisions, underrun or DCD change) - all DMA interrupts */ + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc); + #ifdef __HD64570_H - /* MSCI TX INT IRQ enable */ - sca_out(IE0_TXINT, msci + IE0, card); - sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */ - sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08), - IER0, card); - /* DMA IRQ enable */ + /* MSCI TX INT and RX INT A IRQ enable */ + sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card); + sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card); + sca_out(sca_in(IER0, card) | (phy_node(port) ? 0xC0 : 0x0C), + IER0, card); /* TXINT and RXINT */ + /* enable DMA IRQ */ sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), IER1, card); #else - /* MSCI TX INT IRQ enable */ - sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card); + /* MSCI TXINT and RXINTA interrupt enable */ + sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0, + card); /* DMA & MSCI IRQ enable */ - sca_outl(sca_in(IER0, card) | - (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card); + sca_outl(sca_inl(IER0, card) | + (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card); #endif #ifdef __HD64570_H @@ -600,10 +608,23 @@ static void sca_open(hdlc_device *hdlc) static void sca_close(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); + card_t* card = port_to_card(port); /* reset channel */ netif_stop_queue(hdlc_to_dev(hdlc)); sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); +#ifdef __HD64570_H + /* disable MSCI interrupts */ + sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0), + IER0, card); + /* disable DMA interrupts */ + sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0), + IER1, card); +#else + /* disable DMA & MSCI IRQ */ + sca_outl(sca_inl(IER0, card) & + (phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card); +#endif } @@ -636,7 +657,7 @@ static int sca_attach(hdlc_device *hdlc, unsigned short encoding, -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS static void sca_dump_rings(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); @@ -651,30 +672,26 @@ static void sca_dump_rings(hdlc_device *hdlc) openwin(card, 0); #endif - printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", + printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", sca_ina(get_dmac_rx(port) + CDAL, card), sca_ina(get_dmac_rx(port) + EDAL, card), - sca_in(DSR_RX(phy_node(port)), card), - port->rxin, + sca_in(DSR_RX(phy_node(port)), card), port->rxin, sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) - printk(" %02X", - readb(&(desc_address(port, cnt, 0)->stat))); + printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); - printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " "last=%u %sactive", sca_ina(get_dmac_tx(port) + CDAL, card), sca_ina(get_dmac_tx(port) + EDAL, card), - sca_in(DSR_TX(phy_node(port)), card), port->txin, - port->txlast, + sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast, sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++) - printk(" %02X", - readb(&(desc_address(port, cnt, 1)->stat))); + printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); printk("\n"); - printk(KERN_ERR "MSCI: MD: %02x %02x %02x, " + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, " "ST: %02x %02x %02x %02x" #ifdef __HD64572_H " %02x" @@ -695,14 +712,18 @@ static void sca_dump_rings(hdlc_device *hdlc) sca_in(get_msci(port) + CST1, card)); #ifdef __HD64572_H - printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card)); + printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), + sca_inl(ISR0, card), sca_inl(ISR1, card)); +#else + printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card), + sca_in(ISR1, card), sca_in(ISR2, card)); #endif #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) openwin(card, page); /* Restore original page */ #endif } -#endif /* CONFIG_HDLC_DEBUG_RINGS */ +#endif /* DEBUG_RINGS */ @@ -723,7 +744,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) desc = desc_address(port, port->txin + 1, 1); if (readb(&desc->stat)) { /* allow 1 packet gap */ /* should never happen - previous xmit should stop queue */ -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); #endif netif_stop_queue(dev); @@ -731,7 +752,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) return 1; /* request packet to be queued */ } -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); debug_frame(skb); #endif @@ -828,7 +849,6 @@ static void __devinit sca_init(card_t *card, int wait_states) sca_out(0, DMER, card); /* DMA Master disable */ sca_out(0x03, PCR, card); /* DMA priority */ - sca_out(0, IER1, card); /* DMA interrupt disable */ sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ sca_out(0, DSR_TX(0), card); sca_out(0, DSR_RX(1), card); diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index f6234c5a64cc..c639524042c5 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -24,6 +23,7 @@ #include <linux/rtnetlink.h> #include <linux/hdlc.h> +#undef DEBUG_HARD_HEADER #define CISCO_MULTICAST 0x8F /* Cisco multicast address */ #define CISCO_UNICAST 0x0F /* Cisco unicast address */ @@ -39,7 +39,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned int len) { hdlc_header *data; -#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER +#ifdef DEBUG_HARD_HEADER printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); #endif @@ -182,7 +182,7 @@ static void cisco_rx(struct sk_buff *skb) case CISCO_KEEPALIVE_REQ: hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); - if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) { + if (ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { hdlc->state.cisco.last_poll = jiffies; if (!hdlc->state.cisco.up) { u32 sec, min, hrs, days; @@ -219,11 +219,12 @@ static void cisco_timer(unsigned long arg) { hdlc_device *hdlc = (hdlc_device*)arg; - if (hdlc->state.cisco.up && - jiffies - hdlc->state.cisco.last_poll >= + if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >= hdlc->state.cisco.settings.timeout * HZ) { hdlc->state.cisco.up = 0; printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); } cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, @@ -238,7 +239,7 @@ static void cisco_timer(unsigned long arg) -static int cisco_open(hdlc_device *hdlc) +static void cisco_start(hdlc_device *hdlc) { hdlc->state.cisco.last_poll = 0; hdlc->state.cisco.up = 0; @@ -249,14 +250,15 @@ static int cisco_open(hdlc_device *hdlc) hdlc->state.cisco.timer.function = cisco_timer; hdlc->state.cisco.timer.data = (unsigned long)hdlc; add_timer(&hdlc->state.cisco.timer); - return 0; } -static void cisco_close(hdlc_device *hdlc) +static void cisco_stop(hdlc_device *hdlc) { del_timer_sync(&hdlc->state.cisco.timer); + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); } @@ -301,12 +303,13 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc_proto_detach(hdlc); memcpy(&hdlc->state.cisco.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = cisco_open; - hdlc->stop = cisco_close; - hdlc->netif_rx = cisco_rx; - hdlc->type_trans = cisco_type_trans; - hdlc->proto = IF_PROTO_CISCO; + hdlc->proto.start = cisco_start; + hdlc->proto.stop = cisco_stop; + hdlc->proto.netif_rx = cisco_rx; + hdlc->proto.type_trans = cisco_type_trans; + hdlc->proto.id = IF_PROTO_CISCO; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; dev->type = ARPHRD_CISCO; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index c0b5f1821043..45cbde46c34f 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -9,7 +9,9 @@ * as published by the Free Software Foundation. * - Theory of PVC state in DCE mode: + Theory of PVC state + + DCE mode: (exist,new) -> 0,0 when "PVC create" or if "link unreliable" 0,x -> 1,1 if "link reliable" when sending FULL STATUS @@ -17,9 +19,16 @@ (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" -> 1 when "PVC up" and (exist,new) = 1,0 + + DTE mode: + (exist,new,active) = FULL STATUS if "link reliable" + = 0, 0, 0 if "link unreliable" + No LMI: + active = open and "link reliable" + exist = new = not used + */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -36,12 +45,96 @@ #include <linux/etherdevice.h> #include <linux/hdlc.h> +#undef DEBUG_PKT +#undef DEBUG_ECN +#undef DEBUG_LINK + +#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ + +#define PVC_STATE_NEW 0x01 +#define PVC_STATE_ACTIVE 0x02 +#define PVC_STATE_FECN 0x08 /* FECN condition */ +#define PVC_STATE_BECN 0x10 /* BECN condition */ + + +#define FR_UI 0x03 +#define FR_PAD 0x00 + +#define NLPID_IP 0xCC +#define NLPID_IPV6 0x8E +#define NLPID_SNAP 0x80 +#define NLPID_PAD 0x00 +#define NLPID_Q933 0x08 + + +#define LMI_DLCI 0 /* LMI DLCI */ +#define LMI_PROTO 0x08 +#define LMI_CALLREF 0x00 /* Call Reference */ +#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ +#define LMI_REPTYPE 1 /* report type */ +#define LMI_CCITT_REPTYPE 0x51 +#define LMI_ALIVE 3 /* keep alive */ +#define LMI_CCITT_ALIVE 0x53 +#define LMI_PVCSTAT 7 /* pvc status */ +#define LMI_CCITT_PVCSTAT 0x57 +#define LMI_FULLREP 0 /* full report */ +#define LMI_INTEGRITY 1 /* link integrity report */ +#define LMI_SINGLE 2 /* single pvc report */ +#define LMI_STATUS_ENQUIRY 0x75 +#define LMI_STATUS 0x7D /* reply */ + +#define LMI_REPT_LEN 1 /* report type element length */ +#define LMI_INTEG_LEN 2 /* link integrity element length */ + +#define LMI_LENGTH 13 /* standard LMI frame length */ +#define LMI_ANSI_LENGTH 14 + + +typedef struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned ea1: 1; + unsigned cr: 1; + unsigned dlcih: 6; + + unsigned ea2: 1; + unsigned de: 1; + unsigned becn: 1; + unsigned fecn: 1; + unsigned dlcil: 4; +#else + unsigned dlcih: 6; + unsigned cr: 1; + unsigned ea1: 1; + + unsigned dlcil: 4; + unsigned fecn: 1; + unsigned becn: 1; + unsigned de: 1; + unsigned ea2: 1; +#endif +}__attribute__ ((packed)) fr_hdr; + -__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) +static inline u16 q922_to_dlci(u8 *hdr) +{ + return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); +} + + + +static inline void dlci_to_q922(u8 *hdr, u16 dlci) +{ + hdr[0] = (dlci >> 2) & 0xFC; + hdr[1] = ((dlci << 4) & 0xF0) | 0x01; +} + + + +static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc = hdlc->state.fr.first_pvc; - while(pvc) { + while (pvc) { if (pvc->dlci == dlci) return pvc; if (pvc->dlci > dlci) @@ -53,15 +146,15 @@ __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) } -__inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) +static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; - while(*pvc_p) { + while (*pvc_p) { if ((*pvc_p)->dlci == dlci) return *pvc_p; if ((*pvc_p)->dlci > dlci) - break; /* the listed is sorted */ + break; /* the list is sorted */ pvc_p = &(*pvc_p)->next; } @@ -78,17 +171,37 @@ __inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) } -__inline__ int pvc_is_used(pvc_device *pvc) +static inline int pvc_is_used(pvc_device *pvc) { return pvc->main != NULL || pvc->ether != NULL; } -__inline__ void delete_unused_pvcs(hdlc_device *hdlc) +static inline void pvc_carrier(int on, pvc_device *pvc) +{ + if (on) { + if (pvc->main) + if (!netif_carrier_ok(pvc->main)) + netif_carrier_on(pvc->main); + if (pvc->ether) + if (!netif_carrier_ok(pvc->ether)) + netif_carrier_on(pvc->ether); + } else { + if (pvc->main) + if (netif_carrier_ok(pvc->main)) + netif_carrier_off(pvc->main); + if (pvc->ether) + if (netif_carrier_ok(pvc->ether)) + netif_carrier_off(pvc->ether); + } +} + + +static inline void delete_unused_pvcs(hdlc_device *hdlc) { pvc_device **pvc_p = &hdlc->state.fr.first_pvc; - while(*pvc_p) { + while (*pvc_p) { if (!pvc_is_used(*pvc_p)) { pvc_device *pvc = *pvc_p; *pvc_p = pvc->next; @@ -100,7 +213,7 @@ __inline__ void delete_unused_pvcs(hdlc_device *hdlc) } -__inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) +static inline struct net_device** get_dev_p(pvc_device *pvc, int type) { if (type == ARPHRD_ETHER) return &pvc->ether; @@ -109,20 +222,19 @@ __inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) } -__inline__ u16 status_to_dlci(u8 *status, int *active, int *new) +static inline u16 status_to_dlci(u8 *status, int *active, int *new) { *new = (status[2] & 0x08) ? 1 : 0; *active = (status[2] & 0x02) ? 1 : 0; - return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); + return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3); } -__inline__ void dlci_to_status(u16 dlci, u8 *status, - int active, int new) +static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new) { - status[0] = (dlci>>4) & 0x3F; - status[1] = ((dlci<<3) & 0x78) | 0x80; + status[0] = (dlci >> 4) & 0x3F; + status[1] = ((dlci << 3) & 0x78) | 0x80; status[2] = 0x80; if (new) @@ -138,7 +250,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) u16 head_len; struct sk_buff *skb = *skb_p; - switch(skb->protocol) { + switch (skb->protocol) { case __constant_ntohs(ETH_P_IP): head_len = 4; skb_push(skb, head_len); @@ -204,8 +316,9 @@ static int pvc_open(struct net_device *dev) if (pvc->open_count++ == 0) { if (pvc->master->state.fr.settings.lmi == LMI_NONE) - pvc->state.active = 1; + pvc->state.active = pvc->master->carrier; + pvc_carrier(pvc->state.active, pvc); pvc->master->state.fr.dce_changed = 1; } return 0; @@ -260,7 +373,7 @@ int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } -__inline__ struct net_device_stats *pvc_get_stats(struct net_device *dev) +static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { return (struct net_device_stats *) ((char *)dev + sizeof(struct net_device)); @@ -402,6 +515,7 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) /* ifconfig PVC up */ if (pvc->open_count && !pvc->state.active && pvc->state.exist && !pvc->state.new) { + pvc_carrier(1, pvc); pvc->state.active = 1; fr_log_dlci_active(pvc); } @@ -423,6 +537,41 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) +static void fr_set_link_state(int reliable, hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->state.fr.first_pvc; + + hdlc->state.fr.reliable = reliable; + if (reliable) { + if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + hdlc->state.fr.n391cnt = 0; /* Request full status */ + hdlc->state.fr.dce_changed = 1; + + if (hdlc->state.fr.settings.lmi == LMI_NONE) { + while (pvc) { /* Activate all PVCs */ + pvc_carrier(1, pvc); + pvc->state.exist = pvc->state.active = 1; + pvc->state.new = 0; + pvc = pvc->next; + } + } + } else { + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + + while (pvc) { /* Deactivate all PVCs */ + pvc_carrier(0, pvc); + pvc->state.exist = pvc->state.active = 0; + pvc->state.new = 0; + pvc = pvc->next; + } + } +} + + + static void fr_timer(unsigned long arg) { hdlc_device *hdlc = (hdlc_device*)arg; @@ -449,22 +598,9 @@ static void fr_timer(unsigned long arg) } if (hdlc->state.fr.reliable != reliable) { - pvc_device *pvc = hdlc->state.fr.first_pvc; - - hdlc->state.fr.reliable = reliable; printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), reliable ? "" : "un"); - - if (reliable) { - hdlc->state.fr.n391cnt = 0; /* Request full status */ - hdlc->state.fr.dce_changed = 1; - } else { - while (pvc) { /* Deactivate all PVCs */ - pvc->state.exist = 0; - pvc->state.active = pvc->state.new = 0; - pvc = pvc->next; - } - } + fr_set_link_state(reliable, hdlc); } if (hdlc->state.fr.settings.dce) @@ -636,6 +772,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) !pvc->state.exist) { pvc->state.new = new; pvc->state.active = active; + pvc_carrier(active, pvc); fr_log_dlci_active(pvc); } } @@ -647,6 +784,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) while (pvc) { if (pvc->state.deleted && pvc->state.exist) { + pvc_carrier(0, pvc); pvc->state.active = pvc->state.new = 0; pvc->state.exist = 0; fr_log_dlci_active(pvc); @@ -699,7 +837,7 @@ static void fr_rx(struct sk_buff *skb) pvc = find_pvc(hdlc, dlci); if (!pvc) { -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", hdlc_to_name(hdlc), dlci); #endif @@ -708,7 +846,7 @@ static void fr_rx(struct sk_buff *skb) } if (pvc->state.fecn != fh->fecn) { -#ifdef CONFIG_HDLC_DEBUG_ECN +#ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc), dlci, fh->fecn ? "N" : "FF"); #endif @@ -716,7 +854,7 @@ static void fr_rx(struct sk_buff *skb) } if (pvc->state.becn != fh->becn) { -#ifdef CONFIG_HDLC_DEBUG_ECN +#ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc), dlci, fh->becn ? "N" : "FF"); #endif @@ -787,9 +925,14 @@ static void fr_rx(struct sk_buff *skb) -static int fr_open(hdlc_device *hdlc) +static void fr_start(hdlc_device *hdlc) { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "fr_start\n"); +#endif if (hdlc->state.fr.settings.lmi != LMI_NONE) { + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); hdlc->state.fr.last_poll = 0; hdlc->state.fr.reliable = 0; hdlc->state.fr.dce_changed = 1; @@ -806,9 +949,19 @@ static int fr_open(hdlc_device *hdlc) hdlc->state.fr.timer.data = (unsigned long)hdlc; add_timer(&hdlc->state.fr.timer); } else - hdlc->state.fr.reliable = 1; + fr_set_link_state(1, hdlc); +} - return 0; + + +static void fr_stop(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "fr_stop\n"); +#endif + if (hdlc->state.fr.settings.lmi != LMI_NONE) + del_timer_sync(&hdlc->state.fr.timer); + fr_set_link_state(0, hdlc); } @@ -817,22 +970,17 @@ static void fr_close(hdlc_device *hdlc) { pvc_device *pvc = hdlc->state.fr.first_pvc; - if (hdlc->state.fr.settings.lmi != LMI_NONE) - del_timer_sync(&hdlc->state.fr.timer); - - while(pvc) { /* Shutdown all PVCs for this FRAD */ + while (pvc) { /* Shutdown all PVCs for this FRAD */ if (pvc->main) dev_close(pvc->main); if (pvc->ether) dev_close(pvc->ether); - pvc->state.active = pvc->state.new = pvc->state.fecn = - pvc->state.becn = 0; - pvc->state.exist = 0; pvc = pvc->next; } } + static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) { pvc_device *pvc = NULL; @@ -900,6 +1048,7 @@ static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) return -EIO; } + dev->destructor = (void (*)(struct net_device *)) kfree; *get_dev_p(pvc, type) = dev; if (!used) { hdlc->state.fr.dce_changed = 1; @@ -924,8 +1073,7 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) if (dev->flags & IFF_UP) return -EBUSY; /* PVC in use */ - unregister_netdevice(dev); - kfree(dev); + unregister_netdevice(dev); /* the destructor will kfree(dev) */ *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { @@ -940,24 +1088,24 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) static void fr_destroy(hdlc_device *hdlc) { - pvc_device *pvc = hdlc->state.fr.first_pvc; - while(pvc) { + pvc_device *pvc; + + pvc = hdlc->state.fr.first_pvc; + hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ + hdlc->state.fr.dce_pvc_count = 0; + hdlc->state.fr.dce_changed = 1; + + while (pvc) { pvc_device *next = pvc->next; - if (pvc->main) { + if (pvc->main) /* the destructor will kfree(main + ether) */ unregister_netdevice(pvc->main); - kfree(pvc->main); - } - if (pvc->ether) { + + if (pvc->ether) unregister_netdevice(pvc->ether); - kfree(pvc->ether); - } + kfree(pvc); pvc = next; } - - hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ - hdlc->state.fr.dce_pvc_count = 0; - hdlc->state.fr.dce_changed = 1; } @@ -1012,19 +1160,20 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr) if (result) return result; - if (hdlc->proto != IF_PROTO_FR) { + if (hdlc->proto.id != IF_PROTO_FR) { hdlc_proto_detach(hdlc); hdlc->state.fr.first_pvc = NULL; hdlc->state.fr.dce_pvc_count = 0; } memcpy(&hdlc->state.fr.settings, &new_settings, size); - - hdlc->open = fr_open; - hdlc->stop = fr_close; - hdlc->netif_rx = fr_rx; - hdlc->type_trans = NULL; - hdlc->proto_detach = fr_destroy; - hdlc->proto = IF_PROTO_FR; + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); + + hdlc->proto.close = fr_close; + hdlc->proto.start = fr_start; + hdlc->proto.stop = fr_stop; + hdlc->proto.detach = fr_destroy; + hdlc->proto.netif_rx = fr_rx; + hdlc->proto.id = IF_PROTO_FR; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_FRAD; diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index fd0b3dfeeb19..4d150428ec89 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c @@ -33,7 +33,9 @@ #include <linux/hdlc.h> -static const char* version = "HDLC support module revision 1.14"; +static const char* version = "HDLC support module revision 1.15"; + +#undef DEBUG_LINK static int hdlc_change_mtu(struct net_device *dev, int new_mtu) @@ -57,8 +59,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) { hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->netif_rx) - hdlc->netif_rx(skb); + if (hdlc->proto.netif_rx) + hdlc->proto.netif_rx(skb); else { hdlc->stats.rx_dropped++; /* Shouldn't happen */ dev_kfree_skb(skb); @@ -67,6 +69,103 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, } + +void hdlc_set_carrier(int on, hdlc_device *hdlc) +{ + on = on ? 1 : 0; + +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_set_carrier %i\n", on); +#endif + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier == on) + goto carrier_exit; /* no change in DCD line level */ + + printk(KERN_INFO "%s: carrier %s\n", hdlc_to_name(hdlc), + on ? "ON" : "off"); + hdlc->carrier = on; + + if (!hdlc->open) + goto carrier_exit; + + if (hdlc->carrier) { + if (hdlc->proto.start) + hdlc->proto.start(hdlc); + else if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + } else { /* no carrier */ + if (hdlc->proto.stop) + hdlc->proto.stop(hdlc); + else if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + } + + carrier_exit: + spin_unlock_irq(&hdlc->state_lock); +} + + +/* Must be called by hardware driver when HDLC device is being opened */ +int hdlc_open(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_open carrier %i open %i\n", + hdlc->carrier, hdlc->open); +#endif + + if (hdlc->proto.id == -1) + return -ENOSYS; /* no protocol attached */ + + if (hdlc->proto.open) { + int result = hdlc->proto.open(hdlc); + if (result) + return result; + } + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier) { + if (hdlc->proto.start) + hdlc->proto.start(hdlc); + else if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + } else if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + + hdlc->open = 1; + + spin_unlock_irq(&hdlc->state_lock); + return 0; +} + + + +/* Must be called by hardware driver when HDLC device is being closed */ +void hdlc_close(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_close carrier %i open %i\n", + hdlc->carrier, hdlc->open); +#endif + + spin_lock_irq(&hdlc->state_lock); + + hdlc->open = 0; + if (hdlc->carrier && hdlc->proto.stop) + hdlc->proto.stop(hdlc); + + spin_unlock_irq(&hdlc->state_lock); + + if (hdlc->proto.close) + hdlc->proto.close(hdlc); +} + + + #ifndef CONFIG_HDLC_RAW #define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS #endif @@ -111,7 +210,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; default: - proto = hdlc->proto; + proto = hdlc->proto.id; } switch(proto) { @@ -141,11 +240,14 @@ int register_hdlc_device(hdlc_device *hdlc) dev->flags = IFF_POINTOPOINT | IFF_NOARP; - hdlc->proto = -1; - hdlc->proto_detach = NULL; + hdlc->proto.id = -1; + hdlc->proto.detach = NULL; + hdlc->carrier = 1; + hdlc->open = 0; + spin_lock_init(&hdlc->state_lock); result = dev_alloc_name(dev, "hdlc%d"); - if (result<0) + if (result < 0) return result; result = register_netdev(dev); @@ -171,6 +273,9 @@ MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); MODULE_DESCRIPTION("HDLC support module"); MODULE_LICENSE("GPL v2"); +EXPORT_SYMBOL(hdlc_open); +EXPORT_SYMBOL(hdlc_close); +EXPORT_SYMBOL(hdlc_set_carrier); EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device); diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 1d93f3ac14ed..7eeec068d5a2 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -99,12 +98,12 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr) return result; hdlc_proto_detach(hdlc); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = ppp_open; - hdlc->stop = ppp_close; - hdlc->netif_rx = NULL; - hdlc->type_trans = ppp_type_trans; - hdlc->proto = IF_PROTO_PPP; + hdlc->proto.open = ppp_open; + hdlc->proto.close = ppp_close; + hdlc->proto.type_trans = ppp_type_trans; + hdlc->proto.id = IF_PROTO_PPP; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_PPP; diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index 7bc89d695ecd..6c0aecc442fa 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -75,12 +74,10 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = NULL; - hdlc->stop = NULL; - hdlc->netif_rx = NULL; - hdlc->type_trans = raw_type_trans; - hdlc->proto = IF_PROTO_HDLC; + hdlc->proto.type_trans = raw_type_trans; + hdlc->proto.id = IF_PROTO_HDLC; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 90c69addb6d5..d91a4fc87730 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -89,12 +88,10 @@ int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = NULL; - hdlc->stop = NULL; - hdlc->netif_rx = NULL; - hdlc->type_trans = eth_type_trans; - hdlc->proto = IF_PROTO_HDLC_ETH; + hdlc->proto.type_trans = eth_type_trans; + hdlc->proto.id = IF_PROTO_HDLC_ETH; dev->hard_start_xmit = eth_tx; old_ch_mtu = dev->change_mtu; old_qlen = dev->tx_queue_len; diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index 53b118c5f8d5..7433c966028e 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -199,12 +198,13 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr) return result; hdlc_proto_detach(hdlc); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = x25_open; - hdlc->stop = x25_close; - hdlc->netif_rx = x25_rx; - hdlc->type_trans = NULL; - hdlc->proto = IF_PROTO_X25; + hdlc->proto.open = x25_open; + hdlc->proto.close = x25_close; + hdlc->proto.netif_rx = x25_rx; + hdlc->proto.type_trans = NULL; + hdlc->proto.id = IF_PROTO_X25; dev->hard_start_xmit = x25_xmit; dev->hard_header = NULL; dev->type = ARPHRD_X25; diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index 53e0701da0ff..7e50bc51f021 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -16,7 +16,6 @@ * SDL Inc. PPP/HDLC/CISCO driver */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -34,9 +33,12 @@ #include "hd64570.h" -static const char* version = "SDL RISCom/N2 driver version: 1.14"; +static const char* version = "SDL RISCom/N2 driver version: 1.15"; static const char* devname = "RISCom/N2"; +#undef DEBUG_PKT +#define DEBUG_RINGS + #define USE_WINDOWSIZE 16384 #define USE_BUS16BITS 1 #define CLOCK_BASE 9830400 /* 9.8304 MHz */ @@ -48,6 +50,7 @@ static const char* devname = "RISCom/N2"; #endif #define N2_IOPORTS 0x10 #define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static char *hw = NULL; /* pointer to hw=xxx command line string */ @@ -257,7 +260,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(hdlc); return 0; @@ -415,7 +418,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * (card->tx_ring_buffers + card->rx_ring_buffers); - printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " + printk(KERN_INFO "n2: RISCom/N2 %u KB RAM, IRQ%u, " "using %u TX + %u RX packets rings\n", card->ram_size / 1024, card->irq, card->tx_ring_buffers, card->rx_ring_buffers); @@ -447,7 +450,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; - dev->mem_end = winbase + USE_WINDOWSIZE-1; + dev->mem_end = winbase + USE_WINDOWSIZE - 1; dev->tx_queue_len = 50; dev->do_ioctl = n2_ioctl; dev->open = n2_open; diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index 6b89e9c85f9b..94c967d945e7 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -42,6 +42,9 @@ #define LMI_ANSI 2 /* ANSI Annex D */ #define LMI_CCITT 3 /* ITU-T Annex A */ +#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ +#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ + #ifdef __KERNEL__ @@ -50,78 +53,6 @@ #include <net/syncppp.h> #include <linux/hdlc/ioctl.h> -#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ -#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ - -#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ - -#define PVC_STATE_NEW 0x01 -#define PVC_STATE_ACTIVE 0x02 -#define PVC_STATE_FECN 0x08 /* FECN condition */ -#define PVC_STATE_BECN 0x10 /* BECN condition */ - - -#define FR_UI 0x03 -#define FR_PAD 0x00 - -#define NLPID_IP 0xCC -#define NLPID_IPV6 0x8E -#define NLPID_SNAP 0x80 -#define NLPID_PAD 0x00 -#define NLPID_Q933 0x08 - - -#define LMI_DLCI 0 /* LMI DLCI */ -#define LMI_PROTO 0x08 -#define LMI_CALLREF 0x00 /* Call Reference */ -#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ -#define LMI_REPTYPE 1 /* report type */ -#define LMI_CCITT_REPTYPE 0x51 -#define LMI_ALIVE 3 /* keep alive */ -#define LMI_CCITT_ALIVE 0x53 -#define LMI_PVCSTAT 7 /* pvc status */ -#define LMI_CCITT_PVCSTAT 0x57 -#define LMI_FULLREP 0 /* full report */ -#define LMI_INTEGRITY 1 /* link integrity report */ -#define LMI_SINGLE 2 /* single pvc report */ -#define LMI_STATUS_ENQUIRY 0x75 -#define LMI_STATUS 0x7D /* reply */ - -#define LMI_REPT_LEN 1 /* report type element length */ -#define LMI_INTEG_LEN 2 /* link integrity element length */ - -#define LMI_LENGTH 13 /* standard LMI frame length */ -#define LMI_ANSI_LENGTH 14 - - - -typedef struct { -#if defined(__LITTLE_ENDIAN_BITFIELD) - unsigned ea1 : 1; - unsigned cr : 1; - unsigned dlcih: 6; - - unsigned ea2 : 1; - unsigned de : 1; - unsigned becn : 1; - unsigned fecn : 1; - unsigned dlcil: 4; -#elif defined (__BIG_ENDIAN_BITFIELD) - unsigned dlcih: 6; - unsigned cr : 1; - unsigned ea1 : 1; - - unsigned dlcil: 4; - unsigned fecn : 1; - unsigned becn : 1; - unsigned de : 1; - unsigned ea2 : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif -}__attribute__ ((packed)) fr_hdr; - - typedef struct { /* Used in Cisco and PPP mode */ u8 address; @@ -177,14 +108,25 @@ typedef struct hdlc_device_struct { /* Things below are for HDLC layer internal use only */ - int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); - int (*open)(struct hdlc_device_struct *hdlc); - void (*stop)(struct hdlc_device_struct *hdlc); - void (*proto_detach)(struct hdlc_device_struct *hdlc); - void (*netif_rx)(struct sk_buff *skb); - unsigned short (*type_trans)(struct sk_buff *skb, - struct net_device *dev); - int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */ + struct { + int (*open)(struct hdlc_device_struct *hdlc); + void (*close)(struct hdlc_device_struct *hdlc); + + /* if open & DCD */ + void (*start)(struct hdlc_device_struct *hdlc); + /* if open & !DCD */ + void (*stop)(struct hdlc_device_struct *hdlc); + + void (*detach)(struct hdlc_device_struct *hdlc); + void (*netif_rx)(struct sk_buff *skb); + unsigned short (*type_trans)(struct sk_buff *skb, + struct net_device *dev); + int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */ + }proto; + + int carrier; + int open; + spinlock_t state_lock; union { struct { @@ -271,26 +213,11 @@ static __inline__ const char *hdlc_to_name(hdlc_device *hdlc) } -static __inline__ u16 q922_to_dlci(u8 *hdr) -{ - return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); -} - - - -static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci) -{ - hdr[0] = (dlci >> 2) & 0xFC; - hdr[1] = ((dlci << 4) & 0xF0) | 0x01; -} - - - static __inline__ void debug_frame(const struct sk_buff *skb) { int i; - for (i=0; i<skb->len; i++) { + for (i=0; i < skb->len; i++) { if (i == 100) { printk("...\n"); return; @@ -301,33 +228,19 @@ static __inline__ void debug_frame(const struct sk_buff *skb) } - /* Must be called by hardware driver when HDLC device is being opened */ -static __inline__ int hdlc_open(hdlc_device *hdlc) -{ - if (hdlc->proto == -1) - return -ENOSYS; /* no protocol attached */ - - if (hdlc->open) - return hdlc->open(hdlc); - return 0; -} - - +int hdlc_open(hdlc_device *hdlc); /* Must be called by hardware driver when HDLC device is being closed */ -static __inline__ void hdlc_close(hdlc_device *hdlc) -{ - if (hdlc->stop) - hdlc->stop(hdlc); -} - +void hdlc_close(hdlc_device *hdlc); +/* Called by hardware driver when DCD line level changes */ +void hdlc_set_carrier(int on, hdlc_device *hdlc); /* May be used by hardware driver to gain control over HDLC device */ static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) { - if (hdlc->proto_detach) - hdlc->proto_detach(hdlc); - hdlc->proto_detach = NULL; + if (hdlc->proto.detach) + hdlc->proto.detach(hdlc); + hdlc->proto.detach = NULL; } @@ -335,8 +248,8 @@ static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(skb->dev); - if (hdlc->type_trans) - return hdlc->type_trans(skb, dev); + if (hdlc->proto.type_trans) + return hdlc->proto.type_trans(skb, dev); else return __constant_htons(ETH_P_HDLC); } |
