Commit 4b99dcc3 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Use list.h list for list of online channels

Cleaner and less error-prone than the open coded doubly linked
list.
parent 7b0b00eb
......@@ -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);
......
......@@ -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);
}
/*
......
......@@ -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",
......
......@@ -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 */
......
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