Beaglebone: Building rpmsg_lib.lib

This is the library of functions (rpmsg_lib.lib) and the header file to enable communication between the pru and the arm host.  This was developed by TI.  As of this writing (2/12/2017), these files are located in /opt/source/pru-software-support-package/lib/src/rpmsg_lib and /opt/source/pru-software-support-package/include

Put the header files under the /$(HOME) directory (where HOME:=the name of your home directory, e.g., /root) in a folder, e.g., include (/root/code/include in this example).

Put the source files in a different directory under /$(HOME) such as abw_lib (e.g., /root/code/rpmsg).

Here is the archive. This includes the header files, so you need to move them after unpacking the archive.

Although the files are called out below, there have been some issues with wordpress translating characters (e.g. “) and dropping characters (e.g. <) which may result in the files below needing some repair work.

$(HOME) = /root/code/

$(LIB) = $(HOME)rpmsg/

$(INCLUDE)=$(HOME)include/

pru_rpmsg.c

 /*
* Copyright (C) 2016 Texas Instruments Incorporated – http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*//**
* File : pru_rpmsg.c
*
* Summary : An RPMsg implementation for the PRU to use while communicating
* with the ARM host.
*
* Notes :
* – Implementaion of the interface described in “pru_rpmsg.h”
*/#include <pru_rpmsg.h>struct pru_rpmsg_hdr {
uint32_t src;
uint32_t dst;
uint32_t reserved;
uint16_t len;
uint16_t flags;
uint8_t data[0];
};struct pru_rpmsg_ns_msg {
char name[RPMSG_NAME_SIZE];
char desc[RPMSG_NAME_SIZE];
uint32_t addr;
uint32_t flags;
};int16_t pru_rpmsg_init(
struct pru_rpmsg_transport *transport,
struct fw_rsc_vdev_vring *vring0,
struct fw_rsc_vdev_vring *vring1,
uint32_t to_arm_event,
uint32_t from_arm_event
)
{
if (to_arm_event > MAX_VALID_EVENT || to_arm_event < MIN_VALID_EVENT)
return PRU_RPMSG_INVALID_EVENT;if (from_arm_event > MAX_VALID_EVENT || from_arm_event < MIN_VALID_EVENT)
return PRU_RPMSG_INVALID_EVENT;

pru_virtqueue_init(&transport->virtqueue0, vring0, to_arm_event, from_arm_event);
pru_virtqueue_init(&transport->virtqueue1, vring1, to_arm_event, from_arm_event);

return PRU_RPMSG_SUCCESS;
}

int16_t pru_rpmsg_send(
struct pru_rpmsg_transport *transport,
uint32_t src,
uint32_t dst,
void *data,
uint16_t len
)
{
struct pru_rpmsg_hdr *msg;
uint32_t msg_len;
int16_t head;
struct pru_virtqueue *virtqueue;

/*
* The length of our payload is larger than the maximum RPMsg buffer size
* allowed
*/
if (len > (RPMSG_BUF_SIZE – sizeof(struct pru_rpmsg_hdr)))
return PRU_RPMSG_BUF_TOO_SMALL;

virtqueue = &transport->virtqueue0;

/* Get an available buffer */
head = pru_virtqueue_get_avail_buf(virtqueue, (void **)&msg, &msg_len);

if (head < 0)
return PRU_RPMSG_NO_BUF_AVAILABLE;

/* Copy local data buffer to the descriptor buffer address */
memcpy(msg->data, data, len);
msg->len = len;
msg->dst = dst;
msg->src = src;
msg->flags = 0;
msg->reserved = 0;

/* Add the used buffer */
if (pru_virtqueue_add_used_buf(virtqueue, head, msg_len) < 0)
return PRU_RPMSG_INVALID_HEAD;

/* Kick the ARM host */
pru_virtqueue_kick(virtqueue);

return PRU_RPMSG_SUCCESS;
}

int16_t pru_rpmsg_receive(
struct pru_rpmsg_transport *transport,
uint16_t *src,
uint16_t *dst,
void *data,
uint16_t *len
)
{
int16_t head;
struct pru_rpmsg_hdr *msg;
uint32_t msg_len;
struct pru_virtqueue *virtqueue;

virtqueue = &transport->virtqueue1;

/* Get an available buffer */
head = pru_virtqueue_get_avail_buf(virtqueue, (void **)&msg, &msg_len);

if (head < 0)
return PRU_RPMSG_NO_BUF_AVAILABLE;

/* Copy the message payload to the local data buffer provided */
memcpy(data, msg->data, msg->len);
*src = msg->src;
*dst = msg->dst;
*len = msg->len;

/* Add the used buffer */
if (pru_virtqueue_add_used_buf(virtqueue, head, msg_len) < 0)
return PRU_RPMSG_INVALID_HEAD;

/* Kick the ARM host */
pru_virtqueue_kick(virtqueue);

return PRU_RPMSG_SUCCESS;
}

int16_t pru_rpmsg_channel(
enum pru_rpmsg_ns_flags flags,
struct pru_rpmsg_transport *transport,
char *name,
char *desc,
int32_t port
)
{
struct pru_rpmsg_ns_msg ns_msg;
uint8_t i;

for (i = 0; i < RPMSG_NAME_SIZE; i++) {
ns_msg.name[i] = name[i];
ns_msg.desc[i] = desc[i];
}
ns_msg.addr = port;
ns_msg.flags = flags;

return pru_rpmsg_send(transport, port, 53, &ns_msg, sizeof(ns_msg));
}

pru_rpmsg.h

 /*
* Copyright (C) 2016 Texas Instruments Incorporated – http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*//**
* File : pru_rpmsg.h
*
* Summary : An RPMsg interface for the PRU to use while communicating with
* the ARM host.
*
* Notes :
* – This file creates a structure (pru_rpmsg_transport) that contains
* pointers to two pru_virtqueue structures. This structure is used as the
* underlying transport layer of all RPMsg communication. Only one
* pru_rpmsg_transport structure is needed because multiple logical channels
* can use the same underlying transport.
* – This pru_rpmsg interface is meant to sit on top of the pru_virtqueue
* interface and abstract the communication even further away from the
* underlying data structures. The goal is to make the communication as
* simple as possible at the user application level.
* – The logic for the PRU side is summarized below:
*
* PRU Slave:
* – To receive buffer from the ARM host:
* pru_rpmsg_receive(*transport, *src, *dst, *data, *len);
* – To send buffer to the host:
* pru_rpmsg_send(*transport, src, dst, *data, len);
*/#ifndef _PRU_RPMSG_H_
#define _PRU_RPMSG_H_#include <pru_virtqueue.h>
#include <pru_virtio_ring.h>

/* Return value indicating no kick was sent */
#define PRU_RPMSG_NO_KICK 1
/* Return value indicating success */
#define PRU_RPMSG_SUCCESS 0
/* Return value indicating there were no available buffers */
#define PRU_RPMSG_NO_BUF_AVAILABLE -1
/* Return value indicating that the buffer from the virtqueue was too small */
#define PRU_RPMSG_BUF_TOO_SMALL -2
/* Return value indicating that an invalid head index was given */
#define PRU_RPMSG_INVALID_HEAD -3
/* Return value indication that an invalid event number was given */
#define PRU_RPMSG_INVALID_EVENT -4

/* Max PRU-ICSS system event number for pru_mst_intr */
#define MAX_VALID_EVENT 31
/* Min PRU-ICSS system event number for pru_mst_intr */
#define MIN_VALID_EVENT 16

/* The maximum size of the channel name and description */
#define RPMSG_NAME_SIZE 32
/* The maximum size of the buffer (including the header) */
#define RPMSG_BUF_SIZE 512

enum pru_rpmsg_ns_flags {
RPMSG_NS_CREATE = 0,
RPMSG_NS_DESTROY = 1
};

/**
* Summary : pru_rpmsg_transport is a structure that groups together the
* two pru_virtqueues that are needed for two-way communication
* with the ARM. This structure provides a logical wrapper for
* the transport layer of the application. NOTE: Multiple
* (logical) channels can be implemented on top of the same
* transport layer.
*
* Variables : virtqueue0: contains the pru_virtqueue that is used for the
* PRU->ARM communication
* virtqueue1: contains the pru_virtqueue that is used for
* the ARM->PRU communication
*/
struct pru_rpmsg_transport {
struct pru_virtqueue virtqueue0;
struct pru_virtqueue virtqueue1;
};

/**
* Summary : pru_rpmsg_init initializes the underlying transport layer
* data structures.
*
* Parameters : transport: a pointer to the transport data structure that
* contains the underlying data structures to be
* initialized
* vring0: a pointer to vring0 which is provided by the ARM
* core through the resource table
* vring1: a pointer to vring1 which is provided by the ARM
* core through the resource table
* to_arm_event: the number of the PRU-ICSS system event
* that is specified in the device tree that
* is used to ‘kick’ the ARM core
* from_arm_event: the number of the PRU-ICSS system event
* that is specified in the device tree
* that is used to receive ‘kicks’ from the
* ARM core
*
* Description : pru_rpmsg_init takes the vrings and the events provided
* through the resource table and initializes the transport
* layer. Once this function call is successful RPMsg
* channels can be created and used.
*
* Return Value : Returns PRU_RPMSG_INVALID_EVENT if the values provided
* in to_arm_event or from_arm_event are outside of the
* allowable range of events. Returns PRU_RPMSG_SUCCESS
* if the initialization is successful.
*/
int16_t pru_rpmsg_init(
struct pru_rpmsg_transport *transport,
struct fw_rsc_vdev_vring *vring0,
struct fw_rsc_vdev_vring *vring1,
uint32_t to_arm_event,
uint32_t from_arm_event
);

/**
* Summary : pru_rpmsg_receive receives a message, if available, from
* the ARM host.
*
* Parameters : transport: a pointer to the transport layer from which the
* message should be received
* src: a pointer that is populated with the source address
* where the message originated
* dst: a pointer that is populated with the destination
* address where the message was sent (can help determine
* for which channel the message is intended on the PRU)
* data: a pointer that is populated with a local data buffer
* containing the message payload
* len: a pointer that is populated with the length of the
* message payload
*
* Description : pru_rpmsg_receive uses the pru_virtqueue interface to get
* an available buffer, copy the buffer into local memory,
* add the buffer as a used buffer to the vring, and then kick
* the remote processor if necessary. The src, dst, data, and
* len pointers are populated with the information about the
* message and local buffer data if the reception is
* successful.
*
* Return Value : Returns PRU_RPMSG_NO_BUF_AVAILABLE if there is currently no
* buffer available for receive. Returns PRU_RPMSG_INVALID_HEAD
* if the head index returned for the available buffer is
* invalid. Returns PRU_RPMSG_SUCCESS if the message is
* successfully received.
*/
int16_t pru_rpmsg_receive(
struct pru_rpmsg_transport *transport,
uint16_t *src,
uint16_t *dst,
void *data,
uint16_t *len
);

/**
* Summary : pru_rpmsg_send sends a message to the ARM host using the
* virtqueues in the pru_rpmsg_transport structure. The
* source and destination address of the message are passed
* in as parameters to the function. The data to be sent and
* its length are passed in the data and len parameters.
*
* Parameters : transport: a pointer to the transport layer from which the
* message should be sent
* src: the source address where this message will originate
* dst: the destination address where the message will be sent
* data: a pointer to a local data buffer containing the
* message payload
* len: the length of the message payload
*
* Description : pru_rpmsg_send sends a message to the src parameter and
* from the dst parameter. The transport structure defines the
* underlying transport mechanism that will be used. The
* data parameter is a pointer to a local buffer that should
* be sent to the destination address and the len parameter is
* the length of that buffer.
*
* Return Value : Returns PRU_RPMSG_NO_BUF_AVAILABLE if there is currently no
* buffer available for send. Returns PRU_RPMSG_BUF_TOO_SMALL
* if the buffer from the vring is too small to hold the
* message payload being sent. Returns PRU_RPMSG_INVALID_HEAD
* if the head index returned for the send buffer is invalid.
* Returns PRU_RPMSG_SUCCESS if the message is successfully
* sent.
*/
int16_t pru_rpmsg_send(
struct pru_rpmsg_transport *transport,
uint32_t src,
uint32_t dst,
void *data,
uint16_t len
);

/**
* Summary : pru_rpmsg_channel uses an RPMsg Name Service Announcment
* to either create or destroy an RPMsg channel depending on
* the pru_rpmsg_ns_flags parameter that is specified.
*
* Parameters : flags: an enum that is used to create (RPMSG_NS_CREATE) or
* destroy (RPMSG_NS_DESTROY) an RPMsg channel
* transport: a pointer to the transport layer on which this
* Name Service Announcement will be sent
* name: the name of the channel being created or destroyed
* ******* The name of the channel is very important as
* ******* it is the method that Linux on the ARM uses
* ******* to connect a PRU firmware with a corresponding
* ******* Linux driver
* desc: the description of the RPMsg channel being created
* or destroyed
* port: the local source address of the RPMsg channel. This
* is the address where PRU messages destined for the
* ARM host will originate
*
* Description : pru_rpmsg_channel sends a message letting the ARM
* host know that a channel is to be created or destroyed. If
* a channel is to be created then this message will notify
* the name server on the ARM host to create a new channel. If
* a channel is to be destroyed this will tear down this
* logical channel of communication between the PRU and the
* ARM host.
*
* Return Value : Returns PRU_RPMSG_NO_BUF_AVAILABLE if there is currently no
* buffer available for send. Returns PRU_RPMSG_BUF_TOO_SMALL
* if the buffer from the vring is too small to hold the
* message payload being sent. Returns PRU_RPMSG_INVALID_HEAD
* if the head index returned for the send buffer is invalid.
* Returns PRU_RPMSG_SUCCESS if the message is successfully
* sent.
*/
int16_t pru_rpmsg_channel(
enum pru_rpmsg_ns_flags flags,
struct pru_rpmsg_transport *transport,
char *name,
char *desc,
int32_t port
);

#endif /* _PRU_RPMSG_H_ */

pru_virtqueue.c

/*
* Copyright (C) 2016 Texas Instruments Incorporated – http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*//**
* File : pru_virtqueue.c
*
* Summary : A virtual queue implementation to simplify vring usage.
*
* Notes :
* – Implementaion of the interface described in “pru_virtqueue.h”
*/
#include <pru_virtqueue.h>volatile register uint32_t __R31;/* bit 5 is the valid strobe to generate system events with __R31 */
#define INT_ENABLE (1 << 5)/* __R31[3:0] can generate 15-0 which maps to system events 31-16
* e.g. to generate PRU-ICSS System Event 17 (pru_mst_intr[1])
* __R31 = (INT_ENABLE | (17 – INT_OFFSET));
*/
#define INT_OFFSET 16

void pru_virtqueue_init(
struct pru_virtqueue *vq,
struct fw_rsc_vdev_vring *vring,
uint32_t to_arm_event,
uint32_t from_arm_event
)
{
vq->id = vring->notifyid;
vq->to_arm_event = to_arm_event;
vq->from_arm_event = from_arm_event;
vq->last_avail_idx = 0;

vring_init(&vq->vring, vring->num, (void*)vring->da, vring->align);
}

int16_t pru_virtqueue_get_avail_buf(
struct pru_virtqueue *vq,
void **buf,
uint32_t *len
)
{
int16_t head;
struct vring_desc desc;
struct vring_avail *avail;

avail = vq->vring.avail;

/* There’s nothing available */
if (vq->last_avail_idx == avail->idx)
return PRU_VIRTQUEUE_NO_BUF_AVAILABLE;

/*
* Grab the next descriptor number the ARM host is advertising, and
* increment the last available index we’ve seen.
*/
head = avail->ring[vq->last_avail_idx++ & (vq->vring.num – 1)];

desc = vq->vring.desc[head];
*buf = (void *)(uint32_t)desc.addr;
*len = desc.len;

return (head);
}

int16_t pru_virtqueue_add_used_buf(
struct pru_virtqueue *vq,
int16_t head,
uint32_t len
)
{
struct vring_used_elem *used_elem;
uint32_t num;
struct vring_used *used;

num = vq->vring.num;
used = vq->vring.used;

if (head > num)
return PRU_VIRTQUEUE_INVALID_HEAD;

/*
* The virtqueue’s vring contains a ring of used buffers. Get a pointer to
* the next entry in that used ring.
*/
used_elem = &used->ring[used->idx++ & (num – 1)];
used_elem->id = head;
used_elem->len = len;

return PRU_VIRTQUEUE_SUCCESS;
}

int16_t pru_virtqueue_kick(
struct pru_virtqueue *vq
)
{
/* If requested, do not kick the ARM host */
if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
return PRU_VIRTQUEUE_NO_KICK;

/* Generate a system event to kick the ARM */
__R31 = (INT_ENABLE | (vq->to_arm_event – INT_OFFSET));

return PRU_VIRTQUEUE_SUCCESS;
}

pru_virtqueue.h

 /*
* Copyright (C) 2016 Texas Instruments Incorporated – http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*//**
* File : pru_virtqueue.h
*
* Summary : A virtual queue interface to simplify vring usage.
*
* Notes :
* – This file implements the vring functions needed by the PRU core
* – The PRU core is considered the slave and the ARM core is considered the
* host
* – The ARM host always adds *available* buffers to send/receive, while the
* PRU slave always adds *used* buffers to send/receive.
* – The logic for the PRU side is summarized below:
*
* PRU Slave:
* – To receive buffer from the ARM host:
* virtqueue_getAvailBuf(vq_slave);
* >> empty data from buf <<
* virtqueue_addUsedBuf(vq_slave);
* virtqueue_kick(vq_slave);
* – To send buffer to the host:
* virtqueue_getAvailBuf(vq_host);
* >> copy data into buf <<
* virtqueue_addUsedBuf(vq_host);
* virtqueue_kick(vq_host);
*/#ifndef _PRU_VIRTQUEUE_H_
#define _PRU_VIRTQUEUE_H_

#include <rsc_types.h>
#include <pru_virtio_ring.h>

/* Return value indicating no kick was sent */
#define PRU_VIRTQUEUE_NO_KICK 1
/* Return value indicating success */
#define PRU_VIRTQUEUE_SUCCESS 0
/* Return value indicating there were no available buffers */
#define PRU_VIRTQUEUE_NO_BUF_AVAILABLE -1
/* Return value indicating that an invalid head index was given */
#define PRU_VIRTQUEUE_INVALID_HEAD -2

/**
* Summary : pru_virtqueue is a structure that encapsulates everything
* needed for a ‘virtual queue’. This structure wraps a vring
* with extra information that is needed by the application
* in order to use the vring.
*
* Variables : id: The notification ID of the vring.
* to_arm_event: The PRU-ICSS system event that signals the ARM.
* from_arm_event: The PRU-ICSS system event that the ARM uses to
* signal the PRU.
* last_avail_idx: A local running counter that is used by the
* PRU to determine whether or not a new
* available buffer has been added to the
* vring.
* vring: The underlying virtio structure that is being used
* to pass buffers back and forth between the ARM and
* PRU. See pru_virtio_ring.h.
*/
struct pru_virtqueue {
uint32_t id;
uint32_t to_arm_event;
uint32_t from_arm_event;
uint16_t last_avail_idx;
struct vring vring;
};

/**
* Summary : pru_virtqueue_init initializes the pru_virtqueue structure
* with values from the resource table.
*
* Parameters : vq: a pointer to a pru_virtqueue structure that will be
* initialized
* vring: a pointer to a vring that is populated and returned
* by the ARM host through the resource table (the id,
* number of descriptors, address of the vring, and
* alignment information are contained in this vring
* pointer’s structure
* to_arm_event: the PRU-ICSS system event to trigger in order to
* ‘kick’ the ARM host when sending data
* from_arm_event: the PRU-ICSS system event to check
* for data arriving from the ARM host
*
* Description : This function initializes the pru_virtqueue (vq) with input
* values from the vring in the resource table. This function
* should be called once for each virtqueue/vring. After
* initialization the pru_virtqueue pointer, vq, should be
* passed to the other functions in this header file.
*
* Return Value : No return value.
*/
void pru_virtqueue_init(
struct pru_virtqueue *vq,
struct fw_rsc_vdev_vring *vring,
uint32_t to_arm_event,
uint32_t from_arm_event
);

/**
* Summary : pru_virtqueue_get_avail_buf – gets the next available
* buffer from the pru_virtqueue specified in vq.
*
* Parameters : vq: pointer to the pru_virtqueue from which the available
* buffer should be retrieved
* buf: pointer to be filled with the address of the available
* buffer
* len: pointer to be filled with the length of the available
* buffer
*
* Description : This function compares our last_avail_idx running counter
* against the vring.avail->idx value to see if there is a
* buffer available that we have not used. If our last
* available index running counter matches the vring.avail->idx
* value then there have been no new available buffers added
* by the host. If the two indices do not match then the host
* has added new buffers and and we can set @buf to point to
* the available buffer and @len to match the available buffers
* length. If an available buffer is found we increment out
* last_avail_idx to show that we used another buffer.
*
* Return Value : PRU_VIRTQUEUE_NO_BUF_AVAILABLE if no buffer available.
* Returns the vring.desc index of the available buffer
* otherwise.
*/
int16_t pru_virtqueue_get_avail_buf(
struct pru_virtqueue *vq,
void **buf,
uint32_t *len
);

/**
* Summary : pru_virtqueue_add_used_buf adds a used buffer to the
* pru_virtqueue specified in vq.
*
* Parameters : vq: pointer to the pru_virtqueue where the used buffer
* should be added
* head: vring.desc[] index of the used buffer
* len: length of the used buffer being added
*
* Description : This function makes sure that the head vring.desc index
* (head) is a valid index. If the index is valid, then the
* buffer is added to the used list in the vring contained by
* the pru_virtqueue (vq).
*
* Return Value : PRU_VIRTQUEUE_INVALID_HEAD if head is an invalid index for
* the vring.desc array. Returns PRU_VIRTQUEUE_SUCCESS
* otherwise.
*/
int16_t pru_virtqueue_add_used_buf(
struct pru_virtqueue *vq,
int16_t head,
uint32_t len
);

/**
* Summary : pru_virtqueue_kick sends a notification to the remote
* processor that the PRU has added a buffer to the
* pru_virtqueue.
*
* Parameters : vq: pointer to the pru_virtqueue that is to be kicked
*
* Description : This function is used by the PRU to notify the ARM host in
* two situations:
* 1. That the PRU has consumed a buffer that the ARM
* host sent through the slave pru_virtqueue
* 2. That the PRU has sent a buffer to the ARM through
* the host pru_virtqueue
* If the pru_virtqueue’s VRING_AVAIL_F_NO_INTERRUPT flag is
* set then the pru does not kick the pru_virtqueue.
*
* Return Value : PRU_VIRTQUEUE_NO_KICK if the VRING_AVAIL_F_NO_INTERRUPT
* flag is set or PRU_VIRTQUEUE_SUCCESS otherwise.
*/
int16_t pru_virtqueue_kick(
struct pru_virtqueue *vq
);

#endif /* _PRU_VIRTQUEUE_H_ */

pru_virtio_ring.h

 #ifndef _UAPI_LINUX_VIRTIO_RING_H
#define _UAPI_LINUX_VIRTIO_RING_H
/* An interface for efficient virtio implementation, currently for use by KVM
* and lguest, but hopefully others soon. Do NOT change this since it will
* break existing servers and clients.
*
* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of IBM nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Copyright Rusty Russell IBM Corporation 2007. */
#include <stdint.h>

/* This marks a buffer as continuing via the next field. */
#define VRING_DESC_F_NEXT 1
/* This marks a buffer as write-only (otherwise read-only). */
#define VRING_DESC_F_WRITE 2
/* This means the buffer contains a list of buffer descriptors. */
#define VRING_DESC_F_INDIRECT 4

/* The Host uses this in used->flags to advise the Guest: don’t kick me when
* you add a buffer. It’s unreliable, so it’s simply an optimization. Guest
* will still kick if it’s out of buffers. */
#define VRING_USED_F_NO_NOTIFY 1
/* The Guest uses this in avail->flags to advise the Host: don’t interrupt me
* when you consume a buffer. It’s unreliable, so it’s simply an
* optimization. */
#define VRING_AVAIL_F_NO_INTERRUPT 1

/* We support indirect buffer descriptors */
#define VIRTIO_RING_F_INDIRECT_DESC 28

/* The Guest publishes the used index for which it expects an interrupt
* at the end of the avail ring. Host should ignore the avail->flags field. */
/* The Host publishes the avail index for which it expects a kick
* at the end of the used ring. Guest should ignore the used->flags field. */
#define VIRTIO_RING_F_EVENT_IDX 29

/* Virtio ring descriptors: 16 bytes. These can chain together via “next”. */
struct vring_desc {
/* Address (guest-physical). */
uint64_t addr;
/* Length. */
uint32_t len;
/* The flags as indicated above. */
uint16_t flags;
/* We chain unused descriptors via this, too */
uint16_t next;
};

struct vring_avail {
uint16_t flags;
uint16_t idx;
uint16_t ring[];
};

/* u32 is used here for ids for padding reasons. */
struct vring_used_elem {
/* Index of start of used descriptor chain. */
uint32_t id;
/* Total length of the descriptor chain which was used (written to) */
uint32_t len;
};

struct vring_used {
uint16_t flags;
uint16_t idx;
struct vring_used_elem ring[];
};

struct vring {
uint32_t num;

struct vring_desc *desc;

struct vring_avail *avail;

struct vring_used *used;
};

/* The standard layout for the ring is a continuous chunk of memory which looks
* like this. We assume num is a power of 2.
*
* struct vring
* {
* // The actual descriptors (16 bytes each)
* struct vring_desc desc[num];
*
* // A ring of available descriptor heads with free-running index.
* __u16 avail_flags;
* __u16 avail_idx;
* __u16 available[num];
* __u16 used_event_idx;
*
* // Padding to the next align boundary.
* char pad[];
*
* // A ring of used descriptor heads with free-running index.
* __u16 used_flags;
* __u16 used_idx;
* struct vring_used_elem used[num];
* __u16 avail_event_idx;
* };
*/
/* We publish the used event index at the end of the available ring, and vice
* versa. They are at the end for backwards compatibility. */
#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])

static inline void vring_init(struct vring *vr, uint32_t num, void *p,
uint64_t align)
{
vr->num = num;
vr->desc = p;
vr->avail = (void *)((char *)p + num*sizeof(struct vring_desc));
vr->used = (void *)(uintptr_t)(((uint64_t)&vr->avail->ring[num]
+ sizeof(uint16_t) + align-1) & ~(align – 1));
}

static inline unsigned vring_size(uint16_t num, uint64_t align)
{
return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (3 + num)
+ align – 1) & ~(align – 1))
+ sizeof(uint16_t) * 3 + sizeof(struct vring_used_elem) * num;
}

/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
/* Assuming a given event_idx value from the other size, if
* we have just incremented index from old to new_idx,
* should we trigger an event? */
static inline int vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
{
/* Note: Xen has similar logic for notification hold-off
* in include/xen/interface/io/ring.h with req_event and req_prod
* corresponding to event_idx + 1 and new_idx respectively.
* Note also that req_event and req_prod in Xen start at 1,
* event indexes in virtio start at 0. */
return (uint16_t)(new_idx – event_idx – 1) < (uint16_t)(new_idx – old);
}

#endif /* _UAPI_LINUX_VIRTIO_RING_H */

The commands to make the library:

make pru_rpmsg.object

make pru_virtqueue.object

make rpmsg_lib.lib

Put the Makefile in /$(HOME)/$(LIB).

PRU_TOOLS_ROOT:=/usr/
PRU_TOOLS:=$(PRU_TOOLS_ROOT)bin/
PRU_INCLUDE:=-i/usr/share/ti/cgt-pru/include/ -i/root/code3/abw_include/

CFLAGS=-v3 -O2 --endian=little --hardware_mac=on
LDFLAGS+= -L.

pru_rpmsg.object: pru_rpmsg.c
	$(PRU_TOOLS)clpru $(CFLAGS) $(PRU_INCLUDE) -ppd -ppa -fe pru_rpmsg.object pru_rpmsg.c

rpmsg_lib.lib: pru_rpmsg.object pru_virtqueue.object
	$(PRU_TOOLS)arpru r rpmsg_lib.lib pru_rpmsg.object pru_virtqueue.object

pru_virtqueue.object: pru_virtqueue.c
	$(PRU_TOOLS)clpru $(CFLAGS) $(PRU_INCLUDE) -ppd -ppa -fe pru_virtqueue.object pru_virtqueue.c
Posted in: Robotics

Comments are closed.