src/ssx/occhw/occhw_async_ocb.c
/// Non-blocking write to an OCB PULL (write) queue
///
/// \param queue The target OcbQueue
///
/// \param buf The caller's data buffer containing the write data
///
/// \param bytes The maximum number of bytes to write.  This value must be an
/// even multiple of 8, as this API always writes multiples of 8 bytes.
///
/// \param written The number of bytes actually copied from the caller's buffer to
/// the device buffer.  This may be returned as any value from 0 to \a
/// bytes in multiples of 8 bytes.
///
/// ocb_write() implements a non-blocking copy of data to an OCB write (PULL)
/// queue, with the side effect of advancing the hardware queue pointers.
/// ocb_write() 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_write() may return an error code.  This may indicate a preexisting
/// error in the queue, or may be an error resulting from the current write.
/// In either event any write data should be considered corrupted/nondelivered.
///
/// \retval 0 Success
///
/// \retval -ASYNC_INVALID_ARGUMENT_OCB_WRITE The number of \a bytes is not
/// an even multiple of 8.
///
/// \retval -ASYNC_OCB_ERROR_WRITE_OLD or -ASYNC_OCB_ERROR_WRITE_NEW This code
/// indicates an error associated with the OCB channel represented by the queue.
Non-blocking write to an OCB PULL (write) queue
\param queue The target OcbQueue

\param buf The caller's data buffer containing the write data

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

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

ocb_write() implements a non-blocking copy of data to an OCB write (PULL)
queue, with the side effect of advancing the hardware queue pointers.
ocb_write() 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_write() may return an error code.  This may indicate a preexisting
error in the queue, or may be an error resulting from the current write.
In either event any write data should be considered corrupted/nondelivered.

\retval 0 Success

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

\retval -ASYNC_OCB_ERROR_WRITE_OLD or -ASYNC_OCB_ERROR_WRITE_NEW This code
indicates an error associated with the OCB channel represented by the queue.
Non - blocking write to an OCB PULL ( write ) queue \ param queue The target OcbQueue \ param buf The caller ' s data buffer containing the write data \ param bytes The maximum number of bytes to write . This value must be an even multiple of 8 as this API always writes multiples of 8 bytes . \ param written The number of bytes actually copied from the caller ' s buffer to the device buffer . This may be returned as any value from 0 to \ a bytes in multiples of 8 bytes . ocb_write () implements a non - blocking copy of data to an OCB write ( PULL ) queue with the side effect of advancing the hardware queue pointers . ocb_write () 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_write () may return an error code . This may indicate a preexisting error in the queue or may be an error resulting from the current write . In either event any write data should be considered corrupted / nondelivered . \ retval 0 Success \ retval - ASYNC_INVALID_ARGUMENT_OCB_WRITE The number of \ a bytes is not an even multiple of 8 . \ retval - ASYNC_OCB_ERROR_WRITE_OLD or - ASYNC_OCB_ERROR_WRITE_NEW This code indicates an error associated with the OCB channel represented by the queue .
int
ocb_write(OcbQueue* queue, void* buf, size_t bytes, size_t* written)
{
    ocb_ocbslcsn_t csr;
    ocb_ocbsesn_t ses;
    unsigned qlen, read_ptr, write_ptr, free;
    uint64_t* pcq, *pbuf;
    int rc;
    do
    {
        rc = 0;
        *written = 0;
        if (G_ocb_ffdc.channel[queue->engine / 2].error)
        {
            rc = -ASYNC_OCB_ERROR_WRITE_OLD;
            break;
        }
        if (bytes % 8)
        {
            rc = -ASYNC_INVALID_ARGUMENT_OCB_WRITE;
            break;
        }
        csr.value = in32(G_ocb_ocbsxcsn[queue->engine]);
        qlen = csr.fields.pull_length + 1;
        write_ptr = csr.fields.pull_write_ptr;
        if (csr.fields.pull_full)
        {
            break;
        }
        if (csr.fields.pull_empty)
        {
            free = qlen;
        }
        else
        {
            read_ptr = csr.fields.pull_read_ptr;
            if (write_ptr > read_ptr)
            {
                free = qlen - (write_ptr - read_ptr);
            }
            else
            {
                free = read_ptr - write_ptr;
            }
        }
         Here the code models the evolution of the write_ptr as each datum is
         copied into the queue.
        pbuf = (uint64_t*)buf;
        while (bytes && free--)
        {
            write_ptr++;
            if (write_ptr == qlen)
            {
                write_ptr = 0;
            }
            pcq = queue->cq_base + write_ptr;
            *pcq = *pbuf++;
            dcache_flush_line(pcq);
            in32(G_ocb_ocbsxin[queue->engine]);
            bytes -= 8;
            *written += 8;
        }
    }
    while (0);
     Check for overflow. If found, collect FFDC.
    ses.value = in32(G_ocb_ocbsesn[queue->engine / 2]);
    if (ses.fields.pull_write_overflow)
    {
        ocb_ffdc(queue->engine / 2);
        rc = -ASYNC_OCB_ERROR_WRITE_NEW;
    }
    return rc;
}
int ocb_write ( OcbQueue * queue , void * buf , size_t bytes , size_t * written ) { ocb_ocbslcsn_t csr ; ocb_ocbsesn_t ses ; unsigned qlen , read_ptr , write_ptr , free ; uint64_t * pcq , * pbuf ; int rc ; do { rc = 0 ; * written = 0 ; if ( G_ocb_ffdc . channel [ queue -> engine / 2 ] . error ) { rc = - ASYNC_OCB_ERROR_WRITE_OLD ; break ; } if ( bytes % 8 ) { rc = - ASYNC_INVALID_ARGUMENT_OCB_WRITE ; break ; } csr . value = in32 ( G_ocb_ocbsxcsn [ queue -> engine ] ) ; qlen = csr . fields . pull_length + 1 ; write_ptr = csr . fields . pull_write_ptr ; if ( csr . fields . pull_full ) { break ; } if ( csr . fields . pull_empty ) { free = qlen ; } else { read_ptr = csr . fields . pull_read_ptr ; if ( write_ptr > read_ptr ) { free = qlen - ( write_ptr - read_ptr ) ; } else { free = read_ptr - write_ptr ; } } pbuf = ( uint64_t * ) buf ; while ( bytes && free -- ) { write_ptr ++ ; if ( write_ptr == qlen ) { write_ptr = 0 ; } pcq = queue -> cq_base + write_ptr ; * pcq = * pbuf ++ ; dcache_flush_line ( pcq ) ; in32 ( G_ocb_ocbsxin [ queue -> engine ] ) ; bytes -= 8 ; * written += 8 ; } } while ( 0 ) ; ses . value = in32 ( G_ocb_ocbsesn [ queue -> engine / 2 ] ) ; if ( ses . fields . pull_write_overflow ) { ocb_ffdc ( queue -> engine / 2 ) ; rc = - ASYNC_OCB_ERROR_WRITE_NEW ; } return rc ; }
Non-blocking write to an OCB PULL (write) queue
\param queue The target OcbQueue
Non - blocking write to an OCB PULL ( write ) queue \ param queue The target OcbQueue
// Pre-existing errors immediately abort the read. // Determine the number of free doubleword entries remaining in the // queue. The driver does not keep state, but instead reinterprets the // control/status register each time the write method is called. // This is confusing - remember that 'push' and 'pull' are from the PIB // perspective - here we use 'read' and 'write' from OCC's perspective. // Copy the data into the CQ memory area.  For simplicty of dealing // with cache management each doubleword invokes a line flush before // incrementing the hardware pointer. Alignment requirements enforced // on the data buffer guarantee each doubleword is fully contained in // a single D-cache line. // // Here the code models the evolution of the write_ptr as each datum is // copied into the queue. // Check for overflow. If found, collect FFDC.