netdev
[Top] [All Lists]

Re: ppp control frame passing (was: (none) / Re: your mail)

To: kuznet@xxxxxxxxxxxxx
Subject: Re: ppp control frame passing (was: (none) / Re: your mail)
From: Kai Germaschewski <kai@xxxxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 22 Mar 2000 11:55:27 +0100 (CET)
Cc: netdev@xxxxxxxxxxx, ak@xxxxxx, eis@xxxxxxxxxxxxx
Sender: owner-netdev@xxxxxxxxxxx
>     >> Worse, even if we encode the channel into the skb somehow,
>     >> flow control is a problem. Flow control works the obvious way,
>     >> i.e. netif_stop_queue() if all channels are busy and
>     >> netif_wake_queue() if at least one channel becomes non-busy. So
>     >> now hard_start_xmit() might give us the control frame for a
>     >> specific channel, which could still be busy though, because we
>     >> just know that (any) one channel is non-busy.

> Alert!!! Try to avoid this. This system has _no_ support for multiple
> hardware queues. Essentially, you have two choices: to send control 
> frames
> internally without dev_queue_xmit() (it is easy), or to move channel
> demultiplexing to special qdisc (f.e. as sch_atm does). It is still not
> clear how support for multiple hardware queues can be organized. I am
> inclined to believe that it is simply not well-defined task. Probably,
> it
> is better to try to move channel multiplexing out of hardware level.

Okay, for the time being I went for the former solution, i.e. I do send
control frames internally.

BTW: Sorry for the late reply, this list's lag is incredible.

Just one more question, about backporting: spinlock_bh doesn't exist in
2.2 AFAICS, I guess I need to use spinlock_irqsave?

I'd be very happy if someone could comment on the locking/procedure
I used - thanks!

isdn_net_writebuf_skb(channel, skb)
{
        /* we are guaranteed that this channel is not (yet) busy */
        /* channel is always protected by channel->xmit_lock spinlock */

        write skb to channel;
        atomic_inc (&channel->frame_cnt);
        if (all channels in this bundle busy) {
              /* a channel is busy if channel->frame_cnt >= 2) */
              netif_stop_queue();
        }
}

isdn_net_stat_callback(channel)
/* this is called from hardware channel when frame has actually been sent
   down the line */
/* this may be called in hard-irq context, so we use the task queue
   for sending (don't want to call isdn_net_writebuf_skb() in irq
   context) */
{
        atomic_dec(&channel->frame_cnt);
        if (!(channel_busy(channel))) {
                if (!skb_queue_empty(&channel->super_tx_queue)) { 
                        /* if there is supervisory data waiting,
                           send it first */
                        queue_task(&lchannel->tqueue, &tq_immediate);  
                } else { 
                        netif_wake_queue();
                }
        }
}

where the task on tq_immediate would do the following:
{
        spin_lock_bh(&channel->xmit_lock);
        while (!isdn_net_lp_busy(channel)) {
                skb = skb_dequeue(&channel->super_tx_queue);
                if (!skb)
                        break;  
                isdn_net_writebuf_skb(channel, skb);
        }
        spin_unlock_bh(&channel->xmit_lock);
}


isdn_net_hard_start_xmit(net_device, skb)
{
        for all channels in bundle(net_device) {
                spin_lock_bh(&channel->xmit_lock)
                if (!(channel_busy(channel))
                        break;
                spin_unlock_bh(&channel->xmit_lock)
        }

        if (!channel) /* no non-busy channel found */
               return 1;

        isdn_net_writebuf_skb(channel, skb)
        spin_unlock_bh(&channel->xmit_lock);
        return 0;
}

isdn_net_write_super(channel, skb)
/* this can be called from task queue / process / timer */
/* we send the skb directly if possible, if not we queue it
   on channel->super_tx_queue */
{
        spin_lock_bh(&channel->xmit_lock); }
        if (!channel_busy(channel)) {
                isdn_net_writebuf_skb(channel, skb);
        } else {
                skb_queue_tail(&channel->super_tx_queue, skb);
        }
        spin_unlock_bh(&channel->xmit_lock);
}



<Prev in Thread] Current Thread [Next in Thread>