These patches were generated from: https://github.com/raspberrypi/linux/commits/rpi-6.12.y With the following command: git format-patch -N v6.12.27..HEAD (HEAD -> 8d3206ee456a5ecdf9ddbfd8e5e231e4f0cd716e) Exceptions: - (def)configs patches - github workflows patches - applied & reverted patches - readme patches - wireless patches Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2130 lines
87 KiB
Diff
2130 lines
87 KiB
Diff
From 495def981372b4942906334ba1e9bd44cd89aed4 Mon Sep 17 00:00:00 2001
|
|
From: Naushir Patuck <naush@raspberrypi.com>
|
|
Date: Thu, 23 Jan 2025 14:14:47 +0000
|
|
Subject: [PATCH] drivers: media: pci: Update Hailo accelerator device driver
|
|
to v4.20
|
|
|
|
Sourced from https://github.com/hailo-ai/hailort-drivers
|
|
|
|
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
|
---
|
|
.../media/pci/hailo/common/fw_validation.c | 4 +-
|
|
.../media/pci/hailo/common/fw_validation.h | 14 +-
|
|
.../pci/hailo/common/hailo_ioctl_common.h | 10 +-
|
|
drivers/media/pci/hailo/common/pcie_common.c | 175 +++--
|
|
drivers/media/pci/hailo/common/pcie_common.h | 69 +-
|
|
drivers/media/pci/hailo/common/vdma_common.c | 70 +-
|
|
drivers/media/pci/hailo/common/vdma_common.h | 27 +-
|
|
drivers/media/pci/hailo/src/fops.c | 90 ++-
|
|
drivers/media/pci/hailo/src/nnc.c | 4 +-
|
|
drivers/media/pci/hailo/src/pcie.c | 630 ++++++++++++++++--
|
|
drivers/media/pci/hailo/src/pcie.h | 39 +-
|
|
drivers/media/pci/hailo/src/soc.c | 18 +-
|
|
drivers/media/pci/hailo/utils/compact.h | 8 +
|
|
drivers/media/pci/hailo/vdma/memory.c | 84 ++-
|
|
drivers/media/pci/hailo/vdma/memory.h | 2 +
|
|
15 files changed, 997 insertions(+), 247 deletions(-)
|
|
|
|
--- a/drivers/media/pci/hailo/common/fw_validation.c
|
|
+++ b/drivers/media/pci/hailo/common/fw_validation.c
|
|
@@ -41,8 +41,8 @@ int FW_VALIDATION__validate_fw_header(ui
|
|
case HAILO_BOARD_TYPE_HAILO10H:
|
|
expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO15;
|
|
break;
|
|
- case HAILO_BOARD_TYPE_PLUTO:
|
|
- expected_firmware_magic = FIRMWARE_HEADER_MAGIC_PLUTO;
|
|
+ case HAILO_BOARD_TYPE_HAILO15L:
|
|
+ expected_firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO15L;
|
|
break;
|
|
default:
|
|
err = -EINVAL;
|
|
--- a/drivers/media/pci/hailo/common/fw_validation.h
|
|
+++ b/drivers/media/pci/hailo/common/fw_validation.h
|
|
@@ -9,15 +9,9 @@
|
|
#include "hailo_ioctl_common.h"
|
|
#include <linux/types.h>
|
|
|
|
-#define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0)
|
|
-#define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB)
|
|
-#define FIRMWARE_HEADER_MAGIC_PLUTO (0xF94739AB)
|
|
-
|
|
-#ifndef HAILO_EMULATOR
|
|
-#define FIRMWARE_WAIT_TIMEOUT_MS (5000)
|
|
-#else /* ifndef HAILO_EMULATOR */
|
|
-#define FIRMWARE_WAIT_TIMEOUT_MS (500000)
|
|
-#endif /* ifndef HAILO_EMULATOR */
|
|
+#define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0)
|
|
+#define FIRMWARE_HEADER_MAGIC_HAILO15 (0xE905DAAB)
|
|
+#define FIRMWARE_HEADER_MAGIC_HAILO15L (0xF94739AB)
|
|
|
|
typedef enum {
|
|
FIRMWARE_HEADER_VERSION_INITIAL = 0,
|
|
@@ -61,4 +55,4 @@ int FW_VALIDATION__validate_fw_header(ui
|
|
int FW_VALIDATION__validate_cert_header(uintptr_t firmware_base_address,
|
|
size_t firmware_size, u32 *outer_consumed_firmware_offset, secure_boot_certificate_header_t **out_firmware_cert);
|
|
|
|
-#endif
|
|
\ No newline at end of file
|
|
+#endif
|
|
--- a/drivers/media/pci/hailo/common/hailo_ioctl_common.h
|
|
+++ b/drivers/media/pci/hailo/common/hailo_ioctl_common.h
|
|
@@ -7,7 +7,7 @@
|
|
#define _HAILO_IOCTL_COMMON_H_
|
|
|
|
#define HAILO_DRV_VER_MAJOR 4
|
|
-#define HAILO_DRV_VER_MINOR 19
|
|
+#define HAILO_DRV_VER_MINOR 20
|
|
#define HAILO_DRV_VER_REVISION 0
|
|
|
|
#define _STRINGIFY_EXPANDED( x ) #x
|
|
@@ -22,6 +22,7 @@
|
|
#define MAX_VDMA_ENGINES (3)
|
|
#define SIZE_OF_VDMA_DESCRIPTOR (16)
|
|
#define VDMA_DEST_CHANNELS_START (16)
|
|
+#define MAX_SG_DESCS_COUNT (64 * 1024u)
|
|
|
|
#define HAILO_VDMA_MAX_ONGOING_TRANSFERS (128)
|
|
#define HAILO_VDMA_MAX_ONGOING_TRANSFERS_MASK (HAILO_VDMA_MAX_ONGOING_TRANSFERS - 1)
|
|
@@ -38,6 +39,10 @@
|
|
#define FW_ACCESS_APP_CPU_CONTROL_MASK (1 << FW_ACCESS_CONTROL_INTERRUPT_SHIFT)
|
|
#define FW_ACCESS_DRIVER_SHUTDOWN_SHIFT (2)
|
|
#define FW_ACCESS_DRIVER_SHUTDOWN_MASK (1 << FW_ACCESS_DRIVER_SHUTDOWN_SHIFT)
|
|
+// HRT-15790 TODO: separate nnc interrupts and soc interrupts
|
|
+#define FW_ACCESS_SOFT_RESET_SHIFT (3)
|
|
+#define FW_ACCESS_SOFT_RESET_MASK (1 << FW_ACCESS_SOFT_RESET_SHIFT)
|
|
+
|
|
#define FW_ACCESS_SOC_CONTROL_SHIFT (3)
|
|
#define FW_ACCESS_SOC_CONTROL_MASK (1 << FW_ACCESS_SOC_CONTROL_SHIFT)
|
|
|
|
@@ -184,7 +189,6 @@ enum hailo_dma_data_direction {
|
|
};
|
|
|
|
// Enum that states what type of buffer we are working with in the driver
|
|
-// TODO: HRT-13580 - Add specific type for user allocated and for driver allocated
|
|
enum hailo_dma_buffer_type {
|
|
HAILO_DMA_USER_PTR_BUFFER = 0,
|
|
HAILO_DMA_DMABUF_BUFFER = 1,
|
|
@@ -399,7 +403,7 @@ struct hailo_d2h_notification {
|
|
enum hailo_board_type {
|
|
HAILO_BOARD_TYPE_HAILO8 = 0,
|
|
HAILO_BOARD_TYPE_HAILO15,
|
|
- HAILO_BOARD_TYPE_PLUTO,
|
|
+ HAILO_BOARD_TYPE_HAILO15L,
|
|
HAILO_BOARD_TYPE_HAILO10H,
|
|
HAILO_BOARD_TYPE_HAILO10H_LEGACY,
|
|
HAILO_BOARD_TYPE_COUNT,
|
|
--- a/drivers/media/pci/hailo/common/pcie_common.c
|
|
+++ b/drivers/media/pci/hailo/common/pcie_common.c
|
|
@@ -30,6 +30,8 @@
|
|
|
|
#define ATR0_PCIE_BRIDGE_OFFSET (0x700)
|
|
|
|
+#define ATR_PCIE_BRIDGE_OFFSET(atr_index) (ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20))
|
|
+
|
|
#define MAXIMUM_APP_FIRMWARE_CODE_SIZE (0x40000)
|
|
#define MAXIMUM_CORE_FIRMWARE_CODE_SIZE (0x20000)
|
|
|
|
@@ -40,17 +42,21 @@
|
|
|
|
#define PCIE_CONFIG_VENDOR_OFFSET (0x0098)
|
|
|
|
-#define HAILO_PCIE_HOST_DMA_DATA_ID (0)
|
|
#define HAILO_PCIE_DMA_DEVICE_INTERRUPTS_BITMASK (1 << 4)
|
|
#define HAILO_PCIE_DMA_HOST_INTERRUPTS_BITMASK (1 << 5)
|
|
#define HAILO_PCIE_DMA_SRC_CHANNELS_BITMASK (0x0000FFFF)
|
|
|
|
#define HAILO_PCIE_MAX_ATR_TABLE_INDEX (3)
|
|
|
|
-#define MAX_FILES_PER_STAGE (4)
|
|
-
|
|
#define BOOT_STATUS_UNINITIALIZED (0x1)
|
|
|
|
+#define PCIE_CONTROL_SECTION_ADDRESS_H8 (0x60000000)
|
|
+#define PCIE_BLOCK_ADDRESS_ATR1 (0x200000)
|
|
+
|
|
+#define PCIE_CONFIG_PCIE_CFG_QM_ROUTING_MODE_SET(reg_offset) \
|
|
+ (reg_offset) = (((reg_offset) & ~0x00000004L) | ((uint32_t)(1) << 2))
|
|
+
|
|
+
|
|
struct hailo_fw_addresses {
|
|
u32 boot_fw_header;
|
|
u32 app_fw_code_ram_base;
|
|
@@ -58,19 +64,14 @@ struct hailo_fw_addresses {
|
|
u32 boot_cont_cert;
|
|
u32 core_code_ram_base;
|
|
u32 core_fw_header;
|
|
- u32 atr0_trsl_addr1;
|
|
u32 raise_ready_offset;
|
|
u32 boot_status;
|
|
-};
|
|
-
|
|
-struct loading_stage {
|
|
- const struct hailo_file_batch *batch;
|
|
- u32 trigger_address;
|
|
+ u32 pcie_cfg_regs;
|
|
};
|
|
|
|
struct hailo_board_compatibility {
|
|
struct hailo_fw_addresses fw_addresses;
|
|
- const struct loading_stage stages[MAX_LOADING_STAGES];
|
|
+ const struct hailo_pcie_loading_stage stages[MAX_LOADING_STAGES];
|
|
};
|
|
|
|
static const struct hailo_file_batch hailo10h_files_stg1[] = {
|
|
@@ -134,13 +135,18 @@ static const struct hailo_file_batch hai
|
|
.has_core = false
|
|
},
|
|
{
|
|
- .filename = "hailo/hailo10h/core-image-minimal-hailo10-m2.ext4.gz",
|
|
+ .filename = "hailo/hailo10h/image-fs",
|
|
+#ifndef HAILO_EMULATOR
|
|
.address = 0x88000000,
|
|
+#else
|
|
+ // TODO : HRT-15692 - merge two cases
|
|
+ .address = 0x89000000,
|
|
+#endif /* ifndef HAILO_EMULATOR */
|
|
.max_size = 0x20000000, // Max size 512MB
|
|
.is_mandatory = true,
|
|
.has_header = false,
|
|
.has_core = false
|
|
- },
|
|
+ }
|
|
};
|
|
|
|
// If loading linux from EMMC - only need few files from second batch (u-boot-spl.bin and u-boot-tfa.itb)
|
|
@@ -173,7 +179,7 @@ static const struct hailo_file_batch hai
|
|
|
|
static const struct hailo_file_batch hailo8_files_stg1[] = {
|
|
{
|
|
- .filename = "hailo/hailo8_fw.4.19.0.bin",
|
|
+ .filename = "hailo/hailo8_fw.bin",
|
|
.address = 0x20000,
|
|
.max_size = 0x50000,
|
|
.is_mandatory = true,
|
|
@@ -225,9 +231,10 @@ static const struct hailo_file_batch hai
|
|
}
|
|
};
|
|
|
|
-static const struct hailo_file_batch pluto_files_stg1[] = {
|
|
+// TODO HRT-15014 - Fix names for hailo15l legacy accelerator
|
|
+static const struct hailo_file_batch hailo15l_files_stg1[] = {
|
|
{
|
|
- .filename = "hailo/pluto_fw.bin",
|
|
+ .filename = "hailo/hailo15l_fw.bin",
|
|
.address = 0x20000,
|
|
.max_size = 0x100000,
|
|
.is_mandatory = true,
|
|
@@ -253,14 +260,15 @@ static const struct hailo_board_compatib
|
|
.app_fw_code_ram_base = 0x60000,
|
|
.core_code_ram_base = 0xC0000,
|
|
.core_fw_header = 0xA0000,
|
|
- .atr0_trsl_addr1 = 0x60000000,
|
|
.raise_ready_offset = 0x1684,
|
|
.boot_status = 0xe0000,
|
|
},
|
|
.stages = {
|
|
{
|
|
.batch = hailo8_files_stg1,
|
|
- .trigger_address = 0xE0980
|
|
+ .trigger_address = 0xE0980,
|
|
+ .timeout = FIRMWARE_WAIT_TIMEOUT_MS,
|
|
+ .amount_of_files_in_stage = 3
|
|
},
|
|
},
|
|
},
|
|
@@ -272,14 +280,15 @@ static const struct hailo_board_compatib
|
|
.app_fw_code_ram_base = 0x20000,
|
|
.core_code_ram_base = 0x60000,
|
|
.core_fw_header = 0xC0000,
|
|
- .atr0_trsl_addr1 = 0x000BE000,
|
|
.raise_ready_offset = 0x1754,
|
|
.boot_status = 0x80000,
|
|
},
|
|
.stages = {
|
|
{
|
|
.batch = hailo10h_legacy_files_stg1,
|
|
- .trigger_address = 0x88c98
|
|
+ .trigger_address = 0x88c98,
|
|
+ .timeout = FIRMWARE_WAIT_TIMEOUT_MS,
|
|
+ .amount_of_files_in_stage = 1
|
|
},
|
|
},
|
|
},
|
|
@@ -291,28 +300,34 @@ static const struct hailo_board_compatib
|
|
.app_fw_code_ram_base = 0x20000,
|
|
.core_code_ram_base = 0,
|
|
.core_fw_header = 0,
|
|
- .atr0_trsl_addr1 = 0x000BE000,
|
|
.raise_ready_offset = 0x1754,
|
|
.boot_status = 0x80000,
|
|
+ .pcie_cfg_regs = 0x002009dc,
|
|
},
|
|
.stages = {
|
|
{
|
|
.batch = hailo10h_files_stg1,
|
|
- .trigger_address = 0x88c98
|
|
+ .trigger_address = 0x88c98,
|
|
+ .timeout = FIRMWARE_WAIT_TIMEOUT_MS,
|
|
+ .amount_of_files_in_stage = 3
|
|
},
|
|
{
|
|
.batch = hailo10h_files_stg2,
|
|
- .trigger_address = 0x84000000
|
|
+ .trigger_address = 0x84000000,
|
|
+ .timeout = PCI_EP_WAIT_TIMEOUT_MS,
|
|
+ .amount_of_files_in_stage = 4
|
|
},
|
|
{
|
|
.batch = hailo10h_files_stg2_linux_in_emmc,
|
|
- .trigger_address = 0x84000000
|
|
+ .trigger_address = 0x84000000,
|
|
+ .timeout = FIRMWARE_WAIT_TIMEOUT_MS,
|
|
+ .amount_of_files_in_stage = 2
|
|
},
|
|
},
|
|
},
|
|
// HRT-11344 : none of these matter except raise_ready_offset seeing as we load fw seperately - not through driver
|
|
// After implementing bootloader put correct values here
|
|
- [HAILO_BOARD_TYPE_PLUTO] = {
|
|
+ [HAILO_BOARD_TYPE_HAILO15L] = {
|
|
.fw_addresses = {
|
|
.boot_fw_header = 0x88000,
|
|
.boot_key_cert = 0x88018,
|
|
@@ -320,44 +335,54 @@ static const struct hailo_board_compatib
|
|
.app_fw_code_ram_base = 0x20000,
|
|
.core_code_ram_base = 0x60000,
|
|
.core_fw_header = 0xC0000,
|
|
- .atr0_trsl_addr1 = 0x000BE000,
|
|
// NOTE: After they update hw consts - check register fw_access_interrupt_w1s of pcie_config
|
|
.raise_ready_offset = 0x174c,
|
|
.boot_status = 0x80000,
|
|
},
|
|
.stages = {
|
|
{
|
|
- .batch = pluto_files_stg1,
|
|
- .trigger_address = 0x88c98
|
|
+ .batch = hailo15l_files_stg1,
|
|
+ .trigger_address = 0x88c98,
|
|
+ .timeout = FIRMWARE_WAIT_TIMEOUT_MS,
|
|
+ .amount_of_files_in_stage = 1
|
|
},
|
|
},
|
|
}
|
|
};
|
|
|
|
+const struct hailo_pcie_loading_stage *hailo_pcie_get_loading_stage_info(enum hailo_board_type board_type,
|
|
+ enum loading_stages stage)
|
|
+{
|
|
+ return &compat[board_type].stages[stage];
|
|
+}
|
|
+
|
|
+static u32 read_and_clear_reg(struct hailo_resource *resource, u32 offset)
|
|
+{
|
|
+ u32 value = hailo_resource_read32(resource, offset);
|
|
+ if (value != 0) {
|
|
+ hailo_resource_write32(resource, offset, value);
|
|
+ }
|
|
+ return value;
|
|
+}
|
|
|
|
bool hailo_pcie_read_interrupt(struct hailo_pcie_resources *resources, struct hailo_pcie_interrupt_source *source)
|
|
{
|
|
- u32 channel_data_source = 0;
|
|
- u32 channel_data_dest = 0;
|
|
+ u32 istatus_host = 0;
|
|
memset(source, 0, sizeof(*source));
|
|
|
|
- source->interrupt_bitmask = hailo_resource_read32(&resources->config, BCS_ISTATUS_HOST);
|
|
- if (0 == source->interrupt_bitmask) {
|
|
+ istatus_host = read_and_clear_reg(&resources->config, BCS_ISTATUS_HOST);
|
|
+ if (0 == istatus_host) {
|
|
return false;
|
|
}
|
|
|
|
- // clear signal
|
|
- hailo_resource_write32(&resources->config, BCS_ISTATUS_HOST, source->interrupt_bitmask);
|
|
+ source->sw_interrupts = (istatus_host >> BCS_ISTATUS_HOST_SW_IRQ_SHIFT);
|
|
|
|
- if (source->interrupt_bitmask & BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK) {
|
|
- channel_data_source = hailo_resource_read32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL);
|
|
- hailo_resource_write32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL, channel_data_source);
|
|
- }
|
|
- if (source->interrupt_bitmask & BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK) {
|
|
- channel_data_dest = hailo_resource_read32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL);
|
|
- hailo_resource_write32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL, channel_data_dest);
|
|
+ if (istatus_host & BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK) {
|
|
+ source->vdma_channels_bitmap |= read_and_clear_reg(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL);
|
|
+ }
|
|
+ if (istatus_host & BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK) {
|
|
+ source->vdma_channels_bitmap |= read_and_clear_reg(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL);
|
|
}
|
|
- source->vdma_channels_bitmap = channel_data_source | channel_data_dest;
|
|
|
|
return true;
|
|
}
|
|
@@ -419,6 +444,15 @@ void hailo_pcie_write_firmware_driver_sh
|
|
hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, fw_access_value);
|
|
}
|
|
|
|
+void hailo_pcie_write_firmware_soft_reset(struct hailo_pcie_resources *resources)
|
|
+{
|
|
+ const struct hailo_fw_addresses *fw_addresses = &(compat[resources->board_type].fw_addresses);
|
|
+ const u32 fw_access_value = FW_ACCESS_SOFT_RESET_MASK;
|
|
+
|
|
+ // Write shutdown flag to FW
|
|
+ hailo_resource_write32(&resources->fw_access, fw_addresses->raise_ready_offset, fw_access_value);
|
|
+}
|
|
+
|
|
int hailo_pcie_configure_atr_table(struct hailo_resource *bridge_config, u64 trsl_addr, u32 atr_index)
|
|
{
|
|
size_t offset = 0;
|
|
@@ -431,7 +465,7 @@ int hailo_pcie_configure_atr_table(struc
|
|
};
|
|
|
|
BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index);
|
|
- offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20);
|
|
+ offset = ATR_PCIE_BRIDGE_OFFSET(atr_index);
|
|
|
|
return hailo_resource_write_buffer(bridge_config, offset, sizeof(atr), (void*)&atr);
|
|
}
|
|
@@ -441,7 +475,7 @@ void hailo_pcie_read_atr_table(struct ha
|
|
size_t offset = 0;
|
|
|
|
BUG_ON(HAILO_PCIE_MAX_ATR_TABLE_INDEX < atr_index);
|
|
- offset = ATR0_PCIE_BRIDGE_OFFSET + (atr_index * 0x20);
|
|
+ offset = ATR_PCIE_BRIDGE_OFFSET(atr_index);
|
|
|
|
hailo_resource_read_buffer(bridge_config, offset, sizeof(*atr), (void*)atr);
|
|
}
|
|
@@ -510,7 +544,7 @@ static void read_memory(struct hailo_pci
|
|
hailo_pcie_read_atr_table(&resources->config, &previous_atr, ATR_INDEX);
|
|
|
|
if (base_address != src) {
|
|
- // Data is not aligned, write the first chunk
|
|
+ // Data is not aligned, read the first chunk
|
|
chunk_len = min((u32)(base_address + ATR_TABLE_SIZE - src), len);
|
|
read_memory_chunk(resources, base_address, (u32)(src - base_address), dest, chunk_len);
|
|
offset += chunk_len;
|
|
@@ -526,6 +560,18 @@ static void read_memory(struct hailo_pci
|
|
(((u64)(previous_atr.atr_trsl_addr_2) << 32) | previous_atr.atr_trsl_addr_1), ATR_INDEX);
|
|
}
|
|
|
|
+// Note: This function use for enabling the vDMA transaction host<->device by read modify write of the EP registers in the SOC - for fast boot over vDMA.
|
|
+void hailo_pcie_configure_ep_registers_for_dma_transaction(struct hailo_pcie_resources *resources)
|
|
+{
|
|
+ u32 reg_routing_mercury = 0;
|
|
+
|
|
+ BUG_ON(compat[resources->board_type].fw_addresses.pcie_cfg_regs == 0);
|
|
+
|
|
+ read_memory(resources, compat[resources->board_type].fw_addresses.pcie_cfg_regs, ®_routing_mercury, sizeof(reg_routing_mercury));
|
|
+ PCIE_CONFIG_PCIE_CFG_QM_ROUTING_MODE_SET(reg_routing_mercury);
|
|
+ write_memory(resources, compat[resources->board_type].fw_addresses.pcie_cfg_regs, ®_routing_mercury, sizeof(reg_routing_mercury));
|
|
+}
|
|
+
|
|
static void hailo_write_app_firmware(struct hailo_pcie_resources *resources, firmware_header_t *fw_header,
|
|
secure_boot_certificate_header_t *fw_cert)
|
|
{
|
|
@@ -551,11 +597,11 @@ static void hailo_write_core_firmware(st
|
|
write_memory(resources, fw_addresses->core_fw_header, fw_header, sizeof(firmware_header_t));
|
|
}
|
|
|
|
-void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 address)
|
|
+void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 stage)
|
|
{
|
|
u32 pcie_finished = 1;
|
|
|
|
- write_memory(resources, address, (void*)&pcie_finished, sizeof(pcie_finished));
|
|
+ write_memory(resources, compat[resources->board_type].stages[stage].trigger_address, (void*)&pcie_finished, sizeof(pcie_finished));
|
|
}
|
|
|
|
u32 hailo_get_boot_status(struct hailo_pcie_resources *resources)
|
|
@@ -673,16 +719,14 @@ static int write_single_file(struct hail
|
|
|
|
int hailo_pcie_write_firmware_batch(struct device *dev, struct hailo_pcie_resources *resources, u32 stage)
|
|
{
|
|
- const struct hailo_file_batch *files_batch = compat[resources->board_type].stages[stage].batch;
|
|
+ const struct hailo_pcie_loading_stage *stage_info = hailo_pcie_get_loading_stage_info(resources->board_type, stage);
|
|
+ const struct hailo_file_batch *files_batch = stage_info->batch;
|
|
+ const u8 amount_of_files = stage_info->amount_of_files_in_stage;
|
|
int file_index = 0;
|
|
int err = 0;
|
|
|
|
- for (file_index = 0; file_index < MAX_FILES_PER_STAGE; file_index++)
|
|
+ for (file_index = 0; file_index < amount_of_files; file_index++)
|
|
{
|
|
- if (NULL == files_batch[file_index].filename) {
|
|
- break;
|
|
- }
|
|
-
|
|
dev_notice(dev, "Writing file %s\n", files_batch[file_index].filename);
|
|
|
|
err = write_single_file(resources, &files_batch[file_index], dev);
|
|
@@ -696,31 +740,29 @@ int hailo_pcie_write_firmware_batch(stru
|
|
dev_notice(dev, "File %s written successfully\n", files_batch[file_index].filename);
|
|
}
|
|
|
|
- hailo_trigger_firmware_boot(resources, compat[resources->board_type].stages[stage].trigger_address);
|
|
+ hailo_trigger_firmware_boot(resources, stage);
|
|
|
|
return 0;
|
|
}
|
|
|
|
-// TODO: HRT-14147 - remove this function
|
|
-static bool hailo_pcie_is_device_ready_for_boot(struct hailo_pcie_resources *resources)
|
|
-{
|
|
- return hailo_get_boot_status(resources) == BOOT_STATUS_UNINITIALIZED;
|
|
-}
|
|
-
|
|
bool hailo_pcie_is_firmware_loaded(struct hailo_pcie_resources *resources)
|
|
{
|
|
u32 offset;
|
|
u32 atr_value;
|
|
|
|
- // TODO: HRT-14147
|
|
- if (HAILO_BOARD_TYPE_HAILO10H == resources->board_type) {
|
|
- return !hailo_pcie_is_device_ready_for_boot(resources);
|
|
+ if (HAILO_BOARD_TYPE_HAILO8 == resources->board_type) {
|
|
+ offset = ATR_PCIE_BRIDGE_OFFSET(0) + offsetof(struct hailo_atr_config, atr_trsl_addr_1);
|
|
+ atr_value = hailo_resource_read32(&resources->config, offset);
|
|
+
|
|
+ return (PCIE_CONTROL_SECTION_ADDRESS_H8 == atr_value);
|
|
}
|
|
+ else {
|
|
+ offset = ATR_PCIE_BRIDGE_OFFSET(1) + offsetof(struct hailo_atr_config, atr_trsl_addr_1);
|
|
+ atr_value = hailo_resource_read32(&resources->config, offset);
|
|
|
|
- offset = ATR0_PCIE_BRIDGE_OFFSET + offsetof(struct hailo_atr_config, atr_trsl_addr_1);
|
|
- atr_value = hailo_resource_read32(&resources->config, offset);
|
|
+ return (PCIE_BLOCK_ADDRESS_ATR1 == atr_value);
|
|
+ }
|
|
|
|
- return atr_value == compat[resources->board_type].fw_addresses.atr0_trsl_addr1;
|
|
}
|
|
|
|
bool hailo_pcie_wait_for_firmware(struct hailo_pcie_resources *resources)
|
|
@@ -764,8 +806,7 @@ void hailo_pcie_enable_interrupts(struct
|
|
hailo_resource_write32(&resources->config, BCS_DESTINATION_INTERRUPT_PER_CHANNEL, 0xFFFFFFFF);
|
|
hailo_resource_write32(&resources->config, BCS_SOURCE_INTERRUPT_PER_CHANNEL, 0xFFFFFFFF);
|
|
|
|
- mask |= (BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK | BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION |
|
|
- BCS_ISTATUS_HOST_DRIVER_DOWN | BCS_ISTATUS_SOC_CONNECT_ACCEPTED | BCS_ISTATUS_SOC_CLOSED_IRQ);
|
|
+ mask |= BCS_ISTATUS_HOST_SW_IRQ_MASK;
|
|
hailo_resource_write32(&resources->config, BSC_IMASK_HOST, mask);
|
|
}
|
|
|
|
@@ -822,7 +863,7 @@ int hailo_set_device_type(struct hailo_p
|
|
switch(resources->board_type) {
|
|
case HAILO_BOARD_TYPE_HAILO8:
|
|
case HAILO_BOARD_TYPE_HAILO10H_LEGACY:
|
|
- case HAILO_BOARD_TYPE_PLUTO:
|
|
+ case HAILO_BOARD_TYPE_HAILO15L:
|
|
resources->accelerator_type = HAILO_ACCELERATOR_TYPE_NNC;
|
|
break;
|
|
case HAILO_BOARD_TYPE_HAILO10H:
|
|
--- a/drivers/media/pci/hailo/common/pcie_common.h
|
|
+++ b/drivers/media/pci/hailo/common/pcie_common.h
|
|
@@ -18,11 +18,8 @@
|
|
#include <linux/firmware.h>
|
|
|
|
|
|
-#define BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK (0x04000000)
|
|
-#define BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION (0x02000000)
|
|
-#define BCS_ISTATUS_HOST_DRIVER_DOWN (0x08000000)
|
|
-#define BCS_ISTATUS_SOC_CONNECT_ACCEPTED (0x10000000)
|
|
-#define BCS_ISTATUS_SOC_CLOSED_IRQ (0x20000000)
|
|
+#define BCS_ISTATUS_HOST_SW_IRQ_MASK (0xFF000000)
|
|
+#define BCS_ISTATUS_HOST_SW_IRQ_SHIFT (24)
|
|
#define BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK (0x000000FF)
|
|
#define BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK (0x0000FF00)
|
|
|
|
@@ -36,13 +33,19 @@
|
|
#define HAILO_PCIE_FW_ACCESS_BAR (4)
|
|
|
|
#define HAILO_PCIE_DMA_ENGINES_COUNT (1)
|
|
+#define PCI_VDMA_ENGINE_INDEX (0)
|
|
+
|
|
+#define MAX_FILES_PER_STAGE (4)
|
|
+
|
|
+#define HAILO_PCIE_HOST_DMA_DATA_ID (0)
|
|
+#define HAILO_PCI_EP_HOST_DMA_DATA_ID (6)
|
|
|
|
#define DRIVER_NAME "hailo"
|
|
|
|
#define PCI_VENDOR_ID_HAILO 0x1e60
|
|
#define PCI_DEVICE_ID_HAILO_HAILO8 0x2864
|
|
-#define PCI_DEVICE_ID_HAILO_HAILO15 0x45C4
|
|
-#define PCI_DEVICE_ID_HAILO_PLUTO 0x43a2
|
|
+#define PCI_DEVICE_ID_HAILO_HAILO10H 0x45C4
|
|
+#define PCI_DEVICE_ID_HAILO_HAILO15L 0x43a2
|
|
|
|
typedef u64 hailo_ptr_t;
|
|
|
|
@@ -69,18 +72,24 @@ enum loading_stages {
|
|
MAX_LOADING_STAGES = 3
|
|
};
|
|
|
|
-enum hailo_pcie_interrupt_masks {
|
|
- FW_CONTROL = BCS_ISTATUS_HOST_FW_IRQ_CONTROL_MASK,
|
|
- FW_NOTIFICATION = BCS_ISTATUS_HOST_FW_IRQ_NOTIFICATION,
|
|
- DRIVER_DOWN = BCS_ISTATUS_HOST_DRIVER_DOWN,
|
|
- SOC_CONNECT_ACCEPTED = BCS_ISTATUS_SOC_CONNECT_ACCEPTED,
|
|
- SOC_CLOSED_IRQ = BCS_ISTATUS_SOC_CLOSED_IRQ,
|
|
- VDMA_SRC_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_SRC_IRQ_MASK,
|
|
- VDMA_DEST_IRQ_MASK = BCS_ISTATUS_HOST_VDMA_DEST_IRQ_MASK
|
|
+enum hailo_pcie_nnc_sw_interrupt_masks {
|
|
+ HAILO_PCIE_NNC_FW_NOTIFICATION_IRQ = 0x2,
|
|
+ HAILO_PCIE_NNC_FW_CONTROL_IRQ = 0x4,
|
|
+ HAILO_PCIE_NNC_DRIVER_DOWN_IRQ = 0x8,
|
|
+};
|
|
+
|
|
+enum hailo_pcie_soc_sw_interrupt_masks {
|
|
+ HAILO_PCIE_SOC_CONTROL_IRQ = 0x10,
|
|
+ HAILO_PCIE_SOC_CLOSE_IRQ = 0x20,
|
|
+};
|
|
+
|
|
+enum hailo_pcie_boot_interrupt_masks {
|
|
+ HAILO_PCIE_BOOT_SOFT_RESET_IRQ = 0x1,
|
|
+ HAILO_PCIE_BOOT_IRQ = 0x2,
|
|
};
|
|
|
|
struct hailo_pcie_interrupt_source {
|
|
- u32 interrupt_bitmask;
|
|
+ u32 sw_interrupts;
|
|
u32 vdma_channels_bitmap;
|
|
};
|
|
|
|
@@ -93,6 +102,13 @@ struct hailo_file_batch {
|
|
bool has_core;
|
|
};
|
|
|
|
+struct hailo_pcie_loading_stage {
|
|
+ const struct hailo_file_batch *batch;
|
|
+ u32 trigger_address;
|
|
+ u32 timeout;
|
|
+ u8 amount_of_files_in_stage;
|
|
+};
|
|
+
|
|
// TODO: HRT-6144 - Align Windows/Linux to QNX
|
|
#ifdef __QNX__
|
|
enum hailo_bar_index {
|
|
@@ -117,8 +133,23 @@ enum hailo_bar_index {
|
|
extern "C" {
|
|
#endif
|
|
|
|
+
|
|
+#ifndef HAILO_EMULATOR
|
|
+#define TIME_UNTIL_REACH_BOOTLOADER (10)
|
|
+#define PCI_EP_WAIT_TIMEOUT_MS (40000)
|
|
+#define FIRMWARE_WAIT_TIMEOUT_MS (5000)
|
|
+#else /* ifndef HAILO_EMULATOR */
|
|
+// PCI EP timeout is defined to 50000000 because on Emulator the boot time + linux init time can be very long (4+ hours)
|
|
+#define TIME_UNTIL_REACH_BOOTLOADER (10000)
|
|
+#define PCI_EP_WAIT_TIMEOUT_MS (50000000)
|
|
+#define FIRMWARE_WAIT_TIMEOUT_MS (5000000)
|
|
+#endif /* ifndef HAILO_EMULATOR */
|
|
+
|
|
extern struct hailo_vdma_hw hailo_pcie_vdma_hw;
|
|
|
|
+const struct hailo_pcie_loading_stage* hailo_pcie_get_loading_stage_info(enum hailo_board_type board_type,
|
|
+ enum loading_stages stage);
|
|
+
|
|
// Reads the interrupt source from BARs, return false if there is no interrupt.
|
|
// note - this function clears the interrupt signals.
|
|
bool hailo_pcie_read_interrupt(struct hailo_pcie_resources *resources, struct hailo_pcie_interrupt_source *source);
|
|
@@ -137,7 +168,9 @@ int hailo_pcie_memory_transfer(struct ha
|
|
|
|
bool hailo_pcie_is_device_connected(struct hailo_pcie_resources *resources);
|
|
void hailo_pcie_write_firmware_driver_shutdown(struct hailo_pcie_resources *resources);
|
|
-void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 address);
|
|
+void hailo_pcie_write_firmware_soft_reset(struct hailo_pcie_resources *resources);
|
|
+void hailo_pcie_configure_ep_registers_for_dma_transaction(struct hailo_pcie_resources *resources);
|
|
+void hailo_trigger_firmware_boot(struct hailo_pcie_resources *resources, u32 stage);
|
|
|
|
int hailo_set_device_type(struct hailo_pcie_resources *resources);
|
|
|
|
@@ -157,4 +190,4 @@ void hailo_pcie_soc_read_response(struct
|
|
}
|
|
#endif
|
|
|
|
-#endif /* _HAILO_COMMON_PCIE_COMMON_H_ */
|
|
\ No newline at end of file
|
|
+#endif /* _HAILO_COMMON_PCIE_COMMON_H_ */
|
|
--- a/drivers/media/pci/hailo/common/vdma_common.c
|
|
+++ b/drivers/media/pci/hailo/common/vdma_common.c
|
|
@@ -15,16 +15,6 @@
|
|
#include <linux/kconfig.h>
|
|
#include <linux/printk.h>
|
|
|
|
-
|
|
-#define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5)
|
|
-
|
|
-#define CHANNEL_CONTROL_OFFSET (0x0)
|
|
-#define CHANNEL_DEPTH_ID_OFFSET (0x1)
|
|
-#define CHANNEL_NUM_AVAIL_OFFSET (0x2)
|
|
-#define CHANNEL_NUM_PROC_OFFSET (0x4)
|
|
-#define CHANNEL_ERROR_OFFSET (0x8)
|
|
-#define CHANNEL_DEST_REGS_OFFSET (0x10)
|
|
-
|
|
#define VDMA_CHANNEL_CONTROL_START (0x1)
|
|
#define VDMA_CHANNEL_CONTROL_ABORT (0b00)
|
|
#define VDMA_CHANNEL_CONTROL_ABORT_PAUSE (0b10)
|
|
@@ -160,17 +150,17 @@ static u8 get_channel_id(u8 channel_inde
|
|
return (channel_index < MAX_VDMA_CHANNELS_PER_ENGINE) ? (channel_index & 0xF) : INVALID_VDMA_CHANNEL;
|
|
}
|
|
|
|
-static int program_descriptors_in_chunk(
|
|
+int hailo_vdma_program_descriptors_in_chunk(
|
|
struct hailo_vdma_hw *vdma_hw,
|
|
dma_addr_t chunk_addr,
|
|
unsigned int chunk_size,
|
|
struct hailo_vdma_descriptors_list *desc_list,
|
|
u32 desc_index,
|
|
u32 max_desc_index,
|
|
- u8 channel_id)
|
|
+ u8 channel_index,
|
|
+ u8 data_id)
|
|
{
|
|
const u16 page_size = desc_list->desc_page_size;
|
|
- const u8 ddr_data_id = vdma_hw->ddr_data_id;
|
|
const u32 descs_to_program = DIV_ROUND_UP(chunk_size, page_size);
|
|
const u32 starting_desc_index = desc_index;
|
|
const u32 residue_size = chunk_size % page_size;
|
|
@@ -187,7 +177,7 @@ static int program_descriptors_in_chunk(
|
|
return -ERANGE;
|
|
}
|
|
|
|
- encoded_addr = vdma_hw->hw_ops.encode_desc_dma_address_range(chunk_addr, chunk_addr + chunk_size, page_size, channel_id);
|
|
+ encoded_addr = vdma_hw->hw_ops.encode_desc_dma_address_range(chunk_addr, chunk_addr + chunk_size, page_size, get_channel_id(channel_index));
|
|
if (INVALID_VDMA_ADDRESS == encoded_addr) {
|
|
return -EFAULT;
|
|
}
|
|
@@ -197,7 +187,7 @@ static int program_descriptors_in_chunk(
|
|
// 'desc_index & desc_list_len_mask' is used instead of modulo; see hailo_vdma_descriptors_list documentation.
|
|
hailo_vdma_program_descriptor(
|
|
&desc_list->desc_list[desc_index & desc_list->desc_count_mask],
|
|
- encoded_addr, page_size, ddr_data_id);
|
|
+ encoded_addr, page_size, data_id);
|
|
encoded_addr += page_size;
|
|
}
|
|
|
|
@@ -205,7 +195,7 @@ static int program_descriptors_in_chunk(
|
|
// 'desc_index & desc_list_len_mask' is used instead of modulo; see hailo_vdma_descriptors_list documentation.
|
|
dma_desc = &desc_list->desc_list[desc_index & desc_list->desc_count_mask];
|
|
hailo_vdma_program_descriptor(dma_desc, encoded_addr,
|
|
- (residue_size == 0) ? page_size : (u16)residue_size, ddr_data_id);
|
|
+ (residue_size == 0) ? page_size : (u16)residue_size, data_id);
|
|
|
|
return (int)descs_to_program;
|
|
}
|
|
@@ -241,7 +231,6 @@ static int bind_and_program_descriptors_
|
|
enum hailo_vdma_interrupts_domain last_desc_interrupts,
|
|
bool is_debug)
|
|
{
|
|
- const u8 channel_id = get_channel_id(channel_index);
|
|
int desc_programmed = 0;
|
|
int descs_programmed_in_chunk = 0;
|
|
u32 max_desc_index = 0;
|
|
@@ -279,8 +268,8 @@ static int bind_and_program_descriptors_
|
|
(u32)(sg_dma_len(sg_entry));
|
|
chunk_size = min((u32)program_size, chunk_size);
|
|
|
|
- descs_programmed_in_chunk = program_descriptors_in_chunk(vdma_hw, chunk_start_addr, chunk_size, desc_list,
|
|
- starting_desc, max_desc_index, channel_id);
|
|
+ descs_programmed_in_chunk = hailo_vdma_program_descriptors_in_chunk(vdma_hw, chunk_start_addr, chunk_size, desc_list,
|
|
+ starting_desc, max_desc_index, channel_index, vdma_hw->ddr_data_id);
|
|
if (descs_programmed_in_chunk < 0) {
|
|
return descs_programmed_in_chunk;
|
|
}
|
|
@@ -363,16 +352,16 @@ static int validate_channel_state(struct
|
|
return 0;
|
|
}
|
|
|
|
-static void set_num_avail(u8 __iomem *host_regs, u16 num_avail)
|
|
+void hailo_vdma_set_num_avail(u8 __iomem *regs, u16 num_avail)
|
|
{
|
|
- u32 host_regs_val = ioread32(host_regs);
|
|
- iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, host_regs_val, num_avail),
|
|
- host_regs);
|
|
+ u32 regs_val = ioread32(regs);
|
|
+ iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, CHANNEL_NUM_AVAIL_OFFSET * BITS_IN_BYTE, regs_val, num_avail),
|
|
+ regs);
|
|
}
|
|
|
|
-static u16 get_num_proc(u8 __iomem *host_regs)
|
|
+u16 hailo_vdma_get_num_proc(u8 __iomem *regs)
|
|
{
|
|
- return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(host_regs + CHANNEL_NUM_PROC_OFFSET));
|
|
+ return READ_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, 0, ioread32(regs + CHANNEL_NUM_PROC_OFFSET));
|
|
}
|
|
|
|
int hailo_vdma_launch_transfer(
|
|
@@ -455,7 +444,7 @@ int hailo_vdma_launch_transfer(
|
|
|
|
new_num_avail = (u16)((last_desc + 1) % desc_list->desc_count);
|
|
channel->state.num_avail = new_num_avail;
|
|
- set_num_avail(channel->host_regs, new_num_avail);
|
|
+ hailo_vdma_set_num_avail(channel->host_regs, new_num_avail);
|
|
|
|
return (int)total_descs;
|
|
}
|
|
@@ -463,7 +452,7 @@ int hailo_vdma_launch_transfer(
|
|
static void hailo_vdma_push_timestamp(struct hailo_vdma_channel *channel)
|
|
{
|
|
struct hailo_channel_interrupt_timestamp_list *timestamp_list = &channel->timestamp_list;
|
|
- const u16 num_proc = get_num_proc(channel->host_regs);
|
|
+ const u16 num_proc = hailo_vdma_get_num_proc(channel->host_regs);
|
|
if (TIMESTAMPS_CIRC_SPACE(*timestamp_list) != 0) {
|
|
timestamp_list->timestamps[timestamp_list->head].timestamp_ns = ktime_get_ns();
|
|
timestamp_list->timestamps[timestamp_list->head].desc_num_processed = num_proc;
|
|
@@ -725,7 +714,7 @@ int hailo_vdma_engine_fill_irq_data(stru
|
|
// the actual hw_num_processed is a number between 1 and desc_count.
|
|
// Therefore the value can be desc_count, in this case we change it to
|
|
// zero.
|
|
- hw_num_proc = get_num_proc(channel->host_regs) & channel->state.desc_count_mask;
|
|
+ hw_num_proc = hailo_vdma_get_num_proc(channel->host_regs) & channel->state.desc_count_mask;
|
|
|
|
while (ONGOING_TRANSFERS_CIRC_CNT(channel->ongoing_transfers) > 0) {
|
|
struct hailo_ongoing_transfer *cur_transfer =
|
|
@@ -780,12 +769,13 @@ static void hailo_vdma_channel_abort(u8
|
|
VDMA_CHANNEL_CONTROL_ABORT), host_regs);
|
|
}
|
|
|
|
-int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth,
|
|
+int hailo_vdma_start_channel(u8 __iomem *regs, uint64_t desc_dma_address, uint32_t desc_count,
|
|
uint8_t data_id)
|
|
{
|
|
u16 dma_address_l = 0;
|
|
u32 dma_address_h = 0;
|
|
u32 desc_depth_data_id = 0;
|
|
+ u8 desc_depth = ceil_log2(desc_count);
|
|
|
|
if (((desc_dma_address & 0xFFFF) != 0) ||
|
|
(desc_depth > DESCRIPTOR_LIST_MAX_DEPTH)) {
|
|
@@ -798,22 +788,22 @@ int hailo_vdma_start_channel(u8 __iomem
|
|
}
|
|
|
|
// Stop old channel state
|
|
- hailo_vdma_stop_channel(host_regs);
|
|
+ hailo_vdma_stop_channel(regs);
|
|
|
|
// Configure address, depth and id
|
|
dma_address_l = (uint16_t)((desc_dma_address >> 16) & 0xFFFF);
|
|
iowrite32(WRITE_BITS_AT_OFFSET(WORD_SIZE * BITS_IN_BYTE, (VDMA_CHANNEL__ADDRESS_L_OFFSET -
|
|
- VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET) * BITS_IN_BYTE, ioread32(host_regs +
|
|
- VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET), dma_address_l), host_regs + VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET);
|
|
+ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET) * BITS_IN_BYTE, ioread32(regs +
|
|
+ VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET), dma_address_l), regs + VDMA_CHANNEL__ALIGNED_ADDRESS_L_OFFSET);
|
|
|
|
dma_address_h = (uint32_t)(desc_dma_address >> 32);
|
|
- iowrite32(dma_address_h, host_regs + VDMA_CHANNEL__ADDRESS_H_OFFSET);
|
|
+ iowrite32(dma_address_h, regs + VDMA_CHANNEL__ADDRESS_H_OFFSET);
|
|
|
|
desc_depth_data_id = (uint32_t)(desc_depth << VDMA_CHANNEL_DESC_DEPTH_SHIFT) |
|
|
(data_id << VDMA_CHANNEL_DATA_ID_SHIFT);
|
|
- iowrite32(desc_depth_data_id, host_regs);
|
|
+ iowrite32(desc_depth_data_id, regs);
|
|
|
|
- start_vdma_control_register(host_regs);
|
|
+ start_vdma_control_register(regs);
|
|
|
|
return 0;
|
|
}
|
|
@@ -853,10 +843,10 @@ static int hailo_vdma_wait_until_channel
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
-void hailo_vdma_stop_channel(u8 __iomem *host_regs)
|
|
+void hailo_vdma_stop_channel(u8 __iomem *regs)
|
|
{
|
|
int err = 0;
|
|
- u8 host_side_channel_regs = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(host_regs));
|
|
+ u8 host_side_channel_regs = READ_BITS_AT_OFFSET(BYTE_SIZE * BITS_IN_BYTE, CHANNEL_CONTROL_OFFSET * BITS_IN_BYTE, ioread32(regs));
|
|
|
|
if ((host_side_channel_regs & VDMA_CHANNEL_CONTROL_START_ABORT_PAUSE_RESUME_BITMASK) == VDMA_CHANNEL_CONTROL_ABORT_PAUSE) {
|
|
// The channel is aborted (we set the channel to VDMA_CHANNEL_CONTROL_ABORT_PAUSE at the end of this function)
|
|
@@ -866,17 +856,17 @@ void hailo_vdma_stop_channel(u8 __iomem
|
|
// Pause the channel
|
|
// The channel is paused to allow for "all transfers from fetched descriptors..." to be "...completed"
|
|
// (from PLDA PCIe refernce manual, "9.2.5 Starting a Channel and Transferring Data")
|
|
- hailo_vdma_channel_pause(host_regs);
|
|
+ hailo_vdma_channel_pause(regs);
|
|
|
|
// Even if channel is stuck and not idle, force abort and return error in the end
|
|
- err = hailo_vdma_wait_until_channel_idle(host_regs);
|
|
+ err = hailo_vdma_wait_until_channel_idle(regs);
|
|
// Success oriented - if error occured print error but still abort channel
|
|
if (err < 0) {
|
|
pr_err("Timeout occured while waiting for channel to become idle\n");
|
|
}
|
|
|
|
// Abort the channel (even of hailo_vdma_wait_until_channel_idle function fails)
|
|
- hailo_vdma_channel_abort(host_regs);
|
|
+ hailo_vdma_channel_abort(regs);
|
|
}
|
|
|
|
bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel)
|
|
--- a/drivers/media/pci/hailo/common/vdma_common.h
|
|
+++ b/drivers/media/pci/hailo/common/vdma_common.h
|
|
@@ -16,6 +16,15 @@
|
|
#define VDMA_DESCRIPTOR_LIST_ALIGN (1 << 16)
|
|
#define INVALID_VDMA_ADDRESS (0)
|
|
|
|
+#define CHANNEL_BASE_OFFSET(channel_index) ((channel_index) << 5)
|
|
+
|
|
+#define CHANNEL_CONTROL_OFFSET (0x0)
|
|
+#define CHANNEL_DEPTH_ID_OFFSET (0x1)
|
|
+#define CHANNEL_NUM_AVAIL_OFFSET (0x2)
|
|
+#define CHANNEL_NUM_PROC_OFFSET (0x4)
|
|
+#define CHANNEL_ERROR_OFFSET (0x8)
|
|
+#define CHANNEL_DEST_REGS_OFFSET (0x10)
|
|
+
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
@@ -172,6 +181,20 @@ int hailo_vdma_program_descriptors_list(
|
|
enum hailo_vdma_interrupts_domain last_desc_interrupts,
|
|
bool is_debug);
|
|
|
|
+int hailo_vdma_program_descriptors_in_chunk(
|
|
+ struct hailo_vdma_hw *vdma_hw,
|
|
+ dma_addr_t chunk_addr,
|
|
+ unsigned int chunk_size,
|
|
+ struct hailo_vdma_descriptors_list *desc_list,
|
|
+ u32 desc_index,
|
|
+ u32 max_desc_index,
|
|
+ u8 channel_index,
|
|
+ u8 data_id);
|
|
+
|
|
+void hailo_vdma_set_num_avail(u8 __iomem *regs, u16 num_avail);
|
|
+
|
|
+u16 hailo_vdma_get_num_proc(u8 __iomem *regs);
|
|
+
|
|
/**
|
|
* Launch a transfer on some vdma channel. Includes:
|
|
* 1. Binding the transfer buffers to the descriptors list.
|
|
@@ -249,9 +272,9 @@ int hailo_vdma_engine_fill_irq_data(stru
|
|
struct hailo_vdma_engine *engine, u32 irq_channels_bitmap,
|
|
transfer_done_cb_t transfer_done, void *transfer_done_opaque);
|
|
|
|
-int hailo_vdma_start_channel(u8 __iomem *host_regs, uint64_t desc_dma_address, uint8_t desc_depth, uint8_t data_id);
|
|
+int hailo_vdma_start_channel(u8 __iomem *regs, uint64_t desc_dma_address, uint32_t desc_count, uint8_t data_id);
|
|
|
|
-void hailo_vdma_stop_channel(u8 __iomem *host_regs);
|
|
+void hailo_vdma_stop_channel(u8 __iomem *regs);
|
|
|
|
bool hailo_check_channel_index(u8 channel_index, u32 src_channels_bitmask, bool is_input_channel);
|
|
|
|
--- a/drivers/media/pci/hailo/src/fops.c
|
|
+++ b/drivers/media/pci/hailo/src/fops.c
|
|
@@ -294,6 +294,54 @@ static void firmware_notification_irq_ha
|
|
}
|
|
}
|
|
|
|
+static void boot_irq_handler(struct hailo_pcie_board *board, struct hailo_pcie_interrupt_source *irq_source)
|
|
+{
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_BOOT_SOFT_RESET_IRQ) {
|
|
+ hailo_dbg(board, "soft reset trigger IRQ\n");
|
|
+ complete(&board->soft_reset.reset_completed);
|
|
+ }
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_BOOT_IRQ) {
|
|
+ hailo_dbg(board, "boot trigger IRQ\n");
|
|
+ complete_all(&board->fw_boot.fw_loaded_completion);
|
|
+ } else {
|
|
+ board->fw_boot.boot_used_channel_bitmap &= ~irq_source->vdma_channels_bitmap;
|
|
+ hailo_dbg(board, "boot vDMA data IRQ - channel_bitmap = 0x%x\n", irq_source->vdma_channels_bitmap);
|
|
+ if (0 == board->fw_boot.boot_used_channel_bitmap) {
|
|
+ complete_all(&board->fw_boot.vdma_boot_completion);
|
|
+ hailo_dbg(board, "boot vDMA data trigger IRQ\n");
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void nnc_irq_handler(struct hailo_pcie_board *board, struct hailo_pcie_interrupt_source *irq_source)
|
|
+{
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_NNC_FW_CONTROL_IRQ) {
|
|
+ complete(&board->nnc.fw_control.completion);
|
|
+ }
|
|
+
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_NNC_DRIVER_DOWN_IRQ) {
|
|
+ complete(&board->driver_down.reset_completed);
|
|
+ }
|
|
+
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_NNC_FW_NOTIFICATION_IRQ) {
|
|
+ firmware_notification_irq_handler(board);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void soc_irq_handler(struct hailo_pcie_board *board, struct hailo_pcie_interrupt_source *irq_source)
|
|
+{
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_SOC_CONTROL_IRQ) {
|
|
+ complete_all(&board->soc.control_resp_ready);
|
|
+ }
|
|
+
|
|
+ if (irq_source->sw_interrupts & HAILO_PCIE_SOC_CLOSE_IRQ) {
|
|
+ hailo_info(board, "soc_irq_handler - HAILO_PCIE_SOC_CLOSE_IRQ\n");
|
|
+ // always use bitmap=0xFFFFFFFF - it is ok to wake all interrupts since each handler will check if the stream was aborted or not.
|
|
+ hailo_vdma_wakeup_interrupts(&board->vdma, &board->vdma.vdma_engines[DEFAULT_VDMA_ENGINE_INDEX],
|
|
+ 0xFFFFFFFF);
|
|
+ }
|
|
+}
|
|
+
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
|
|
irqreturn_t hailo_irqhandler(int irq, void *dev_id, struct pt_regs *regs)
|
|
#else
|
|
@@ -320,39 +368,21 @@ irqreturn_t hailo_irqhandler(int irq, vo
|
|
|
|
return_value = IRQ_HANDLED;
|
|
|
|
- // wake fw_control if needed
|
|
- if (irq_source.interrupt_bitmask & FW_CONTROL) {
|
|
- complete(&board->nnc.fw_control.completion);
|
|
- }
|
|
-
|
|
- // wake driver_down if needed
|
|
- if (irq_source.interrupt_bitmask & DRIVER_DOWN) {
|
|
- complete(&board->driver_down.reset_completed);
|
|
- }
|
|
-
|
|
- if (irq_source.interrupt_bitmask & FW_NOTIFICATION) {
|
|
- if (!completion_done(&board->fw_loaded_completion)) {
|
|
- // Complete firmware loaded completion
|
|
- complete_all(&board->fw_loaded_completion);
|
|
+ if (board->fw_boot.is_in_boot) {
|
|
+ boot_irq_handler(board, &irq_source);
|
|
+ } else {
|
|
+ if (HAILO_ACCELERATOR_TYPE_NNC == board->pcie_resources.accelerator_type) {
|
|
+ nnc_irq_handler(board, &irq_source);
|
|
+ } else if (HAILO_ACCELERATOR_TYPE_SOC == board->pcie_resources.accelerator_type) {
|
|
+ soc_irq_handler(board, &irq_source);
|
|
} else {
|
|
- firmware_notification_irq_handler(board);
|
|
+ hailo_err(board, "Invalid accelerator type %d\n", board->pcie_resources.accelerator_type);
|
|
}
|
|
- }
|
|
-
|
|
- if (irq_source.interrupt_bitmask & SOC_CONNECT_ACCEPTED) {
|
|
- complete_all(&board->soc.control_resp_ready);
|
|
- }
|
|
|
|
- if (irq_source.interrupt_bitmask & SOC_CLOSED_IRQ) {
|
|
- hailo_info(board, "hailo_irqhandler - SOC_CLOSED_IRQ\n");
|
|
- // always use bitmap=0xFFFFFFFF - it is ok to wake all interrupts since each handler will check if the stream was aborted or not.
|
|
- hailo_vdma_wakeup_interrupts(&board->vdma, &board->vdma.vdma_engines[DEFAULT_VDMA_ENGINE_INDEX],
|
|
- 0xFFFFFFFF);
|
|
- }
|
|
-
|
|
- if (0 != irq_source.vdma_channels_bitmap) {
|
|
- hailo_vdma_irq_handler(&board->vdma, DEFAULT_VDMA_ENGINE_INDEX,
|
|
- irq_source.vdma_channels_bitmap);
|
|
+ if (0 != irq_source.vdma_channels_bitmap) {
|
|
+ hailo_vdma_irq_handler(&board->vdma, DEFAULT_VDMA_ENGINE_INDEX,
|
|
+ irq_source.vdma_channels_bitmap);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
--- a/drivers/media/pci/hailo/src/nnc.c
|
|
+++ b/drivers/media/pci/hailo/src/nnc.c
|
|
@@ -148,8 +148,8 @@ static long hailo_read_notification_ioct
|
|
|
|
// Check if was disabled
|
|
if (current_waiting_thread->is_disabled) {
|
|
- hailo_info(board, "HAILO_READ_NOTIFICATION, can't find notification wait for tgid=%d\n", current->tgid);
|
|
- err = -EINVAL;
|
|
+ hailo_info(board, "HAILO_READ_NOTIFICATION - notification disabled for tgid=%d\n", current->tgid);
|
|
+ err = -ECANCELED;
|
|
goto l_exit;
|
|
}
|
|
|
|
--- a/drivers/media/pci/hailo/src/pcie.c
|
|
+++ b/drivers/media/pci/hailo/src/pcie.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/pagemap.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/kthread.h>
|
|
+#include <linux/delay.h>
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
|
#include <linux/dma-direct.h>
|
|
@@ -29,6 +30,7 @@
|
|
#include "utils/logs.h"
|
|
#include "utils/compact.h"
|
|
#include "vdma/vdma.h"
|
|
+#include "vdma/memory.h"
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION( 5, 4, 0 )
|
|
#include <linux/pci-aspm.h>
|
|
@@ -46,8 +48,9 @@ enum hailo_allocate_driver_buffer_driver
|
|
static int force_desc_page_size = 0;
|
|
static bool g_is_power_mode_enabled = true;
|
|
static int force_allocation_from_driver = HAILO_NO_FORCE_BUFFER;
|
|
-static bool force_hailo15_legacy_mode = false;
|
|
+static bool force_hailo10h_legacy_mode = false;
|
|
static bool force_boot_linux_from_eemc = false;
|
|
+static bool support_soft_reset = true;
|
|
|
|
#define DEVICE_NODE_NAME "hailo"
|
|
static int char_major = 0;
|
|
@@ -291,12 +294,468 @@ static void hailo_pcie_remove_board(stru
|
|
up(&g_hailo_add_board_mutex);
|
|
}
|
|
|
|
-static bool wait_for_firmware_completion(struct completion *fw_load_completion)
|
|
+/**
|
|
+ * Wait until the relevant completion is done.
|
|
+ *
|
|
+ * @param completion - pointer to the completion struct to wait for.
|
|
+ * @param msecs - the amount of time to wait in milliseconds.
|
|
+ * @return false if timed out, true if completed.
|
|
+ */
|
|
+static bool wait_for_firmware_completion(struct completion *completion, unsigned int msecs)
|
|
+{
|
|
+ return (0 != wait_for_completion_timeout(completion, msecs_to_jiffies(msecs)));
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Program one FW file descriptors to the vDMA engine.
|
|
+ *
|
|
+ * @param dev - pointer to the device struct we are working on.
|
|
+ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources.
|
|
+ * @param file_address - the address of the file in the device memory.
|
|
+ * @param transfer_buffer - the buffer to program to the vDMA engine.
|
|
+ * @param channel_index - the index of the channel to program.
|
|
+ * @param filename - the name of the file to program.
|
|
+ * @param raise_int_on_completion - true if this is the last descriptors chunk in the specific channel in the boot flow, false otherwise. If true - will enable
|
|
+ * an IRQ for the relevant channel when the transfer is finished.
|
|
+ * @return the amount of descriptors programmed on success, negative error code on failure.
|
|
+ */
|
|
+static int pcie_vdma_program_one_file_descriptors(struct device *dev, struct hailo_pcie_boot_dma_channel_state *boot_channel_state,
|
|
+ u32 file_address, struct hailo_vdma_mapped_transfer_buffer transfer_buffer, u8 channel_index, const char *filename, bool raise_int_on_completion)
|
|
+{
|
|
+ int device_desc = 0, host_desc = 0;
|
|
+ enum hailo_vdma_interrupts_domain interrupts_domain = raise_int_on_completion ? HAILO_VDMA_INTERRUPTS_DOMAIN_HOST :
|
|
+ HAILO_VDMA_INTERRUPTS_DOMAIN_NONE;
|
|
+
|
|
+ hailo_dev_dbg(dev, "channel_index = %d, file_name = %s, file_address = 0x%x, transfer_buffer.offset = 0x%x,\
|
|
+ size_to_program = 0x%x, starting_desc/desc_index = 0x%x\n", channel_index, filename, file_address,
|
|
+ transfer_buffer.offset, transfer_buffer.size, boot_channel_state->desc_program_num);
|
|
+
|
|
+ // program descriptors
|
|
+ device_desc = hailo_vdma_program_descriptors_in_chunk(&hailo_pcie_vdma_hw, file_address, transfer_buffer.size,
|
|
+ &boot_channel_state->device_descriptors_buffer.desc_list, boot_channel_state->desc_program_num,
|
|
+ (boot_channel_state->device_descriptors_buffer.desc_list.desc_count - 1), channel_index, HAILO_PCI_EP_HOST_DMA_DATA_ID);
|
|
+ if (device_desc < 0) {
|
|
+ hailo_dev_err(dev, "Failed to program device descriptors, error = %u\n", device_desc);
|
|
+ return device_desc;
|
|
+ }
|
|
+
|
|
+ host_desc = hailo_vdma_program_descriptors_list(&hailo_pcie_vdma_hw, &boot_channel_state->host_descriptors_buffer.desc_list,
|
|
+ boot_channel_state->desc_program_num, &transfer_buffer, true, channel_index, interrupts_domain, false);
|
|
+ if (host_desc < 0) {
|
|
+ hailo_dev_err(dev, "Failed to program host descriptors, error = %u\n", host_desc);
|
|
+ return host_desc;
|
|
+ }
|
|
+
|
|
+ // checks that same amount of decsriptors were programmed on device side and host side
|
|
+ if (host_desc != device_desc) {
|
|
+ hailo_dev_err(dev, "Host and device descriptors should be the same\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return host_desc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Program one FW file to the vDMA engine.
|
|
+ *
|
|
+ * @param board - pointer to the board struct we are working on.
|
|
+ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources.
|
|
+ * @param file_address - the address of the file in the device memory.
|
|
+ * @param filename - the name of the file to program.
|
|
+ * @param raise_int_on_completion - true if this is the last file in the boot flow, false otherwise. uses to enable an IRQ for the
|
|
+ * relevant channel when the transfer is finished.
|
|
+ * @return 0 on success, negative error code on failure. at the end of the function the firmware is released.
|
|
+ */
|
|
+static int pcie_vdma_program_one_file(struct hailo_pcie_board *board, struct hailo_pcie_boot_dma_state *boot_dma_state, u32 file_address,
|
|
+ const char *filename, bool raise_int_on_completion)
|
|
+{
|
|
+ const struct firmware *firmware = NULL;
|
|
+ struct hailo_vdma_mapped_transfer_buffer transfer_buffer = {0};
|
|
+ int desc_programmed = 0;
|
|
+ int err = 0;
|
|
+ size_t bytes_copied = 0, remaining_size = 0, data_offset = 0, desc_num_left = 0, current_desc_to_program = 0;
|
|
+
|
|
+ hailo_notice(board, "Programing file %s for dma transfer\n", filename);
|
|
+
|
|
+ // load firmware directly without usermode helper for the relevant file
|
|
+ err = request_firmware_direct(&firmware, filename, board->vdma.dev);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Failed to allocate memory for file %s\n", filename);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ // set the remaining size as the whole file size to begin with
|
|
+ remaining_size = firmware->size;
|
|
+
|
|
+ while (remaining_size > 0) {
|
|
+ struct hailo_pcie_boot_dma_channel_state *channel = &boot_dma_state->channels[boot_dma_state->curr_channel_index];
|
|
+ bool is_last_desc_chunk_of_curr_channel = false;
|
|
+ bool rais_interrupt_on_last_chunk = false;
|
|
+
|
|
+ hailo_dbg(board, "desc_program_num = 0x%x, desc_page_size = 0x%x, on channel = %d\n",
|
|
+ channel->desc_program_num, HAILO_PCI_OVER_VDMA_PAGE_SIZE, boot_dma_state->curr_channel_index);
|
|
+
|
|
+ // increment the channel index if the current channel is full
|
|
+ if ((MAX_SG_DESCS_COUNT - 1) == channel->desc_program_num) {
|
|
+ boot_dma_state->curr_channel_index++;
|
|
+ channel = &boot_dma_state->channels[boot_dma_state->curr_channel_index];
|
|
+ board->fw_boot.boot_used_channel_bitmap |= (1 << boot_dma_state->curr_channel_index);
|
|
+ }
|
|
+
|
|
+ // calculate the number of descriptors left to program and the number of bytes left to program
|
|
+ desc_num_left = (MAX_SG_DESCS_COUNT - 1) - channel->desc_program_num;
|
|
+
|
|
+ // prepare the transfer buffer to make sure all the fields are initialized
|
|
+ transfer_buffer.sg_table = &channel->sg_table;
|
|
+ transfer_buffer.size = min(remaining_size, (desc_num_left * HAILO_PCI_OVER_VDMA_PAGE_SIZE));
|
|
+ // no need to check for overflow since the variables are constant and always desc_program_num <= max u16 (65536)
|
|
+ // & the buffer max size is 256 Mb << 4G (max u32)
|
|
+ transfer_buffer.offset = (channel->desc_program_num * HAILO_PCI_OVER_VDMA_PAGE_SIZE);
|
|
+
|
|
+ // check if this is the last descriptor chunk to program in the whole boot flow
|
|
+ current_desc_to_program = (transfer_buffer.size / HAILO_PCI_OVER_VDMA_PAGE_SIZE);
|
|
+ is_last_desc_chunk_of_curr_channel = ((MAX_SG_DESCS_COUNT - 1) ==
|
|
+ (current_desc_to_program + channel->desc_program_num));
|
|
+ rais_interrupt_on_last_chunk = (is_last_desc_chunk_of_curr_channel || (raise_int_on_completion &&
|
|
+ (remaining_size == transfer_buffer.size)));
|
|
+
|
|
+ // try to copy the file to the buffer, if failed, release the firmware and return
|
|
+ bytes_copied = sg_pcopy_from_buffer(transfer_buffer.sg_table->sgl, transfer_buffer.sg_table->orig_nents,
|
|
+ &firmware->data[data_offset], transfer_buffer.size, transfer_buffer.offset);
|
|
+ if (transfer_buffer.size != bytes_copied) {
|
|
+ hailo_err(board, "There is not enough memory allocated to copy file %s\n", filename);
|
|
+ release_firmware(firmware);
|
|
+ return -EFBIG;
|
|
+ }
|
|
+
|
|
+ // program the descriptors
|
|
+ desc_programmed = pcie_vdma_program_one_file_descriptors(&board->pDev->dev, channel, (file_address + data_offset),
|
|
+ transfer_buffer, boot_dma_state->curr_channel_index, filename, rais_interrupt_on_last_chunk);
|
|
+ if (desc_programmed < 0) {
|
|
+ hailo_err(board, "Failed to program descriptors for file %s, on cahnnel = %d\n", filename,
|
|
+ boot_dma_state->curr_channel_index);
|
|
+ release_firmware(firmware);
|
|
+ return desc_programmed;
|
|
+ }
|
|
+
|
|
+ // Update remaining size, data_offset and desc_program_num for the next iteration
|
|
+ remaining_size -= transfer_buffer.size;
|
|
+ data_offset += transfer_buffer.size;
|
|
+ channel->desc_program_num += desc_programmed;
|
|
+ }
|
|
+
|
|
+ hailo_notice(board, "File %s programed successfully\n", filename);
|
|
+
|
|
+ release_firmware(firmware);
|
|
+
|
|
+ return desc_programmed;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Program the entire batch of firmware files to the vDMA engine.
|
|
+ *
|
|
+ * @param board - pointer to the board struct we are working on.
|
|
+ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources.
|
|
+ * @param resources - pointer to the hailo_pcie_resources struct.
|
|
+ * @param stage - the stage to program.
|
|
+ * @return 0 on success, negative error code on failure.
|
|
+ */
|
|
+static long pcie_vdma_program_entire_batch(struct hailo_pcie_board *board, struct hailo_pcie_boot_dma_state *boot_dma_state,
|
|
+ struct hailo_pcie_resources *resources, u32 stage)
|
|
+{
|
|
+ long err = 0;
|
|
+ int file_index = 0;
|
|
+ const struct hailo_pcie_loading_stage *stage_info = hailo_pcie_get_loading_stage_info(resources->board_type, stage);
|
|
+ const struct hailo_file_batch *files_batch = stage_info->batch;
|
|
+ const u8 amount_of_files = stage_info->amount_of_files_in_stage;
|
|
+ const char *filename = NULL;
|
|
+ u32 file_address = 0;
|
|
+
|
|
+ for (file_index = 0; file_index < amount_of_files; file_index++)
|
|
+ {
|
|
+ filename = files_batch[file_index].filename;
|
|
+ file_address = files_batch[file_index].address;
|
|
+
|
|
+ if (NULL == filename) {
|
|
+ hailo_err(board, "The amount of files wasn't specified for stage %d\n", stage);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ err = pcie_vdma_program_one_file(board, boot_dma_state, file_address, filename,
|
|
+ (file_index == (amount_of_files - 1)));
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Failed to program file %s\n", filename);
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Release noncontinuous memory (virtual continuous memory). (sg table and kernel_addrs)
|
|
+ *
|
|
+ * @param dev - pointer to the device struct we are working on.
|
|
+ * @param sg_table - the sg table to release.
|
|
+ * @param kernel_addrs - the kernel address to release.
|
|
+ */
|
|
+static void pcie_vdma_release_noncontinuous_memory(struct device *dev, struct sg_table *sg_table, void *kernel_addrs)
|
|
+{
|
|
+ dma_unmap_sg(dev, sg_table->sgl, sg_table->orig_nents, DMA_TO_DEVICE);
|
|
+ sg_free_table(sg_table);
|
|
+ vfree(kernel_addrs);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Allocate noncontinuous memory (virtual continuous memory).
|
|
+ *
|
|
+ * @param dev - pointer to the device struct we are working on.
|
|
+ * @param buffer_size - the size of the buffer to allocate.
|
|
+ * @param kernel_addrs - pointer to the allocated buffer.
|
|
+ * @param sg_table - pointer to the sg table struct.
|
|
+ * @return 0 on success, negative error code on failure. on failure all resurces are released. (pages array, sg table, kernel_addrs)
|
|
+ */
|
|
+static long pcie_vdma_allocate_noncontinuous_memory(struct device *dev, u64 buffer_size, void **kernel_addrs, struct sg_table *sg_table)
|
|
+{
|
|
+ struct page **pages = NULL;
|
|
+ size_t npages = 0;
|
|
+ struct scatterlist *sgl = NULL;
|
|
+ long err = 0;
|
|
+ size_t i = 0;
|
|
+
|
|
+ // allocate noncontinuous memory for the kernel address (virtual continuous memory)
|
|
+ *kernel_addrs = vmalloc(buffer_size);
|
|
+ if (NULL == *kernel_addrs) {
|
|
+ hailo_dev_err(dev, "Failed to allocate memory for kernel_addrs\n");
|
|
+ err = -ENOMEM;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ // map the memory to pages
|
|
+ npages = DIV_ROUND_UP(buffer_size, PAGE_SIZE);
|
|
+
|
|
+ // allocate memory for a virtually contiguous array for the pages
|
|
+ pages = kvmalloc_array(npages, sizeof(*pages), GFP_KERNEL);
|
|
+ if (!pages) {
|
|
+ err = -ENOMEM;
|
|
+ hailo_dev_err(dev, "Failed to allocate memory for pages\n");
|
|
+ goto release_user_addrs;
|
|
+ }
|
|
+
|
|
+ // walk a vmap address to the struct page it maps
|
|
+ for (i = 0; i < npages; i++) {
|
|
+ pages[i] = vmalloc_to_page(*kernel_addrs + (i * PAGE_SIZE));
|
|
+ if (!pages[i]) {
|
|
+ err = -ENOMEM;
|
|
+ hailo_dev_err(dev, "Failed to get page from vmap address\n");
|
|
+ goto release_array;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // allocate and initialize the sg table from a list of pages
|
|
+ sgl = sg_alloc_table_from_pages_segment_compat(sg_table, pages, npages, 0, buffer_size, SGL_MAX_SEGMENT_SIZE, NULL,
|
|
+ 0, GFP_KERNEL);
|
|
+ if (IS_ERR(sgl)) {
|
|
+ err = PTR_ERR(sgl);
|
|
+ hailo_dev_err(dev, "sg table alloc failed (err %ld)..\n", err);
|
|
+ goto release_array;
|
|
+ }
|
|
+
|
|
+ // map the sg list
|
|
+ sg_table->nents = dma_map_sg(dev, sg_table->sgl, sg_table->orig_nents, DMA_TO_DEVICE);
|
|
+ if (0 == sg_table->nents) {
|
|
+ hailo_dev_err(dev, "failed to map sg list for user buffer\n");
|
|
+ err = -ENXIO;
|
|
+ goto release_sg_table;
|
|
+ }
|
|
+
|
|
+ // clean exit - just release the pages array & return err = 0
|
|
+ err = 0;
|
|
+ kfree(pages);
|
|
+ goto exit;
|
|
+
|
|
+release_sg_table:
|
|
+ dma_unmap_sg(dev, sg_table->sgl, sg_table->orig_nents, DMA_TO_DEVICE);
|
|
+release_array:
|
|
+ kfree(pages);
|
|
+release_user_addrs:
|
|
+ vfree(*kernel_addrs);
|
|
+exit:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Release all boot resources.
|
|
+ *
|
|
+ * @param board - pointer to the board struct we are working on.
|
|
+ * @param engine - pointer to the vdma engine struct.
|
|
+ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources.
|
|
+ */
|
|
+static void pcie_vdme_release_boot_resources(struct hailo_pcie_board *board, struct hailo_vdma_engine *engine,
|
|
+ struct hailo_pcie_boot_dma_state *boot_dma_state)
|
|
+{
|
|
+ u8 channel_index = 0;
|
|
+
|
|
+ // release all the resources
|
|
+ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) {
|
|
+ struct hailo_pcie_boot_dma_channel_state *channel = &boot_dma_state->channels[channel_index];
|
|
+ // release descriptor lists
|
|
+ if (channel->host_descriptors_buffer.kernel_address != NULL) {
|
|
+ hailo_desc_list_release(&board->pDev->dev, &channel->host_descriptors_buffer);
|
|
+ }
|
|
+ if (channel->device_descriptors_buffer.kernel_address != NULL) {
|
|
+ hailo_desc_list_release(&board->pDev->dev, &channel->device_descriptors_buffer);
|
|
+ }
|
|
+
|
|
+ // stops all boot vDMA channels
|
|
+ hailo_vdma_stop_channel(engine->channels[channel_index].host_regs);
|
|
+ hailo_vdma_stop_channel(engine->channels[channel_index].device_regs);
|
|
+
|
|
+ // release noncontinuous memory (virtual continuous memory)
|
|
+ if (channel->kernel_addrs != NULL) {
|
|
+ pcie_vdma_release_noncontinuous_memory(&board->pDev->dev, &channel->sg_table, channel->kernel_addrs);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Allocate boot resources for vDMA transfer.
|
|
+ *
|
|
+ * @param desc_page_size - the size of the descriptor page.
|
|
+ * @param board - pointer to the board struct we are working on.
|
|
+ * @param boot_dma_state - pointer to the boot dma state struct which includes all of the boot resources.
|
|
+ * @param engine - pointer to the vDMA engine struct.
|
|
+ * @return 0 on success, negative error code on failure. in case of failure descriptor lists are released,
|
|
+ * boot vDMA channels are stopped and memory is released.
|
|
+ */
|
|
+static long pcie_vdme_allocate_boot_resources(u32 desc_page_size, struct hailo_pcie_board *board,
|
|
+ struct hailo_pcie_boot_dma_state *boot_dma_state, struct hailo_vdma_engine *engine)
|
|
+{
|
|
+ long err = 0;
|
|
+ uintptr_t device_handle = 0, host_handle = 0;
|
|
+ u8 channel_index = 0;
|
|
+
|
|
+ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) {
|
|
+ struct hailo_pcie_boot_dma_channel_state *channel = &boot_dma_state->channels[channel_index];
|
|
+
|
|
+ // create 2 descriptors list - 1 for the host & 1 for the device for each channel
|
|
+ err = hailo_desc_list_create(&board->pDev->dev, MAX_SG_DESCS_COUNT, desc_page_size, host_handle, false,
|
|
+ &channel->host_descriptors_buffer);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "failed to allocate host descriptors list buffer\n");
|
|
+ goto release_all_resources;
|
|
+ }
|
|
+
|
|
+ err = hailo_desc_list_create(&board->pDev->dev, MAX_SG_DESCS_COUNT, desc_page_size, device_handle, false,
|
|
+ &channel->device_descriptors_buffer);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "failed to allocate device descriptors list buffer\n");
|
|
+ goto release_all_resources;
|
|
+ }
|
|
+
|
|
+ // start vDMA channels - both sides with DDR at the host side (AKA ID 0)
|
|
+ err = hailo_vdma_start_channel(engine->channels[channel_index].host_regs,
|
|
+ channel->host_descriptors_buffer.dma_address,
|
|
+ channel->host_descriptors_buffer.desc_list.desc_count, board->vdma.hw->ddr_data_id);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Error starting host vdma channel\n");
|
|
+ goto release_all_resources;
|
|
+ }
|
|
+
|
|
+ err = hailo_vdma_start_channel(engine->channels[channel_index].device_regs,
|
|
+ channel->device_descriptors_buffer.dma_address,
|
|
+ channel->device_descriptors_buffer.desc_list.desc_count, board->vdma.hw->ddr_data_id);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Error starting device vdma channel\n");
|
|
+ goto release_all_resources;
|
|
+ }
|
|
+
|
|
+ // initialize the buffer size per channel
|
|
+ channel->buffer_size = (MAX_SG_DESCS_COUNT * desc_page_size);
|
|
+
|
|
+ // allocate noncontinuous memory (virtual continuous memory)
|
|
+ err = pcie_vdma_allocate_noncontinuous_memory(&board->pDev->dev, channel->buffer_size, &channel->kernel_addrs,
|
|
+ &channel->sg_table);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Failed to allocate noncontinuous memory\n");
|
|
+ goto release_all_resources;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+release_all_resources:
|
|
+ pcie_vdme_release_boot_resources(board, engine, boot_dma_state);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Write FW boot files over vDMA using multiple channels for timing optimizations.
|
|
+ *
|
|
+ * The function is divided into the following steps:
|
|
+ * 1) Allocate resources for the boot process.
|
|
+ * 2) Programs descriptors to point to the memory and start the vDMA.
|
|
+ * 3) Waits until the vDMA is done and triggers the device to start the boot process.
|
|
+ * 4) Releases all the resources.
|
|
+ *
|
|
+ * @param board - pointer to the board struct.
|
|
+ * @param stage - the stage of the boot process.
|
|
+ * @param desc_page_size - the size of the descriptor page.
|
|
+ * @return 0 on success, negative error code on failure. in any case all resurces are released.
|
|
+ */
|
|
+static long pcie_write_firmware_batch_over_dma(struct hailo_pcie_board *board, u32 stage, u32 desc_page_size)
|
|
{
|
|
- return (0 != wait_for_completion_timeout(fw_load_completion, msecs_to_jiffies(FIRMWARE_WAIT_TIMEOUT_MS)));
|
|
+ long err = 0;
|
|
+ struct hailo_vdma_engine *engine = &board->vdma.vdma_engines[PCI_VDMA_ENGINE_INDEX];
|
|
+ u8 channel_index = 0;
|
|
+
|
|
+ err = pcie_vdme_allocate_boot_resources(desc_page_size, board, &board->fw_boot.boot_dma_state, engine);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Failed to create descriptors and start channels\n");
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ // initialize the completion for the vDMA boot data completion
|
|
+ reinit_completion(&board->fw_boot.vdma_boot_completion);
|
|
+
|
|
+ err = pcie_vdma_program_entire_batch(board, &board->fw_boot.boot_dma_state, &board->pcie_resources, stage);
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Failed to program entire batch\n");
|
|
+ goto release_all;
|
|
+ }
|
|
+
|
|
+ // sync the sg tables for the device before statirng the vDMA
|
|
+ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) {
|
|
+ dma_sync_sgtable_for_device(&board->pDev->dev, &board->fw_boot.boot_dma_state.channels[channel_index].sg_table,
|
|
+ DMA_TO_DEVICE);
|
|
+ }
|
|
+
|
|
+ // start the vDMA transfer on all channels
|
|
+ for (channel_index = 0; channel_index < HAILO_PCI_OVER_VDMA_NUM_CHANNELS; channel_index++) {
|
|
+ struct hailo_pcie_boot_dma_channel_state *channel = &board->fw_boot.boot_dma_state.channels[channel_index];
|
|
+ if (channel->desc_program_num != 0) {
|
|
+ hailo_vdma_set_num_avail(engine->channels[channel_index].host_regs, channel->desc_program_num);
|
|
+ hailo_vdma_set_num_avail(engine->channels[channel_index].device_regs, channel->desc_program_num);
|
|
+ hailo_dbg(board, "Set num avail to %u, on channel %u\n", channel->desc_program_num, channel_index);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!wait_for_firmware_completion(&board->fw_boot.vdma_boot_completion, hailo_pcie_get_loading_stage_info(board->pcie_resources.board_type, SECOND_STAGE)->timeout)) {
|
|
+ hailo_err(board, "Timeout waiting for vDMA boot data completion\n");
|
|
+ err = -ETIMEDOUT;
|
|
+ goto release_all;
|
|
+ }
|
|
+
|
|
+ hailo_notice(board, "vDMA transfer completed, triggering boot\n");
|
|
+ reinit_completion(&board->fw_boot.fw_loaded_completion);
|
|
+ hailo_trigger_firmware_boot(&board->pcie_resources, stage);
|
|
+
|
|
+release_all:
|
|
+ pcie_vdme_release_boot_resources(board, engine, &board->fw_boot.boot_dma_state);
|
|
+ return err;
|
|
}
|
|
|
|
-static int hailo_load_soc_firmware(struct hailo_pcie_resources *resources,
|
|
+static int load_soc_firmware(struct hailo_pcie_board *board, struct hailo_pcie_resources *resources,
|
|
struct device *dev, struct completion *fw_load_completion)
|
|
{
|
|
u32 boot_status = 0;
|
|
@@ -304,104 +763,165 @@ static int hailo_load_soc_firmware(struc
|
|
u32 second_stage = force_boot_linux_from_eemc ? SECOND_STAGE_LINUX_IN_EMMC : SECOND_STAGE;
|
|
|
|
if (hailo_pcie_is_firmware_loaded(resources)) {
|
|
- hailo_dev_warn(dev, "Firmware batch was already loaded\n");
|
|
+ hailo_dev_warn(dev, "SOC Firmware batch was already loaded\n");
|
|
return 0;
|
|
}
|
|
|
|
+ // configure the EP registers for the DMA transaction
|
|
+ hailo_pcie_configure_ep_registers_for_dma_transaction(resources);
|
|
+
|
|
init_completion(fw_load_completion);
|
|
+ init_completion(&board->fw_boot.vdma_boot_completion);
|
|
|
|
err = hailo_pcie_write_firmware_batch(dev, resources, FIRST_STAGE);
|
|
if (err < 0) {
|
|
- hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err);
|
|
+ hailo_dev_err(dev, "Failed writing SOC FIRST_STAGE firmware files. err %d\n", err);
|
|
return err;
|
|
}
|
|
|
|
- if (!wait_for_firmware_completion(fw_load_completion)) {
|
|
+ if (!wait_for_firmware_completion(fw_load_completion, hailo_pcie_get_loading_stage_info(resources->board_type, FIRST_STAGE)->timeout)) {
|
|
boot_status = hailo_get_boot_status(resources);
|
|
- hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status);
|
|
+ hailo_dev_err(dev, "Timeout waiting for SOC FIRST_STAGE firmware file, boot status %u\n", boot_status);
|
|
return -ETIMEDOUT;
|
|
}
|
|
+
|
|
reinit_completion(fw_load_completion);
|
|
|
|
- err = hailo_pcie_write_firmware_batch(dev, resources, second_stage);
|
|
+ err = (int)pcie_write_firmware_batch_over_dma(board, second_stage, HAILO_PCI_OVER_VDMA_PAGE_SIZE);
|
|
if (err < 0) {
|
|
- hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err);
|
|
+ hailo_dev_err(dev, "Failed writing SOC SECOND_STAGE firmware files over vDMA. err %d\n", err);
|
|
return err;
|
|
}
|
|
|
|
- if (!wait_for_firmware_completion(fw_load_completion)) {
|
|
+ if (!wait_for_firmware_completion(fw_load_completion, hailo_pcie_get_loading_stage_info(resources->board_type, SECOND_STAGE)->timeout)) {
|
|
boot_status = hailo_get_boot_status(resources);
|
|
- hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status);
|
|
+ hailo_dev_err(dev, "Timeout waiting for SOC SECOND_STAGE firmware file, boot status %u\n", boot_status);
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
- hailo_dev_notice(dev, "Firmware Batch loaded successfully\n");
|
|
+ reinit_completion(fw_load_completion);
|
|
+ reinit_completion(&board->fw_boot.vdma_boot_completion);
|
|
+
|
|
+ hailo_dev_notice(dev, "SOC Firmware Batch loaded successfully\n");
|
|
|
|
return 0;
|
|
}
|
|
-
|
|
-static int hailo_load_nnc_firmware(struct hailo_pcie_resources *resources,
|
|
- struct device *dev, struct completion *fw_load_completion)
|
|
+static int load_nnc_firmware(struct hailo_pcie_board *board)
|
|
{
|
|
u32 boot_status = 0;
|
|
int err = 0;
|
|
+ struct device *dev = &board->pDev->dev;
|
|
|
|
- if (hailo_pcie_is_firmware_loaded(resources)) {
|
|
- hailo_dev_warn(dev, "Firmware batch was already loaded\n");
|
|
- return 0;
|
|
+ if (hailo_pcie_is_firmware_loaded(&board->pcie_resources)) {
|
|
+ if (support_soft_reset) {
|
|
+ err = hailo_pcie_soft_reset(&board->pcie_resources, &board->soft_reset.reset_completed); // send control, wait for done
|
|
+ if (err < 0) {
|
|
+ hailo_dev_err(dev, "Failed hailo pcie soft reset. err %d\n", err);
|
|
+ return 0;
|
|
+ }
|
|
+ hailo_dev_notice(dev, "Soft reset done\n");
|
|
+ } else {
|
|
+ hailo_dev_warn(dev, "NNC Firmware batch was already loaded\n");
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
|
|
- init_completion(fw_load_completion);
|
|
+ init_completion(&board->fw_boot.fw_loaded_completion);
|
|
|
|
- err = hailo_pcie_write_firmware_batch(dev, resources, FIRST_STAGE);
|
|
+ err = hailo_pcie_write_firmware_batch(dev, &board->pcie_resources, FIRST_STAGE);
|
|
if (err < 0) {
|
|
- hailo_dev_err(dev, "Failed writing firmware files. err %d\n", err);
|
|
+ hailo_dev_err(dev, "Failed writing NNC firmware files. err %d\n", err);
|
|
return err;
|
|
}
|
|
|
|
- if (!wait_for_firmware_completion(fw_load_completion)) {
|
|
- boot_status = hailo_get_boot_status(resources);
|
|
- hailo_dev_err(dev, "Timeout waiting for firmware file, boot status %u\n", boot_status);
|
|
+ if (!wait_for_firmware_completion(&board->fw_boot.fw_loaded_completion, hailo_pcie_get_loading_stage_info(board->pcie_resources.board_type, FIRST_STAGE)->timeout)) {
|
|
+ boot_status = hailo_get_boot_status(&board->pcie_resources);
|
|
+ hailo_dev_err(dev, "Timeout waiting for NNC firmware file, boot status %u\n", boot_status);
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
- hailo_dev_notice(dev, "Firmware loaded successfully\n");
|
|
+ hailo_dev_notice(dev, "NNC Firmware loaded successfully\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static int hailo_activate_board(struct hailo_pcie_board *board)
|
|
+int hailo_pcie_soft_reset(struct hailo_pcie_resources *resources, struct completion *reset_completed)
|
|
{
|
|
+ bool completion_result = false;
|
|
int err = 0;
|
|
|
|
- (void)hailo_pcie_disable_aspm(board, PCIE_LINK_STATE_L0S, false);
|
|
+ hailo_pcie_write_firmware_soft_reset(resources);
|
|
|
|
- err = hailo_enable_interrupts(board);
|
|
- if (err < 0) {
|
|
- hailo_err(board, "Failed Enabling interrupts %d\n", err);
|
|
+ reinit_completion(reset_completed);
|
|
+
|
|
+ // Wait for response
|
|
+ completion_result =
|
|
+ wait_for_firmware_completion(reset_completed, msecs_to_jiffies(FIRMWARE_WAIT_TIMEOUT_MS));
|
|
+ if (completion_result == false) {
|
|
+ pr_warn("hailo reset firmware, timeout waiting for shutdown response (timeout_ms=%d)\n", FIRMWARE_WAIT_TIMEOUT_MS);
|
|
+ err = -ETIMEDOUT;
|
|
return err;
|
|
}
|
|
|
|
+ msleep(TIME_UNTIL_REACH_BOOTLOADER);
|
|
+ pr_notice("hailo_driver_down finished\n");
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int load_firmware(struct hailo_pcie_board *board)
|
|
+{
|
|
switch (board->pcie_resources.accelerator_type) {
|
|
case HAILO_ACCELERATOR_TYPE_SOC:
|
|
- err = hailo_load_soc_firmware(&board->pcie_resources, &board->pDev->dev,
|
|
- &board->fw_loaded_completion);
|
|
- break;
|
|
+ return load_soc_firmware(board, &board->pcie_resources, &board->pDev->dev, &board->fw_boot.fw_loaded_completion);
|
|
case HAILO_ACCELERATOR_TYPE_NNC:
|
|
- err = hailo_load_nnc_firmware(&board->pcie_resources, &board->pDev->dev,
|
|
- &board->fw_loaded_completion);
|
|
- break;
|
|
+ return load_nnc_firmware(board);
|
|
default:
|
|
- hailo_err(board, "Invalid board type");
|
|
- err = -EINVAL;
|
|
+ hailo_err(board, "Invalid board type %d\n", board->pcie_resources.accelerator_type);
|
|
+ return -EINVAL;
|
|
}
|
|
+}
|
|
+
|
|
+static int enable_boot_interrupts(struct hailo_pcie_board *board)
|
|
+{
|
|
+ int err = hailo_enable_interrupts(board);
|
|
if (err < 0) {
|
|
- hailo_err(board, "Firmware load failed\n");
|
|
- hailo_disable_interrupts(board);
|
|
+ hailo_err(board, "Failed enabling interrupts %d\n", err);
|
|
return err;
|
|
}
|
|
|
|
+ board->fw_boot.is_in_boot = true;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void disable_boot_interrupts(struct hailo_pcie_board *board)
|
|
+{
|
|
+ board->fw_boot.is_in_boot = false;
|
|
hailo_disable_interrupts(board);
|
|
+}
|
|
+
|
|
+static int hailo_activate_board(struct hailo_pcie_board *board)
|
|
+{
|
|
+ int err = 0;
|
|
+ ktime_t start_time = 0, end_time = 0;
|
|
+
|
|
+ (void)hailo_pcie_disable_aspm(board, PCIE_LINK_STATE_L0S, false);
|
|
+
|
|
+ err = enable_boot_interrupts(board);
|
|
+ if (err < 0) {
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ start_time = ktime_get();
|
|
+ err = load_firmware(board);
|
|
+ end_time = ktime_get();
|
|
+ hailo_notice(board, "FW loaded, took %lld ms\n", ktime_to_ms(ktime_sub(end_time, start_time)));
|
|
+ disable_boot_interrupts(board);
|
|
+
|
|
+ if (err < 0) {
|
|
+ hailo_err(board, "Firmware load failed\n");
|
|
+ return err;
|
|
+ }
|
|
|
|
if (power_mode_enabled()) {
|
|
// Setting the device to low power state, until the user opens the device
|
|
@@ -520,12 +1040,9 @@ static int pcie_resources_init(struct pc
|
|
}
|
|
|
|
|
|
- // There is no HAILO15 as mercury through pcie unless it's legacy mode (H15 as accelerator) or HAILO-10H
|
|
- if (HAILO_BOARD_TYPE_HAILO15 == board_type){
|
|
- if (true == force_hailo15_legacy_mode) {
|
|
+ if (HAILO_BOARD_TYPE_HAILO10H == board_type){
|
|
+ if (true == force_hailo10h_legacy_mode) {
|
|
board_type = HAILO_BOARD_TYPE_HAILO10H_LEGACY;
|
|
- } else {
|
|
- board_type = HAILO_BOARD_TYPE_HAILO10H;
|
|
}
|
|
}
|
|
|
|
@@ -696,7 +1213,8 @@ static int hailo_pcie_probe(struct pci_d
|
|
}
|
|
|
|
pBoard->interrupts_enabled = false;
|
|
- init_completion(&pBoard->fw_loaded_completion);
|
|
+ pBoard->fw_boot.is_in_boot = false;
|
|
+ init_completion(&pBoard->fw_boot.fw_loaded_completion);
|
|
|
|
sema_init(&pBoard->mutex, 1);
|
|
atomic_set(&pBoard->ref_count, 0);
|
|
@@ -707,6 +1225,7 @@ static int hailo_pcie_probe(struct pci_d
|
|
hailo_soc_init(&pBoard->soc);
|
|
|
|
init_completion(&pBoard->driver_down.reset_completed);
|
|
+ init_completion(&pBoard->soft_reset.reset_completed);
|
|
|
|
memset(&pBoard->memory_transfer_params, 0, sizeof(pBoard->memory_transfer_params));
|
|
|
|
@@ -724,6 +1243,10 @@ static int hailo_pcie_probe(struct pci_d
|
|
goto probe_release_pcie_resources;
|
|
}
|
|
|
|
+ // Initialize the boot channel bitmap to 1 since channel 0 is always used for boot
|
|
+ // (we will always use at least 1 channel which is LSB in the bitmap)
|
|
+ pBoard->fw_boot.boot_used_channel_bitmap = (1 << 0);
|
|
+ memset(&pBoard->fw_boot.boot_dma_state, 0, sizeof(pBoard->fw_boot.boot_dma_state));
|
|
err = hailo_activate_board(pBoard);
|
|
if (err < 0) {
|
|
hailo_err(pBoard, "Failed activating board %d\n", err);
|
|
@@ -927,8 +1450,8 @@ static const struct pci_error_handlers h
|
|
static struct pci_device_id hailo_pcie_id_table[] =
|
|
{
|
|
{PCI_DEVICE_DATA(HAILO, HAILO8, HAILO_BOARD_TYPE_HAILO8)},
|
|
- {PCI_DEVICE_DATA(HAILO, HAILO15, HAILO_BOARD_TYPE_HAILO15)},
|
|
- {PCI_DEVICE_DATA(HAILO, PLUTO, HAILO_BOARD_TYPE_PLUTO)},
|
|
+ {PCI_DEVICE_DATA(HAILO, HAILO10H, HAILO_BOARD_TYPE_HAILO10H)},
|
|
+ {PCI_DEVICE_DATA(HAILO, HAILO15L, HAILO_BOARD_TYPE_HAILO15L)},
|
|
{0,0,0,0,0,0,0 },
|
|
};
|
|
|
|
@@ -1024,12 +1547,15 @@ MODULE_PARM_DESC(force_allocation_from_d
|
|
module_param(force_desc_page_size, int, S_IRUGO);
|
|
MODULE_PARM_DESC(force_desc_page_size, "Determines the maximum DMA descriptor page size (must be a power of 2)");
|
|
|
|
-module_param(force_hailo15_legacy_mode, bool, S_IRUGO);
|
|
-MODULE_PARM_DESC(force_hailo15_legacy_mode, "Forces work with Hailo15 in legacy mode(relevant for emulators)");
|
|
+module_param(force_hailo10h_legacy_mode, bool, S_IRUGO);
|
|
+MODULE_PARM_DESC(force_hailo10h_legacy_mode, "Forces work with Hailo10h in legacy mode(relevant for emulators)");
|
|
|
|
module_param(force_boot_linux_from_eemc, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(force_boot_linux_from_eemc, "Boot the linux image from eemc (Requires special Image)");
|
|
|
|
+module_param(support_soft_reset, bool, S_IRUGO);
|
|
+MODULE_PARM_DESC(support_soft_reset, "enables driver reload to reload a new firmware as well");
|
|
+
|
|
MODULE_AUTHOR("Hailo Technologies Ltd.");
|
|
MODULE_DESCRIPTION("Hailo PCIe driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
--- a/drivers/media/pci/hailo/src/pcie.h
|
|
+++ b/drivers/media/pci/hailo/src/pcie.h
|
|
@@ -19,6 +19,9 @@
|
|
|
|
#include <linux/ioctl.h>
|
|
|
|
+#define HAILO_PCI_OVER_VDMA_NUM_CHANNELS (8)
|
|
+#define HAILO_PCI_OVER_VDMA_PAGE_SIZE (512)
|
|
+
|
|
struct hailo_fw_control_info {
|
|
// protects that only one fw control will be send at a time
|
|
struct semaphore mutex;
|
|
@@ -33,6 +36,11 @@ struct hailo_pcie_driver_down_info {
|
|
struct completion reset_completed;
|
|
};
|
|
|
|
+struct hailo_pcie_soft_reset {
|
|
+ // called from the interrupt handler to notify that FW completed reset
|
|
+ struct completion reset_completed;
|
|
+};
|
|
+
|
|
struct hailo_fw_boot {
|
|
// the filp that enabled interrupts for fw boot. the interrupt is enabled if this is not null
|
|
struct file *filp;
|
|
@@ -64,6 +72,32 @@ struct hailo_file_context {
|
|
u32 soc_used_channels_bitmap;
|
|
};
|
|
|
|
+struct hailo_pcie_boot_dma_channel_state {
|
|
+ struct hailo_descriptors_list_buffer host_descriptors_buffer;
|
|
+ struct hailo_descriptors_list_buffer device_descriptors_buffer;
|
|
+ struct sg_table sg_table;
|
|
+ u64 buffer_size;
|
|
+ void *kernel_addrs;
|
|
+ u32 desc_program_num;
|
|
+};
|
|
+
|
|
+struct hailo_pcie_boot_dma_state {
|
|
+ struct hailo_pcie_boot_dma_channel_state channels[HAILO_PCI_OVER_VDMA_NUM_CHANNELS];
|
|
+ u8 curr_channel_index;
|
|
+};
|
|
+
|
|
+struct hailo_pcie_fw_boot {
|
|
+ struct hailo_pcie_boot_dma_state boot_dma_state;
|
|
+ // is_in_boot is set to true when the board is in boot mode
|
|
+ bool is_in_boot;
|
|
+ // boot_used_channel_bitmap is a bitmap of the channels that are used for boot
|
|
+ u16 boot_used_channel_bitmap;
|
|
+ // fw_loaded_completion is used to notify that the FW was loaded - SOC & NNC
|
|
+ struct completion fw_loaded_completion;
|
|
+ // vdma_boot_completion is used to notify that the vDMA boot data was transferred completely on all used channels for boot
|
|
+ struct completion vdma_boot_completion;
|
|
+};
|
|
+
|
|
struct hailo_pcie_board {
|
|
struct list_head board_list;
|
|
struct pci_dev *pDev;
|
|
@@ -74,13 +108,15 @@ struct hailo_pcie_board {
|
|
struct hailo_pcie_nnc nnc;
|
|
struct hailo_pcie_soc soc;
|
|
struct hailo_pcie_driver_down_info driver_down;
|
|
+ struct hailo_pcie_soft_reset soft_reset;
|
|
struct semaphore mutex;
|
|
struct hailo_vdma_controller vdma;
|
|
|
|
+ struct hailo_pcie_fw_boot fw_boot;
|
|
+
|
|
struct hailo_memory_transfer_params memory_transfer_params;
|
|
u32 desc_max_page_size;
|
|
enum hailo_allocation_mode allocation_mode;
|
|
- struct completion fw_loaded_completion;
|
|
bool interrupts_enabled;
|
|
};
|
|
|
|
@@ -89,6 +125,7 @@ bool power_mode_enabled(void);
|
|
struct hailo_pcie_board* hailo_pcie_get_board_index(u32 index);
|
|
void hailo_disable_interrupts(struct hailo_pcie_board *board);
|
|
int hailo_enable_interrupts(struct hailo_pcie_board *board);
|
|
+int hailo_pcie_soft_reset(struct hailo_pcie_resources *resources, struct completion *reset_completed);
|
|
|
|
#endif /* _HAILO_PCI_PCIE_H_ */
|
|
|
|
--- a/drivers/media/pci/hailo/src/soc.c
|
|
+++ b/drivers/media/pci/hailo/src/soc.c
|
|
@@ -12,12 +12,15 @@
|
|
#include "vdma_common.h"
|
|
#include "utils/logs.h"
|
|
#include "vdma/memory.h"
|
|
+#include "pcie_common.h"
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
-#define PCI_SOC_VDMA_ENGINE_INDEX (0)
|
|
+#ifndef HAILO_EMULATOR
|
|
#define PCI_SOC_CONTROL_CONNECT_TIMEOUT_MS (1000)
|
|
-#define PCI_SOC_INPUT_CHANNEL_BITMASK (0x000000FF)
|
|
+#else
|
|
+#define PCI_SOC_CONTROL_CONNECT_TIMEOUT_MS (1000000)
|
|
+#endif /* ifndef HAILO_EMULATOR */
|
|
|
|
void hailo_soc_init(struct hailo_pcie_soc *soc)
|
|
{
|
|
@@ -84,10 +87,9 @@ long hailo_soc_connect_ioctl(struct hail
|
|
struct hailo_soc_connect_params params;
|
|
struct hailo_vdma_channel *input_channel = NULL;
|
|
struct hailo_vdma_channel *output_channel = NULL;
|
|
- struct hailo_vdma_engine *vdma_engine = &controller->vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX];
|
|
+ struct hailo_vdma_engine *vdma_engine = &controller->vdma_engines[PCI_VDMA_ENGINE_INDEX];
|
|
struct hailo_descriptors_list_buffer *input_descriptors_buffer = NULL;
|
|
struct hailo_descriptors_list_buffer *output_descriptors_buffer = NULL;
|
|
- uint8_t depth = 0;
|
|
int err = 0;
|
|
|
|
if (copy_from_user(¶ms, (void *)arg, sizeof(params))) {
|
|
@@ -136,9 +138,8 @@ long hailo_soc_connect_ioctl(struct hail
|
|
}
|
|
|
|
// configure and start input channel
|
|
- depth = ceil_log2(input_descriptors_buffer->desc_list.desc_count);
|
|
// DMA Direction is only to get channel index - so
|
|
- err = hailo_vdma_start_channel(input_channel->host_regs, input_descriptors_buffer->dma_address, depth,
|
|
+ err = hailo_vdma_start_channel(input_channel->host_regs, input_descriptors_buffer->dma_address, input_descriptors_buffer->desc_list.desc_count,
|
|
board->vdma.hw->ddr_data_id);
|
|
if (err < 0) {
|
|
hailo_dev_err(&board->pDev->dev, "Error starting vdma input channel index %u\n", params.input_channel_index);
|
|
@@ -149,9 +150,8 @@ long hailo_soc_connect_ioctl(struct hail
|
|
hailo_set_bit(params.input_channel_index, &context->soc_used_channels_bitmap);
|
|
|
|
// configure and start output channel
|
|
- depth = ceil_log2(output_descriptors_buffer->desc_list.desc_count);
|
|
// DMA Direction is only to get channel index - so
|
|
- err = hailo_vdma_start_channel(output_channel->host_regs, output_descriptors_buffer->dma_address, depth,
|
|
+ err = hailo_vdma_start_channel(output_channel->host_regs, output_descriptors_buffer->dma_address, output_descriptors_buffer->desc_list.desc_count,
|
|
board->vdma.hw->ddr_data_id);
|
|
if (err < 0) {
|
|
hailo_dev_err(&board->pDev->dev, "Error starting vdma output channel index %u\n", params.output_channel_index);
|
|
@@ -175,7 +175,7 @@ static int close_channels(struct hailo_p
|
|
{
|
|
struct hailo_pcie_soc_request request = {0};
|
|
struct hailo_pcie_soc_response response = {0};
|
|
- struct hailo_vdma_engine *engine = &board->vdma.vdma_engines[PCI_SOC_VDMA_ENGINE_INDEX];
|
|
+ struct hailo_vdma_engine *engine = &board->vdma.vdma_engines[PCI_VDMA_ENGINE_INDEX];
|
|
struct hailo_vdma_channel *channel = NULL;
|
|
u8 channel_index = 0;
|
|
|
|
--- a/drivers/media/pci/hailo/utils/compact.h
|
|
+++ b/drivers/media/pci/hailo/utils/compact.h
|
|
@@ -48,6 +48,14 @@ static inline long get_user_pages_compac
|
|
}
|
|
#endif
|
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
|
|
+static inline void dma_sync_sgtable_for_device(struct device *dev,
|
|
+ struct sg_table *sgt, enum dma_data_direction dir)
|
|
+{
|
|
+ dma_sync_sg_for_device(dev, sgt->sgl, sgt->orig_nents, dir);
|
|
+}
|
|
+#endif
|
|
+
|
|
#ifndef _LINUX_MMAP_LOCK_H
|
|
static inline void mmap_read_lock(struct mm_struct *mm)
|
|
{
|
|
--- a/drivers/media/pci/hailo/vdma/memory.c
|
|
+++ b/drivers/media/pci/hailo/vdma/memory.c
|
|
@@ -18,6 +18,8 @@
|
|
#define SGL_MAX_SEGMENT_SIZE (0x10000)
|
|
// See linux/mm.h
|
|
#define MMIO_AND_NO_PAGES_VMA_MASK (VM_IO | VM_PFNMAP)
|
|
+// The linux kernel names the dmabuf's vma vm_file field "dmabuf"
|
|
+#define VMA_VM_FILE_DMABUF_NAME ("dmabuf")
|
|
|
|
static int map_mmio_address(uintptr_t user_address, u32 size, struct vm_area_struct *vma,
|
|
struct sg_table *sgt);
|
|
@@ -27,10 +29,16 @@ static void clear_sg_table(struct sg_tab
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 )
|
|
|
|
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0)
|
|
+#define DMA_NS_NAME DMA_BUF
|
|
+#else
|
|
+#define DMA_NS_NAME "DMA_BUF"
|
|
+#endif // LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0)
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
|
|
// Import DMA_BUF namespace for needed kernels
|
|
-MODULE_IMPORT_NS(DMA_BUF);
|
|
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) */
|
|
+MODULE_IMPORT_NS(DMA_NS_NAME);
|
|
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) */
|
|
|
|
static int hailo_map_dmabuf(struct device *dev, int dmabuf_fd, enum dma_data_direction direction, struct sg_table *sgt,
|
|
struct hailo_dmabuf_info *dmabuf_info)
|
|
@@ -103,6 +111,39 @@ static void hailo_unmap_dmabuf(struct ha
|
|
|
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION( 3, 3, 0 ) */
|
|
|
|
+// Function that checks if the vma is backed by a mapped dmabuf
|
|
+static bool is_dmabuf_vma(struct vm_area_struct *vma)
|
|
+{
|
|
+ return (vma && vma->vm_file && (0 == strcmp(vma->vm_file->f_path.dentry->d_name.name, VMA_VM_FILE_DMABUF_NAME)));
|
|
+}
|
|
+
|
|
+static int create_fd_from_vma(struct device *dev, struct vm_area_struct *vma) {
|
|
+ struct file *file = NULL;
|
|
+ int fd = 0;
|
|
+
|
|
+ if (!vma || !vma->vm_file) {
|
|
+ dev_err(dev, "Invalid VMA or no associated file.\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ file = vma->vm_file;
|
|
+
|
|
+ // This functions increments the ref count of the file
|
|
+ get_file(file);
|
|
+
|
|
+ // 0 for default flags
|
|
+ fd = get_unused_fd_flags(0);
|
|
+ if (fd < 0) {
|
|
+ dev_err(dev, "Failed to get unused file descriptor.\n");
|
|
+ fput(file);
|
|
+ return fd;
|
|
+ }
|
|
+
|
|
+ // Install the file into the file descriptor table
|
|
+ fd_install(fd, file);
|
|
+ return fd;
|
|
+}
|
|
+
|
|
struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev,
|
|
uintptr_t user_address, size_t size, enum dma_data_direction direction,
|
|
enum hailo_dma_buffer_type buffer_type, struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer)
|
|
@@ -113,6 +154,7 @@ struct hailo_vdma_buffer *hailo_vdma_buf
|
|
struct vm_area_struct *vma = NULL;
|
|
bool is_mmio = false;
|
|
struct hailo_dmabuf_info dmabuf_info = {0};
|
|
+ bool created_dmabuf_fd_from_vma = false;
|
|
|
|
mapped_buffer = kzalloc(sizeof(*mapped_buffer), GFP_KERNEL);
|
|
if (NULL == mapped_buffer) {
|
|
@@ -121,12 +163,27 @@ struct hailo_vdma_buffer *hailo_vdma_buf
|
|
goto cleanup;
|
|
}
|
|
|
|
- if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING) && (HAILO_DMA_DMABUF_BUFFER != buffer_type)) {
|
|
+ if (HAILO_DMA_DMABUF_BUFFER != buffer_type) {
|
|
vma = find_vma(current->mm, user_address);
|
|
- if (NULL == vma) {
|
|
- dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", user_address, size);
|
|
- ret = -EFAULT;
|
|
- goto cleanup;
|
|
+ if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING)) {
|
|
+ if (NULL == vma) {
|
|
+ dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", user_address, size);
|
|
+ ret = -EFAULT;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (is_dmabuf_vma(vma)) {
|
|
+ dev_dbg(dev, "Given vma is backed by dmabuf - creating fd and mapping as dmabuf\n");
|
|
+ buffer_type = HAILO_DMA_DMABUF_BUFFER;
|
|
+ ret = create_fd_from_vma(dev, vma);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "Failed creating fd from vma in given dmabuf\n");
|
|
+ goto cleanup;
|
|
+ }
|
|
+ // Override user address with fd to the dmabuf - like normal dmabuf flow
|
|
+ user_address = ret;
|
|
+ created_dmabuf_fd_from_vma = true;
|
|
}
|
|
}
|
|
|
|
@@ -157,6 +214,11 @@ struct hailo_vdma_buffer *hailo_vdma_buf
|
|
dev_err(dev, "Failed mapping dmabuf\n");
|
|
goto cleanup;
|
|
}
|
|
+ // If created dmabuf fd from vma need to decrement refcount and release fd
|
|
+ if (created_dmabuf_fd_from_vma) {
|
|
+ fput(vma->vm_file);
|
|
+ put_unused_fd(user_address);
|
|
+ }
|
|
} else {
|
|
// user_address is a standard 'struct page' backed memory address
|
|
ret = prepare_sg_table(&sgt, user_address, size, low_mem_driver_allocated_buffer);
|
|
@@ -331,7 +393,7 @@ int hailo_desc_list_create(struct device
|
|
dev_err(dev, "Failed to allocate descriptors list, desc_count 0x%x, buffer_size 0x%zx, This failure means there is not a sufficient amount of CMA memory "
|
|
"(contiguous physical memory), This usually is caused by lack of general system memory. Please check you have sufficient memory.\n",
|
|
descriptors_count, buffer_size);
|
|
- return -ENOMEM;
|
|
+ return -ENOBUFS;
|
|
}
|
|
|
|
descriptors->buffer_size = buffer_size;
|
|
@@ -467,7 +529,7 @@ int hailo_vdma_continuous_buffer_alloc(s
|
|
if (NULL == kernel_address) {
|
|
dev_warn(dev, "Failed to allocate continuous buffer, size 0x%zx. This failure means there is not a sufficient amount of CMA memory "
|
|
"(contiguous physical memory), This usually is caused by lack of general system memory. Please check you have sufficent memory.\n", size);
|
|
- return -ENOMEM;
|
|
+ return -ENOBUFS;
|
|
}
|
|
|
|
continuous_buffer->kernel_address = kernel_address;
|
|
--- a/drivers/media/pci/hailo/vdma/memory.h
|
|
+++ b/drivers/media/pci/hailo/vdma/memory.h
|
|
@@ -11,6 +11,8 @@
|
|
|
|
#include "vdma/vdma.h"
|
|
|
|
+#define SGL_MAX_SEGMENT_SIZE (0x10000)
|
|
+
|
|
struct hailo_vdma_buffer *hailo_vdma_buffer_map(struct device *dev, uintptr_t user_address, size_t size,
|
|
enum dma_data_direction direction, enum hailo_dma_buffer_type buffer_type,
|
|
struct hailo_vdma_low_memory_buffer *low_mem_driver_allocated_buffer);
|