diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c index f19cc262a0..098de0c090 100644 --- a/drivers/raw/ifpga/base/ifpga_api.c +++ b/drivers/raw/ifpga/base/ifpga_api.c @@ -268,6 +268,14 @@ static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page) return fpga_reload(fme, type, page); } +static int ifpga_mgr_read_flash(struct opae_manager *mgr, u32 address, + u32 size, void *buf) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_read_flash(fme, address, size, buf); +} + struct opae_manager_ops ifpga_mgr_ops = { .flash = ifpga_mgr_flash, .get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info, @@ -277,6 +285,7 @@ struct opae_manager_ops ifpga_mgr_ops = { .update_flash = ifpga_mgr_update_flash, .stop_flash_update = ifpga_mgr_stop_flash_update, .reload = ifpga_mgr_reload, + .read_flash = ifpga_mgr_read_flash }; static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset, diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h index a637eb59ef..7a2f2e5817 100644 --- a/drivers/raw/ifpga/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h @@ -223,4 +223,6 @@ int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme, int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme, struct opae_sensor_info *sensor, unsigned int *value); +int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address, + u32 size, void *buf); #endif /* _IFPGA_FEATURE_DEV_H_ */ diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c index 608a3520a3..25ff819955 100644 --- a/drivers/raw/ifpga/base/ifpga_fme.c +++ b/drivers/raw/ifpga/base/ifpga_fme.c @@ -1658,3 +1658,11 @@ struct ifpga_feature_ops fme_pmci_ops = { .init = fme_pmci_init, .uinit = fme_pmci_uinit, }; + +int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address, + u32 size, void *buf) +{ + struct intel_max10_device *max10 = fme->max10_dev; + + return opae_read_flash(max10, address, size, buf); +} diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c index 87256fc8b2..fd083263a8 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.c +++ b/drivers/raw/ifpga/base/opae_hw_api.c @@ -1041,3 +1041,23 @@ int opae_mgr_reload(struct opae_manager *mgr, int type, int page) return -ENOENT; } +/** + * opae_mgr_read_flash - read flash content + * @mgr: targeted manager + * @address: the start address of flash + * @size: the size of flash + * @buf: the read buffer + * + * Return: 0 on success, otherwise error code. + */ +int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, + u32 size, void *buf) +{ + if (!mgr) + return -EINVAL; + + if (mgr->ops && mgr->ops->read_flash) + return mgr->ops->read_flash(mgr, address, size, buf); + + return -ENOENT; +} diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h index fd40e09857..de1e984684 100644 --- a/drivers/raw/ifpga/base/opae_hw_api.h +++ b/drivers/raw/ifpga/base/opae_hw_api.h @@ -60,6 +60,7 @@ struct opae_manager_ops { u64 *status); int (*stop_flash_update)(struct opae_manager *mgr, int force); int (*reload)(struct opae_manager *mgr, int type, int page); + int (*read_flash)(struct opae_manager *mgr, u32 address, u32 size, void *buf); }; /* networking management ops in FME */ @@ -368,4 +369,5 @@ int opae_mgr_update_flash(struct opae_manager *mgr, const char *image, uint64_t *status); int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force); int opae_mgr_reload(struct opae_manager *mgr, int type, int page); +int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, u32 size, void *buf); #endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga/base/opae_intel_max10.c b/drivers/raw/ifpga/base/opae_intel_max10.c index 26f323c6a1..9c01729913 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.c +++ b/drivers/raw/ifpga/base/opae_intel_max10.c @@ -58,6 +58,279 @@ int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset, return max10_sys_write(dev, offset, temp); } +static int n3000_bulk_raw_write(struct intel_max10_device *dev, uint32_t addr, + void *buf, uint32_t len) +{ + uint32_t v = 0; + uint32_t i = 0; + char *p = buf; + int ret = 0; + + len = IFPGA_ALIGN(len, 4); + + for (i = 0; i < len; i += 4) { + v = *(uint32_t *)(p + i); + ret = max10_reg_write(dev, addr + i, v); + if (ret < 0) { + dev_err(dev, + "Failed to write to staging area 0x%08x [e:%d]\n", + addr + i, ret); + return ret; + } + } + + return 0; +} + +static int n3000_bulk_raw_read(struct intel_max10_device *dev, + uint32_t addr, void *buf, uint32_t len) +{ + u32 v, i; + char *p = buf; + int ret; + + len = IFPGA_ALIGN(len, 4); + + for (i = 0; i < len; i += 4) { + ret = max10_reg_read(dev, addr + i, &v); + if (ret < 0) { + dev_err(dev, + "Failed to write to staging area 0x%08x [e:%d]\n", + addr + i, ret); + return ret; + } + *(u32 *)(p + i) = v; + } + + return 0; +} + +static int n3000_flash_read(struct intel_max10_device *dev, + u32 addr, void *buf, u32 size) +{ + if (!dev->raw_blk_ops.read_blk) + return -ENODEV; + + return dev->raw_blk_ops.read_blk(dev, addr, buf, size); +} + +static int n3000_flash_write(struct intel_max10_device *dev, + u32 addr, void *buf, u32 size) +{ + if (!dev->raw_blk_ops.write_blk) + return -ENODEV; + + return dev->raw_blk_ops.write_blk(dev, addr, buf, size); +} + +static u32 +pmci_get_write_space(struct intel_max10_device *dev, u32 size) +{ + u32 count, val; + int ret; + + ret = opae_readl_poll_timeout(dev->mmio + PMCI_FLASH_CTRL, val, + GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) == + PMCI_FIFO_MAX_WORDS, + PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US); + if (ret == -ETIMEDOUT) + return 0; + + count = GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) * 4; + + return (size > count) ? count : size; +} + +static void pmci_write_fifo(void __iomem *base, char *buf, size_t count) +{ + size_t i; + u32 val; + + for (i = 0; i < count/4 ; i++) { + val = *(u32 *)(buf + i * 4); + writel(val, base); + } +} + +static void pmci_read_fifo(void __iomem *base, char *buf, size_t count) +{ + size_t i; + u32 val; + + for (i = 0; i < count/4; i++) { + val = readl(base); + *(u32 *)(buf + i * 4) = val; + } +} + +static int +__pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + UNUSED(addr); + u32 blk_size, n_offset = 0; + + while (size) { + blk_size = pmci_get_write_space(dev, size); + if (blk_size == 0) { + dev_err(pmci->dev, "get FIFO available size fail\n"); + return -EIO; + } + size -= blk_size; + pmci_write_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + n_offset, + blk_size); + n_offset += blk_size; + } + + return 0; +} + +static int +pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + int ret; + + pthread_mutex_lock(dev->bmc_ops.mutex); + + ret = __pmci_flash_bulk_write(dev, addr, buf, size); + + pthread_mutex_unlock(dev->bmc_ops.mutex); + return ret; +} + +static int +pmci_set_flash_host_mux(struct intel_max10_device *dev, bool request) +{ + u32 ctrl; + int ret; + + ret = max10_sys_update_bits(dev, + m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL, + FLASH_HOST_REQUEST, + SET_FIELD(FLASH_HOST_REQUEST, request)); + if (ret) + return ret; + + return opae_max10_read_poll_timeout(dev, m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL, + ctrl, request ? (get_flash_mux(ctrl) == FLASH_MUX_HOST) : + (get_flash_mux(ctrl) != FLASH_MUX_HOST), + PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US); +} + +static int +pmci_get_mux(struct intel_max10_device *dev) +{ + pthread_mutex_lock(dev->bmc_ops.mutex); + return pmci_set_flash_host_mux(dev, true); +} + +static int +pmci_put_mux(struct intel_max10_device *dev) +{ + int ret; + + ret = pmci_set_flash_host_mux(dev, false); + pthread_mutex_unlock(dev->bmc_ops.mutex); + return ret; +} + +static int +__pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + u32 blk_size, offset = 0, val; + int ret; + + while (size) { + blk_size = min_t(u32, size, PMCI_READ_BLOCK_SIZE); + + opae_writel(addr + offset, dev->mmio + PMCI_FLASH_ADDR); + + opae_writel(SET_FIELD(PMCI_FLASH_READ_COUNT, blk_size / 4) + | PMCI_FLASH_RD_MODE, + dev->mmio + PMCI_FLASH_CTRL); + + ret = opae_readl_poll_timeout((dev->mmio + PMCI_FLASH_CTRL), + val, !(val & PMCI_FLASH_BUSY), + PMCI_FLASH_INT_US, + PMCI_FLASH_TIMEOUT_US); + if (ret) { + dev_err(dev, "%s timed out on reading flash 0x%xn", + __func__, val); + return ret; + } + + pmci_read_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + offset, + blk_size); + + size -= blk_size; + offset += blk_size; + + opae_writel(0, dev->mmio + PMCI_FLASH_CTRL); + } + + return 0; +} + +static int +pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr, + void *buf, u32 size) +{ + int ret; + + ret = pmci_get_mux(dev); + if (ret) + goto fail; + + ret = __pmci_flash_bulk_read(dev, addr, buf, size); + if (ret) + goto fail; + + return pmci_put_mux(dev); + +fail: + pmci_put_mux(dev); + return ret; +} + +static int pmci_check_flash_address(u32 start, u32 end) +{ + if (start < PMCI_FLASH_START || end > PMCI_FLASH_END) + return -EINVAL; + + return 0; +} + +int opae_read_flash(struct intel_max10_device *dev, u32 addr, + u32 size, void *buf) +{ + int ret; + + if (!dev->bmc_ops.flash_read) + return -ENODEV; + + if (!buf) + return -EINVAL; + + if (dev->bmc_ops.check_flash_range) { + ret = dev->bmc_ops.check_flash_range(addr, addr + size); + if (ret) + return ret; + } else { + u32 top_addr = dev->staging_area_base + dev->staging_area_size; + if ((addr < dev->staging_area_base) || + ((addr + size) >= top_addr)) + return -EINVAL; + } + + ret = dev->bmc_ops.flash_read(dev, addr, buf, size); + if (ret) + return ret; + + return 0; +} + static int max10_spi_read(struct intel_max10_device *dev, unsigned int addr, unsigned int *val) { @@ -841,6 +1114,11 @@ intel_max10_device_init(struct intel_max10_device *dev) dev->ops = &m10bmc_n3000_regmap; dev->csr = &m10bmc_spi_csr; + dev->raw_blk_ops.write_blk = n3000_bulk_raw_write; + dev->raw_blk_ops.read_blk = n3000_bulk_raw_read; + dev->bmc_ops.flash_read = n3000_flash_read; + dev->bmc_ops.flash_write = n3000_flash_write; + /* check the max10 version */ ret = check_max10_version(dev); if (ret) { @@ -871,6 +1149,10 @@ intel_max10_device_init(struct intel_max10_device *dev) dev->staging_area_size = MAX_STAGING_AREA_SIZE; dev->flags |= MAX10_FLAGS_SECURE; + dev->bmc_ops.flash_read = pmci_flash_bulk_read; + dev->bmc_ops.flash_write = pmci_flash_bulk_write; + dev->bmc_ops.check_flash_range = pmci_check_flash_address; + ret = pthread_mutex_init(&dev->bmc_ops.lock, NULL); if (ret) return ret; diff --git a/drivers/raw/ifpga/base/opae_intel_max10.h b/drivers/raw/ifpga/base/opae_intel_max10.h index 6a1b122a26..0f3360edb6 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.h +++ b/drivers/raw/ifpga/base/opae_intel_max10.h @@ -61,10 +61,23 @@ struct m10bmc_csr { unsigned int auth_result; }; +/** + * struct flash_raw_blk_ops - device specific operations for flash R/W + * @write_blk: write a block of data to flash + * @read_blk: read a block of data from flash + */ +struct flash_raw_blk_ops { + int (*write_blk)(struct intel_max10_device *dev, uint32_t addr, + void *buf, uint32_t size); + int (*read_blk)(struct intel_max10_device *dev, uint32_t addr, + void *buf, uint32_t size); +}; + /** * struct m10bmc_ops - device specific operations * @lock: prevent concurrent flash read/write * @mutex: prevent concurrent bmc read/write + * @check_flash_range: validate flash address * @flash_read: read a block of data from flash * @flash_write: write a block of data to flash */ @@ -92,6 +105,7 @@ struct intel_max10_device { enum m10bmc_type type; const struct m10bmc_regmap *ops; const struct m10bmc_csr *csr; + struct flash_raw_blk_ops raw_blk_ops; struct m10bmc_ops bmc_ops; u8 *mmio; /* mmio address for PMCI */ }; @@ -431,6 +445,22 @@ struct opae_sensor_info { #define PMCI_FPGA_RECONF_PAGE GENMASK(22, 20) #define PMCI_FPGA_RP_LOAD BIT(23) +#define PMCI_FLASH_CTRL 0x40 +#define PMCI_FLASH_WR_MODE BIT(0) +#define PMCI_FLASH_RD_MODE BIT(1) +#define PMCI_FLASH_BUSY BIT(2) +#define PMCI_FLASH_FIFO_SPACE GENMASK(13, 4) +#define PMCI_FLASH_READ_COUNT GENMASK(25, 16) + +#define PMCI_FLASH_INT_US 1 +#define PMCI_FLASH_TIMEOUT_US 10000 + +#define PMCI_FLASH_ADDR 0x44 +#define PMCI_FLASH_FIFO 0x800 +#define PMCI_READ_BLOCK_SIZE 0x800 +#define PMCI_FIFO_MAX_BYTES 0x800 +#define PMCI_FIFO_MAX_WORDS (PMCI_FIFO_MAX_BYTES / 4) + #define M10BMC_PMCI_FPGA_POC 0xb0 #define PMCI_FPGA_POC BIT(0) #define PMCI_NIOS_REQ_CLEAR BIT(1) @@ -447,6 +477,16 @@ struct opae_sensor_info { #define PMCI_FPGA_BOOT_PAGE GENMASK(2, 0) #define PMCI_FPGA_CONFIGURED BIT(3) +#define M10BMC_PMCI_FLASH_CTRL 0x1d0 +#define FLASH_MUX_SELECTION GENMASK(2, 0) +#define FLASH_MUX_IDLE 0 +#define FLASH_MUX_NIOS 1 +#define FLASH_MUX_HOST 2 +#define FLASH_MUX_PFL 4 +#define get_flash_mux(mux) GET_FIELD(FLASH_MUX_SELECTION, mux) +#define FLASH_NIOS_REQUEST BIT(4) +#define FLASH_HOST_REQUEST BIT(5) + #define M10BMC_PMCI_SDM_CTRL_STS 0x230 #define PMCI_SDM_IMG_REQ BIT(0) #define PMCI_SDM_STAT GENMASK(23, 16) @@ -472,4 +512,10 @@ struct opae_sensor_info { #define SDM_STAT_CS_MIS 0x12 #define SDM_STAT_PR_MIS 0x13 #define SDM_STAT_MAX SDM_STAT_PR_MIS + +#define PMCI_FLASH_START 0x10000 +#define PMCI_FLASH_END 0xC7FFFFF + +int opae_read_flash(struct intel_max10_device *dev, u32 addr, + u32 size, void *buf); #endif diff --git a/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h b/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h index 3ff49a8926..68499e65fb 100644 --- a/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h +++ b/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h @@ -39,6 +39,16 @@ #define min(a, b) RTE_MIN(a, b) #define max(a, b) RTE_MAX(a, b) +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1 : __min2; }) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1 : __max2; }) + #define spinlock_t rte_spinlock_t #define spinlock_init(x) rte_spinlock_init(x) #define spinlock_lock(x) rte_spinlock_lock(x)