f-stack/dpdk/drivers/raw/ifpga/base/ifpga_fme_pr.c

358 lines
8.5 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2018 Intel Corporation
*/
#include "ifpga_feature_dev.h"
static u64
pr_err_handle(struct feature_fme_pr *fme_pr)
{
struct feature_fme_pr_status fme_pr_status;
unsigned long err_code;
u64 fme_pr_error;
int i;
fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status);
if (!fme_pr_status.pr_status)
return 0;
err_code = readq(&fme_pr->ccip_fme_pr_err);
fme_pr_error = err_code;
for (i = 0; i < PR_MAX_ERR_NUM; i++) {
if (err_code & (1 << i))
dev_info(NULL, "%s\n", pr_err_msg[i]);
}
writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err);
return fme_pr_error;
}
static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev,
struct fpga_pr_info *info)
{
struct feature_fme_pr *fme_pr;
struct feature_fme_pr_ctl fme_pr_ctl;
struct feature_fme_pr_status fme_pr_status;
fme_pr = get_fme_feature_ioaddr_by_index(fme_dev,
FME_FEATURE_ID_PR_MGMT);
if (!fme_pr)
return -EINVAL;
if (info->flags != FPGA_MGR_PARTIAL_RECONFIG)
return -EINVAL;
dev_info(fme_dev, "resetting PR before initiated PR\n");
fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control);
fme_pr_ctl.pr_reset = 1;
writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control);
fme_pr_ctl.pr_reset_ack = 1;
if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl,
&fme_pr->ccip_fme_pr_control,
PR_WAIT_TIMEOUT, 1)) {
dev_err(fme_dev, "maximum PR timeout\n");
return -ETIMEDOUT;
}
fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control);
fme_pr_ctl.pr_reset = 0;
writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control);
dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n");
fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE;
if (fpga_wait_register_field(pr_host_status, fme_pr_status,
&fme_pr->ccip_fme_pr_status,
PR_WAIT_TIMEOUT, 1)) {
dev_err(fme_dev, "maximum PR timeout\n");
return -ETIMEDOUT;
}
dev_info(fme_dev, "check if have any previous PR error\n");
pr_err_handle(fme_pr);
return 0;
}
static int fme_pr_write(struct ifpga_fme_hw *fme_dev,
int port_id, const char *buf, size_t count,
struct fpga_pr_info *info)
{
struct feature_fme_pr *fme_pr;
struct feature_fme_pr_ctl fme_pr_ctl;
struct feature_fme_pr_status fme_pr_status;
struct feature_fme_pr_data fme_pr_data;
int delay, pr_credit;
int ret = 0;
fme_pr = get_fme_feature_ioaddr_by_index(fme_dev,
FME_FEATURE_ID_PR_MGMT);
if (!fme_pr)
return -EINVAL;
dev_info(fme_dev, "set PR port ID and start request\n");
fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control);
fme_pr_ctl.pr_regionid = port_id;
fme_pr_ctl.pr_start_req = 1;
writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control);
dev_info(fme_dev, "pushing data from bitstream to HW\n");
fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status);
pr_credit = fme_pr_status.pr_credit;
while (count > 0) {
delay = 0;
while (pr_credit <= 1) {
if (delay++ > PR_WAIT_TIMEOUT) {
dev_err(fme_dev, "maximum try\n");
info->pr_err = pr_err_handle(fme_pr);
return info->pr_err ? -EIO : -ETIMEDOUT;
}
udelay(1);
fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status);
pr_credit = fme_pr_status.pr_credit;
};
if (count >= fme_dev->pr_bandwidth) {
switch (fme_dev->pr_bandwidth) {
case 4:
fme_pr_data.rsvd = 0;
fme_pr_data.pr_data_raw = *((const u32 *)buf);
writeq(fme_pr_data.csr,
&fme_pr->ccip_fme_pr_data);
break;
default:
ret = -EFAULT;
goto done;
}
buf += fme_dev->pr_bandwidth;
count -= fme_dev->pr_bandwidth;
pr_credit--;
} else {
WARN_ON(1);
ret = -EINVAL;
goto done;
}
}
done:
return ret;
}
static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev,
struct fpga_pr_info *info)
{
struct feature_fme_pr *fme_pr;
struct feature_fme_pr_ctl fme_pr_ctl;
fme_pr = get_fme_feature_ioaddr_by_index(fme_dev,
FME_FEATURE_ID_PR_MGMT);
fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control);
fme_pr_ctl.pr_push_complete = 1;
writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control);
dev_info(fme_dev, "green bitstream push complete\n");
dev_info(fme_dev, "waiting for HW to release PR resource\n");
fme_pr_ctl.pr_start_req = 0;
if (fpga_wait_register_field(pr_start_req, fme_pr_ctl,
&fme_pr->ccip_fme_pr_control,
PR_WAIT_TIMEOUT, 1)) {
printf("maximum try.\n");
return -ETIMEDOUT;
}
dev_info(fme_dev, "PR operation complete, checking status\n");
info->pr_err = pr_err_handle(fme_pr);
if (info->pr_err)
return -EIO;
dev_info(fme_dev, "PR done successfully\n");
return 0;
}
static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev,
struct fpga_pr_info *info, const char *buf,
size_t count)
{
int ret;
info->state = FPGA_PR_STATE_WRITE_INIT;
ret = fme_pr_write_init(fme_dev, info);
if (ret) {
dev_err(fme_dev, "Error preparing FPGA for writing\n");
info->state = FPGA_PR_STATE_WRITE_INIT_ERR;
return ret;
}
/*
* Write the FPGA image to the FPGA.
*/
info->state = FPGA_PR_STATE_WRITE;
ret = fme_pr_write(fme_dev, info->port_id, buf, count, info);
if (ret) {
dev_err(fme_dev, "Error while writing image data to FPGA\n");
info->state = FPGA_PR_STATE_WRITE_ERR;
return ret;
}
/*
* After all the FPGA image has been written, do the device specific
* steps to finish and set the FPGA into operating mode.
*/
info->state = FPGA_PR_STATE_WRITE_COMPLETE;
ret = fme_pr_write_complete(fme_dev, info);
if (ret) {
dev_err(fme_dev, "Error after writing image data to FPGA\n");
info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR;
return ret;
}
info->state = FPGA_PR_STATE_DONE;
return 0;
}
static int fme_pr(struct ifpga_hw *hw, u32 port_id, const char *buffer,
u32 size, u64 *status)
{
struct feature_fme_header *fme_hdr;
struct feature_fme_capability fme_capability;
struct ifpga_fme_hw *fme = &hw->fme;
struct fpga_pr_info info;
struct ifpga_port_hw *port;
int ret = 0;
if (!buffer || size == 0)
return -EINVAL;
if (fme->state != IFPGA_FME_IMPLEMENTED)
return -EINVAL;
/*
* Padding extra zeros to align PR buffer with PR bandwidth, HW will
* ignore these zeros automatically.
*/
size = IFPGA_ALIGN(size, fme->pr_bandwidth);
/* get fme header region */
fme_hdr = get_fme_feature_ioaddr_by_index(fme,
FME_FEATURE_ID_HEADER);
if (!fme_hdr)
return -EINVAL;
/* check port id */
fme_capability.csr = readq(&fme_hdr->capability);
if (port_id >= fme_capability.num_ports) {
dev_err(fme, "port number more than maximum\n");
return -EINVAL;
}
opae_memset(&info, 0, sizeof(struct fpga_pr_info));
info.flags = FPGA_MGR_PARTIAL_RECONFIG;
info.port_id = port_id;
spinlock_lock(&fme->lock);
/* get port device by port_id */
port = &hw->port[port_id];
/* Disable Port before PR */
fpga_port_disable(port);
ret = fpga_pr_buf_load(fme, &info, buffer, size);
*status = info.pr_err;
/* Re-enable Port after PR finished */
fpga_port_enable(port);
spinlock_unlock(&fme->lock);
return ret;
}
int do_pr(struct ifpga_hw *hw, u32 port_id, const char *buffer,
u32 size, u64 *status)
{
const struct bts_header *bts_hdr;
const char *buf;
struct ifpga_port_hw *port;
int ret;
u32 header_size;
if (!buffer || size == 0) {
dev_err(hw, "invalid parameter\n");
return -EINVAL;
}
bts_hdr = (const struct bts_header *)buffer;
if (is_valid_bts(bts_hdr)) {
dev_info(hw, "this is a valid bitsteam..\n");
header_size = sizeof(struct bts_header) +
bts_hdr->metadata_len;
if (size < header_size)
return -EINVAL;
size -= header_size;
buf = buffer + header_size;
} else {
dev_err(hw, "this is an invalid bitstream..\n");
return -EINVAL;
}
/* clean port error before do PR */
port = &hw->port[port_id];
ret = port_clear_error(port);
if (ret) {
dev_err(hw, "port cannot clear error\n");
return -EINVAL;
}
return fme_pr(hw, port_id, buf, size, status);
}
static int fme_pr_mgmt_init(struct ifpga_feature *feature)
{
struct feature_fme_pr *fme_pr;
struct feature_header fme_pr_header;
struct ifpga_fme_hw *fme;
dev_info(NULL, "FME PR MGMT Init.\n");
fme = (struct ifpga_fme_hw *)feature->parent;
fme_pr = (struct feature_fme_pr *)feature->addr;
fme_pr_header.csr = readq(&fme_pr->header);
if (fme_pr_header.revision == 2) {
dev_info(NULL, "using 512-bit PR\n");
fme->pr_bandwidth = 64;
} else {
dev_info(NULL, "using 32-bit PR\n");
fme->pr_bandwidth = 4;
}
return 0;
}
static void fme_pr_mgmt_uinit(struct ifpga_feature *feature)
{
UNUSED(feature);
dev_info(NULL, "FME PR MGMT UInit.\n");
}
struct ifpga_feature_ops fme_pr_mgmt_ops = {
.init = fme_pr_mgmt_init,
.uinit = fme_pr_mgmt_uinit,
};