lkml.org 
[lkml]   [1999]   [Oct]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectISDN patch: new tbusy logic

Hi,

according to the "Re: 1000ms delay in networking stack or driver, new bug?"
post-discussion, I've now prepared a new patch that cleans up the tbusy
logic for drivers/isdn/isdn_net.c.

This attached patch is against
2.2.13pre14, as this already contains the most up-to-date isdn drivers
and has other network delay bugs fixed as well. With some minimal handwork
(you need to changes "struct device" to "struct net_device", it should also
work with 2.3.18). You can also fetch the equivalent stuff for 2.3.18
from the isdn4linux cvs server.

Please review and test this, in particular with multilink raw-ip links
as I could not do this myself due to lack of access to multilinks.

Henner


--- linux-2.2.13pre14/drivers/isdn/isdn_net.c_old_tbusy Sat Oct 2 12:13:04 1999
+++ linux-2.2.13pre14/drivers/isdn/isdn_net.c Sat Oct 2 12:18:40 1999
@@ -375,6 +375,44 @@
#endif


+/*
+ * Outline of new tbusy handling:
+ *
+ * Old method, roughly spoken, consisted of setting tbusy when entering
+ * isdn_net_start_xmit() and at several other locations and clearing
+ * it from isdn_net_start_xmit() thread when sending was successful.
+ *
+ * With 2.3.x multithreaded network core, to prevent problems, tbusy should
+ * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
+ * condition is detected. Other threads (in particular isdn_net_stat_callb())
+ * are only allowed to clear tbusy.
+ *
+ * -HE
+ */
+
+/*
+ * Tell upper layers that the network device is ready to xmit more frames.
+ */
+static void __inline__ isdn_net_dev_xon(struct device * dev)
+{
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+}
+
+static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+{
+ lp->netdev->dev.tbusy = 0;
+ if(lp->master) lp->master->tbusy = 0;
+ mark_bh(NET_BH);
+}
+
+/*
+ * Ask upper layers to temporarily cease passing us more xmit frames.
+ */
+static void __inline__ isdn_net_dev_xoff(struct device * dev)
+{
+ dev->tbusy = 1;
+}

/* Prototypes */

@@ -424,7 +462,7 @@
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
dev->interrupt = 0;
- dev->tbusy = 0;
+ isdn_net_dev_xon(dev);
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops && dops )
cprot -> pops -> restart ( cprot, dev, dops );
@@ -638,13 +676,11 @@
mdev = &lp->netdev->dev;
if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
lp->sav_skb = NULL;
- mark_bh(NET_BH);
} else {
return 1;
}
}
- if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
- mark_bh(NET_BH);
+ isdn_net_lp_xon(lp);
}
return 1;
case ISDN_STAT_DCONN:
@@ -727,7 +763,6 @@
lp->dialstarted = 0;
lp->dialwait_timer = 0;

- /* Immediately send first skb to speed up arp */
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_wakeup_daemon(lp);
@@ -738,19 +773,13 @@
if( pops->connect_ind)
pops->connect_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
+ /* Immediately send first skb to speed up arp */
if (lp->first_skb) {

if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
lp->first_skb = NULL;
}
- else {
- /*
- * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
- * With an empty lp->first_skb, we need to do this ourselves
- */
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH);
- }
+ if(! lp->first_skb) isdn_net_lp_xon(lp);
return 1;
}
break;
@@ -1203,7 +1232,6 @@
* standard send-routine, else send directly.
*
* Return: 0 on success, !0 on failure.
- * Side-effects: ndev->tbusy is cleared on success.
*/
int
isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
@@ -1215,13 +1243,11 @@
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret == len) {
lp->transcount += len;
- clear_bit(0, (void *) &(ndev->tbusy));
return 0;
}
if (ret < 0) {
dev_kfree_skb(skb);
lp->stats.tx_errors++;
- clear_bit(0, (void *) &(ndev->tbusy));
return 0;
}
return 1;
@@ -1267,7 +1293,7 @@
if (lp->srobin == ndev)
ret = isdn_net_send_skb(ndev, lp, skb);
else
- ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin);
+ ret = isdn_net_start_xmit(skb, lp->srobin);
lp->srobin = (slp->slave) ? slp->slave : ndev;
slp = (isdn_net_local *) (lp->srobin->priv);
if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
@@ -1327,8 +1353,8 @@
if (!lp->dialstate)
lp->stats.tx_errors++;
ndev->trans_start = jiffies;
+ isdn_net_dev_xon(ndev);
}
- ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
#ifdef CONFIG_ISDN_X25
/* At this point hard_start_xmit() passes control to the encapsulation
protocol (if present).
@@ -1342,7 +1368,9 @@
when a dl_establish request is received from the upper layer.
*/
if( cprot ) {
- return cprot -> pops -> encap_and_xmit ( cprot , skb);
+ int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
+ if(ret) isdn_net_dev_xoff(ndev);
+ return ret;
} else
#endif
/* auto-dialing xmit function */
@@ -1361,7 +1389,6 @@
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
dev_kfree_skb(skb);
- ndev->tbusy = 0;
return 0;
}
if (lp->phone[1]) {
@@ -1377,7 +1404,6 @@
if(jiffies < lp->dialwait_timer) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
- ndev->tbusy = 0;
restore_flags(flags);
return 0;
} else
@@ -1401,7 +1427,6 @@
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
- ndev->tbusy = 0;
return 0;
}
/* Log packet, which triggered dialing */
@@ -1421,6 +1446,7 @@
}
restore_flags(flags);
isdn_net_dial(); /* Initiate dialing */
+ isdn_net_dev_xoff(ndev);
return 1; /* let upper layer requeue skb packet */
}
#endif
@@ -1434,7 +1460,6 @@
}
lp->first_skb = skb;
/* Initiate dialing */
- ndev->tbusy = 0;
restore_flags(flags);
isdn_net_dial();
return 0;
@@ -1442,21 +1467,26 @@
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
- ndev->tbusy = 0;
return 0;
}
} else {
- /* Connection is established, try sending */
+ /* Device is connected to an ISDN channel */
ndev->trans_start = jiffies;
if (!lp->dialstate) {
+ /* ISDN connection is established, try sending */
+ int ret;
if (lp->first_skb) {
- if (isdn_net_xmit(ndev, lp, lp->first_skb))
+ if (isdn_net_xmit(ndev, lp, lp->first_skb)){
+ isdn_net_dev_xoff(ndev);
return 1;
+}
lp->first_skb = NULL;
}
- return (isdn_net_xmit(ndev, lp, skb));
+ ret = (isdn_net_xmit(ndev, lp, skb));
+ if(ret) isdn_net_dev_xoff(ndev);
+ return ret;
} else
- ndev->tbusy = 1;
+ isdn_net_dev_xoff(ndev);
}
}
return 1;



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:54    [W:1.956 / U:0.004 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site