下面三个文件可以使用:
main文件:
/* pci_debug.c
*
* 6/21/2010 D. W. Hawkins
*
* PCI debug registers interface.
*
* This tool provides a debug interface for reading and writing
* to PCI registers via the device base address registers (BARs).
* The tool uses the PCI resource nodes automatically created
* by recently Linux kernels.
*
* The readline library is used for the command line interface
* so that up-arrow command recall works. Command-line history
* is not implemented. Use -lreadline -lcurses when building.
*
* ----------------------------------------------------------------
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Readline support */
#include <readline/readline.h>
#include <readline/history.h>
#include "generic_api.h"
#include "pci_utils.h"
void display_help(void);
void parse_command(void);
int process_command(char *cmd);
int handle_reg(char *cmd);
int handle_hbm(char *cmd);
void handle_reg_read(uint64_t addr, uint32_t len);
void handle_hbm_read(uint64_t addr, uint32_t len, uint32_t width);
void handle_hbm_fill(uint64_t addr, uint64_t val, uint64_t len, uint32_t inc, uint32_t width);
int handle_csb(char *cmd);
void handle_csb_read(uint64_t addr, uint32_t len);
/* Usage */
static void show_usage()
{
printf("\nUsage: pci_debug -s <device>>\n"\
" -h Help (this message)\n"\
" -s <device> PCIe slot/device (as per lspci)\n\n");
}
int main(int argc, char *argv[])
{
printf("//------------------------------\n");
printf("// PCI_DEBUG start...\n");
printf("//------------------------------\n\n");
char *device = 0;
int opt;
uint32_t i;
setbuf(stdout, NULL);
while ((opt = getopt(argc, argv, "hs:")) != -1) {
switch (opt) {
case 'h':
show_usage();
return -1;
case 's':
device = optarg;
break;
default:
show_usage();
return -1;
}
}
if (device == 0) {
//show_usage();
//return -1;
}
if (pci_init(device)) {
printf("PCI_DEBUG: ERROR! PCIe device init fail, device=%s\n", device);
return 1;
}
/* Display help */
display_help();
/* Process commands */
parse_command();
// Test end
pci_cleanup();
printf("//------------------------------\n");
printf("// PCI_DEBUG finish...\n");
printf("//------------------------------\n\n");
return 0;
}
void
parse_command()
{
char *line;
int len;
int status;
while(1) {
line = readline("PCI> ");
/* Ctrl-D check */
if (line == NULL) {
printf("\n");
continue;
}
/* Empty line check */
len = strlen(line);
if (len == 0) {
continue;
}
/* Process the line */
status = process_command(line);
if (status < 0) {
break;
}
/* Add it to the history */
add_history(line);
free(line);
}
return;
}
/*--------------------------------------------------------------------
* User interface
*--------------------------------------------------------------------
*/
void
display_help()
{
printf("\n");
printf(" ? Help\n");
printf(" regr addr len Display register starting from addr\n");
printf(" regw addr val Change register at addr to val\n");
printf(" csbr addr len Display CSB starting from addr\n");
printf(" csbw addr val Change CSB at addr to val\n");
printf(" hbmr[width] addr len Display HBM starting from addr\n");
printf(" [width]\n");
printf(" 32 - 32-bit access (default)\n");
printf(" 64 - 64-bit access (default)\n");
printf(" hbmw[width] addr val Change HBM at addr to val\n");
printf(" hbmf[width] addr val len inc Fill memory\n");
printf(" addr - start address\n");
printf(" val - start value\n");
printf(" len - length (in bytes)\n");
printf(" inc - increment (defaults to 1)\n");
printf(" q Quit\n");
printf("\n Notes:\n");
printf(" 1. addr, len, and val are interpreted as hex values\n");
printf(" addresses are always byte based\n");
printf("\n");
}
int process_command(char *cmd)
{
if (cmd[0] == '\0') {
return 0;
}
switch (cmd[0]) {
case '?':
display_help();
break;
case 'r':
case 'R':
return handle_reg(cmd);
case 'c':
case 'C':
return handle_csb(cmd);
case 'h':
case 'H':
return handle_hbm(cmd);
case 'q':
case 'Q':
return -1;
default:
break;
}
return 0;
}
int handle_reg(char *cmd)
{
uint64_t addr = 0;
uint32_t len = 0;
uint64_t val = 0;
int status;
int i;
if (cmd[3] == 'r') {
status = sscanf(cmd, "%*s %lx %d", &addr, &len);
if (status != 2) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
handle_reg_read(addr, len);
} else if (cmd[3] == 'w') {
status = sscanf(cmd, "%*s %lx %lx", &addr, &val);
if (status != 2) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
reg_write(addr, val);
} else {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
printf("\n");
return 0;
}
void handle_reg_read(uint64_t addr, uint32_t len)
{
uint32_t rdata;
uint32_t i;
for (i = 0; i < len; i+=4) {
if ((i%16) == 0) {
printf("\n%.8lX: ", addr+i);
}
reg_read(addr+i, &rdata);
printf("%.8X ", rdata);
}
printf("\n");
}
void handle_csb_read(uint64_t addr, uint32_t len)
{
uint32_t rdata;
uint32_t i;
for (i = 0; i < len; i+=4) {
if ((i%16) == 0) {
printf("\n%.8lX: ", addr+i);
}
csb_read(addr+i, &rdata);
printf("%.8X ", rdata);
}
printf("\n");
}
int handle_csb(char *cmd)
{
uint64_t addr = 0;
uint32_t len = 0;
uint64_t val = 0;
int status;
int i;
if (cmd[3] == 'r') {
status = sscanf(cmd, "%*s %lx %d", &addr, &len);
if (status != 2) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
handle_csb_read(addr, len);
} else if (cmd[3] == 'w') {
status = sscanf(cmd, "%*s %lx %lx", &addr, &val);
if (status != 2) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
csb_write(addr, val);
} else {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
printf("\n");
return 0;
}
int handle_hbm(char *cmd)
{
uint32_t width = 32;
uint64_t addr = 0;
uint32_t len = 0;
uint64_t val = 0;
uint32_t inc = 1;
int status;
int i;
uint32_t rdata32;
uint64_t rdata64;
if (cmd[3] == 'r') {
if (cmd[4] == ' ') {
status = sscanf(cmd, "%*s %lx %d", &addr, &len);
if (status != 2) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
} else {
status = sscanf(cmd+4, "%d %lx %d", &width, &addr, &len);
if (status != 3) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
}
if (width == 32 || width == 64) {
handle_hbm_read(addr, len, width);
} else {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
} else if (cmd[3] == 'w') {
if (cmd[4] == ' ') {
status = sscanf(cmd, "%*s %lx %lx", &addr, &val);
if (status != 2) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
mem_write32(addr, val);
} else {
status = sscanf(cmd+4, "%d %lx %lx", &width, &addr, &val);
if (status != 3) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
if (width == 32) {
mem_write32(addr, val);
} else if (width == 64) {
mem_write64(addr, val);
} else {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
}
} else if (cmd[3] == 'f') {
if (cmd[4] == ' ') {
status = sscanf(cmd, "%*s %lx %lx %d %x", &addr, &val, &len, &inc);
if ((status != 3) && (status != 4)) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
if (status == 3) {
inc = 1;
}
} else {
status = sscanf(cmd+4, "%d %lx %lx %d %x", &width, &addr, &val, &len, &inc);
if ((status != 4) && (status != 5)) {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
if (status == 4) {
inc = 1;
}
}
if (width == 32 || width == 64) {
handle_hbm_fill(addr, val, len, inc, width);
} else {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
} else {
printf("Syntax error (use ? for help), %s %d\n", __FILE__, __LINE__);
/* Don't break out of command processing loop */
return 0;
}
printf("\n");
return 0;
}
void handle_hbm_read(uint64_t addr, uint32_t len, uint32_t width)
{
uint32_t i;
uint32_t rdata32;
uint64_t rdata64;
if (width == 32) {
for (i = 0; i < len; i+=4) {
if ((i%16) == 0) {
printf("\n%.8lX: ", addr+i);
}
mem_read32(addr+i, &rdata32);
printf("%.8X ", rdata32);
}
} else if (width == 64) {
for (i = 0; i < len; i+=8) {
if ((i%16) == 0) {
printf("\n%.8lX: ", addr+i);
}
mem_read64(addr+i, &rdata64);
printf("%.8lX ", rdata64);
}
}
printf("\n");
}
void handle_hbm_fill(uint64_t addr, uint64_t val, uint64_t len, uint32_t inc, uint32_t width)
{
int i;
uint32_t wdata32;
uint64_t wdata64;
if (width == 32) {
for (i = 0; i < len; i+=4) {
wdata32 = (uint32_t)(val + i*inc);
mem_write32(addr+i, wdata32);
}
} else if (width == 64) {
for (i = 0; i < len; i+=8) {
wdata64 = (uint64_t)(val + i*inc);
mem_write64(addr+i, wdata64);
}
}
}
generic_api
#ifndef GENERIC_API_H_
#define GENERIC_API_H_
#ifdef __cplusplus
extern "C" {
#endif
void reg_write(uint64_t offset, uint32_t wdata);
void reg_read(uint64_t offset, uint32_t *rdata);
void reg_pull(uint64_t offset, uint32_t exp_data);
void mem_write32(uint64_t offset, uint32_t wdata);
void mem_read32(uint64_t offset, uint32_t *rdata);
void mem_write64(uint64_t offset, uint64_t wdata);
void mem_read64(uint64_t offset, uint64_t *rdata);
void csb_write(uint64_t offset, uint32_t wdata);
void csb_read(uint64_t offset, uint32_t *rdata);
//int kmem_alloc(uint32_t size, uint64_t *paddr, void **vaddr);
//int kmem_release(uint32_t id);
int wait_irq(uint32_t vec);
#ifdef __cplusplus
}
#endif
#endif
#include <stdio.h>
#include <stdint.h>
/* Libraries for accessing PCIe devices */
#ifdef __cplusplus
extern "C" {
#endif
void pci_init(char *device);
void pci_cleanup();
void bar_write(uint32_t idx, uint64_t offset, uint64_t data, uint32_t ndw);
void bar_read(uint32_t idx, uint64_t offset, uint64_t *data, uint32_t ndw);
void pci_cfg_write(uint32_t offset, uint32_t data);
void pci_cfg_read(uint32_t offset, uint32_t *data);
int kmem_reserve(uint32_t size);
int kmem_release(uint32_t id);
uint64_t kmem_get_paddr(uint32_t id);
void* kmem_mmap(uint32_t id, uint32_t size);
int wait_msi_vector(uint32_t vec);
#ifdef __cplusplus
}
#endif
#define REG_BAR 1
#define MEM_BAR 2
#define CSB_BAR 4
void reg_write(uint64_t offset, uint32_t wdata)
{
bar_write(REG_BAR, offset, wdata, 0x1);
}
void reg_read(uint64_t offset, uint32_t *rdata)
{
uint64_t rdata64;
bar_read(REG_BAR, offset, &rdata64, 0x1);
*rdata = 0xFFFFFFFF & rdata64;
}
void reg_pull(uint64_t offset, uint32_t exp_data)
{
uint32_t rdata;
do {
reg_read(offset, &rdata);
} while (rdata != exp_data);
}
void mem_write32(uint64_t offset, uint32_t wdata)
{
bar_write(MEM_BAR, offset, wdata, 0x1);
}
void mem_read32(uint64_t offset, uint32_t *rdata)
{
uint64_t rdata64;
bar_read(MEM_BAR, offset, &rdata64, 0x1);
*rdata = 0xFFFFFFFF & rdata64;
}
void mem_write64(uint64_t offset, uint64_t wdata)
{
bar_write(MEM_BAR, offset, wdata, 0x2);
}
void mem_read64(uint64_t offset, uint64_t *rdata)
{
bar_read(MEM_BAR, offset, rdata, 0x2);
}
void csb_write(uint64_t offset, uint32_t wdata)
{
bar_write(CSB_BAR, offset, wdata, 0x1);
}
void csb_read(uint64_t offset, uint32_t *rdata)
{
uint64_t rdata64;
bar_read(CSB_BAR, offset, &rdata64, 0x1);
*rdata = 0xFFFFFFFF & rdata64;
}
void cfg_write(uint32_t offset, uint32_t data)
{
pci_cfg_write(offset, data);
}
void cfg_read(uint32_t offset, uint32_t *data)
{
pci_cfg_read(offset, data);
}
int kmem_new(uint32_t size, uint64_t *paddr, void **vaddr)
{
int ret;
ret = kmem_reserve(size);
if (ret < 0) {
printf("ERROR while trying to reserve kernel space\n");
return ret;
}
*paddr = kmem_get_paddr(ret);
*vaddr = kmem_mmap(ret, size);
return ret;
}
int kmem_delete(uint32_t id)
{
//return kmem_release(id);
}
int wait_irq(uint32_t vec)
{
// return wait_msi_vector(vec);
}
pci_utils
#ifndef DPI_TASKS_H_
#define DPI_TASKS_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Initialize PCIe device
int pci_init(char *device);
// Cleanup PCIe device
int pci_cleanup();
// Access PCIe bars
void bar_write(uint32_t idx, uint64_t offset, uint64_t data, uint32_t ndw);
void bar_read(uint32_t idx, uint64_t offset, uint64_t *data, uint32_t ndw);
uint64_t bar_offset(uint32_t idx);
// Access PCIe configuration space
void pci_cfg_write(uint32_t offset, uint32_t data);
void pci_cfg_read(uint32_t offset, uint32_t *data);
// Kernal memory initialization
int kmem_init();
// Allocate/De-allocate kernel memory
int kmem_reserve(uint32_t size);
int kmem_release(uint32_t id);
// Get physical address of kernel memory
uint64_t kmem_get_paddr(uint32_t id);
// Get virtual address of kernel memory
void* kmem_mmap(uint32_t id, uint32_t size);
// MSI interrupt
int msi_init(void);
void msi_cleanup(void);
int wait_msi_vector(uint32_t vec);
#ifdef __cplusplus
}
#endif
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <byteswap.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "uio_pci_msi.h"
#include "pci_utils.h"
#include "pts_config.h"
//---------------------------------------------------------
// Type define and global variables
//---------------------------------------------------------
// Support maximum 32 interrupt vectors
#define MAX_IRQ_VEC 1
#ifdef SCORPIO
#define ECF_BUS_OFFSET 0x2000000
#else
#define ECF_BUS_OFFSET 0x00000
#endif
// PCIe device type define
typedef struct {
/* Base address region */
unsigned int bar;
/* Slot info */
unsigned int domain;
unsigned int bus;
unsigned int slot;
unsigned int function;
/* Resource filename */
char filename[100];
/* File descriptor of the resource */
int fd;
/* Memory mapped resource */
unsigned char *maddr;
unsigned long int size;
unsigned int offset;
/* PCI physical address */
unsigned int phys;
/* Address to pass to read/write (includes offset) */
unsigned char *addr;
} device_t;
// Variables for ecf and edf device
device_t edf_device;
device_t ecf_device;
device_t csb_device;
// Variables for kernel memory access
int kmem_fd;
// Variables for MSI interrupt
struct uio_msi_irq_set msi_set[MAX_IRQ_VEC];
//---------------------------------------------------------
// Functions
//---------------------------------------------------------
// PCIe device initialization
int pci_init(char *device)
{
int status;
struct stat statbuf;
/* Clear the structure fields */
memset(&edf_device, 0, sizeof(device_t));
memset(&ecf_device, 0, sizeof(device_t));
memset(&csb_device, 0, sizeof(device_t));
FILE * fp;
char buffer[80];
char command[50];
char type[50];
strcpy( command, "lspci -d 1e36:" );
//strcpy( command, "lspci -d 1ea0:" );
strcpy( type, "r" );
fp=popen(command,type);
fgets(buffer,sizeof(buffer),fp);
printf("lspci -d 1e36: = %s",buffer);
pclose(fp);
//system(command);
status = sscanf(buffer, "%2x:%2x.%1x",
//status = sscanf(device, "%2x:%2x.%1x",
&(edf_device.bus), &(edf_device.slot), &(edf_device.function));
if (status != 3) {
printf("Error parsing slot information!\n");
return -1;
}
ecf_device.bus = edf_device.bus;
ecf_device.slot = edf_device.slot;
ecf_device.function = edf_device.function;
csb_device.bus = edf_device.bus;
csb_device.slot = edf_device.slot;
csb_device.function = edf_device.function;
ecf_device.bar = 1;
edf_device.bar = 2;
csb_device.bar = 4;
/* Convert to a sysfs resource filename and open the resource */
snprintf(ecf_device.filename, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/resource%d",
ecf_device.domain, ecf_device.bus, ecf_device.slot, ecf_device.function, ecf_device.bar);
ecf_device.fd = open(ecf_device.filename, O_RDWR | O_SYNC);
if (ecf_device.fd < 0) {
printf("Open failed for file '%s': errno %d, %s\n",
ecf_device.filename, errno, strerror(errno));
return -1;
}
/* Convert to a sysfs resource filename and open the resource */
snprintf(edf_device.filename, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/resource%d",
edf_device.domain, edf_device.bus, edf_device.slot, edf_device.function, edf_device.bar);
edf_device.fd = open(edf_device.filename, O_RDWR | O_SYNC);
if (edf_device.fd < 0) {
printf("Open failed for file '%s': errno %d, %s\n",
edf_device.filename, errno, strerror(errno));
return -1;
}
/* Convert to a sysfs resource filename and open the resource */
snprintf(csb_device.filename, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/resource%d",
csb_device.domain, csb_device.bus, csb_device.slot, csb_device.function, csb_device.bar);
csb_device.fd = open(csb_device.filename, O_RDWR | O_SYNC);
if (csb_device.fd < 0) {
printf("Open failed for file '%s': errno %d, %s\n",
csb_device.filename, errno, strerror(errno));
return -1;
}
/* PCI memory size */
status = fstat(ecf_device.fd, &statbuf);
if (status < 0) {
printf("fstat() failed: errno %d, %s\n",
errno, strerror(errno));
return -1;
}
ecf_device.size = statbuf.st_size;
//printf("ecf_device.size = 0x%lx\n", ecf_device.size);
status = fstat(edf_device.fd, &statbuf);
if (status < 0) {
printf("fstat() failed: errno %d, %s\n",
errno, strerror(errno));
return -1;
}
edf_device.size = statbuf.st_size;
//printf("edf_device.size = 0x%lx\n", edf_device.size);
status = fstat(csb_device.fd, &statbuf);
if (status < 0) {
printf("fstat() failed: errno %d, %s\n",
errno, strerror(errno));
return -1;
}
csb_device.size = statbuf.st_size;
//printf("csb_device.size = 0x%lx\n", csb_device.size);
/* Map */
ecf_device.maddr = (unsigned char *)mmap(
NULL,
(size_t)(ecf_device.size),
PROT_READ|PROT_WRITE,
MAP_SHARED,
ecf_device.fd,
0);
if (ecf_device.maddr == (unsigned char *)MAP_FAILED) {
printf("BARs that are I/O ports are not supported by this tool\n");
ecf_device.maddr = 0;
close(ecf_device.fd);
return -1;
}
edf_device.maddr = (unsigned char *)mmap(
NULL,
(size_t)(edf_device.size),
PROT_READ|PROT_WRITE,
MAP_SHARED,
edf_device.fd,
0);
if (edf_device.maddr == (unsigned char *)MAP_FAILED) {
printf("BARs that are I/O ports are not supported by this tool\n");
edf_device.maddr = 0;
close(edf_device.fd);
return -1;
}
csb_device.maddr = (unsigned char *)mmap(
NULL,
(size_t)(csb_device.size),
PROT_READ|PROT_WRITE,
MAP_SHARED,
csb_device.fd,
0);
if (csb_device.maddr == (unsigned char *)MAP_FAILED) {
printf("BARs that are I/O ports are not supported by this tool\n");
csb_device.maddr = 0;
close(csb_device.fd);
return -1;
}
/* Device regions smaller than a 4k page in size can be offset
* relative to the mapped base address. The offset is
* the physical address modulo 4k
*/
{
char configname[100];
int fd;
snprintf(configname, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/config",
ecf_device.domain, ecf_device.bus, ecf_device.slot, ecf_device.function);
fd = open(configname, O_RDWR | O_SYNC);
if (fd < 0) {
printf("Open failed for file '%s': errno %d, %s\n",
configname, errno, strerror(errno));
return -1;
}
status = lseek(fd, 0x10 + 4*ecf_device.bar, SEEK_SET);
if (status < 0) {
printf("Error: configuration space lseek failed\n");
close(fd);
return -1;
}
status = read(fd, &ecf_device.phys, 4);
if (status < 0) {
printf("Error: configuration space read failed\n");
close(fd);
return -1;
}
ecf_device.offset = ((ecf_device.phys & 0xFFFFFFF0) % 0x1000);
ecf_device.addr = ecf_device.maddr + ecf_device.offset;
close(fd);
}
{
char configname[100];
int fd;
snprintf(configname, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/config",
edf_device.domain, edf_device.bus, edf_device.slot, edf_device.function);
fd = open(configname, O_RDWR | O_SYNC);
if (fd < 0) {
printf("Open failed for file '%s': errno %d, %s\n",
configname, errno, strerror(errno));
return -1;
}
status = lseek(fd, 0x10 + 4*edf_device.bar, SEEK_SET);
if (status < 0) {
printf("Error: configuration space lseek failed\n");
close(fd);
return -1;
}
status = read(fd, &edf_device.phys, 4);
if (status < 0) {
printf("Error: configuration space read failed\n");
close(fd);
return -1;
}
edf_device.offset = ((edf_device.phys & 0xFFFFFFF0) % 0x1000);
edf_device.addr = edf_device.maddr + edf_device.offset;
close(fd);
}
{
char configname[100];
int fd;
snprintf(configname, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/config",
csb_device.domain, csb_device.bus, csb_device.slot, csb_device.function);
fd = open(configname, O_RDWR | O_SYNC);
if (fd < 0) {
printf("Open failed for file '%s': errno %d, %s\n",
configname, errno, strerror(errno));
return -1;
}
status = lseek(fd, 0x10 + 4*csb_device.bar, SEEK_SET);
if (status < 0) {
printf("Error: configuration space lseek failed\n");
close(fd);
return -1;
}
status = read(fd, &csb_device.phys, 4);
if (status < 0) {
printf("Error: configuration space read failed\n");
close(fd);
return -1;
}
csb_device.offset = ((csb_device.phys & 0xFFFFFFF0) % 0x1000);
csb_device.addr = csb_device.maddr + csb_device.offset;
close(fd);
}
// Initialize kernel memory
// status = kmem_init();
// if (status < 0) {
// printf("Warning: initialize kmem failed\n");
// return -1;
// }
// Initialize MSI interrupt
// status = msi_init();
// if (status < 0) {
// printf("Warning: initialize msi failed\n");
// return -1;
// }
return 0;
}
// Cleanup PCIe devices
int pci_cleanup()
{
msi_cleanup();
}
uint64_t bar_offset(uint32_t idx)
{
if (idx == 1) {
return ecf_device.addr;
} else if (idx == 2) {
return edf_device.addr;
} else if (idx == 4) {
return csb_device.addr;
}
}
// Write PCIe bar space
void bar_write(uint32_t idx, uint64_t offset, uint64_t data, uint32_t ndw)
{
if (idx == 1) {
assert(ndw == 1);
assert(offset%4 == 0);
*(volatile uint32_t *)(ecf_device.addr + offset - ECF_BUS_OFFSET) = data;
msync((void *)(ecf_device.addr + offset - ECF_BUS_OFFSET), 4, MS_SYNC | MS_INVALIDATE);
} else if (idx == 2) {
if (ndw == 2) {
assert(offset%8 == 0);
*(volatile uint64_t *)(edf_device.addr + offset) = data;
msync((void *)(edf_device.addr + offset), 8, MS_SYNC | MS_INVALIDATE);
} else if (ndw == 1) {
assert(offset%4 == 0);
*(volatile uint32_t *)(edf_device.addr + offset) = data;
msync((void *)(edf_device.addr + offset), 4, MS_SYNC | MS_INVALIDATE);
} else {
assert(0);
}
} else if (idx == 4) {
assert(ndw == 1);
assert(offset%4 == 0);
*(volatile uint32_t *)(csb_device.addr + offset) = data;
msync((void *)(csb_device.addr + offset), 4, MS_SYNC | MS_INVALIDATE);
} else {
assert(0);
}
}
// Read PCIe bar space
void bar_read(uint32_t idx, uint64_t offset, uint64_t *data, uint32_t ndw)
{
if (idx == 1) {
assert(ndw == 1);
assert(offset%4 == 0);
uint32_t rdata = *(volatile uint32_t *)(ecf_device.addr + offset - ECF_BUS_OFFSET);
*data = rdata;
} else if (idx == 2) {
if (ndw == 2) {
assert(offset%8 == 0);
uint64_t rdata = *(volatile uint64_t *)(edf_device.addr + offset);
*data = rdata;
} else if (ndw == 1) {
assert(offset%4 == 0);
uint32_t rdata = *(volatile uint32_t *)(edf_device.addr + offset);
*data = rdata;
} else {
assert(0);
}
} else if (idx == 4) {
assert(ndw == 1);
assert(offset%4 == 0);
uint32_t rdata = *(volatile uint32_t *)(csb_device.addr + offset);
*data = rdata;
} else {
assert(0);
}
}
// Write PCIe config space
void pci_cfg_write(uint32_t offset, uint32_t data)
{
printf("ERROR! pci_cfg_write not implemented!\n");
assert(0);
}
// Read PCIe config space
void pci_cfg_read(uint32_t offset, uint32_t *data)
{
printf("ERROR! pci_cfg_read not implemented!\n");
assert(0);
}
// Kernel memory initialization
int kmem_init()
{
kmem_fd = open("/dev/uio0", O_RDWR);
if (kmem_fd == -1) {
//printf("ERROR! cannot open device /dev/uio0\n");
return -1;
}
}
// Allocate kernel memory
int kmem_reserve(uint32_t size)
{
return ioctl(kmem_fd, UIO_MSI_DMEM_RESERVE, size);
}
// De-allocate kernel memory
int kmem_release(uint32_t id)
{
return ioctl(kmem_fd, UIO_MSI_DMEM_RELEASE, id);
}
// Get physical address of kernel memory
uint64_t kmem_get_paddr(uint32_t id)
{
return ioctl(kmem_fd, UIO_MSI_DMEM_GET_PHYSICAL, id);
}
// Get virtual address of kernel memory
void* kmem_mmap(uint32_t id, uint32_t size)
{
if (ioctl(kmem_fd, UIO_MSI_DMEM_ACTIVATE_BUFFER, id) < 0) {
printf("ERROR while trying to activate kmem buffer %d\n", id);
return NULL;
}
return mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, kmem_fd, 0);
}
// Initialize MSI interrupt
int msi_init(void)
{
int i;
for (i=0; i<MAX_IRQ_VEC; i++) {
msi_set[i].vec = i;
msi_set[i].fd = eventfd(0, 0);
if (msi_set[i].fd < 0) {
printf("ERROR trying to create fd for MSI vector %d\n", i);
return -1;
}
if (ioctl(kmem_fd, UIO_MSI_IRQ_SET, &msi_set[i]) < 0) {
printf("ERROR while trying to enable msi vector %d\n", i);
}
}
return 0;
}
// MSI interrupt cleanup
void msi_cleanup(void)
{
int i;
for (i=0; i<MAX_IRQ_VEC; i++) {
if (msi_set[i].fd >= 0) {
close(msi_set[i].fd);
}
}
}
// Wait MSI interrupt vector
int wait_msi_vector(uint32_t vec)
{
if (vec >= MAX_IRQ_VEC) {
printf("ERROR! wait_msi_vector vec=%d, MAX_IRQ_VEC=%d", vec, MAX_IRQ_VEC);
return -1;
}
uint32_t i;
uint64_t cnt;
if (read(msi_set[vec].fd, &cnt, sizeof(cnt)) < 0) {
printf("NO MSI GET\n");
return -1;
}
return cnt;
}