Commit 2424dc63 authored by Krzysztof Halasa's avatar Krzysztof Halasa Committed by Jeff Garzik

[PATCH] 2.6 Generic HDLC update

The attached patch updates generic HDLC:
- fixed some carrier-related problems (Cisco HDLC and FR links could
  report valid link when no carrier was detected at startup).
- fixed kbuild problems with wanxl firmware (building kernel in separate
  tree). $(src)/wanxlfw.inc is now wanxlfw.inc_shipped.
parent ee4571db
......@@ -61,6 +61,9 @@ obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
ifeq ($(CONFIG_WANXL_BUILD_FIRMWARE),y)
ifeq ($(ARCH),m68k)
AS68K = $(AS)
......@@ -72,12 +75,12 @@ endif
quiet_cmd_build_wanxlfw = BLD FW $@
cmd_build_wanxlfw = \
$(CPP) -Wp,-MD,$(depfile) -Iinclude $(obj)/wanxlfw.S | $(AS68K) -m68360 -o $(obj)/wanxlfw.o; \
$(CPP) -Wp,-MD,$(depfile) -I$(srctree)/include $< | $(AS68K) -m68360 -o $(obj)/wanxlfw.o; \
$(LD68K) --oformat binary -Ttext 0x1000 $(obj)/wanxlfw.o -o $(obj)/wanxlfw.bin; \
hexdump -ve '"\n" 16/1 "0x%02X,"' $(obj)/wanxlfw.bin | sed 's/0x ,//g;1s/^/static u8 firmware[]={/;$$s/,$$/\n};\n/' >$(obj)/wanxlfw.inc; \
rm -f $(obj)/wanxlfw.bin $(obj)/wanxlfw.o
$(obj)/wanxlfw.inc: $(obj)/wanxlfw.S
$(obj)/wanxlfw.inc: $(src)/wanxlfw.S
$(call if_changed_dep,build_wanxlfw)
targets += wanxlfw.inc
endif
......@@ -379,8 +379,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
return result;
}
/* XXX: are we OK with having that done when card is already up? */
sca_init_sync_port(card); /* Set up C101 memory */
hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), dev);
......
......@@ -180,7 +180,8 @@ static int 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 (hdlc->state.cisco.request_sent &&
ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
hdlc->state.cisco.last_poll = jiffies;
if (!hdlc->state.cisco.up) {
u32 sec, min, hrs, days;
......@@ -192,9 +193,10 @@ static int cisco_rx(struct sk_buff *skb)
"uptime %ud%uh%um%us)\n",
dev->name, days, hrs,
min, sec);
}
netif_carrier_on(dev);
hdlc->state.cisco.up = 1;
}
}
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
......@@ -219,17 +221,18 @@ static void cisco_timer(unsigned long arg)
struct net_device *dev = (struct net_device *)arg;
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >=
hdlc->state.cisco.settings.timeout * HZ) {
if (hdlc->state.cisco.up &&
time_after(jiffies, hdlc->state.cisco.last_poll +
hdlc->state.cisco.settings.timeout * HZ)) {
hdlc->state.cisco.up = 0;
printk(KERN_INFO "%s: Link down\n", dev->name);
if (netif_carrier_ok(dev))
netif_carrier_off(dev);
}
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
++hdlc->state.cisco.txseq,
hdlc->state.cisco.rxseq);
hdlc->state.cisco.request_sent = 1;
hdlc->state.cisco.timer.expires = jiffies +
hdlc->state.cisco.settings.interval * HZ;
hdlc->state.cisco.timer.function = cisco_timer;
......@@ -242,8 +245,8 @@ static void cisco_timer(unsigned long arg)
static void cisco_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
hdlc->state.cisco.last_poll = 0;
hdlc->state.cisco.up = 0;
hdlc->state.cisco.request_sent = 0;
hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
init_timer(&hdlc->state.cisco.timer);
......@@ -257,9 +260,12 @@ static void cisco_start(struct net_device *dev)
static void cisco_stop(struct net_device *dev)
{
del_timer_sync(&dev_to_hdlc(dev)->state.cisco.timer);
hdlc_device *hdlc = dev_to_hdlc(dev);
del_timer_sync(&hdlc->state.cisco.timer);
if (netif_carrier_ok(dev))
netif_carrier_off(dev);
hdlc->state.cisco.up = 0;
hdlc->state.cisco.request_sent = 0;
}
......
......@@ -584,7 +584,8 @@ static void fr_timer(unsigned long arg)
u32 list;
if (hdlc->state.fr.settings.dce)
reliable = (jiffies - hdlc->state.fr.last_poll <
reliable = hdlc->state.fr.request &&
time_before(jiffies, hdlc->state.fr.last_poll +
hdlc->state.fr.settings.t392 * HZ);
else {
hdlc->state.fr.last_errors <<= 1; /* Shift the list */
......@@ -617,6 +618,7 @@ static void fr_timer(unsigned long arg)
fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
hdlc->state.fr.last_poll = jiffies;
hdlc->state.fr.request = 1;
hdlc->state.fr.timer.expires = jiffies +
hdlc->state.fr.settings.t391 * HZ;
......@@ -689,6 +691,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
dev->name, reptype);
return 1;
}
hdlc->state.fr.last_poll = jiffies;
}
error = 0;
......@@ -728,7 +731,12 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
/* DTE */
if (reptype != LMI_FULLREP || error)
hdlc->state.fr.request = 0; /* got response, no request pending */
if (error)
return 0;
if (reptype != LMI_FULLREP)
return 0;
stat_len = 3;
......@@ -829,9 +837,6 @@ static int fr_rx(struct sk_buff *skb)
if (fr_lmi_recv(ndev, skb))
goto rx_error;
else {
/* No request pending */
hdlc->state.fr.request = 0;
hdlc->state.fr.last_poll = jiffies;
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
}
......@@ -946,9 +951,6 @@ static void fr_start(struct net_device *dev)
printk(KERN_DEBUG "fr_start\n");
#endif
if (hdlc->state.fr.settings.lmi != LMI_NONE) {
if (netif_carrier_ok(dev))
netif_carrier_off(dev);
hdlc->state.fr.last_poll = 0;
hdlc->state.fr.reliable = 0;
hdlc->state.fr.dce_changed = 1;
hdlc->state.fr.request = 0;
......
......@@ -15,6 +15,11 @@
* * X.25
*
* Use sethdlc utility to set line parameters, protocol and PVCs
*
* How does it work:
* - proto.open(), close(), start(), stop() calls are serialized.
* The order is: open, [ start, stop ... ] close ...
* - proto.start() and stop() are called with spin_lock_irq held.
*/
#include <linux/config.h>
......@@ -33,7 +38,7 @@
#include <linux/hdlc.h>
static const char* version = "HDLC support module revision 1.16";
static const char* version = "HDLC support module revision 1.17";
#undef DEBUG_LINK
......@@ -69,51 +74,75 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
static void __hdlc_set_carrier_on(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto.start)
return hdlc->proto.start(dev);
#ifdef DEBUG_LINK
if (netif_carrier_ok(dev))
printk(KERN_ERR "hdlc_set_carrier_on(): already on\n");
#endif
netif_carrier_on(dev);
}
static void __hdlc_set_carrier_off(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto.stop)
return hdlc->proto.stop(dev);
#ifdef DEBUG_LINK
if (!netif_carrier_ok(dev))
printk(KERN_ERR "hdlc_set_carrier_off(): already off\n");
#endif
netif_carrier_off(dev);
}
void hdlc_set_carrier(int on, struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
unsigned long flags;
on = on ? 1 : 0;
#ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_set_carrier %i\n", on);
#endif
spin_lock_irq(&hdlc->state_lock);
spin_lock_irqsave(&hdlc->state_lock, flags);
if (hdlc->carrier == on)
goto carrier_exit; /* no change in DCD line level */
printk(KERN_INFO "%s: carrier %s\n", dev->name,
on ? "ON" : "off");
#ifdef DEBUG_LINK
printk(KERN_INFO "%s: carrier %s\n", dev->name, on ? "ON" : "off");
#endif
hdlc->carrier = on;
if (!hdlc->open)
goto carrier_exit;
if (hdlc->carrier) {
if (hdlc->proto.start)
hdlc->proto.start(dev);
else if (!netif_carrier_ok(dev))
netif_carrier_on(dev);
if (hdlc->carrier)
__hdlc_set_carrier_on(dev);
else
__hdlc_set_carrier_off(dev);
} else { /* no carrier */
if (hdlc->proto.stop)
hdlc->proto.stop(dev);
else if (netif_carrier_ok(dev))
netif_carrier_off(dev);
}
carrier_exit:
spin_unlock_irq(&hdlc->state_lock);
carrier_exit:
spin_unlock_irqrestore(&hdlc->state_lock, flags);
}
/* Must be called by hardware driver when HDLC device is being opened */
int hdlc_open(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_open carrier %i open %i\n",
printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n",
hdlc->carrier, hdlc->open);
#endif
......@@ -128,14 +157,8 @@ int hdlc_open(struct net_device *dev)
spin_lock_irq(&hdlc->state_lock);
if (hdlc->carrier) {
if (hdlc->proto.start)
hdlc->proto.start(dev);
else if (!netif_carrier_ok(dev))
netif_carrier_on(dev);
} else if (netif_carrier_ok(dev))
netif_carrier_off(dev);
if (hdlc->carrier)
__hdlc_set_carrier_on(dev);
hdlc->open = 1;
......@@ -150,15 +173,15 @@ void hdlc_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_close carrier %i open %i\n",
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(dev);
if (hdlc->carrier)
__hdlc_set_carrier_off(dev);
spin_unlock_irq(&hdlc->state_lock);
......@@ -257,25 +280,7 @@ struct net_device *alloc_hdlcdev(void *priv)
int register_hdlc_device(struct net_device *dev)
{
int result;
hdlc_device *hdlc = dev_to_hdlc(dev);
dev->get_stats = hdlc_get_stats;
dev->change_mtu = hdlc_change_mtu;
dev->mtu = HDLC_MAX_MTU;
dev->type = ARPHRD_RAWHDLC;
dev->hard_header_len = 16;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
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");
int result = dev_alloc_name(dev, "hdlc%d");
if (result < 0)
return result;
......@@ -283,6 +288,9 @@ int register_hdlc_device(struct net_device *dev)
if (result != 0)
return -EIO;
if (netif_carrier_ok(dev))
netif_carrier_off(dev); /* no carrier until DCD goes up */
return 0;
}
......
......@@ -134,7 +134,7 @@ typedef struct hdlc_device_struct {
int dce_pvc_count;
struct timer_list timer;
int last_poll;
unsigned long last_poll;
int reliable;
int dce_changed;
int request;
......@@ -149,8 +149,9 @@ typedef struct hdlc_device_struct {
cisco_proto settings;
struct timer_list timer;
int last_poll;
unsigned long last_poll;
int up;
int request_sent;
u32 txseq; /* TX sequence number */
u32 rxseq; /* RX sequence number */
}cisco;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment