Data transfer between Processor and FPGA through GPMC using EDMA - linux

We are working on a board containing AM3359 processor.
SDK we are using is ti-processor-sdk-linux-am335x-evm-05.00.00.15.
Our customer wants to see the throughput of the data transfer between processor (AM3359) and FPGA connected through 8 GPMC lines using EDMA
All we want now is to implement GPMC_EDMA data transfer program as per the below flow.
Processor and FPGA lines
Processor booted ----> Run GPMC_EDMA Data transfer program ----> Complete data transfer ----> Calculate throughput.
Here is my code for transferring data to FPGA through 8 GPMC lines.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/mman.h>
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
int verbose = 0;
#define BUF_SIZE 4096
int main(){
int i,fd;char ch;
int buf[BUF_SIZE];
volatile uint8_t *map_base;
int a=1;
for(i=0;i<BUF_SIZE;i++){
if(i%100==0){
a++;
printf("i: %d, a: %d\n",i,a);
}
buf[i]=a;
}
//buf[BUF_SIZE]=43;
if((fd=open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
printf("Error in opening gpmc\n");return 0;
}
printf("Successfully opened\n");
map_base =(uint8_t *) mmap((void*)0x01000000, 0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x01000000);
if(map_base == (void *) -1) FATAL;
if (verbose) {
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
}
volatile uint32_t *p32 = (uint32_t *) &map_base[0x0800];
//while(1/*(ch=getchar())!='\n'*/){
//*p32 = 0x1;
for(i=0;i<BUF_SIZE;i++){
*p32 = buf[i];
}
printf("Sent %d bytes\n",BUF_SIZE);
//}
printf("Closing FD\n");
close(fd);
}
Someone kindly help me to proceed further as we have a severe time restriction and also we are new to this one.
Regards
Vamsi

Related

Funny network packets with unknown hardware address

I have written a little program to investigate my home network, to see what packets are underway. I print the hardware address, and the number of packets.
Looks quite normal, i know all these addresses. But when i start Firefox, some new source addresses pop up. What are these? Normally i would say, there is a bug in my code, but they appear, when i start firefox, especially if i open a new tab?!
I have a Kubuntu 22.04 with Firefox 101.0.1
device: 00:00:40:11:4f:a5 --> 1 packets
device: 00:00:40:11:54:fa --> 1 packets
device: 00:00:40:11:66:c5 --> 1 packets
device: 00:00:40:11:69:30 --> 1 packets
device: 00:00:40:11:69:4e --> 1 packets
device: 00:00:40:11:6e:e1 --> 1 packets
device: 00:00:40:11:79:3a --> 1 packets
device: 00:00:40:11:7d:32 --> 1 packets
device: 00:00:40:11:83:05 --> 1 packets
device: 00:00:40:11:9a:ca --> 1 packets
device: 00:00:40:11:9c:2d --> 1 packets
device: 00:00:40:11:9c:30 --> 1 packets
My code is (g++ code.cpp -o code, run it with sudo):
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netpacket/packet.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <ctime>
#include <map>
#define BUFSIZE 2048*8
struct hwaddr{
uint8_t c[6];
bool operator<(const struct hwaddr &other) const{
for(int i = 0; i<6; i++){
if(c[i] != other.c[i]){
return c[i] < other.c[i];
}
}
return false;
}
};
void printeth(struct ether_header * e){
uint8_t * hwa;
hwa = e->ether_dhost;
printf("dest: %02x:%02x:%02x:%02x:%02x:%02x ", hwa[0], hwa[1], hwa[2], hwa[3], hwa[4], hwa[5]);
hwa = e->ether_shost;
printf("sour: %02x:%02x:%02x:%02x:%02x:%02x ", hwa[0], hwa[1], hwa[2], hwa[3], hwa[4], hwa[5]);
printf("type: %04x\n", (int)ntohs(e->ether_type));
}
void printcounter(std::map<struct hwaddr, uint64_t> const & counter){
static uint64_t last = std::time(0);
uint64_t const now = std::time(0);
if(now == last){
return;
}
last = now;
printf("\033[2J\033[1;1H");
printf("size: %d\n", (int)counter.size());
for(const auto & a : counter){
uint8_t * hwa = (uint8_t*)&a.first;
printf("device: %02x:%02x:%02x:%02x:%02x:%02x --> %8lu packets\n", hwa[0], hwa[1], hwa[2], hwa[3], hwa[4], hwa[5], a.second);
}
}
int main(int argc, char ** argv){
char buf[sizeof(struct ether_header)];
std::map<struct hwaddr,uint64_t> counter;
int const sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sockfd < 0){
printf("ERROR opening socket: %s\n", strerror(errno));
return 0;
}
while (1) {
int const n = recv(sockfd, buf, sizeof(struct ether_header), 0);
if(n >= sizeof(struct ether_header)){
struct ether_header * e = (struct ether_header*)buf;
//printeth(e);
counter[*(struct hwaddr*)&e->ether_shost]++;
printcounter(counter);
}
}
return 0;
}

NETLINK_NFLOG support in Linux 4.14

I've this program which runs fine on Linux 2.6.34. While porting this program to 4.14, socket creation is giving error "Error: : Protocol not supported". As per http://man7.org/linux/man-pages/man7/netlink.7.html
NETLINK_NFLOG (up to and including Linux 3.16)
Netfilter/iptables ULOG.
Do we know what is the alternative in 4.14 ?
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <pthread.h>
#include <netinet/ip.h>
#include <linux/types.h>
#include <linux/netlink.h>
int main()
{
struct sockaddr_nl addr;
int mypid;
int status;
int sockfd = -1;
/* mypid = getpid(); */
mypid = pthread_self();
sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NFLOG);
if (sockfd <= 0) {
printf("netlink socket() failed - rc:%d, errno:%d\n",
sockfd, errno);
perror("Error: ");
return (-1);
}
/* set up socket address */
memset(&addr, 0, sizeof (addr));
addr.nl_pid = mypid;
addr.nl_family = AF_NETLINK;
/*
nl_groups is the multicast
group ID to which the ULOG
messages will be sent.It
is bitmap of hexadecimal
format
*/
addr.nl_groups = 1;
/* bind socket to listen on
* multicast group 1 */
status = bind(sockfd, (struct sockaddr *)&addr, sizeof (addr));
if (status < 0) {
perror("bind:");
close(sockfd);
return (-1);
}
printf("socket bind successful\n");
close(sockfd);
return (0);
}
I tried to browse kernel source but couldn't identify.
I've below config
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_ADVANCED is not set
CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_LOG=y
# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set
CONFIG_NETFILTER_XTABLES=y
CONFIG_NETFILTER_XT_MARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
CONFIG_NETFILTER_XT_NAT=y
# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
NETLINK_NFLOG (up to and including Linux 3.16)
see worked example in libnml

setsockopt IPT_SO_SET_REPLACE flag return error (linux)

I try to use setsockopt with the flag IPT_SO_SET_REPLACE but i keep getting the wired error from errno Protocol not available this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <fcntl.h>
int main(void) {
int sock;
int ret;
void *data;
size_t size;
struct ipt_replace *repl;
sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock == -1) {
perror("socket");
return -1;
}
size = sizeof(struct ipt_replace);
data = malloc(size); Protocol not available
if (data == NULL) {
perror("malloc");
return -1;
}
memset(data, 0, size);
repl = (struct ipt_replace *) data;
repl->num_counters = 0x1;
repl->size = 0xffffffff;
repl->valid_hooks = 0x1;
repl->num_entries = 0x1;
ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, size);
printf("\ndone %d\n", ret);
perror("error: ");
return 0;
}
this is the output :
sock:3
data:
size:92
done -1
error: : Protocol not available
Looking briefly at the kernel code, this would seem to indicate that the IP tables module isn't available (i.e. the kernel wasn't built with it configured, or it can't be found or loaded).
It appears to me that for a socket of the kind you created, the code flow is:
enter raw_setsockopt: level != SOL_RAW so...
call ip_setsockopt: level == SOL_IP but option isn't any of the IP_xxx options so...
call nf_setsockopt: Search loaded netfilter modules for one that has registered IPT_SO_SET_REPLACE.
I think the last must have failed, so you get ENOPROTOOPT back (== Protocol not available)

Example code on using PACKET_QDISC_BYPASS option on ethernet raw socket on linux

According to http://man7.org/linux/man-pages/man7/packet.7.html, there is a new option
PACKET_QDISC_BYPASS since linux 3.14. This has the potential of sending and receiving packets a lot faster.
Saw a sample code: https://github.com/netoptimizer/network-testing/blob/master/src/raw_packet_send.c, but unfortunately it doesn't have the code on sending packets.
I added some code to send packets but it has a problem with sendto.
# ./raw_packet_send p6p1 64
Lame RAW/PF_PACKET socket TX test program
Enabled kernel qdisc bypass
error sendto : Invalid argument
Not sure why. Here is the code (original raw_packet_send.c with my silly code). Please let me know how could make it work or point me to some good simple sample code. Thanks.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
//#include <stdio.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <sys/socket.h>
//#include <sys/mman.h>
//#include <linux/filter.h>
//#include <ctype.h>
//#include <fcntl.h>
//#include <unistd.h>
//#include <bits/wordsize.h>
//#include <net/ethernet.h>
//#include <netinet/ip.h>
//#include <arpa/inet.h>
//#include <stdint.h>
//#include <string.h>
//#include <assert.h>
//#include <net/if.h>
//#include <inttypes.h>
//#include <poll.h>
//#include <unistd.h>
#ifndef PACKET_QDISC_BYPASS
#define PACKET_QDISC_BYPASS 20
#endif
#include "common_socket.h"
char pkt[2000] = {0x00, 1,2,3,4,0, 0,1,2,3,4,1, 8, 0};;
int len = 96;
char intfName[100] = "em1";
/* Avail in kernel >= 3.14
* in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option)
*/
void set_sock_qdisc_bypass(int fd, int verbose)
{
int ret, val = 1;
ret = setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &val, sizeof(val));
if (ret < 0) {
printf("[DEBUG] %s(): err:%d errno:%d\n", __func__, ret, errno);
if (errno == ENOPROTOOPT) {
if (verbose)
printf("No kernel support for PACKET_QDISC_BYPASS"
" (kernel < 3.14?)\n");
} else {
perror("Cannot set PACKET_QDISC_BYPASS");
}
} else
if (verbose) printf("Enabled kernel qdisc bypass\n");
}
int pf_tx_socket(int ver)
{
int ret, val = 1;
/* Don't use proto htons(ETH_P_ALL) as we only want to transmit */
int sock = socket(PF_PACKET, SOCK_RAW, 0);
//int sock = socket(AF_INET,SOCK_PACKET,htons(3));
if (sock == -1) {
perror("Creation of RAW PF_SOCKET failed!\n");
exit(1);
}
ret = Setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver));
return sock;
}
void mybind(int sock, char *intf) {
struct ifreq ifr;
int rc;
memset((char*)&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), intf);
if ((rc = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0)
{
perror("Server-setsockopt() error for SO_BINDTODEVICE");
printf("%s\n", strerror(errno));
close(sock);
exit(-1);
}
}
int flood (int sock) {
struct sockaddr intfAddrs;
char cmd[100];
int tmp;
memset((char*)&intfAddrs, 0, sizeof (struct sockaddr));
intfAddrs.sa_family = PF_PACKET;
strcpy((char*)(intfAddrs.sa_data), intfName);
sprintf(cmd, "ifconfig %s promisc", intfName); system(cmd);
while (1) {
while (1) {
tmp = sendto(sock, pkt, len, 0, &intfAddrs, sizeof(intfAddrs));
if (tmp != len) {perror("error sendto "); exit(0); }
}
}
}
int main(int argc, char **argv)
{
if (argc > 1) { strcpy(intfName, argv[1]); }
if (argc > 2) { len = atoi(argv[2]); }
printf("Lame RAW/PF_PACKET socket TX test program\n");
int sock = pf_tx_socket(0);
set_sock_qdisc_bypass(sock, 1);
mybind(sock, intfName);
flood(sock);
return 0;
}
I think you need to change from PF_PACKET to AF_PACKET (although it looks like PF_PACKET is an alias to AF_PACKET) but I don't have any success when using PF_PACKET.
This code works for me:
// Create a raw socket
sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd == -1) {
perror("Can't create AF_PACKET socket");
return EXIT_FAILURE;
}
// Check kernel version
static const int32_t sock_qdisc_bypass = 1;
int32_t sock_qdisc_ret = setsockopt(thd_opt->sock_fd, SOL_PACKET, PACKET_QDISC_BYPASS, &sock_qdisc_bypass, sizeof(sock_qdisc_bypass));
if (sock_qdisc_ret == -1) {
perror("Can't enable QDISC bypass on socket");
return EXIT_FAILURE;
}
This is from setup_socket_mmap() here

What's the max file mapping size in 64bits machine

I'm new to 64-bits architecture. Could you tell me what's MAX file size supported by file mapping in 64 bits linux machine. I want to open more than 20GB files by file mapping, is it available?
I write a sample code. But it causes Bus Error when I get the value of the pointer in GBSIZE offset:
unsigned char* pCur = pBegin + GBSIZE;
//pBegin is the pointer returned by mmap
printf("%c",*pCur);
BTW, printf("%c",*pBegin ); works fine. and my address sizes : 38 bits physical, 48 bits virtual
Here is the full code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
//#define FILEPATH "smallfile"
#define FILEPATH "bigfile"
#define GBSIZE (1024L*1024L*1024L)
#define TBSIZE (1024L*GBSIZE)
#define NUMSIZE (20L * GBSIZE)
//#define NUMSIZE (10)
#define FILESIZE (NUMINTS * sizeof(int))
int main(int argc, char *argv[])
{
int i;
int fd;
unsigned char *pBegin;
fd = open(FILEPATH, O_RDONLY);
if (fd == -1) {
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
pBegin = mmap(0, NUMSIZE, PROT_READ, MAP_SHARED, fd, 0);
if (pBegin == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/** ERROR happens here!!! **/
unsigned char* pCur = pBegin + GBSIZE;
printf("%c",*pCur);
if (munmap(pBegin, NUMSIZE) == -1) {
perror("Error un-mmapping the file");
}
close(fd);
return 0;
}
Although pointers are 64-bit wide, most processors do not actually support virtual addresses using the full 64 bits. To see what size virtual addresses your processor supports, look in /proc/cpuinfo (48 bits is typical).
grep "address sizes" /proc/cpuinfo
Additionally, half of the virtual address space is used by the kernel and not available to userspace - leaving 47 bits in the current Linux implementation.
However, even taking this into account, you will still have plenty of room for a 20GB file. 47 bits in theory means a virtual address space of 128TB.
From the mmap(2) man page:
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
length is a size_t, which on 64-bit machines is 64 bits in length. Therefore yes, you can theoretically map a 20GB file.
64-bit addresses allow for many orders of magnitude more than 20 GB.
(This answer was originally edited into the question by OP)
You have requested a 20GB map onto a file which was only 50MB in size.
As described by the mmap man page, mmap succeeds when you request the length too big, however it will give SIGBUS or SIGSEGV when you actually try to read beyond the end of the underlying file.
Agree with MarkR, you are dereference an invalid address.
// A bug in these lines.
unsigned char* pCur = pBegin + GBSIZE;
printf("%c",*pCur);
unsigned char* pEnd = pBegin + NUMSIZE;
unsigned char* pLast = pEnd - 1;
unsigned char* pCur = pLast;
I modified your code to use HUGE TLB flags as the following.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define MAP_HUGETLB 0x40000 /* create a huge page mapping */
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
#define KSIZE 1024L
#define MSIZE (1024L*1024L)
#define GSIZE (1024L*1024L*1024L)
#define TSIZE (1024L*GSIZE)
#define INIT_MEM 0
// Fail on my MacBook Pro (Retina, 13-inch, Early 2015)
// Darwin Kernel Version 16.5.0:x86_64
// #define NUMSIZE (16L * TSIZE)
// mmap ok; init: got killed; signal 9
// #define NUMSIZE (8L * TSIZE)
// Got killed signal 9
// #define NUMSIZE (1L * TSIZE)
// OK
// #define NUMSIZE (200L * GSIZE)
// OK
#define NUMSIZE (20L * GSIZE)
typedef unsigned long long ETYPE;
#define MEMSIZE (NUMSIZE*sizeof(ETYPE))
#define PGSIZE (16*KSIZE)
void init(ETYPE* ptr) {
*ptr = (ETYPE)ptr;
}
int verify(ETYPE* ptr) {
if (*ptr != (ETYPE)ptr) {
fprintf(stderr, "ERROR: 0x%016llx != %p.\n", *ptr, ptr);
return -1;
}
else {
fprintf(stdout, "OK: 0x%016llx = %p.\n", *ptr, ptr);
}
return 0;
}
int main(int argc, char *argv[])
{
int i;
int fd;
ETYPE *pBegin;
int flags = MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_1GB;
printf("mmap memory size:%lu GB\n", MEMSIZE/GSIZE);
pBegin = (ETYPE*) mmap(0, MEMSIZE, PROT_READ | PROT_WRITE, flags, -1, 0);
if (pBegin == MAP_FAILED) {
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
ETYPE* pEnd = pBegin + NUMSIZE;
ETYPE* pCur = pBegin;
#if INIT_MEM
while (pCur < pEnd) {
init(pCur);
// ++pCur; //slow if init all addresses.
pCur += (PGSIZE/sizeof(ETYPE));
}
#endif
init(&pBegin[0]);
init(&pBegin[NUMSIZE-1]);
verify(&pBegin[0]);
verify(&pBegin[NUMSIZE-1]);
if (munmap(pBegin, MEMSIZE) == -1) {
perror("Error un-mmapping the file");
}
return 0;
}

Resources