Blame tools/extra/mmlink/main.cpp

Packit 534379
// Copyright(c) 2017-2020, Intel Corporation
Packit 534379
//
Packit 534379
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 534379
// modification, are permitted provided that the following conditions are met:
Packit 534379
//
Packit 534379
// * Redistributions of  source code  must retain the  above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer.
Packit 534379
// * Redistributions in binary form must reproduce the above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer in the documentation
Packit 534379
//   and/or other materials provided with the distribution.
Packit 534379
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 534379
//   may be used to  endorse or promote  products derived  from this  software
Packit 534379
//   without specific prior written permission.
Packit 534379
//
Packit 534379
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 534379
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 534379
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 534379
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 534379
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 534379
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 534379
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 534379
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 534379
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 534379
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 534379
// POSSIBILITY OF SUCH DAMAGE.
Packit 534379
Packit 534379
#ifdef HAVE_CONFIG_H
Packit 534379
#include <config.h>
Packit 534379
#endif // HAVE_CONFIG_H
Packit 534379
#include <stdlib.h>
Packit 534379
#include <getopt.h>
Packit 534379
#include <signal.h>
Packit 534379
#include <new>
Packit 534379
#include <arpa/inet.h>
Packit 534379
Packit 534379
#include <opae/fpga.h>
Packit 534379
#include "mmlink_server.h"
Packit 534379
#include "mm_debug_link_interface.h"
Packit 534379
Packit 534379
// STP index in AFU
Packit 534379
#define FPGA_PORT_INDEX_STP               1
Packit 534379
#define FPGA_PORT_STP_DFH_REVBIT         12
Packit 534379
Packit 534379
#define GETOPT_STRING ":hB:D:F:S:P:Iv"
Packit 534379
Packit 534379
#define PRINT_ERR(format, ...) \
Packit 534379
	printf("%s:%u:%s() : " format "\n", __FILE__, __LINE__, __func__,\
Packit 534379
               ## __VA_ARGS__)
Packit 534379
Packit 534379
struct option longopts[] = {
Packit 534379
		{"help",        no_argument,       NULL, 'h'},
Packit 534379
		{"segment",     required_argument, NULL, 0xe},
Packit 534379
		{"bus",         required_argument, NULL, 'B'},
Packit 534379
		{"device",      required_argument, NULL, 'D'},
Packit 534379
		{"function",    required_argument, NULL, 'F'},
Packit 534379
		{"socket-id",   required_argument, NULL, 'S'},
Packit 534379
		{"port",        required_argument, NULL, 'P'},
Packit 534379
		{"ip",          required_argument, NULL, 'I'},
Packit 534379
    {"version",     no_argument,       NULL, 'v'},
Packit 534379
		{0,0,0,0}
Packit 534379
};
Packit 534379
Packit 534379
// mmlink Command line struct
Packit 534379
struct  MMLinkCommandLine
Packit 534379
{
Packit 534379
	int      segment;
Packit 534379
	int      bus;
Packit 534379
	int      device;
Packit 534379
	int      function;
Packit 534379
	int      socket;
Packit 534379
	int      port;
Packit 534379
	char     ip[16];
Packit 534379
};
Packit 534379
Packit 534379
struct MMLinkCommandLine mmlinkCmdLine = { -1, -1, -1, -1, -1, 0, { 0, } };
Packit 534379
Packit 534379
// mmlink Command line input help
Packit 534379
void MMLinkAppShowHelp()
Packit 534379
{
Packit 534379
	printf("Usage:\n");
Packit 534379
	printf("mmlink\n");
Packit 534379
	printf("<Segment>             --segment=<SEGMENT NUMBER>\n");
Packit 534379
	printf("<Bus>                 --bus=<BUS NUMBER>           "
Packit 534379
		"OR  -B <BUS NUMBER>\n");
Packit 534379
	printf("<Device>              --device=<DEVICE NUMBER>     "
Packit 534379
		"OR  -D <DEVICE NUMBER>\n");
Packit 534379
	printf("<Function>            --function=<FUNCTION NUMBER> "
Packit 534379
		"OR  -F <FUNCTION NUMBER>\n");
Packit 534379
	printf("<Socket-id>           --socket-id=<SOCKET NUMBER>  "
Packit 534379
		"OR  -S <SOCKET NUMBER>\n");
Packit 534379
	printf("<TCP PORT>            --port=<PORT>                "
Packit 534379
		"OR  -P <PORT>\n");
Packit 534379
	printf("<IP ADDRESS>          --ip=<IP ADDRESS>            "
Packit 534379
		"OR  -I <IP ADDRESS>\n");
Packit 534379
  printf("<Version>             -v,--version Print version and exit\n");
Packit 534379
	printf("\n");
Packit 534379
Packit 534379
}
Packit 534379
Packit 534379
/*
Packit 534379
 * macro to check return codes, print error message, and goto cleanup label
Packit 534379
 * NOTE: this changes the program flow (uses goto)!
Packit 534379
 */
Packit 534379
#define ON_ERR_GOTO(res, label, desc)                    \
Packit 534379
		do {                                       \
Packit 534379
			if ((res) != FPGA_OK) {            \
Packit 534379
				print_err((desc), (res));  \
Packit 534379
				goto label;                \
Packit 534379
			}                                  \
Packit 534379
		} while (0)
Packit 534379
Packit 534379
void print_err(const char *s, fpga_result res)
Packit 534379
{
Packit 534379
	fprintf(stderr, "Error %s: %s\n", s, fpgaErrStr(res));
Packit 534379
}
Packit 534379
Packit 534379
void mmlink_sig_handler(int sig)
Packit 534379
{
Packit 534379
	UNUSED_PARAM(sig);
Packit 534379
	perror("SIGINT: stopping the server\n");
Packit 534379
}
Packit 534379
Packit 534379
int ParseCmds(struct MMLinkCommandLine *mmlinkCmdLine,
Packit 534379
		int argc,
Packit 534379
		char *argv[]);
Packit 534379
int run_mmlink(fpga_handle  port_handle,
Packit 534379
		uint64_t *mmio_ptr,
Packit 534379
		struct MMLinkCommandLine *mmlinkCmdLine );
Packit 534379
Packit 534379
int main( int argc, char** argv )
Packit 534379
{
Packit 534379
	fpga_properties filter             = NULL;
Packit 534379
	uint32_t num_matches               = 1;
Packit 534379
	fpga_result result                 = FPGA_OK;
Packit 534379
	fpga_token port_token              = NULL;
Packit 534379
	fpga_handle  port_handle           = NULL;
Packit 534379
	uint64_t *mmio_ptr                 = NULL;
Packit 534379
	int res;
Packit 534379
Packit 534379
	// Parse command line
Packit 534379
	if ( argc < 2 ) {
Packit 534379
		MMLinkAppShowHelp();
Packit 534379
		return 1;
Packit 534379
	} else if ( 0 != (res = ParseCmds(&mmlinkCmdLine, argc, argv)) ) {
Packit 534379
		if (res != -2)
Packit 534379
			PRINT_ERR( "Error scanning command line \n.");
Packit 534379
		return 2;
Packit 534379
	}
Packit 534379
Packit 534379
	if ('\0' == mmlinkCmdLine.ip[0]) {
Packit 534379
		strncpy(mmlinkCmdLine.ip, "0.0.0.0", 8);
Packit 534379
		mmlinkCmdLine.ip[7] = '\0';
Packit 534379
	}
Packit 534379
Packit 534379
	printf(" ------- Command line Input START ----\n\n");
Packit 534379
Packit 534379
	printf(" Segment               : %d\n", mmlinkCmdLine.segment);
Packit 534379
	printf(" Bus                   : %d\n", mmlinkCmdLine.bus);
Packit 534379
	printf(" Device                : %d\n", mmlinkCmdLine.device);
Packit 534379
	printf(" Function              : %d\n", mmlinkCmdLine.function);
Packit 534379
	printf(" Socket-id             : %d\n", mmlinkCmdLine.socket);
Packit 534379
	printf(" Port                  : %d\n", mmlinkCmdLine.port);
Packit 534379
	printf(" IP address            : %s\n", mmlinkCmdLine.ip);
Packit 534379
	printf(" ------- Command line Input END   ----\n\n");
Packit 534379
Packit 534379
	// Signal Handler
Packit 534379
	signal(SIGINT, mmlink_sig_handler);
Packit 534379
Packit 534379
	// Enum FPGA device
Packit 534379
	result = fpgaGetProperties(NULL, &filter);
Packit 534379
	ON_ERR_GOTO(result, out_exit, "creating properties object");
Packit 534379
Packit 534379
	result = fpgaPropertiesSetObjectType(filter, FPGA_ACCELERATOR);
Packit 534379
	ON_ERR_GOTO(result, out_destroy_prop, "setting object type");
Packit 534379
Packit 534379
	if (mmlinkCmdLine.segment > -1){
Packit 534379
		result = fpgaPropertiesSetSegment(filter, mmlinkCmdLine.segment);
Packit 534379
		ON_ERR_GOTO(result, out_destroy_prop, "setting segment");
Packit 534379
	}
Packit 534379
Packit 534379
	if (mmlinkCmdLine.bus > -1){
Packit 534379
		result = fpgaPropertiesSetBus(filter, mmlinkCmdLine.bus);
Packit 534379
		ON_ERR_GOTO(result, out_destroy_prop, "setting bus");
Packit 534379
	}
Packit 534379
Packit 534379
	if (mmlinkCmdLine.device > -1) {
Packit 534379
		result = fpgaPropertiesSetDevice(filter, mmlinkCmdLine.device);
Packit 534379
		ON_ERR_GOTO(result, out_destroy_prop, "setting device");
Packit 534379
	}
Packit 534379
Packit 534379
	if (mmlinkCmdLine.function > -1){
Packit 534379
		result = fpgaPropertiesSetFunction(filter, mmlinkCmdLine.function);
Packit 534379
		ON_ERR_GOTO(result, out_destroy_prop, "setting function");
Packit 534379
	}
Packit 534379
Packit 534379
	if (mmlinkCmdLine.socket > -1){
Packit 534379
		result = fpgaPropertiesSetSocketID(filter, mmlinkCmdLine.socket);
Packit 534379
		ON_ERR_GOTO(result, out_destroy_prop, "setting socket");
Packit 534379
	}
Packit 534379
Packit 534379
	result = fpgaEnumerate(&filter, 1, &port_token,1, &num_matches);
Packit 534379
	ON_ERR_GOTO(result, out_destroy_prop, "enumerating FPGAs");
Packit 534379
Packit 534379
	if (num_matches < 1) {
Packit 534379
		fprintf(stderr, "PORT  Resource not found.\n");
Packit 534379
		result = fpgaDestroyProperties(&filter);
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
	fprintf(stderr, "PORT Resource found.\n");
Packit 534379
Packit 534379
	result = fpgaOpen(port_token, &port_handle, FPGA_OPEN_SHARED);
Packit 534379
	ON_ERR_GOTO(result, out_destroy_tok, "opening accelerator");
Packit 534379
Packit 534379
	result = fpgaMapMMIO(port_handle, FPGA_PORT_INDEX_STP, &mmio_ptr);
Packit 534379
	ON_ERR_GOTO(result, out_close, "mapping MMIO space");
Packit 534379
Packit 534379
	if( run_mmlink(port_handle,mmio_ptr,&mmlinkCmdLine) != 0) {
Packit 534379
		PRINT_ERR( "Failed to connect MMLINK  \n.");
Packit 534379
		result = FPGA_NOT_SUPPORTED;
Packit 534379
	}
Packit 534379
Packit 534379
	/* Unmap MMIO space */
Packit 534379
	result = fpgaUnmapMMIO(port_handle, FPGA_PORT_INDEX_STP);
Packit 534379
	ON_ERR_GOTO(result, out_close, "unmapping MMIO space");
Packit 534379
Packit 534379
	/* Close driver handle */
Packit 534379
out_close:
Packit 534379
	result = fpgaClose(port_handle);
Packit 534379
	ON_ERR_GOTO(result, out_destroy_tok, "closing Port");
Packit 534379
Packit 534379
	/* Destroy token */
Packit 534379
out_destroy_tok:
Packit 534379
	result = fpgaDestroyToken(&port_token);
Packit 534379
	ON_ERR_GOTO(result, out_destroy_prop, "destroying token");
Packit 534379
Packit 534379
	/* Destroy properties object */
Packit 534379
out_destroy_prop:
Packit 534379
	result = fpgaDestroyProperties(&filter);
Packit 534379
	ON_ERR_GOTO(result, out_exit, "destroying properties object");
Packit 534379
Packit 534379
out_exit:
Packit 534379
	return result;
Packit 534379
Packit 534379
}
Packit 534379
Packit 534379
// run MMLink server
Packit 534379
int run_mmlink(fpga_handle  port_handle,
Packit 534379
		uint64_t *mmio_ptr,
Packit 534379
		struct MMLinkCommandLine *mmlinkCmdLine )
Packit 534379
{
Packit 534379
	mmlink_server *server          = NULL;
Packit 534379
	int res                        = 0;
Packit 534379
	struct sockaddr_in sock;
Packit 534379
	uint64_t value                 = 0;
Packit 534379
Packit 534379
	if (mmio_ptr == NULL) {
Packit 534379
		PRINT_ERR("Invalid input mmio pointer \n");
Packit 534379
		return -1;
Packit 534379
	}
Packit 534379
Packit 534379
	if (mmlinkCmdLine == NULL) {
Packit 534379
		PRINT_ERR("Invalid input command line \n");
Packit 534379
		return -1;
Packit 534379
	}
Packit 534379
Packit 534379
	memset(&sock, 0, sizeof(sock));
Packit 534379
	sock.sin_family = AF_INET;
Packit 534379
	sock.sin_port = htons(mmlinkCmdLine->port);
Packit 534379
	if (1 != inet_pton(AF_INET, mmlinkCmdLine->ip, &sock.sin_addr)) {
Packit 534379
		PRINT_ERR("Failed to convert IP address: %s\n", mmlinkCmdLine->ip);
Packit 534379
		return -1;
Packit 534379
	}
Packit 534379
Packit 534379
	res = fpgaReadMMIO64(port_handle, FPGA_PORT_INDEX_STP, 0, &value);
Packit 534379
	if (res != 0) {
Packit 534379
		PRINT_ERR("Failed to read STP DFH \n");
Packit 534379
		return -1;
Packit 534379
	}
Packit 534379
	//printf("STP DFH = 0x%lx\n" ,value);
Packit 534379
Packit 534379
	value &= 0x1000;
Packit 534379
	value = value >> FPGA_PORT_STP_DFH_REVBIT;
Packit 534379
	if(1 != value){
Packit 534379
		PRINT_ERR("Invalid STP revision number \n");
Packit 534379
		return -1;
Packit 534379
	}
Packit 534379
	mm_debug_link_interface *driver = get_mm_debug_link();
Packit 534379
	server = new (std::nothrow) mmlink_server(&sock, driver);
Packit 534379
	if (!server) {
Packit 534379
		PRINT_ERR("Failed to allocate memory \n");
Packit 534379
		return -1;
Packit 534379
	}
Packit 534379
Packit 534379
	// Run MMLink server
Packit 534379
	res = server->run((unsigned char*)mmio_ptr);
Packit 534379
Packit 534379
	if (server)
Packit 534379
		delete server;
Packit 534379
Packit 534379
	return res;
Packit 534379
}
Packit 534379
Packit 534379
// parse Input command line
Packit 534379
int ParseCmds(struct MMLinkCommandLine *mmlinkCmdLine, int argc, char *argv[])
Packit 534379
{
Packit 534379
	int getopt_ret     = 0 ;
Packit 534379
	int option_index   = 0;
Packit 534379
	char *endptr       = NULL;
Packit 534379
Packit 534379
	while( -1 != ( getopt_ret = getopt_long(argc, argv, GETOPT_STRING,
Packit 534379
			longopts, &option_index))){
Packit 534379
		const char *tmp_optarg = optarg;
Packit 534379
Packit 534379
		if((optarg) &&
Packit 534379
		   ('=' == *tmp_optarg)){
Packit 534379
			++tmp_optarg;
Packit 534379
		}
Packit 534379
Packit 534379
		if((!optarg) && (optind < argc) &&
Packit 534379
	 	   (NULL != argv[optind]) &&
Packit 534379
		   ('-' != argv[optind][0]) ) {
Packit 534379
			tmp_optarg = argv[optind++];
Packit 534379
		}
Packit 534379
Packit 534379
		switch(getopt_ret){
Packit 534379
		case 'h':
Packit 534379
			// Command line help
Packit 534379
			MMLinkAppShowHelp();
Packit 534379
			return -2;
Packit 534379
			break;
Packit 534379
Packit 534379
		case 0xe:
Packit 534379
			// segment number
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --segment");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			endptr = NULL;
Packit 534379
			mmlinkCmdLine->segment = strtol(tmp_optarg, &endptr, 0);
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'B':
Packit 534379
			// bus number
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --bus");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			endptr = NULL;
Packit 534379
			mmlinkCmdLine->bus = strtol(tmp_optarg, &endptr, 0);
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'D':
Packit 534379
			// Device number
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --device");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			endptr = NULL;
Packit 534379
			mmlinkCmdLine->device = strtol(tmp_optarg, &endptr, 0);
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'F':
Packit 534379
			// Function number
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --function");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			endptr = NULL;
Packit 534379
			mmlinkCmdLine->function = strtol(tmp_optarg,
Packit 534379
							&endptr, 0);
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'S':
Packit 534379
			// Socket number
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --socket");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			endptr = NULL;
Packit 534379
			mmlinkCmdLine->socket = strtol(tmp_optarg, &endptr, 0);
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'P':
Packit 534379
			// TCP Port 
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --port");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			endptr = NULL;
Packit 534379
			mmlinkCmdLine->port = strtol(tmp_optarg, &endptr, 0);
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'I':
Packit 534379
			// Ip address
Packit 534379
			if (!tmp_optarg) {
Packit 534379
				PRINT_ERR("Missing required argument for --ip");
Packit 534379
				return -1;
Packit 534379
			}
Packit 534379
			strncpy(mmlinkCmdLine->ip, tmp_optarg, 15);
Packit 534379
			mmlinkCmdLine->ip[15] = '\0';
Packit 534379
			break;
Packit 534379
Packit 534379
		case 'v':
Packit 534379
			// Version
Packit 534379
			printf("mmlink %s %s%s\n",
Packit 534379
				OPAE_VERSION,
Packit 534379
				OPAE_GIT_COMMIT_HASH,
Packit 534379
				OPAE_GIT_SRC_TREE_DIRTY ? "*":"");
Packit 534379
			return -2;
Packit 534379
Packit 534379
		case '?':
Packit 534379
		default: /* invalid option */
Packit 534379
			printf("Invalid cmdline options.\n");
Packit 534379
			return -1;
Packit 534379
		}
Packit 534379
	}
Packit 534379
Packit 534379
	return 0;
Packit 534379
}