mirror of https://github.com/F-Stack/f-stack.git
295 lines
6.3 KiB
C
295 lines
6.3 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2010-2018 Intel Corporation
|
|
*/
|
|
|
|
#include "ifpga_api.h"
|
|
#include "ifpga_enumerate.h"
|
|
#include "ifpga_feature_dev.h"
|
|
|
|
#include "opae_hw_api.h"
|
|
|
|
/* Accelerator APIs */
|
|
static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
|
|
struct uuid *uuid)
|
|
{
|
|
struct opae_bridge *br = acc->br;
|
|
struct ifpga_port_hw *port;
|
|
|
|
if (!br || !br->data)
|
|
return -EINVAL;
|
|
|
|
port = br->data;
|
|
|
|
return fpga_get_afu_uuid(port, uuid);
|
|
}
|
|
|
|
static int ifpga_acc_set_irq(struct opae_accelerator *acc,
|
|
u32 start, u32 count, s32 evtfds[])
|
|
{
|
|
struct ifpga_afu_info *afu_info = acc->data;
|
|
struct opae_bridge *br = acc->br;
|
|
struct ifpga_port_hw *port;
|
|
struct fpga_uafu_irq_set irq_set;
|
|
|
|
if (!br || !br->data)
|
|
return -EINVAL;
|
|
|
|
if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs)
|
|
return -EINVAL;
|
|
|
|
port = br->data;
|
|
|
|
irq_set.start = start;
|
|
irq_set.count = count;
|
|
irq_set.evtfds = evtfds;
|
|
|
|
return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id,
|
|
IFPGA_PORT_FEATURE_ID_UINT, &irq_set);
|
|
}
|
|
|
|
static int ifpga_acc_get_info(struct opae_accelerator *acc,
|
|
struct opae_acc_info *info)
|
|
{
|
|
struct ifpga_afu_info *afu_info = acc->data;
|
|
|
|
if (!afu_info)
|
|
return -ENODEV;
|
|
|
|
info->num_regions = afu_info->num_regions;
|
|
info->num_irqs = afu_info->num_irqs;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifpga_acc_get_region_info(struct opae_accelerator *acc,
|
|
struct opae_acc_region_info *info)
|
|
{
|
|
struct ifpga_afu_info *afu_info = acc->data;
|
|
|
|
if (!afu_info)
|
|
return -EINVAL;
|
|
|
|
if (info->index >= afu_info->num_regions)
|
|
return -EINVAL;
|
|
|
|
/* always one RW region only for AFU now */
|
|
info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO;
|
|
info->len = afu_info->region[info->index].len;
|
|
info->addr = afu_info->region[info->index].addr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx,
|
|
u64 offset, unsigned int byte, void *data)
|
|
{
|
|
struct ifpga_afu_info *afu_info = acc->data;
|
|
struct opae_reg_region *region;
|
|
|
|
if (!afu_info)
|
|
return -EINVAL;
|
|
|
|
if (offset + byte <= offset)
|
|
return -EINVAL;
|
|
|
|
if (region_idx >= afu_info->num_regions)
|
|
return -EINVAL;
|
|
|
|
region = &afu_info->region[region_idx];
|
|
if (offset + byte > region->len)
|
|
return -EINVAL;
|
|
|
|
switch (byte) {
|
|
case 8:
|
|
*(u64 *)data = opae_readq(region->addr + offset);
|
|
break;
|
|
case 4:
|
|
*(u32 *)data = opae_readl(region->addr + offset);
|
|
break;
|
|
case 2:
|
|
*(u16 *)data = opae_readw(region->addr + offset);
|
|
break;
|
|
case 1:
|
|
*(u8 *)data = opae_readb(region->addr + offset);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifpga_acc_write(struct opae_accelerator *acc,
|
|
unsigned int region_idx, u64 offset,
|
|
unsigned int byte, void *data)
|
|
{
|
|
struct ifpga_afu_info *afu_info = acc->data;
|
|
struct opae_reg_region *region;
|
|
|
|
if (!afu_info)
|
|
return -EINVAL;
|
|
|
|
if (offset + byte <= offset)
|
|
return -EINVAL;
|
|
|
|
if (region_idx >= afu_info->num_regions)
|
|
return -EINVAL;
|
|
|
|
region = &afu_info->region[region_idx];
|
|
if (offset + byte > region->len)
|
|
return -EINVAL;
|
|
|
|
/* normal mmio case */
|
|
switch (byte) {
|
|
case 8:
|
|
opae_writeq(*(u64 *)data, region->addr + offset);
|
|
break;
|
|
case 4:
|
|
opae_writel(*(u32 *)data, region->addr + offset);
|
|
break;
|
|
case 2:
|
|
opae_writew(*(u16 *)data, region->addr + offset);
|
|
break;
|
|
case 1:
|
|
opae_writeb(*(u8 *)data, region->addr + offset);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct opae_accelerator_ops ifpga_acc_ops = {
|
|
.read = ifpga_acc_read,
|
|
.write = ifpga_acc_write,
|
|
.set_irq = ifpga_acc_set_irq,
|
|
.get_info = ifpga_acc_get_info,
|
|
.get_region_info = ifpga_acc_get_region_info,
|
|
.get_uuid = ifpga_acc_get_uuid,
|
|
};
|
|
|
|
/* Bridge APIs */
|
|
|
|
static int ifpga_br_reset(struct opae_bridge *br)
|
|
{
|
|
struct ifpga_port_hw *port = br->data;
|
|
|
|
return fpga_port_reset(port);
|
|
}
|
|
|
|
struct opae_bridge_ops ifpga_br_ops = {
|
|
.reset = ifpga_br_reset,
|
|
};
|
|
|
|
/* Manager APIs */
|
|
static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf,
|
|
u32 size, u64 *status)
|
|
{
|
|
struct ifpga_fme_hw *fme = mgr->data;
|
|
struct ifpga_hw *hw = fme->parent;
|
|
|
|
return ifpga_pr(hw, id, buf, size, status);
|
|
}
|
|
|
|
struct opae_manager_ops ifpga_mgr_ops = {
|
|
.flash = ifpga_mgr_flash,
|
|
};
|
|
|
|
/* Adapter APIs */
|
|
static int ifpga_adapter_enumerate(struct opae_adapter *adapter)
|
|
{
|
|
struct ifpga_hw *hw = malloc(sizeof(*hw));
|
|
|
|
if (hw) {
|
|
memset(hw, 0, sizeof(*hw));
|
|
hw->pci_data = adapter->data;
|
|
hw->adapter = adapter;
|
|
if (ifpga_bus_enumerate(hw))
|
|
goto error;
|
|
return ifpga_bus_init(hw);
|
|
}
|
|
|
|
error:
|
|
return -ENOMEM;
|
|
}
|
|
|
|
struct opae_adapter_ops ifpga_adapter_ops = {
|
|
.enumerate = ifpga_adapter_enumerate,
|
|
};
|
|
|
|
/**
|
|
* ifpga_pr - do the partial reconfiguration for a given port device
|
|
* @hw: pointer to the HW structure
|
|
* @port_id: the port device id
|
|
* @buffer: the buffer of the bitstream
|
|
* @size: the size of the bitstream
|
|
* @status: hardware status including PR error code if return -EIO.
|
|
*
|
|
* @return
|
|
* - 0: Success, partial reconfiguration finished.
|
|
* - <0: Error code returned in partial reconfiguration.
|
|
**/
|
|
int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size,
|
|
u64 *status)
|
|
{
|
|
if (!is_valid_port_id(hw, port_id))
|
|
return -ENODEV;
|
|
|
|
return do_pr(hw, port_id, buffer, size, status);
|
|
}
|
|
|
|
int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id,
|
|
struct feature_prop *prop)
|
|
{
|
|
if (!hw || !prop)
|
|
return -EINVAL;
|
|
|
|
switch (fiu_id) {
|
|
case FEATURE_FIU_ID_FME:
|
|
return fme_get_prop(&hw->fme, prop);
|
|
case FEATURE_FIU_ID_PORT:
|
|
if (!is_valid_port_id(hw, port_id))
|
|
return -ENODEV;
|
|
return port_get_prop(&hw->port[port_id], prop);
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|
|
|
|
int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id,
|
|
struct feature_prop *prop)
|
|
{
|
|
if (!hw || !prop)
|
|
return -EINVAL;
|
|
|
|
switch (fiu_id) {
|
|
case FEATURE_FIU_ID_FME:
|
|
return fme_set_prop(&hw->fme, prop);
|
|
case FEATURE_FIU_ID_PORT:
|
|
if (!is_valid_port_id(hw, port_id))
|
|
return -ENODEV;
|
|
return port_set_prop(&hw->port[port_id], prop);
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|
|
|
|
int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id,
|
|
u32 feature_id, void *irq_set)
|
|
{
|
|
if (!hw || !irq_set)
|
|
return -EINVAL;
|
|
|
|
switch (fiu_id) {
|
|
case FEATURE_FIU_ID_FME:
|
|
return fme_set_irq(&hw->fme, feature_id, irq_set);
|
|
case FEATURE_FIU_ID_PORT:
|
|
if (!is_valid_port_id(hw, port_id))
|
|
return -ENODEV;
|
|
return port_set_irq(&hw->port[port_id], feature_id, irq_set);
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|