src/ssx/occhw/occhw_async_ocb.c
/// Non-blocking read from an OCB PUSH (read) queue
///
/// \param queue The target OcbQueue
///
/// \param buf The caller's data buffer to receive the read data
///
/// \param bytes The maximum number of bytes to read.  This value must be an
/// even multiple of 8, as this API always reads multiples of 8 bytes.
///
/// \param read The number of bytes actually copied from the device buffer to
/// the caller's buffer.  This may be returned as any value from 0 to \a
/// bytes in multiples of 8 bytes.
///
/// ocb_read() implements a non-blocking copy of data from an OCB read (PUSH)
/// queue data area to the caller's data area, with the side effect of
/// advancing the hardware queue pointers.  ocb_read() does not implement
/// locking, critical sections or any other type of synchronization for access
/// to the OCB queue data - that is the responsibility of the caller.
///
/// ocb_read() may return an error code.  This may indicate a preexisting
/// error in the queue, or may be an error resulting from the current read.
/// In either event any read data should be considered corrupted.
///
/// \retval 0 Success
///
/// \retval -ASYNC_INVALID_ARGUMENT_OCB_READ The number of \a bytes is not
/// an even multiple of 8.
///
/// \retval -ASYNC_OCB_ERROR_READ_OLD or -ASYNC_OCB_ERROR_READ_NEW This code
/// indicates an error associated with the OCB channel represented by the queue.
Non-blocking read from an OCB PUSH (read) queue
\param queue The target OcbQueue

\param buf The caller's data buffer to receive the read data

\param bytes The maximum number of bytes to read.  This value must be an
even multiple of 8, as this API always reads multiples of 8 bytes.

\param read The number of bytes actually copied from the device buffer to
the caller's buffer.  This may be returned as any value from 0 to \a
bytes in multiples of 8 bytes.

ocb_read() implements a non-blocking copy of data from an OCB read (PUSH)
queue data area to the caller's data area, with the side effect of
advancing the hardware queue pointers.  ocb_read() does not implement
locking, critical sections or any other type of synchronization for access
to the OCB queue data - that is the responsibility of the caller.

ocb_read() may return an error code.  This may indicate a preexisting
error in the queue, or may be an error resulting from the current read.
In either event any read data should be considered corrupted.

\retval 0 Success

\retval -ASYNC_INVALID_ARGUMENT_OCB_READ The number of \a bytes is not
an even multiple of 8.

\retval -ASYNC_OCB_ERROR_READ_OLD or -ASYNC_OCB_ERROR_READ_NEW This code
indicates an error associated with the OCB channel represented by the queue.
Non - blocking read from an OCB PUSH ( read ) queue \ param queue The target OcbQueue \ param buf The caller ' s data buffer to receive the read data \ param bytes The maximum number of bytes to read . This value must be an even multiple of 8 as this API always reads multiples of 8 bytes . \ param read The number of bytes actually copied from the device buffer to the caller ' s buffer . This may be returned as any value from 0 to \ a bytes in multiples of 8 bytes . ocb_read () implements a non - blocking copy of data from an OCB read ( PUSH ) queue data area to the caller ' s data area with the side effect of advancing the hardware queue pointers . ocb_read () does not implement locking critical sections or any other type of synchronization for access to the OCB queue data - that is the responsibility of the caller . ocb_read () may return an error code . This may indicate a preexisting error in the queue or may be an error resulting from the current read . In either event any read data should be considered corrupted . \ retval 0 Success \ retval - ASYNC_INVALID_ARGUMENT_OCB_READ The number of \ a bytes is not an even multiple of 8 . \ retval - ASYNC_OCB_ERROR_READ_OLD or - ASYNC_OCB_ERROR_READ_NEW This code indicates an error associated with the OCB channel represented by the queue .
int
ocb_read(OcbQueue* queue, void* buf, size_t bytes, size_t* read)
{
    ocb_ocbshcsn_t csr;
    ocb_ocbsesn_t ses;
    unsigned qlen, read_ptr, write_ptr, to_read;
    uint64_t* pcq, *pbuf;
    int rc;
    do
    {
        rc = 0;
        *read = 0;
        if (G_ocb_ffdc.channel[queue->engine / 2].error)
        {
            rc = -ASYNC_OCB_ERROR_READ_OLD;
            break;
        }
        if (bytes % 8)
        {
            rc = -ASYNC_INVALID_ARGUMENT_OCB_READ;
            break;
        }
        csr.value = in32(G_ocb_ocbsxcsn[queue->engine]);
        qlen = csr.fields.push_length + 1;
        read_ptr = csr.fields.push_read_ptr;
        if (csr.fields.push_empty)
        {
            break;
        }
        else if (csr.fields.push_full)
        {
            to_read = qlen;
        }
        else
        {
            write_ptr = csr.fields.push_write_ptr;
            if (read_ptr > write_ptr)
            {
                to_read = qlen - (read_ptr - write_ptr);
            }
            else
            {
                to_read = write_ptr - read_ptr;
            }
        }
         Here the code models the evolution of the read_ptr as each datum is
         copied from the queue.
        pbuf = (uint64_t*)buf;
        while (bytes && to_read--)
        {
            read_ptr++;
            if (read_ptr == qlen)
            {
                read_ptr = 0;
            }
            pcq = queue->cq_base + read_ptr;
            dcache_invalidate_line(pcq);
            *pbuf++ = *pcq;
            out32(G_ocb_ocbsxin[queue->engine], 0);
            bytes -= 8;
            *read += 8;
        }
    }
    while (0);
     Check for underflow errors. If found, collect FFDC.
    ses.value = in32(G_ocb_ocbsesn[queue->engine / 2]);
    if (ses.fields.push_read_underflow)
    {
        ocb_ffdc(queue->engine / 2);
        rc = -ASYNC_OCB_ERROR_READ_NEW;
    }
    return rc;
}
int ocb_read ( OcbQueue * queue , void * buf , size_t bytes , size_t * read ) { ocb_ocbshcsn_t csr ; ocb_ocbsesn_t ses ; unsigned qlen , read_ptr , write_ptr , to_read ; uint64_t * pcq , * pbuf ; int rc ; do { rc = 0 ; * read = 0 ; if ( G_ocb_ffdc . channel [ queue -> engine / 2 ] . error ) { rc = - ASYNC_OCB_ERROR_READ_OLD ; break ; } if ( bytes % 8 ) { rc = - ASYNC_INVALID_ARGUMENT_OCB_READ ; break ; } csr . value = in32 ( G_ocb_ocbsxcsn [ queue -> engine ] ) ; qlen = csr . fields . push_length + 1 ; read_ptr = csr . fields . push_read_ptr ; if ( csr . fields . push_empty ) { break ; } else if ( csr . fields . push_full ) { to_read = qlen ; } else { write_ptr = csr . fields . push_write_ptr ; if ( read_ptr > write_ptr ) { to_read = qlen - ( read_ptr - write_ptr ) ; } else { to_read = write_ptr - read_ptr ; } } pbuf = ( uint64_t * ) buf ; while ( bytes && to_read -- ) { read_ptr ++ ; if ( read_ptr == qlen ) { read_ptr = 0 ; } pcq = queue -> cq_base + read_ptr ; dcache_invalidate_line ( pcq ) ; * pbuf ++ = * pcq ; out32 ( G_ocb_ocbsxin [ queue -> engine ] , 0 ) ; bytes -= 8 ; * read += 8 ; } } while ( 0 ) ; ses . value = in32 ( G_ocb_ocbsesn [ queue -> engine / 2 ] ) ; if ( ses . fields . push_read_underflow ) { ocb_ffdc ( queue -> engine / 2 ) ; rc = - ASYNC_OCB_ERROR_READ_NEW ; } return rc ; }
Non-blocking read from an OCB PUSH (read) queue
\param queue The target OcbQueue
Non - blocking read from an OCB PUSH ( read ) queue \ param queue The target OcbQueue
// If pre-existing errors exist then immediately abort the read. // Determine the number of doubleword entries remaining to be read in // the queue. The driver does not keep state, but instead reinterprets // the control/status register each time ocb_read() is called. // This may be confusing - remember that 'push' and 'pull' are from // the PIB perspective - here we use 'read' and 'write' from OCC's // perspective. // Copy the data from the CQ memory area to the user's buffer.  For // simplicty of dealing with cache management each doubleword invokes // a line invalidate before refetching the fresh data from // memory. Alignment requirements enforced on the data buffer // guarantee the buffers are cache-line aligned and each doubleword is // fully contained in a single D-cache line. // // Here the code models the evolution of the read_ptr as each datum is // copied from the queue. // Check for underflow errors. If found, collect FFDC.