Messages in this thread Patch in this message | | | Date | Sat, 2 Oct 1999 13:13:44 +0200 | From | Henner Eisen <> | Subject | ISDN 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/
| |