• Thomas Gleixner's avatar
    can: c_can: Reduce register access · c0a9f4d3
    Thomas Gleixner authored
    commit 4ce78a83 (can: c_can: Speed up rx_poll function) hyped a
    performance improvement by reducing the access to the interrupt
    pending register from a dual 16 bit to a single 16 bit access. Wow!
    
    Thereby it crippled the driver to cast the 16 msg objects in stone,
    which is completly braindead as contemporary hardware has up to 128
    message objects. Supporting larger object buffers is a major surgery,
    but it'd be definitely worth it especially as the driver does not
    support HW message filtering ....
    
    The logic of the "FIFO" implementation is to split the FIFO in half.
    
    For the lower half we read the buffers and clear the interrupt pending
    bit, but keep the newdat bit set, so the HW will queue above those
    buffers.
    
    When we read out the last low buffer then we reenable all the low half
    buffers by clearing the newdat bit.
    
    The upper half buffers clear the newdat and the interrupt pending bit
    right away as we know that the lower half bits are clear and give us a
    headstart against the hardware.
    
    Now the implementation is:
    
        transfer_message_object()
        read_object_and_put_into_skb();
    
        if (obj < END_OF_LOW_BUF)
           clear_intpending(obj)
        else if (obj > END_OF_LOW_BUF)
           clear_intpending_and_newdat(obj)
        else if (obj == END_OF_LOW_BUF)
           clear_newdat_of_all_low_objects()
    
    The hardware allows to avoid most of the mess simply because we can
    tell the transfer_message_object() function to clear bits right away.
    
    So we can be clever and do:
    
       if (obj <= END_OF_LOW_BUF)
          ctrl = TRANSFER_MSG | CLEAR_INTPND;
       else
          ctrl = TRANSFER_MSG | CLEAR_INTPND | CLEAR_NEWDAT;
    
        transfer_message_object(ctrl)
        read_object_and_put_into_skb();
    
        if (obj == END_OF_LOW_BUF)
           clear_newdat_of_all_low_objects()
    
    So we save a complete control operation on all message objects except
    the one which is the end of the low buffer. That's a few micro seconds
    per object.
    
    I'm not adding a boasting profile to that, simply because it's self
    explaining.
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    [mkl: adjusted subject and commit message]
    Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
    c0a9f4d3
c_can.c 36 KB