lkml.org 
[lkml]   [2002]   [Aug]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject[PATCH 2.5] : ir255_nsc_speed-4.diff
    From
    ir255_nsc_speed-4.diff :
    ----------------------
    o [FEATURE] Cleanly change speed back to 9600bps
    o [CORRECT] Change speed under spinlock/irq disabled
    o [CORRECT] Make sure interrupt handlers don't mess irq mask
    o [CORRECT] Don't change speed if we haven't fully finished to Tx


    diff -u -p linux/include/net/irda/nsc-ircc.d2.h linux/include/net/irda/nsc-ircc.h
    --- linux/include/net/irda/nsc-ircc.d2.h Mon Jul 15 16:13:58 2002
    +++ linux/include/net/irda/nsc-ircc.h Mon Jul 15 16:18:55 2002
    @@ -253,6 +253,7 @@ struct nsc_ircc_cb {

    __u32 flags; /* Interface flags */
    __u32 new_speed;
    + int speed_cnt; /* Number of frames before speed change */
    int index; /* Instance index */

    struct pm_dev *dev;
    diff -u -p linux/drivers/net/irda/nsc-ircc.d2.c linux/drivers/net/irda/nsc-ircc.c
    --- linux/drivers/net/irda/nsc-ircc.d2.c Mon Jul 15 15:42:50 2002
    +++ linux/drivers/net/irda/nsc-ircc.c Tue Jul 16 10:43:37 2002
    @@ -953,6 +953,7 @@ static void nsc_ircc_change_dongle_speed
    *
    * Change the speed of the device
    *
    + * This function *must* be called with irq off and spin-lock.
    */
    static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
    {
    @@ -1048,7 +1049,6 @@ static void nsc_ircc_change_speed(struct

    /* Restore BSR */
    outb(bank, iobase+BSR);
    - netif_wake_queue(dev);

    }

    @@ -1074,20 +1074,30 @@ static int nsc_ircc_hard_xmit_sir(struct

    netif_stop_queue(dev);

    + /* Make sure tests *& speed change are atomic */
    + spin_lock_irqsave(&self->lock, flags);
    +
    /* Check if we need to change the speed */
    speed = irda_get_next_speed(skb);
    if ((speed != self->io.speed) && (speed != -1)) {
    - /* Check for empty frame */
    + /* Check for empty frame. */
    if (!skb->len) {
    - nsc_ircc_change_speed(self, speed);
    + /* If we just sent a frame, we get called before
    + * the last bytes get out (because of the SIR FIFO).
    + * If this is the case, let interrupt handler change
    + * the speed itself... Jean II */
    + if (self->io.direction == IO_RECV)
    + nsc_ircc_change_speed(self, speed);
    + else
    + self->new_speed = speed;
    + spin_unlock_irqrestore(&self->lock, flags);
    dev_kfree_skb(skb);
    + netif_wake_queue(dev);
    return 0;
    } else
    self->new_speed = speed;
    }

    - spin_lock_irqsave(&self->lock, flags);
    -
    /* Save current bank */
    bank = inb(iobase+BSR);

    @@ -1126,20 +1136,34 @@ static int nsc_ircc_hard_xmit_fir(struct

    netif_stop_queue(dev);

    + /* Make sure tests *& speed change are atomic */
    + spin_lock_irqsave(&self->lock, flags);
    +
    /* Check if we need to change the speed */
    speed = irda_get_next_speed(skb);
    if ((speed != self->io.speed) && (speed != -1)) {
    - /* Check for empty frame */
    + /* Check for empty frame. */
    if (!skb->len) {
    - nsc_ircc_change_speed(self, speed);
    + /* If we are currently transmitting, defer to
    + * interrupt handler. - Jean II */
    + if(self->tx_fifo.len == 0)
    + nsc_ircc_change_speed(self, speed);
    + else {
    + self->new_speed = speed;
    + self->speed_cnt = self->tx_fifo.len;
    + }
    + spin_unlock_irqrestore(&self->lock, flags);
    dev_kfree_skb(skb);
    + netif_wake_queue(dev);
    return 0;
    - } else
    + } else {
    self->new_speed = speed;
    + /* Save the number of frames currently in the fifo
    + * so that we know *when* to change the speed. */
    + self->speed_cnt = self->tx_fifo.len + 1;
    + }
    }

    - spin_lock_irqsave(&self->lock, flags);
    -
    /* Save current bank */
    bank = inb(iobase+BSR);

    @@ -1334,16 +1358,23 @@ static int nsc_ircc_dma_xmit_complete(st
    self->stats.tx_packets++;
    }

    - /* Check if we need to change the speed */
    - if (self->new_speed) {
    - nsc_ircc_change_speed(self, self->new_speed);
    - self->new_speed = 0;
    - }
    -
    /* Finished with this frame, so prepare for next */
    self->tx_fifo.ptr++;
    self->tx_fifo.len--;

    + /* Check if we need to change the speed.
    + * Do it after self->tx_fifo.len--; to avoid races with
    + * nsc_ircc_hard_xmit_fir().
    + * We do it synchronous to the packets in the fifo, so that's
    + * why we wait for the right frame to do it. - Jean II */
    + if ((self->new_speed) && (--self->speed_cnt == 0)) {
    + /* There seem to be some issue with corrupting the
    + * frame just before a speed change. Workaround. Jean II */
    + udelay(100);
    + nsc_ircc_change_speed(self, self->new_speed);
    + self->new_speed = 0;
    + }
    +
    /* Any frames to be sent back-to-back? */
    if (self->tx_fifo.len) {
    nsc_ircc_dma_xmit(self, iobase);
    @@ -1634,7 +1665,12 @@ static void nsc_ircc_sir_interrupt(struc
    }
    /* Check if transmission has completed */
    if (eir & EIR_TXEMP_EV) {
    - /* Check if we need to change the speed? */
    + /* Turn around and get ready to receive some data */
    + self->io.direction = IO_RECV;
    + self->ier = IER_RXHDL_IE;
    + /* Check if we need to change the speed?
    + * Need to be after self->io.direction to avoid race with
    + * nsc_ircc_hard_xmit_sir() - Jean II */
    if (self->new_speed) {
    IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
    nsc_ircc_change_speed(self, self->new_speed);
    @@ -1649,9 +1685,6 @@ static void nsc_ircc_sir_interrupt(struc
    return;
    }
    }
    - /* Turn around and get ready to receive some data */
    - self->io.direction = IO_RECV;
    - self->ier = IER_RXHDL_IE;
    }

    /* Rx FIFO threshold or timeout */
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-03-22 13:28    [W:0.031 / U:2.268 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site