From 4b99dcc37d1a622a42e560991e71ba0c59a6c01d Mon Sep 17 00:00:00 2001 From: Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> Date: Tue, 1 Oct 2002 03:07:24 -0500 Subject: [PATCH] ISDN: Use list.h list for list of online channels Cleaner and less error-prone than the open coded doubly linked list. --- drivers/isdn/i4l/isdn_net.c | 39 +++++++++++++------------- drivers/isdn/i4l/isdn_net.h | 56 +++++++++++++------------------------ drivers/isdn/i4l/isdn_ppp.c | 8 ++---- include/linux/isdn.h | 10 +++---- 4 files changed, 47 insertions(+), 66 deletions(-) diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 7d3b3d8962b4..af241fadf8ed 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -126,9 +126,9 @@ isdn_net_dev_stop_queue(isdn_net_dev *idev) static inline int isdn_net_device_busy(isdn_net_dev *idev) { - isdn_net_dev *ndev; isdn_net_local *mlp; unsigned long flags; + int retval = 1; if (!isdn_net_dev_busy(idev)) return 0; @@ -138,17 +138,15 @@ isdn_net_device_busy(isdn_net_dev *idev) else mlp = &idev->local; - spin_lock_irqsave(&mlp->queue_lock, flags); - ndev = idev->next; - while (ndev != idev) { - if (!isdn_net_dev_busy(ndev)) { - spin_unlock_irqrestore(&mlp->queue_lock, flags); - return 0; + spin_lock_irqsave(&mlp->online_lock, flags); + list_for_each_entry(idev, &mlp->online, online) { + if (!isdn_net_dev_busy(idev)) { + retval = 0; + break; } - ndev = ndev->next; } - spin_unlock_irqrestore(&mlp->queue_lock, flags); - return 1; + spin_unlock_irqrestore(&mlp->online_lock, flags); + return retval; } static inline @@ -394,10 +392,14 @@ static void isdn_net_connected(isdn_net_dev *idev) add_timer(&idev->hup_timer); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { - if (idev->master) { /* is lp a slave? */ - isdn_net_local *mlp = idev->master; - isdn_net_add_to_bundle(mlp, idev); - } + isdn_net_local *mlp; + + if (idev->master) + mlp = idev->master; + else + mlp = &idev->local; + + isdn_net_add_to_bundle(mlp, idev); } printk(KERN_INFO "isdn_net: %s connected\n", idev->name); /* If first Chargeinfo comes before B-Channel connect, @@ -994,7 +996,8 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) idev->sqfull = 0; } /* this is a hack to allow auto-hangup for slaves on moderate loads */ - mlp->queue = mlp->netdev; + list_del(&mlp->online); + list_add_tail(&mlp->online, &lp->netdev->online); } return retv; @@ -1581,11 +1584,9 @@ isdn_net_new(char *name, struct net_device *master) } netdev->local.magic = ISDN_NET_MAGIC; - netdev->local.queue = netdev; - spin_lock_init(&netdev->local.queue_lock); + INIT_LIST_HEAD(&netdev->local.online); + spin_lock_init(&netdev->local.online_lock); - netdev->last = netdev; - netdev->next = netdev; netdev->local.netdev = netdev; tasklet_init(&netdev->tlet, isdn_net_tasklet, (unsigned long) netdev); diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index f14ac3dc0cb0..0876c6570a1b 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -87,26 +87,23 @@ isdn_net_get_locked_dev(isdn_net_local *mlp) { unsigned long flags; isdn_net_dev *idev; - isdn_net_dev *head; - spin_lock_irqsave(&mlp->queue_lock, flags); - head = mlp->queue; - idev = head; - spin_lock_bh(&idev->xmit_lock); - while (isdn_net_dev_busy(idev)) { - spin_unlock_bh(&idev->xmit_lock); - mlp->queue = mlp->queue->next; - idev = mlp->queue; - if (idev == head) { /* not found -- should never happen */ - idev = NULL; - goto errout; - } + spin_lock_irqsave(&mlp->online_lock, flags); + + list_for_each_entry(idev, &mlp->online, online) { spin_lock_bh(&idev->xmit_lock); + if (!isdn_net_dev_busy(idev)) { + /* point the head to next online channel */ + list_del(&mlp->online); + list_add(&mlp->online, &idev->online); + goto found; + } + spin_unlock_bh(&idev->xmit_lock); } - idev = mlp->queue; - mlp->queue = mlp->queue->next; -errout: - spin_unlock_irqrestore(&mlp->queue_lock, flags); + idev = NULL; + + found: + spin_unlock_irqrestore(&mlp->online_lock, flags); return idev; } @@ -116,19 +113,11 @@ isdn_net_get_locked_dev(isdn_net_local *mlp) static inline void isdn_net_add_to_bundle(isdn_net_local *mlp, isdn_net_dev *idev) { - isdn_net_dev *qdev; unsigned long flags; - spin_lock_irqsave(&mlp->queue_lock, flags); - - qdev = mlp->queue; - idev->last = qdev->last; - qdev->last->next = idev; - qdev->last = idev; - idev->next = qdev; - mlp->queue = idev; - - spin_unlock_irqrestore(&mlp->queue_lock, flags); + spin_lock_irqsave(&mlp->online_lock, flags); + list_add(&idev->online, &mlp->online); + spin_unlock_irqrestore(&mlp->online_lock, flags); } /* * remove a channel from the bundle it belongs to @@ -144,14 +133,9 @@ isdn_net_rm_from_bundle(isdn_net_dev *idev) else mlp = &idev->local; - spin_lock_irqsave(&mlp->queue_lock, flags); - idev->last->next = idev->next; - idev->next->last = idev->last; - if (mlp->queue == idev) { - mlp->queue = idev->next; - } - idev->next = idev->last = idev; /* (re)set own pointers */ - spin_unlock_irqrestore(&mlp->queue_lock, flags); + spin_lock_irqsave(&mlp->online_lock, flags); + list_del(&idev->online); + spin_unlock_irqrestore(&mlp->online_lock, flags); } /* diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index edf82f6bff1b..94f95dbe9e16 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1396,7 +1396,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) is->mp_seqno = 0; if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) return -ENOMEM; - idev->next = idev->last = idev; /* nobody else in a queue */ + lp->netdev->pb->frags = NULL; lp->netdev->pb->frames = 0; lp->netdev->pb->seq = LONG_MAX; @@ -1468,7 +1468,7 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, /* find the minimum received sequence number over all links */ is->last_link_seqno = minseq = newseq; - for (qdev = lp->queue;;) { + list_for_each_entry(qdev, &lp->online, online) { slot = qdev->ppp_slot; if (slot < 0 || slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", @@ -1478,8 +1478,6 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, if (MP_LT(lls, minseq)) minseq = lls; } - if ((qdev = qdev->next) == lp->queue) - break; } if (MP_LT(minseq, mp->seq)) minseq = mp->seq; /* can't go beyond already processed @@ -1781,7 +1779,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit) spin_lock_irqsave(&p->pb->lock, flags); nidev = is->idev; - idev = p->local.queue; + idev = list_entry(p->local.online.next, isdn_net_dev, online); if( nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS || idev ->ppp_slot < 0 || idev ->ppp_slot >= ISDN_MAX_CHANNELS ) { printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n", diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 89ab9c70e193..3bd1f510b71b 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -336,10 +336,10 @@ typedef struct isdn_net_local_s { /* phone[1] = Outgoing Numbers */ struct isdn_net_dev_s *netdev; /* Ptr to netdev */ - struct isdn_net_dev_s *queue; /* circular list of all bundled + struct list_head online; /* circular list of all bundled channels, which are currently online */ - spinlock_t queue_lock; /* lock to protect queue */ + spinlock_t online_lock; /* lock to protect queue */ #ifdef CONFIG_ISDN_X25 struct concap_device_ops *dops; /* callbacks used by encapsulator */ @@ -404,12 +404,10 @@ typedef struct isdn_net_dev_s { isdn_net_local *master; /* Ptr to Master device for slaves */ struct isdn_net_dev_s *slave; /* Ptr to Slave device for masters */ - struct isdn_net_dev_s *next; /* Ptr to next link in bundle */ - struct isdn_net_dev_s *last; /* Ptr to last link in bundle */ - + struct list_head online; /* Members of local->online */ char name[10]; /* Name of device */ - struct list_head global_list; /* global list of all isdn_net_devs */ + struct list_head global_list; /* global list of all isdn_net_devs */ #ifdef CONFIG_ISDN_PPP ippp_bundle * pb; /* pointer to the common bundle structure * with the per-bundle data */ -- 2.30.9