Blame opae-libs/tests/xfpga/test_open_close_c.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
extern "C"{
Packit 534379
#include "token_list_int.h"
Packit 534379
}
Packit 534379
Packit 534379
#include "gtest/gtest.h"
Packit 534379
#include "mock/test_system.h"
Packit 534379
#include "xfpga.h"
Packit 534379
#include "types_int.h"
Packit 534379
#include "opae/mmio.h"
Packit 534379
#include "intel-fpga.h"
Packit 534379
#include "fpga-dfl.h"
Packit 534379
#include "opae/access.h"
Packit 534379
#include "linux/ioctl.h"
Packit 534379
#include "cstdarg"
Packit 534379
Packit 534379
#include "error_int.h"
Packit 534379
Packit 534379
extern "C" {
Packit 534379
int xfpga_plugin_initialize(void);
Packit 534379
int xfpga_plugin_finalize(void);
Packit 534379
}
Packit 534379
Packit 534379
using namespace opae::testing;
Packit 534379
Packit 534379
#ifndef BUILD_ASE
Packit 534379
/*
Packit 534379
 * On hardware, the mmio map is a hash table.
Packit 534379
 */
Packit 534379
static bool mmio_map_is_empty(struct wsid_tracker *root) {
Packit 534379
  if (!root || (root->n_hash_buckets == 0))
Packit 534379
    return true;
Packit 534379
Packit 534379
  for (uint32_t i = 0; i < root->n_hash_buckets; i += 1) {
Packit 534379
    if (root->table[i])
Packit 534379
      return false;
Packit 534379
  }
Packit 534379
Packit 534379
  return true;
Packit 534379
}
Packit 534379
Packit 534379
#else
Packit 534379
/*
Packit 534379
 * In ASE, the mmio map is a list.
Packit 534379
 */
Packit 534379
static bool mmio_map_is_empty(struct wsid_map *root) {
Packit 534379
  return !root;
Packit 534379
}
Packit 534379
#endif
Packit 534379
Packit 534379
#undef FPGA_MSG
Packit 534379
#define FPGA_MSG(fmt, ...) \
Packit 534379
	printf("MOCK " fmt "\n", ## __VA_ARGS__)
Packit 534379
Packit 534379
int mmio_ioctl(mock_object * m, int request, va_list argp){
Packit 534379
    int retval = -1;
Packit 534379
    errno = EINVAL;
Packit 534379
    UNUSED_PARAM(m);
Packit 534379
    UNUSED_PARAM(request);
Packit 534379
    struct fpga_port_region_info *rinfo = va_arg(argp, struct fpga_port_region_info *);
Packit 534379
    if (!rinfo) {
Packit 534379
      FPGA_MSG("rinfo is NULL");
Packit 534379
      goto out_EINVAL;
Packit 534379
    }
Packit 534379
    if (rinfo->argsz != sizeof(*rinfo)) {
Packit 534379
      FPGA_MSG("wrong structure size");
Packit 534379
      goto out_EINVAL;
Packit 534379
    }
Packit 534379
    if (rinfo->index > 1 ) {
Packit 534379
      FPGA_MSG("unsupported MMIO index");
Packit 534379
      goto out_EINVAL;
Packit 534379
    }
Packit 534379
    if (rinfo->padding != 0) {
Packit 534379
      FPGA_MSG("unsupported padding");
Packit 534379
      goto out_EINVAL;
Packit 534379
    }
Packit 534379
    rinfo->flags = FPGA_REGION_READ | FPGA_REGION_WRITE | FPGA_REGION_MMAP;
Packit 534379
    rinfo->size = 0x40000;
Packit 534379
    rinfo->offset = 0;
Packit 534379
    retval = 0;
Packit 534379
    errno = 0;
Packit 534379
out:
Packit 534379
    return retval;
Packit 534379
Packit 534379
out_EINVAL:
Packit 534379
    retval = -1;
Packit 534379
    errno = EINVAL;
Packit 534379
    goto out;
Packit 534379
}
Packit 534379
Packit 534379
Packit 534379
class openclose_c_p
Packit 534379
    : public ::testing::TestWithParam<std::string> {
Packit 534379
 protected:
Packit 534379
  openclose_c_p()
Packit 534379
  : handle_(nullptr),
Packit 534379
    tokens_{{nullptr, nullptr}} {}
Packit 534379
Packit 534379
  virtual void SetUp() override {
Packit 534379
    ASSERT_TRUE(test_platform::exists(GetParam()));
Packit 534379
    platform_ = test_platform::get(GetParam());
Packit 534379
    system_ = test_system::instance();
Packit 534379
    system_->initialize();
Packit 534379
    system_->prepare_syfs(platform_);
Packit 534379
    ASSERT_EQ(xfpga_plugin_initialize(), FPGA_OK);
Packit 534379
    ASSERT_EQ(xfpga_fpgaGetProperties(nullptr, &filter_), FPGA_OK);
Packit 534379
    ASSERT_EQ(fpgaPropertiesSetObjectType(filter_, FPGA_ACCELERATOR), FPGA_OK);
Packit 534379
    ASSERT_EQ(xfpga_fpgaEnumerate(&filter_, 1, tokens_.data(), tokens_.size(),
Packit 534379
                            &num_matches_),
Packit 534379
              FPGA_OK);
Packit 534379
  }
Packit 534379
Packit 534379
  virtual void TearDown() override {
Packit 534379
    EXPECT_EQ(fpgaDestroyProperties(&filter_), FPGA_OK);
Packit 534379
Packit 534379
    for (auto &t : tokens_){
Packit 534379
      if (t) {
Packit 534379
        EXPECT_EQ(FPGA_OK, xfpga_fpgaDestroyToken(&t);;
Packit 534379
        t = nullptr;
Packit 534379
      }
Packit 534379
    }
Packit 534379
    xfpga_plugin_finalize();
Packit 534379
    system_->finalize();
Packit 534379
  }
Packit 534379
Packit 534379
  fpga_handle handle_;
Packit 534379
  std::array<fpga_token, 2> tokens_;
Packit 534379
  fpga_properties filter_;
Packit 534379
  uint32_t num_matches_;
Packit 534379
  test_platform platform_;
Packit 534379
  test_system *system_;
Packit 534379
};
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_01
Packit 534379
 *
Packit 534379
 * @brief      When the fpga_handle * parameter to xfpga_fpgaOpen is NULL, the
Packit 534379
 *             function returns FPGA_INVALID_PARAM.
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, open_01) {
Packit 534379
  fpga_result res;
Packit 534379
  res = xfpga_fpgaOpen(NULL, NULL, 0);
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, res);
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_02
Packit 534379
 *
Packit 534379
 * @brief      When the fpga_token parameter to xfpga_fpgaOpen is NULL, the
Packit 534379
 *             function returns FPGA_INVALID_PARAM.
Packit 534379
 */
Packit 534379
Packit 534379
TEST_P(openclose_c_p, open_02) {
Packit 534379
  fpga_handle handle_;
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaOpen(NULL, &handle_, 0));
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_03
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is invalid, the
Packit 534379
 *             function returns FPGA_INVALID_PARAM.
Packit 534379
 *
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, open_03) {
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaOpen(tokens_[0], NULL, 42));
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaOpen(tokens_[0], &handle_, 42));
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_04
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is invalid, the
Packit 534379
 *             function returns FPGA_INVALID_PARAM.
Packit 534379
 *
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, open_04) {
Packit 534379
  auto _token = (struct _fpga_token*)tokens_[0];
Packit 534379
  auto res = xfpga_fpgaOpen(tokens_[0], &handle_, 42);
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, res);
Packit 534379
Packit 534379
  // Invalid token magic
Packit 534379
  _token->magic = 0x123;
Packit 534379
  res = xfpga_fpgaOpen(tokens_[0], &handle_, FPGA_OPEN_SHARED);
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, res);
Packit 534379
Packit 534379
  // Reset token magic
Packit 534379
  _token->magic = FPGA_TOKEN_MAGIC;
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_05
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is invalid, the
Packit 534379
 *             function returns FPGA_INVALID_PARAM and FPGA_NO_DRIVER.
Packit 534379
 *
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, open_05) {
Packit 534379
  fpga_result res;
Packit 534379
  struct _fpga_token* _token = (struct _fpga_token*)tokens_[0];
Packit 534379
Packit 534379
  // Invalid flag
Packit 534379
  res = xfpga_fpgaOpen(tokens_[0], &handle_, 42);
Packit 534379
  ASSERT_EQ(FPGA_INVALID_PARAM, res);
Packit 534379
 
Packit 534379
  handle_ = nullptr; 
Packit 534379
  // Valid flag
Packit 534379
  res = xfpga_fpgaOpen(tokens_[0], &handle_, FPGA_OPEN_SHARED);
Packit 534379
  ASSERT_EQ(FPGA_OK, res);
Packit 534379
  ASSERT_EQ(FPGA_OK, xfpga_fpgaClose(handle_));
Packit 534379
Packit 534379
  // Invalid token path
Packit 534379
  strcpy(_token->devpath,"/dev/intel-fpga-fme.01");
Packit 534379
  res = xfpga_fpgaOpen(tokens_[0], &handle_, FPGA_OPEN_SHARED);
Packit 534379
  ASSERT_EQ(FPGA_NO_DRIVER, res);
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_06
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is valid, 
Packit 534379
 *             but malloc fails. the function returns FPGA_NO_MEMORY.
Packit 534379
 *
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, open_06) {
Packit 534379
  system_->invalidate_malloc();
Packit 534379
  auto res = xfpga_fpgaOpen(tokens_[0], &handle_, 0);
Packit 534379
  ASSERT_EQ(FPGA_NO_MEMORY, res);
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       close_01 
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is valid, 
Packit 534379
 *             but handle fd is invalid. the function returns 
Packit 534379
 *             FPGA_INVALID_PARAM.
Packit 534379
 *
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, close_01) {
Packit 534379
  int fddev = -1;
Packit 534379
  auto res = xfpga_fpgaOpen(tokens_[0], &handle_, 0);
Packit 534379
  ASSERT_EQ(FPGA_OK, res);
Packit 534379
Packit 534379
  struct _fpga_handle* _handle = (struct _fpga_handle*)handle_;
Packit 534379
Packit 534379
  // Invalid handle fd
Packit 534379
  fddev = _handle->fddev;
Packit 534379
  _handle->fddev = -1;
Packit 534379
  res = xfpga_fpgaClose(handle_);
Packit 534379
  EXPECT_EQ(res, FPGA_INVALID_PARAM);
Packit 534379
Packit 534379
  // Valid handle fd
Packit 534379
  _handle->fddev = fddev;
Packit 534379
   res = xfpga_fpgaClose(handle_);
Packit 534379
  EXPECT_EQ(res, FPGA_OK);
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       invalid_close
Packit 534379
 *
Packit 534379
 * @brief      When the fpga_handle parameter to fpgaClose is NULL, the
Packit 534379
 *             function returns FPGA_INVALID_PARAM.
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, invalid_close) {
Packit 534379
  EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaClose(NULL));
Packit 534379
}
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       close_03
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is valid, it 
Packit 534379
 *             returns FPGA_OK.  
Packit 534379
 *             the function returns FPGA_INVALID_PARAM.
Packit 534379
 *
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_p, close_03) {
Packit 534379
  uint64_t * mmio_ptr = nullptr;
Packit 534379
  auto res = xfpga_fpgaOpen(tokens_[0], &handle_, 0);
Packit 534379
  ASSERT_EQ(FPGA_OK, res);
Packit 534379
Packit 534379
  // Register valid ioctl
Packit 534379
  system_->register_ioctl_handler(FPGA_PORT_GET_REGION_INFO, mmio_ioctl);
Packit 534379
  system_->register_ioctl_handler(DFL_FPGA_PORT_GET_REGION_INFO, mmio_ioctl);
Packit 534379
  EXPECT_TRUE(mmio_map_is_empty(((struct _fpga_handle*)handle_)->mmio_root));
Packit 534379
Packit 534379
  ASSERT_EQ(FPGA_OK, xfpga_fpgaMapMMIO(handle_, 0, &mmio_ptr));
Packit 534379
  EXPECT_NE(mmio_ptr,nullptr);
Packit 534379
Packit 534379
  res = xfpga_fpgaClose(handle_);
Packit 534379
  EXPECT_EQ(res, FPGA_OK);
Packit 534379
}
Packit 534379
Packit 534379
INSTANTIATE_TEST_CASE_P(openclose_c, openclose_c_p, 
Packit 534379
                        ::testing::ValuesIn(test_platform::platforms({})));
Packit 534379
Packit 534379
class openclose_c_skx_dcp_p
Packit 534379
    : public openclose_c_p {};
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_share
Packit 534379
 *
Packit 534379
 * @brief      When the parameters are valid and the drivers are loaded,
Packit 534379
 *             and the flag FPGA_OPEN_SHARED is given, fpgaOpen on an
Packit 534379
 *             already opened token returns FPGA_OK.
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_skx_dcp_p, open_share) {
Packit 534379
  fpga_handle h1 = nullptr;
Packit 534379
  fpga_handle h2 = nullptr;
Packit 534379
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaOpen(tokens_[0], &h1, FPGA_OPEN_SHARED));
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaOpen(tokens_[0], &h2, FPGA_OPEN_SHARED));
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaClose(h1));
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaClose(h2));
Packit 534379
}
Packit 534379
Packit 534379
INSTANTIATE_TEST_CASE_P(openclose_c_skx_dcp, openclose_c_skx_dcp_p,
Packit 534379
                        ::testing::ValuesIn(test_platform::platforms({}, fpga_driver::linux_intel)));
Packit 534379
Packit 534379
class openclose_c_dfl_p
Packit 534379
    : public openclose_c_p {};
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       open_share
Packit 534379
 *
Packit 534379
 * @brief      When the parameters are valid and the drivers are loaded,
Packit 534379
 *             and the flag FPGA_OPEN_SHARED is given, fpgaOpen on an
Packit 534379
 *             already opened token returns FPGA_BUSY.
Packit 534379
 */
Packit 534379
TEST_P(openclose_c_dfl_p, open_share) {
Packit 534379
  fpga_handle h1 = nullptr;
Packit 534379
  fpga_handle h2 = nullptr;
Packit 534379
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaOpen(tokens_[0], &h1, FPGA_OPEN_SHARED));
Packit 534379
  EXPECT_EQ(FPGA_BUSY, xfpga_fpgaOpen(tokens_[0], &h2, FPGA_OPEN_SHARED));
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaClose(h1));
Packit 534379
}
Packit 534379
Packit 534379
INSTANTIATE_TEST_CASE_P(openclose_c_dfl, openclose_c_dfl_p,
Packit 534379
                        ::testing::ValuesIn(test_platform::hw_platforms({}, fpga_driver::linux_dfl0)));
Packit 534379
Packit 534379
/**
Packit 534379
 * @test       invalid_open_close
Packit 534379
 *
Packit 534379
 * @brief      When the flags parameter to xfpga_fpgaOpen is valid, 
Packit 534379
 *             but driver is not loaded. the function returns FPGA_NO_DRIVER.
Packit 534379
 *
Packit 534379
 */
Packit 534379
class openclose_c_mock_p
Packit 534379
    : public ::testing::TestWithParam<std::string> {
Packit 534379
 protected:
Packit 534379
  openclose_c_mock_p() {}
Packit 534379
Packit 534379
};
Packit 534379
Packit 534379
TEST_P(openclose_c_mock_p, invalid_open_close) {
Packit 534379
  struct _fpga_token _tok;
Packit 534379
  fpga_token tok = &_tok;
Packit 534379
  fpga_handle h;
Packit 534379
Packit 534379
  const std::string sysfs_port = "/sys/class/fpga/intel-fpga-dev.0/intel-fpga-port.0";
Packit 534379
  const std::string dev_port = "/dev/intel-fpga-port.0";
Packit 534379
Packit 534379
  // token setup
Packit 534379
  strncpy(_tok.sysfspath, sysfs_port.c_str(), sysfs_port.size() + 1);
Packit 534379
  strncpy(_tok.devpath, dev_port.c_str(), dev_port.size() + 1);
Packit 534379
  _tok.magic = FPGA_TOKEN_MAGIC;
Packit 534379
  _tok.errors = nullptr;
Packit 534379
  std::string errpath = sysfs_port + "/errors";
Packit 534379
  build_error_list(errpath.c_str(), &_tok.errors);
Packit 534379
Packit 534379
#ifdef BUILD_ASE
Packit 534379
  ASSERT_EQ(FPGA_OK, xfpga_fpgaOpen(tok, &h, 0));
Packit 534379
  ASSERT_EQ(FPGA_OK, xfpga_fpgaClose(h));
Packit 534379
  EXPECT_EQ(fpgaDestroyProperties(&filter), FPGA_OK);
Packit 534379
  EXPECT_EQ(FPGA_OK, xfpga_fpgaDestroyToken(&tok));
Packit 534379
#else
Packit 534379
  EXPECT_EQ(FPGA_NO_DRIVER, xfpga_fpgaOpen(tok, &h, 0));
Packit 534379
#endif
Packit 534379
}
Packit 534379
Packit 534379
INSTANTIATE_TEST_CASE_P(openclose_c, openclose_c_mock_p, 
Packit 534379
                        ::testing::ValuesIn(test_platform::mock_platforms({})));