libnfb examples

Simple access to the control registers

This example will perform some writes and reads to the user component in the firmware.

#include <nfb/nfb.h>

#define SUPERCORE_REG_CMD           0x00
#define SUPERCORE_REG_CMD_ADD       (1 << 0)
#define SUPERCORE_REG_CMD_MULT      (1 << 1)

#define SUPERCORE_REG_STATUS        0x04
#define SUPERCORE_REG_DATA          0x08

int main(int argc, char *argv[])
{
    int node;

    /* This is the path to device node, you can use
       - NULL or default: nfb_default_dev_path()
       - full path:       "/dev/nfb0"
         or its shortcut: "0"
       - persistent path: "/dev/nfb/by-pci-slot/0000:03:00.0"
                          "/dev/nfb/by-serial-no/COMBO-400G1/15432"
    */
    const char *path = nfb_default_dev_path();

    struct nfb_device *dev;
    struct nfb_comp *comp;

    /* Get handle to NFB device for futher operation */
    dev = nfb_open(path);
    if (!dev)
        errx(1, "Can't open device file");

    /* Find first supercore unit in Device Tree and get its FDT node offset */
    node = nfb_comp_find(dev, "mycompany,supercore", 0);

    /* Get access to the component described with Device Tree node */
    comp = nfb_comp_open(dev, node);
    if (comp == NULL)
        errx(2, "Can't open component");

    /* Perform some writes and reads to the acceleration core */
    nfb_comp_write64(comp, SUPERCORE_REG_DATA, 0xBEEFBEEFBEEFBEEFll);
    nfb_comp_write32(comp, SUPERCORE_REG_CMD, SUPERCORE_REG_CMD_ADD);

    if (nfb_comp_read8(comp, SUPERCORE_REG_STATUS) != 0)
        errx(3, "Operation ADD failed");

    /* Cleanup */
    nfb_comp_close(comp);
    nfb_close(dev);
    return 0;
}

Do not forget to compile with -lnfb switch.

NDP data transmit example

#include <stdio.h>
#include <nfb/nfb.h>
#include <nfb/ndp.h>

#define NDP_PACKET_COUNT 16

int main(int argc, char *argv[])
{
    int i, ret, bursts;
    struct nfb_device *dev;
    struct ndp_queue *rxq, *txq;
    struct ndp_packet pkts[NDP_PACKET_COUNT];

    /* Get handle to NFB device for futher operation */
    if ((dev = nfb_open("0")) == NULL)
        errx(1, "Can't open device file");

    /* Open one RX and one TX NDP queue for data transmit */
    rxq = ndp_open_rx_queue(dev, 0);
    txq = ndp_open_tx_queue(dev, 0);

    if (rxq == NULL || txq == NULL)
        errx(1, "Can't open queue");

    /* Start transmission on both queues */
    ndp_queue_start(rxq);
    ndp_queue_start(txq);

    for (i = 0; i < NDP_PACKET_COUNT; i++) {
        /* Request space for some packets */
        pkts[i].data_length = 64 + i;
        pkts[i].header_length = 0;
    }

    /* Request placeholders for packets with specified length */
    ret = ndp_tx_burst_get(txq, pkts, NDP_PACKET_COUNT);
    if (ret != NDP_PACKET_COUNT)
        warnx("Requested %d packet placeholders to send, got %d", NDP_PACKET_COUNT, ret);

    for (i = 0; i < ret; i++) {
        /* Fill data space with some values */
        memset(pkts[i].data, 0, pkts[i].data_length);
        /* Pretend IPv4 */
        pkts[i].data[13] = 0x08;
    }
    /* Optional PUT (rather just for symmetricity)
       Beware the PUT operation may not send immediately,
       it can wait for more packets to be PUTed for best throughput */
    // ndp_tx_burst_put(txq);

    /* Force send immediately (implies PUT) */
    ndp_tx_burst_flush(txq);

    /* Let try to receive some packets */
    for (bursts = 0; bursts < 32; bursts++) {
        /* Let the library fill at most NDP_PACKET_COUNT, but it may be less */
        ret = ndp_rx_burst_get(rxq, pkts, NDP_PACKET_COUNT);
        if (ret == 0) {
            usleep(10000);
            continue;
        }

        for (i = 0; i < ret; i++) {
            /* If the metadata is present, it typically holds packet timestamp at offset 0 */
            if (pkts[i].header_length >= 8)
                printf("Timestamp: %lld\n", *((uint64_t*) (pkts[i].header + 0)));
        }
        /* We must ensure the return of the processed packets
           (although this doesn't have to be done for every GET) */
        if ((bursts % 5) == 4)
            ndp_rx_burst_put(rxq);
    }

    ndp_rx_burst_put(rxq);

    /* Cleanup */
    ndp_close_tx_queue(txq);
    ndp_close_rx_queue(rxq);
    nfb_close(dev);
    return 0;
}