linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/15] habanalabs: various improvements and updates
@ 2019-03-17 19:59 Oded Gabbay
  2019-03-17 19:59 ` [PATCH 01/15] habanalabs: add new device CPU boot status Oded Gabbay
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

This patch-set contains various improvements to existing code and some
updates from our internal tree at habanalabs.

None of the patches here is critical fix for the 5.1 kernel release, and
they will be queued in the main pull request for the 5.2 merge window.

Thanks,
Oded

Dotan Barak (1):
  habanalabs: remove implicit include from header files

Igor Grinberg (1):
  habanalabs: add new device CPU boot status

Oded Gabbay (7):
  habanalabs: rename goya_non_fatal_events array to all events
  habanalabs: use EQ MSI/X ID per chip
  habanalabs: remove unused defines
  habanalabs: ratelimit warnings at start of IOCTLs
  uapi/habanalabs: add some comments in habanalabs.h
  habanalabs: keep track of the device's dma mask
  habanalabs: never fail hard reset of device

Omer Shpigelman (1):
  habanalabs: add MMU shadow mapping

Tomer Tayar (5):
  habanalabs: Move device CPU code into common file
  habanalabs: Move PCI code into common file
  habanalabs: Remove unneeded function pointers
  habanalabs: Add a printout with the name of a busy engine
  habanalabs: Allow accessing DRAM virtual addresses via debugfs

 drivers/misc/habanalabs/Makefile              |   2 +-
 drivers/misc/habanalabs/command_submission.c  |   2 +-
 drivers/misc/habanalabs/debugfs.c             |  96 ++-
 drivers/misc/habanalabs/device.c              |  19 +-
 drivers/misc/habanalabs/firmware_if.c         | 324 ++++++++
 drivers/misc/habanalabs/goya/goya.c           | 719 +++---------------
 drivers/misc/habanalabs/goya/goyaP.h          |  29 +-
 drivers/misc/habanalabs/goya/goya_security.c  |   1 +
 drivers/misc/habanalabs/habanalabs.h          |  72 +-
 drivers/misc/habanalabs/habanalabs_drv.c      |   3 +
 drivers/misc/habanalabs/habanalabs_ioctl.c    |   4 +-
 drivers/misc/habanalabs/include/armcp_if.h    |  10 +-
 .../include/goya/asic_reg/goya_masks.h        |  12 -
 drivers/misc/habanalabs/include/goya/goya.h   |   4 -
 .../include/goya/goya_async_events.h          |   9 +
 .../misc/habanalabs/include/goya/goya_fw_if.h |   2 +
 drivers/misc/habanalabs/include/hl_boot_if.h  |   3 +-
 .../include/hw_ip/mmu/mmu_general.h           |  16 +-
 .../include/hw_ip/pci/pci_general.h           |  23 +
 drivers/misc/habanalabs/mmu.c                 | 597 ++++++++-------
 drivers/misc/habanalabs/pci.c                 | 402 ++++++++++
 include/uapi/misc/habanalabs.h                |   7 +-
 22 files changed, 1404 insertions(+), 952 deletions(-)
 create mode 100644 drivers/misc/habanalabs/firmware_if.c
 create mode 100644 drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h
 create mode 100644 drivers/misc/habanalabs/pci.c

-- 
2.17.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/15] habanalabs: add new device CPU boot status
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 02/15] habanalabs: rename goya_non_fatal_events array to all events Oded Gabbay
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Igor Grinberg

From: Igor Grinberg <igrinberg@habana.ai>

This patch adds a definition of a new status in the device CPU boot stages
and add the handling of the new status.

Signed-off-by: Igor Grinberg <igrinberg@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya.c          | 5 +++++
 drivers/misc/habanalabs/include/hl_boot_if.h | 3 ++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index ea979ebd62fb..0185f11c5577 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -2550,6 +2550,11 @@ static int goya_init_cpu(struct hl_device *hdev, u32 cpu_timeout)
 				"ARM status %d - DDR initialization failed\n",
 				status);
 			break;
+		case CPU_BOOT_STATUS_UBOOT_NOT_READY:
+			dev_err(hdev->dev,
+				"ARM status %d - u-boot stopped by user\n",
+				status);
+			break;
 		default:
 			dev_err(hdev->dev,
 				"ARM status %d - Invalid status code\n",
diff --git a/drivers/misc/habanalabs/include/hl_boot_if.h b/drivers/misc/habanalabs/include/hl_boot_if.h
index 7475732b9996..4cd04c090285 100644
--- a/drivers/misc/habanalabs/include/hl_boot_if.h
+++ b/drivers/misc/habanalabs/include/hl_boot_if.h
@@ -18,7 +18,8 @@ enum cpu_boot_status {
 	CPU_BOOT_STATUS_IN_SPL,
 	CPU_BOOT_STATUS_IN_UBOOT,
 	CPU_BOOT_STATUS_DRAM_INIT_FAIL,
-	CPU_BOOT_STATUS_FIT_CORRUPTED
+	CPU_BOOT_STATUS_FIT_CORRUPTED,
+	CPU_BOOT_STATUS_UBOOT_NOT_READY,
 };
 
 enum kmd_msg {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/15] habanalabs: rename goya_non_fatal_events array to all events
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
  2019-03-17 19:59 ` [PATCH 01/15] habanalabs: add new device CPU boot status Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 03/15] habanalabs: remove implicit include from header files Oded Gabbay
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

The goya_non_fatal_events array actually contains all the possible events
the driver can receive from the F/W. Therefore, use a proper name
for the array.

The patch also adds missing event Ids to the goya_async_event_id enum.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya.c                      | 8 +++-----
 drivers/misc/habanalabs/include/goya/goya_async_events.h | 9 +++++++++
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index 0185f11c5577..3dfac5393269 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -176,9 +176,7 @@ static u64 goya_mmu_regs[GOYA_MMU_REGS_NUM] = {
 	mmMME_WBC_CONTROL_DATA
 };
 
-#define GOYA_ASYC_EVENT_GROUP_NON_FATAL_SIZE 121
-
-static u32 goya_non_fatal_events[GOYA_ASYC_EVENT_GROUP_NON_FATAL_SIZE] = {
+static u32 goya_all_events[] = {
 	GOYA_ASYNC_EVENT_ID_PCIE_IF,
 	GOYA_ASYNC_EVENT_ID_TPC0_ECC,
 	GOYA_ASYNC_EVENT_ID_TPC1_ECC,
@@ -4627,8 +4625,8 @@ static int goya_soft_reset_late_init(struct hl_device *hdev)
 	 * Unmask all IRQs since some could have been received
 	 * during the soft reset
 	 */
-	return goya_unmask_irq_arr(hdev, goya_non_fatal_events,
-			sizeof(goya_non_fatal_events));
+	return goya_unmask_irq_arr(hdev, goya_all_events,
+					sizeof(goya_all_events));
 }
 
 static int goya_unmask_irq(struct hl_device *hdev, u16 event_type)
diff --git a/drivers/misc/habanalabs/include/goya/goya_async_events.h b/drivers/misc/habanalabs/include/goya/goya_async_events.h
index 497937a17ee9..bb7a1aa3279e 100644
--- a/drivers/misc/habanalabs/include/goya/goya_async_events.h
+++ b/drivers/misc/habanalabs/include/goya/goya_async_events.h
@@ -9,7 +9,9 @@
 #define __GOYA_ASYNC_EVENTS_H_
 
 enum goya_async_event_id {
+	GOYA_ASYNC_EVENT_ID_PCIE_CORE = 32,
 	GOYA_ASYNC_EVENT_ID_PCIE_IF = 33,
+	GOYA_ASYNC_EVENT_ID_PCIE_PHY = 34,
 	GOYA_ASYNC_EVENT_ID_TPC0_ECC = 36,
 	GOYA_ASYNC_EVENT_ID_TPC1_ECC = 39,
 	GOYA_ASYNC_EVENT_ID_TPC2_ECC = 42,
@@ -23,6 +25,8 @@ enum goya_async_event_id {
 	GOYA_ASYNC_EVENT_ID_MMU_ECC = 63,
 	GOYA_ASYNC_EVENT_ID_DMA_MACRO = 64,
 	GOYA_ASYNC_EVENT_ID_DMA_ECC = 66,
+	GOYA_ASYNC_EVENT_ID_DDR0_PARITY = 69,
+	GOYA_ASYNC_EVENT_ID_DDR1_PARITY = 72,
 	GOYA_ASYNC_EVENT_ID_CPU_IF_ECC = 75,
 	GOYA_ASYNC_EVENT_ID_PSOC_MEM = 78,
 	GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT = 79,
@@ -72,6 +76,7 @@ enum goya_async_event_id {
 	GOYA_ASYNC_EVENT_ID_MME_WACSD = 142,
 	GOYA_ASYNC_EVENT_ID_PLL0 = 143,
 	GOYA_ASYNC_EVENT_ID_PLL1 = 144,
+	GOYA_ASYNC_EVENT_ID_PLL2 = 145,
 	GOYA_ASYNC_EVENT_ID_PLL3 = 146,
 	GOYA_ASYNC_EVENT_ID_PLL4 = 147,
 	GOYA_ASYNC_EVENT_ID_PLL5 = 148,
@@ -81,6 +86,7 @@ enum goya_async_event_id {
 	GOYA_ASYNC_EVENT_ID_PSOC = 160,
 	GOYA_ASYNC_EVENT_ID_PCIE_FLR = 171,
 	GOYA_ASYNC_EVENT_ID_PCIE_HOT_RESET = 172,
+	GOYA_ASYNC_EVENT_ID_PCIE_PERST = 173,
 	GOYA_ASYNC_EVENT_ID_PCIE_QID0_ENG0 = 174,
 	GOYA_ASYNC_EVENT_ID_PCIE_QID0_ENG1 = 175,
 	GOYA_ASYNC_EVENT_ID_PCIE_QID0_ENG2 = 176,
@@ -144,8 +150,11 @@ enum goya_async_event_id {
 	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_U16_0 = 330,
 	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_U16_1 = 331,
 	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_U16_2 = 332,
+	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_U16_3 = 333,
+	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_U16_4 = 334,
 	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET = 356,
 	GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT = 361,
+	GOYA_ASYNC_EVENT_ID_FAN = 425,
 	GOYA_ASYNC_EVENT_ID_TPC0_CMDQ = 430,
 	GOYA_ASYNC_EVENT_ID_TPC1_CMDQ = 431,
 	GOYA_ASYNC_EVENT_ID_TPC2_CMDQ = 432,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/15] habanalabs: remove implicit include from header files
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
  2019-03-17 19:59 ` [PATCH 01/15] habanalabs: add new device CPU boot status Oded Gabbay
  2019-03-17 19:59 ` [PATCH 02/15] habanalabs: rename goya_non_fatal_events array to all events Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 04/15] habanalabs: Move device CPU code into common file Oded Gabbay
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Dotan Barak

From: Dotan Barak <dbarak@habana.ai>

This will prevent unneeded include of header files, which may increase
compilation time.

Signed-off-by: Dotan Barak <dbarak@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya_security.c | 1 +
 drivers/misc/habanalabs/include/goya/goya.h  | 4 ----
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goya_security.c b/drivers/misc/habanalabs/goya/goya_security.c
index 575003238401..9d2dee67e46f 100644
--- a/drivers/misc/habanalabs/goya/goya_security.c
+++ b/drivers/misc/habanalabs/goya/goya_security.c
@@ -6,6 +6,7 @@
  */
 
 #include "goyaP.h"
+#include "include/goya/asic_reg/goya_regs.h"
 
 /*
  * goya_set_block_as_protected - set the given block as protected
diff --git a/drivers/misc/habanalabs/include/goya/goya.h b/drivers/misc/habanalabs/include/goya/goya.h
index 614149efa412..3f02a52ba4ce 100644
--- a/drivers/misc/habanalabs/include/goya/goya.h
+++ b/drivers/misc/habanalabs/include/goya/goya.h
@@ -8,10 +8,6 @@
 #ifndef GOYA_H
 #define GOYA_H
 
-#include "asic_reg/goya_regs.h"
-
-#include <linux/types.h>
-
 #define SRAM_CFG_BAR_ID		0
 #define MSIX_BAR_ID		2
 #define DDR_BAR_ID		4
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/15] habanalabs: Move device CPU code into common file
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (2 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 03/15] habanalabs: remove implicit include from header files Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 05/15] habanalabs: use EQ MSI/X ID per chip Oded Gabbay
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Tomer Tayar

From: Tomer Tayar <ttayar@habana.ai>

This patch moves the code that is responsible of the communication
vs. the F/W to a dedicated file. This will allow us to share the code
between different ASICs.

Signed-off-by: Tomer Tayar <ttayar@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/Makefile           |   2 +-
 drivers/misc/habanalabs/firmware_if.c      | 324 +++++++++++++++++++
 drivers/misc/habanalabs/goya/goya.c        | 360 ++++-----------------
 drivers/misc/habanalabs/goya/goyaP.h       |  11 -
 drivers/misc/habanalabs/habanalabs.h       |  17 +
 drivers/misc/habanalabs/include/armcp_if.h |   8 +
 6 files changed, 407 insertions(+), 315 deletions(-)
 create mode 100644 drivers/misc/habanalabs/firmware_if.c

diff --git a/drivers/misc/habanalabs/Makefile b/drivers/misc/habanalabs/Makefile
index c6592db59b25..598740d235f8 100644
--- a/drivers/misc/habanalabs/Makefile
+++ b/drivers/misc/habanalabs/Makefile
@@ -6,7 +6,7 @@ obj-m	:= habanalabs.o
 
 habanalabs-y := habanalabs_drv.o device.o context.o asid.o habanalabs_ioctl.o \
 		command_buffer.o hw_queue.o irq.o sysfs.o hwmon.o memory.o \
-		command_submission.o mmu.o
+		command_submission.o mmu.o firmware_if.o
 
 habanalabs-$(CONFIG_DEBUG_FS) += debugfs.o
 
diff --git a/drivers/misc/habanalabs/firmware_if.c b/drivers/misc/habanalabs/firmware_if.c
new file mode 100644
index 000000000000..9bf5203e8922
--- /dev/null
+++ b/drivers/misc/habanalabs/firmware_if.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2016-2019 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ */
+
+#include "habanalabs.h"
+
+#include <linux/firmware.h>
+#include <linux/genalloc.h>
+
+/**
+ * hl_fw_push_fw_to_device() - Push FW code to device.
+ * @hdev: pointer to hl_device structure.
+ *
+ * Copy fw code from firmware file to device memory.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+int hl_fw_push_fw_to_device(struct hl_device *hdev, const char *fw_name,
+				void __iomem *dst)
+{
+	const struct firmware *fw;
+	const u64 *fw_data;
+	size_t fw_size, i;
+	int rc;
+
+	rc = request_firmware(&fw, fw_name, hdev->dev);
+	if (rc) {
+		dev_err(hdev->dev, "Failed to request %s\n", fw_name);
+		goto out;
+	}
+
+	fw_size = fw->size;
+	if ((fw_size % 4) != 0) {
+		dev_err(hdev->dev, "illegal %s firmware size %zu\n",
+			fw_name, fw_size);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);
+
+	fw_data = (const u64 *) fw->data;
+
+	if ((fw->size % 8) != 0)
+		fw_size -= 8;
+
+	for (i = 0 ; i < fw_size ; i += 8, fw_data++, dst += 8) {
+		if (!(i & (0x80000 - 1))) {
+			dev_dbg(hdev->dev,
+				"copied so far %zu out of %zu for %s firmware",
+				i, fw_size, fw_name);
+			usleep_range(20, 100);
+		}
+
+		writeq(*fw_data, dst);
+	}
+
+	if ((fw->size % 8) != 0)
+		writel(*(const u32 *) fw_data, dst);
+
+out:
+	release_firmware(fw);
+	return rc;
+}
+
+int hl_fw_send_pci_access_msg(struct hl_device *hdev, u32 opcode)
+{
+	struct armcp_packet pkt = {};
+
+	pkt.ctl = cpu_to_le32(opcode << ARMCP_PKT_CTL_OPCODE_SHIFT);
+
+	return hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt,
+				sizeof(pkt), HL_DEVICE_TIMEOUT_USEC, NULL);
+}
+
+int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
+				u16 len, u32 timeout, long *result)
+{
+	struct armcp_packet *pkt;
+	dma_addr_t pkt_dma_addr;
+	u32 tmp;
+	int rc = 0;
+
+	if (len > HL_CPU_CB_SIZE) {
+		dev_err(hdev->dev, "Invalid CPU message size of %d bytes\n",
+			len);
+		return -ENOMEM;
+	}
+
+	pkt = hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev, len,
+								&pkt_dma_addr);
+	if (!pkt) {
+		dev_err(hdev->dev,
+			"Failed to allocate DMA memory for packet to CPU\n");
+		return -ENOMEM;
+	}
+
+	memcpy(pkt, msg, len);
+
+	mutex_lock(&hdev->send_cpu_message_lock);
+
+	if (hdev->disabled)
+		goto out;
+
+	if (hdev->device_cpu_disabled) {
+		rc = -EIO;
+		goto out;
+	}
+
+	rc = hl_hw_queue_send_cb_no_cmpl(hdev, hw_queue_id, len, pkt_dma_addr);
+	if (rc) {
+		dev_err(hdev->dev, "Failed to send CB on CPU PQ (%d)\n", rc);
+		goto out;
+	}
+
+	rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) &pkt->fence,
+					timeout, &tmp);
+
+	hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);
+
+	if (rc == -ETIMEDOUT) {
+		dev_err(hdev->dev, "Timeout while waiting for device CPU\n");
+		hdev->device_cpu_disabled = true;
+		goto out;
+	}
+
+	if (tmp == ARMCP_PACKET_FENCE_VAL) {
+		u32 ctl = le32_to_cpu(pkt->ctl);
+
+		rc = (ctl & ARMCP_PKT_CTL_RC_MASK) >> ARMCP_PKT_CTL_RC_SHIFT;
+		if (rc) {
+			dev_err(hdev->dev,
+				"F/W ERROR %d for CPU packet %d\n",
+				rc, (ctl & ARMCP_PKT_CTL_OPCODE_MASK)
+						>> ARMCP_PKT_CTL_OPCODE_SHIFT);
+			rc = -EINVAL;
+		} else if (result) {
+			*result = (long) le64_to_cpu(pkt->result);
+		}
+	} else {
+		dev_err(hdev->dev, "CPU packet wrong fence value\n");
+		rc = -EINVAL;
+	}
+
+out:
+	mutex_unlock(&hdev->send_cpu_message_lock);
+
+	hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev, len, pkt);
+
+	return rc;
+}
+
+int hl_fw_test_cpu_queue(struct hl_device *hdev)
+{
+	struct armcp_packet test_pkt = {};
+	long result;
+	int rc;
+
+	test_pkt.ctl = cpu_to_le32(ARMCP_PACKET_TEST <<
+					ARMCP_PKT_CTL_OPCODE_SHIFT);
+	test_pkt.value = cpu_to_le64(ARMCP_PACKET_FENCE_VAL);
+
+	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &test_pkt,
+			sizeof(test_pkt), HL_DEVICE_TIMEOUT_USEC, &result);
+
+	if (!rc) {
+		if (result == ARMCP_PACKET_FENCE_VAL)
+			dev_info(hdev->dev,
+				"queue test on CPU queue succeeded\n");
+		else
+			dev_err(hdev->dev,
+				"CPU queue test failed (0x%08lX)\n", result);
+	} else {
+		dev_err(hdev->dev, "CPU queue test failed, error %d\n", rc);
+	}
+
+	return rc;
+}
+
+void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
+						dma_addr_t *dma_handle)
+{
+	u64 kernel_addr;
+
+	/* roundup to HL_CPU_PKT_SIZE */
+	size = (size + (HL_CPU_PKT_SIZE - 1)) & HL_CPU_PKT_MASK;
+
+	kernel_addr = gen_pool_alloc(hdev->cpu_accessible_dma_pool, size);
+
+	*dma_handle = hdev->cpu_accessible_dma_address +
+		(kernel_addr - (u64) (uintptr_t) hdev->cpu_accessible_dma_mem);
+
+	return (void *) (uintptr_t) kernel_addr;
+}
+
+void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
+					void *vaddr)
+{
+	/* roundup to HL_CPU_PKT_SIZE */
+	size = (size + (HL_CPU_PKT_SIZE - 1)) & HL_CPU_PKT_MASK;
+
+	gen_pool_free(hdev->cpu_accessible_dma_pool, (u64) (uintptr_t) vaddr,
+			size);
+}
+
+int hl_fw_send_heartbeat(struct hl_device *hdev)
+{
+	struct armcp_packet hb_pkt = {};
+	long result;
+	int rc;
+
+	hb_pkt.ctl = cpu_to_le32(ARMCP_PACKET_TEST <<
+					ARMCP_PKT_CTL_OPCODE_SHIFT);
+	hb_pkt.value = cpu_to_le64(ARMCP_PACKET_FENCE_VAL);
+
+	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &hb_pkt,
+			sizeof(hb_pkt), HL_DEVICE_TIMEOUT_USEC, &result);
+
+	if ((rc) || (result != ARMCP_PACKET_FENCE_VAL))
+		rc = -EIO;
+
+	return rc;
+}
+
+int hl_fw_armcp_info_get(struct hl_device *hdev)
+{
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	struct armcp_packet pkt = {};
+	void *armcp_info_cpu_addr;
+	dma_addr_t armcp_info_dma_addr;
+	long result;
+	int rc;
+
+	armcp_info_cpu_addr =
+			hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev,
+					sizeof(struct armcp_info),
+					&armcp_info_dma_addr);
+	if (!armcp_info_cpu_addr) {
+		dev_err(hdev->dev,
+			"Failed to allocate DMA memory for ArmCP info packet\n");
+		return -ENOMEM;
+	}
+
+	memset(armcp_info_cpu_addr, 0, sizeof(struct armcp_info));
+
+	pkt.ctl = cpu_to_le32(ARMCP_PACKET_INFO_GET <<
+				ARMCP_PKT_CTL_OPCODE_SHIFT);
+	pkt.addr = cpu_to_le64(armcp_info_dma_addr +
+				prop->host_phys_base_address);
+	pkt.data_max_size = cpu_to_le32(sizeof(struct armcp_info));
+
+	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
+					HL_ARMCP_INFO_TIMEOUT_USEC, &result);
+	if (rc) {
+		dev_err(hdev->dev,
+			"Failed to send armcp info pkt, error %d\n", rc);
+		goto out;
+	}
+
+	memcpy(&prop->armcp_info, armcp_info_cpu_addr,
+			sizeof(prop->armcp_info));
+
+	rc = hl_build_hwmon_channel_info(hdev, prop->armcp_info.sensors);
+	if (rc) {
+		dev_err(hdev->dev,
+			"Failed to build hwmon channel info, error %d\n", rc);
+		rc = -EFAULT;
+		goto out;
+	}
+
+out:
+	hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev,
+			sizeof(struct armcp_info), armcp_info_cpu_addr);
+
+	return rc;
+}
+
+int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)
+{
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	struct armcp_packet pkt = {};
+	void *eeprom_info_cpu_addr;
+	dma_addr_t eeprom_info_dma_addr;
+	long result;
+	int rc;
+
+	eeprom_info_cpu_addr =
+			hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev,
+					max_size, &eeprom_info_dma_addr);
+	if (!eeprom_info_cpu_addr) {
+		dev_err(hdev->dev,
+			"Failed to allocate DMA memory for EEPROM info packet\n");
+		return -ENOMEM;
+	}
+
+	memset(eeprom_info_cpu_addr, 0, max_size);
+
+	pkt.ctl = cpu_to_le32(ARMCP_PACKET_EEPROM_DATA_GET <<
+				ARMCP_PKT_CTL_OPCODE_SHIFT);
+	pkt.addr = cpu_to_le64(eeprom_info_dma_addr +
+				prop->host_phys_base_address);
+	pkt.data_max_size = cpu_to_le32(max_size);
+
+	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
+			HL_ARMCP_EEPROM_TIMEOUT_USEC, &result);
+
+	if (rc) {
+		dev_err(hdev->dev,
+			"Failed to send armcp EEPROM pkt, error %d\n", rc);
+		goto out;
+	}
+
+	/* result contains the actual size */
+	memcpy(data, eeprom_info_cpu_addr, min((size_t)result, max_size));
+
+out:
+	hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev, max_size,
+			eeprom_info_cpu_addr);
+
+	return rc;
+}
diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index 3dfac5393269..a578d01a56a6 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -12,7 +12,6 @@
 
 #include <linux/pci.h>
 #include <linux/genalloc.h>
-#include <linux/firmware.h>
 #include <linux/hwmon.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/io-64-nonatomic-hi-lo.h>
@@ -373,18 +372,6 @@ static void goya_get_fixed_properties(struct hl_device *hdev)
 	prop->high_pll = PLL_HIGH_DEFAULT;
 }
 
-int goya_send_pci_access_msg(struct hl_device *hdev, u32 opcode)
-{
-	struct armcp_packet pkt;
-
-	memset(&pkt, 0, sizeof(pkt));
-
-	pkt.ctl = cpu_to_le32(opcode << ARMCP_PKT_CTL_OPCODE_SHIFT);
-
-	return hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt,
-			sizeof(pkt), HL_DEVICE_TIMEOUT_USEC, NULL);
-}
-
 /*
  * goya_pci_bars_map - Map PCI BARS of Goya device
  *
@@ -802,7 +789,7 @@ static int goya_late_init(struct hl_device *hdev)
 	 */
 	WREG32(mmMMU_LOG2_DDR_SIZE, ilog2(prop->dram_size));
 
-	rc = goya_send_pci_access_msg(hdev, ARMCP_PACKET_ENABLE_PCI_ACCESS);
+	rc = hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_ENABLE_PCI_ACCESS);
 	if (rc) {
 		dev_err(hdev->dev, "Failed to enable PCI access from CPU\n");
 		return rc;
@@ -828,7 +815,7 @@ static int goya_late_init(struct hl_device *hdev)
 	return 0;
 
 disable_pci_access:
-	goya_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
+	hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
 
 	return rc;
 }
@@ -900,19 +887,16 @@ static int goya_sw_init(struct hl_device *hdev)
 
 	hdev->cpu_accessible_dma_mem =
 			hdev->asic_funcs->dma_alloc_coherent(hdev,
-					CPU_ACCESSIBLE_MEM_SIZE,
+					HL_CPU_ACCESSIBLE_MEM_SIZE,
 					&hdev->cpu_accessible_dma_address,
 					GFP_KERNEL | __GFP_ZERO);
 
 	if (!hdev->cpu_accessible_dma_mem) {
-		dev_err(hdev->dev,
-			"failed to allocate %d of dma memory for CPU accessible memory space\n",
-			CPU_ACCESSIBLE_MEM_SIZE);
 		rc = -ENOMEM;
 		goto free_dma_pool;
 	}
 
-	hdev->cpu_accessible_dma_pool = gen_pool_create(CPU_PKT_SHIFT, -1);
+	hdev->cpu_accessible_dma_pool = gen_pool_create(HL_CPU_PKT_SHIFT, -1);
 	if (!hdev->cpu_accessible_dma_pool) {
 		dev_err(hdev->dev,
 			"Failed to create CPU accessible DMA pool\n");
@@ -922,7 +906,7 @@ static int goya_sw_init(struct hl_device *hdev)
 
 	rc = gen_pool_add(hdev->cpu_accessible_dma_pool,
 				(uintptr_t) hdev->cpu_accessible_dma_mem,
-				CPU_ACCESSIBLE_MEM_SIZE, -1);
+				HL_CPU_ACCESSIBLE_MEM_SIZE, -1);
 	if (rc) {
 		dev_err(hdev->dev,
 			"Failed to add memory to CPU accessible DMA pool\n");
@@ -937,7 +921,7 @@ static int goya_sw_init(struct hl_device *hdev)
 free_cpu_pq_pool:
 	gen_pool_destroy(hdev->cpu_accessible_dma_pool);
 free_cpu_pq_dma_mem:
-	hdev->asic_funcs->dma_free_coherent(hdev, CPU_ACCESSIBLE_MEM_SIZE,
+	hdev->asic_funcs->dma_free_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE,
 			hdev->cpu_accessible_dma_mem,
 			hdev->cpu_accessible_dma_address);
 free_dma_pool:
@@ -960,7 +944,7 @@ static int goya_sw_fini(struct hl_device *hdev)
 
 	gen_pool_destroy(hdev->cpu_accessible_dma_pool);
 
-	hdev->asic_funcs->dma_free_coherent(hdev, CPU_ACCESSIBLE_MEM_SIZE,
+	hdev->asic_funcs->dma_free_coherent(hdev, HL_CPU_ACCESSIBLE_MEM_SIZE,
 			hdev->cpu_accessible_dma_mem,
 			hdev->cpu_accessible_dma_address);
 
@@ -1240,7 +1224,7 @@ static int goya_init_cpu_queues(struct hl_device *hdev)
 
 	WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_5, HL_QUEUE_SIZE_IN_BYTES);
 	WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_4, HL_EQ_SIZE_IN_BYTES);
-	WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_10, CPU_ACCESSIBLE_MEM_SIZE);
+	WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_10, HL_CPU_ACCESSIBLE_MEM_SIZE);
 
 	/* Used for EQ CI */
 	WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_6, 0);
@@ -2328,67 +2312,45 @@ static void goya_halt_engines(struct hl_device *hdev, bool hard_reset)
 }
 
 /*
- * goya_push_fw_to_device - Push FW code to device
- *
- * @hdev: pointer to hl_device structure
+ * goya_push_uboot_to_device() - Push u-boot FW code to device.
+ * @hdev: Pointer to hl_device structure.
  *
- * Copy fw code from firmware file to device memory.
- * Returns 0 on success
+ * Copy u-boot fw code from firmware file to SRAM BAR.
  *
+ * Return: 0 on success, non-zero for failure.
  */
-static int goya_push_fw_to_device(struct hl_device *hdev, const char *fw_name,
-					void __iomem *dst)
+static int goya_push_uboot_to_device(struct hl_device *hdev)
 {
-	const struct firmware *fw;
-	const u64 *fw_data;
-	size_t fw_size, i;
-	int rc;
-
-	rc = request_firmware(&fw, fw_name, hdev->dev);
-
-	if (rc) {
-		dev_err(hdev->dev, "Failed to request %s\n", fw_name);
-		goto out;
-	}
-
-	fw_size = fw->size;
-	if ((fw_size % 4) != 0) {
-		dev_err(hdev->dev, "illegal %s firmware size %zu\n",
-			fw_name, fw_size);
-		rc = -EINVAL;
-		goto out;
-	}
-
-	dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);
-
-	fw_data = (const u64 *) fw->data;
+	char fw_name[200];
+	void __iomem *dst;
 
-	if ((fw->size % 8) != 0)
-		fw_size -= 8;
+	snprintf(fw_name, sizeof(fw_name), "habanalabs/goya/goya-u-boot.bin");
+	dst = hdev->pcie_bar[SRAM_CFG_BAR_ID] + UBOOT_FW_OFFSET;
 
-	for (i = 0 ; i < fw_size ; i += 8, fw_data++, dst += 8) {
-		if (!(i & (0x80000 - 1))) {
-			dev_dbg(hdev->dev,
-				"copied so far %zu out of %zu for %s firmware",
-				i, fw_size, fw_name);
-			usleep_range(20, 100);
-		}
+	return hl_fw_push_fw_to_device(hdev, fw_name, dst);
+}
 
-		writeq(*fw_data, dst);
-	}
+/*
+ * goya_push_linux_to_device() - Push LINUX FW code to device.
+ * @hdev: Pointer to hl_device structure.
+ *
+ * Copy LINUX fw code from firmware file to HBM BAR.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+static int goya_push_linux_to_device(struct hl_device *hdev)
+{
+	char fw_name[200];
+	void __iomem *dst;
 
-	if ((fw->size % 8) != 0)
-		writel(*(const u32 *) fw_data, dst);
+	snprintf(fw_name, sizeof(fw_name), "habanalabs/goya/goya-fit.itb");
+	dst = hdev->pcie_bar[DDR_BAR_ID] + LINUX_FW_OFFSET;
 
-out:
-	release_firmware(fw);
-	return rc;
+	return hl_fw_push_fw_to_device(hdev, fw_name, dst);
 }
 
 static int goya_pldm_init_cpu(struct hl_device *hdev)
 {
-	char fw_name[200];
-	void __iomem *dst;
 	u32 val, unit_rst_val;
 	int rc;
 
@@ -2406,15 +2368,11 @@ static int goya_pldm_init_cpu(struct hl_device *hdev)
 	WREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N, unit_rst_val);
 	val = RREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N);
 
-	snprintf(fw_name, sizeof(fw_name), "habanalabs/goya/goya-u-boot.bin");
-	dst = hdev->pcie_bar[SRAM_CFG_BAR_ID] + UBOOT_FW_OFFSET;
-	rc = goya_push_fw_to_device(hdev, fw_name, dst);
+	rc = goya_push_uboot_to_device(hdev);
 	if (rc)
 		return rc;
 
-	snprintf(fw_name, sizeof(fw_name), "habanalabs/goya/goya-fit.itb");
-	dst = hdev->pcie_bar[DDR_BAR_ID] + LINUX_FW_OFFSET;
-	rc = goya_push_fw_to_device(hdev, fw_name, dst);
+	rc = goya_push_linux_to_device(hdev);
 	if (rc)
 		return rc;
 
@@ -2476,8 +2434,6 @@ static void goya_read_device_fw_version(struct hl_device *hdev,
 static int goya_init_cpu(struct hl_device *hdev, u32 cpu_timeout)
 {
 	struct goya_device *goya = hdev->asic_specific;
-	char fw_name[200];
-	void __iomem *dst;
 	u32 status;
 	int rc;
 
@@ -2574,9 +2530,7 @@ static int goya_init_cpu(struct hl_device *hdev, u32 cpu_timeout)
 		goto out;
 	}
 
-	snprintf(fw_name, sizeof(fw_name), "habanalabs/goya/goya-fit.itb");
-	dst = hdev->pcie_bar[DDR_BAR_ID] + LINUX_FW_OFFSET;
-	rc = goya_push_fw_to_device(hdev, fw_name, dst);
+	rc = goya_push_linux_to_device(hdev);
 	if (rc)
 		return rc;
 
@@ -2762,7 +2716,7 @@ static int goya_hw_init(struct hl_device *hdev)
 	return 0;
 
 disable_pci_access:
-	goya_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
+	hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
 disable_msix:
 	goya_disable_msix(hdev);
 disable_queues:
@@ -2869,7 +2823,7 @@ int goya_suspend(struct hl_device *hdev)
 {
 	int rc;
 
-	rc = goya_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
+	rc = hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
 	if (rc)
 		dev_err(hdev->dev, "Failed to disable PCI access from CPU\n");
 
@@ -3150,10 +3104,6 @@ int goya_send_cpu_message(struct hl_device *hdev, u32 *msg, u16 len,
 				u32 timeout, long *result)
 {
 	struct goya_device *goya = hdev->asic_specific;
-	struct armcp_packet *pkt;
-	dma_addr_t pkt_dma_addr;
-	u32 tmp;
-	int rc = 0;
 
 	if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) {
 		if (result)
@@ -3161,74 +3111,8 @@ int goya_send_cpu_message(struct hl_device *hdev, u32 *msg, u16 len,
 		return 0;
 	}
 
-	if (len > CPU_CB_SIZE) {
-		dev_err(hdev->dev, "Invalid CPU message size of %d bytes\n",
-			len);
-		return -ENOMEM;
-	}
-
-	pkt = hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev, len,
-								&pkt_dma_addr);
-	if (!pkt) {
-		dev_err(hdev->dev,
-			"Failed to allocate DMA memory for packet to CPU\n");
-		return -ENOMEM;
-	}
-
-	memcpy(pkt, msg, len);
-
-	mutex_lock(&hdev->send_cpu_message_lock);
-
-	if (hdev->disabled)
-		goto out;
-
-	if (hdev->device_cpu_disabled) {
-		rc = -EIO;
-		goto out;
-	}
-
-	rc = hl_hw_queue_send_cb_no_cmpl(hdev, GOYA_QUEUE_ID_CPU_PQ, len,
-			pkt_dma_addr);
-	if (rc) {
-		dev_err(hdev->dev, "Failed to send CB on CPU PQ (%d)\n", rc);
-		goto out;
-	}
-
-	rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) &pkt->fence,
-					timeout, &tmp);
-
-	hl_hw_queue_inc_ci_kernel(hdev, GOYA_QUEUE_ID_CPU_PQ);
-
-	if (rc == -ETIMEDOUT) {
-		dev_err(hdev->dev, "Timeout while waiting for device CPU\n");
-		hdev->device_cpu_disabled = true;
-		goto out;
-	}
-
-	if (tmp == ARMCP_PACKET_FENCE_VAL) {
-		u32 ctl = le32_to_cpu(pkt->ctl);
-
-		rc = (ctl & ARMCP_PKT_CTL_RC_MASK) >> ARMCP_PKT_CTL_RC_SHIFT;
-		if (rc) {
-			dev_err(hdev->dev,
-				"F/W ERROR %d for CPU packet %d\n",
-				rc, (ctl & ARMCP_PKT_CTL_OPCODE_MASK)
-						>> ARMCP_PKT_CTL_OPCODE_SHIFT);
-			rc = -EINVAL;
-		} else if (result) {
-			*result = (long) le64_to_cpu(pkt->result);
-		}
-	} else {
-		dev_err(hdev->dev, "CPU packet wrong fence value\n");
-		rc = -EINVAL;
-	}
-
-out:
-	mutex_unlock(&hdev->send_cpu_message_lock);
-
-	hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev, len, pkt);
-
-	return rc;
+	return hl_fw_send_cpu_message(hdev, GOYA_QUEUE_ID_CPU_PQ, msg, len,
+					timeout, result);
 }
 
 int goya_test_queue(struct hl_device *hdev, u32 hw_queue_id)
@@ -3306,33 +3190,16 @@ int goya_test_queue(struct hl_device *hdev, u32 hw_queue_id)
 
 int goya_test_cpu_queue(struct hl_device *hdev)
 {
-	struct armcp_packet test_pkt;
-	long result;
-	int rc;
-
-	/* cpu_queues_enable flag is always checked in send cpu message */
-
-	memset(&test_pkt, 0, sizeof(test_pkt));
-
-	test_pkt.ctl = cpu_to_le32(ARMCP_PACKET_TEST <<
-					ARMCP_PKT_CTL_OPCODE_SHIFT);
-	test_pkt.value = cpu_to_le64(ARMCP_PACKET_FENCE_VAL);
-
-	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &test_pkt,
-			sizeof(test_pkt), HL_DEVICE_TIMEOUT_USEC, &result);
+	struct goya_device *goya = hdev->asic_specific;
 
-	if (!rc) {
-		if (result == ARMCP_PACKET_FENCE_VAL)
-			dev_info(hdev->dev,
-				"queue test on CPU queue succeeded\n");
-		else
-			dev_err(hdev->dev,
-				"CPU queue test failed (0x%08lX)\n", result);
-	} else {
-		dev_err(hdev->dev, "CPU queue test failed, error %d\n", rc);
-	}
+	/*
+	 * check capability here as send_cpu_message() won't update the result
+	 * value if no capability
+	 */
+	if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q))
+		return 0;
 
-	return rc;
+	return hl_fw_test_cpu_queue(hdev);
 }
 
 static int goya_test_queues(struct hl_device *hdev)
@@ -3373,27 +3240,13 @@ static void goya_dma_pool_free(struct hl_device *hdev, void *vaddr,
 static void *goya_cpu_accessible_dma_pool_alloc(struct hl_device *hdev,
 					size_t size, dma_addr_t *dma_handle)
 {
-	u64 kernel_addr;
-
-	/* roundup to CPU_PKT_SIZE */
-	size = (size + (CPU_PKT_SIZE - 1)) & CPU_PKT_MASK;
-
-	kernel_addr = gen_pool_alloc(hdev->cpu_accessible_dma_pool, size);
-
-	*dma_handle = hdev->cpu_accessible_dma_address +
-		(kernel_addr - (u64) (uintptr_t) hdev->cpu_accessible_dma_mem);
-
-	return (void *) (uintptr_t) kernel_addr;
+	return hl_fw_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle);
 }
 
 static void goya_cpu_accessible_dma_pool_free(struct hl_device *hdev,
 						size_t size, void *vaddr)
 {
-	/* roundup to CPU_PKT_SIZE */
-	size = (size + (CPU_PKT_SIZE - 1)) & CPU_PKT_MASK;
-
-	gen_pool_free(hdev->cpu_accessible_dma_pool, (u64) (uintptr_t) vaddr,
-			size);
+	hl_fw_cpu_accessible_dma_pool_free(hdev, size, vaddr);
 }
 
 static int goya_dma_map_sg(struct hl_device *hdev, struct scatterlist *sg,
@@ -5032,72 +4885,26 @@ static int goya_mmu_update_asid_hop0_addr(struct hl_device *hdev, u32 asid,
 int goya_send_heartbeat(struct hl_device *hdev)
 {
 	struct goya_device *goya = hdev->asic_specific;
-	struct armcp_packet hb_pkt;
-	long result;
-	int rc;
 
 	if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q))
 		return 0;
 
-	memset(&hb_pkt, 0, sizeof(hb_pkt));
-
-	hb_pkt.ctl = cpu_to_le32(ARMCP_PACKET_TEST <<
-					ARMCP_PKT_CTL_OPCODE_SHIFT);
-	hb_pkt.value = cpu_to_le64(ARMCP_PACKET_FENCE_VAL);
-
-	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &hb_pkt,
-			sizeof(hb_pkt), HL_DEVICE_TIMEOUT_USEC, &result);
-
-	if ((rc) || (result != ARMCP_PACKET_FENCE_VAL))
-		rc = -EIO;
-
-	return rc;
+	return hl_fw_send_heartbeat(hdev);
 }
 
 static int goya_armcp_info_get(struct hl_device *hdev)
 {
 	struct goya_device *goya = hdev->asic_specific;
 	struct asic_fixed_properties *prop = &hdev->asic_prop;
-	struct armcp_packet pkt;
-	void *armcp_info_cpu_addr;
-	dma_addr_t armcp_info_dma_addr;
 	u64 dram_size;
-	long result;
 	int rc;
 
 	if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q))
 		return 0;
 
-	armcp_info_cpu_addr =
-			hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev,
-			sizeof(struct armcp_info), &armcp_info_dma_addr);
-	if (!armcp_info_cpu_addr) {
-		dev_err(hdev->dev,
-			"Failed to allocate DMA memory for ArmCP info packet\n");
-		return -ENOMEM;
-	}
-
-	memset(armcp_info_cpu_addr, 0, sizeof(struct armcp_info));
-
-	memset(&pkt, 0, sizeof(pkt));
-
-	pkt.ctl = cpu_to_le32(ARMCP_PACKET_INFO_GET <<
-				ARMCP_PKT_CTL_OPCODE_SHIFT);
-	pkt.addr = cpu_to_le64(armcp_info_dma_addr +
-				prop->host_phys_base_address);
-	pkt.data_max_size = cpu_to_le32(sizeof(struct armcp_info));
-
-	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-			GOYA_ARMCP_INFO_TIMEOUT, &result);
-
-	if (rc) {
-		dev_err(hdev->dev,
-			"Failed to send armcp info pkt, error %d\n", rc);
-		goto out;
-	}
-
-	memcpy(&prop->armcp_info, armcp_info_cpu_addr,
-			sizeof(prop->armcp_info));
+	rc = hl_fw_armcp_info_get(hdev);
+	if (rc)
+		return rc;
 
 	dram_size = le64_to_cpu(prop->armcp_info.dram_size);
 	if (dram_size) {
@@ -5113,19 +4920,7 @@ static int goya_armcp_info_get(struct hl_device *hdev)
 		prop->dram_end_address = prop->dram_base_address + dram_size;
 	}
 
-	rc = hl_build_hwmon_channel_info(hdev, prop->armcp_info.sensors);
-	if (rc) {
-		dev_err(hdev->dev,
-			"Failed to build hwmon channel info, error %d\n", rc);
-		rc = -EFAULT;
-		goto out;
-	}
-
-out:
-	hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev,
-			sizeof(struct armcp_info), armcp_info_cpu_addr);
-
-	return rc;
+	return 0;
 }
 
 static void goya_init_clock_gating(struct hl_device *hdev)
@@ -5214,52 +5009,11 @@ static int goya_get_eeprom_data(struct hl_device *hdev, void *data,
 				size_t max_size)
 {
 	struct goya_device *goya = hdev->asic_specific;
-	struct asic_fixed_properties *prop = &hdev->asic_prop;
-	struct armcp_packet pkt;
-	void *eeprom_info_cpu_addr;
-	dma_addr_t eeprom_info_dma_addr;
-	long result;
-	int rc;
 
 	if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q))
 		return 0;
 
-	eeprom_info_cpu_addr =
-			hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev,
-					max_size, &eeprom_info_dma_addr);
-	if (!eeprom_info_cpu_addr) {
-		dev_err(hdev->dev,
-			"Failed to allocate DMA memory for EEPROM info packet\n");
-		return -ENOMEM;
-	}
-
-	memset(eeprom_info_cpu_addr, 0, max_size);
-
-	memset(&pkt, 0, sizeof(pkt));
-
-	pkt.ctl = cpu_to_le32(ARMCP_PACKET_EEPROM_DATA_GET <<
-				ARMCP_PKT_CTL_OPCODE_SHIFT);
-	pkt.addr = cpu_to_le64(eeprom_info_dma_addr +
-				prop->host_phys_base_address);
-	pkt.data_max_size = cpu_to_le32(max_size);
-
-	rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-			GOYA_ARMCP_EEPROM_TIMEOUT, &result);
-
-	if (rc) {
-		dev_err(hdev->dev,
-			"Failed to send armcp EEPROM pkt, error %d\n", rc);
-		goto out;
-	}
-
-	/* result contains the actual size */
-	memcpy(data, eeprom_info_cpu_addr, min((size_t)result, max_size));
-
-out:
-	hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev, max_size,
-			eeprom_info_cpu_addr);
-
-	return rc;
+	return hl_fw_get_eeprom_data(hdev, data, max_size);
 }
 
 static enum hl_device_hw_state goya_get_hw_state(struct hl_device *hdev)
diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h
index 830551b6b062..6fdc76b5bde0 100644
--- a/drivers/misc/habanalabs/goya/goyaP.h
+++ b/drivers/misc/habanalabs/goya/goyaP.h
@@ -49,9 +49,6 @@
 
 #define MAX_POWER_DEFAULT		200000		/* 200W */
 
-#define GOYA_ARMCP_INFO_TIMEOUT		10000000	/* 10s */
-#define GOYA_ARMCP_EEPROM_TIMEOUT	10000000	/* 10s */
-
 #define DRAM_PHYS_DEFAULT_SIZE		0x100000000ull	/* 4GB */
 
 /* DRAM Memory Map */
@@ -142,13 +139,6 @@
 #define HW_CAP_GOLDEN		0x00000400
 #define HW_CAP_TPC		0x00000800
 
-#define CPU_PKT_SHIFT		5
-#define CPU_PKT_SIZE		(1 << CPU_PKT_SHIFT)
-#define CPU_PKT_MASK		(~((1 << CPU_PKT_SHIFT) - 1))
-#define CPU_MAX_PKTS_IN_CB	32
-#define CPU_CB_SIZE		(CPU_PKT_SIZE * CPU_MAX_PKTS_IN_CB)
-#define CPU_ACCESSIBLE_MEM_SIZE	(HL_QUEUE_LENGTH * CPU_CB_SIZE)
-
 enum goya_fw_component {
 	FW_COMP_UBOOT,
 	FW_COMP_PREBOOT
@@ -192,7 +182,6 @@ void goya_init_security(struct hl_device *hdev);
 u64 goya_get_max_power(struct hl_device *hdev);
 void goya_set_max_power(struct hl_device *hdev, u64 value);
 
-int goya_send_pci_access_msg(struct hl_device *hdev, u32 opcode);
 void goya_late_fini(struct hl_device *hdev);
 int goya_suspend(struct hl_device *hdev);
 int goya_resume(struct hl_device *hdev);
diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h
index a8ee52c880cd..1445ba1cafd4 100644
--- a/drivers/misc/habanalabs/habanalabs.h
+++ b/drivers/misc/habanalabs/habanalabs.h
@@ -33,6 +33,9 @@
 
 #define HL_PLL_LOW_JOB_FREQ_USEC	5000000 /* 5 s */
 
+#define HL_ARMCP_INFO_TIMEOUT_USEC	10000000 /* 10s */
+#define HL_ARMCP_EEPROM_TIMEOUT_USEC	10000000 /* 10s */
+
 #define HL_MAX_QUEUES			128
 
 #define HL_MAX_JOBS_PER_CS		64
@@ -1351,6 +1354,20 @@ int hl_mmu_unmap(struct hl_ctx *ctx, u64 virt_addr, u32 page_size);
 void hl_mmu_swap_out(struct hl_ctx *ctx);
 void hl_mmu_swap_in(struct hl_ctx *ctx);
 
+int hl_fw_push_fw_to_device(struct hl_device *hdev, const char *fw_name,
+				void __iomem *dst);
+int hl_fw_send_pci_access_msg(struct hl_device *hdev, u32 opcode);
+int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
+				u16 len, u32 timeout, long *result);
+int hl_fw_test_cpu_queue(struct hl_device *hdev);
+void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
+						dma_addr_t *dma_handle);
+void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
+					void *vaddr);
+int hl_fw_send_heartbeat(struct hl_device *hdev);
+int hl_fw_armcp_info_get(struct hl_device *hdev);
+int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size);
+
 long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr);
 void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq);
 long hl_get_temperature(struct hl_device *hdev, int sensor_index, u32 attr);
diff --git a/drivers/misc/habanalabs/include/armcp_if.h b/drivers/misc/habanalabs/include/armcp_if.h
index 9dddb917e72c..ccb82390241e 100644
--- a/drivers/misc/habanalabs/include/armcp_if.h
+++ b/drivers/misc/habanalabs/include/armcp_if.h
@@ -302,6 +302,14 @@ enum armcp_pwm_attributes {
 	armcp_pwm_enable
 };
 
+#define HL_CPU_PKT_SHIFT		5
+#define HL_CPU_PKT_SIZE			(1 << HL_CPU_PKT_SHIFT)
+#define HL_CPU_PKT_MASK			(~((1 << HL_CPU_PKT_SHIFT) - 1))
+#define HL_CPU_MAX_PKTS_IN_CB		32
+#define HL_CPU_CB_SIZE			(HL_CPU_PKT_SIZE * \
+					 HL_CPU_MAX_PKTS_IN_CB)
+#define HL_CPU_ACCESSIBLE_MEM_SIZE	(HL_QUEUE_LENGTH * HL_CPU_CB_SIZE)
+
 /* Event Queue Packets */
 
 struct eq_generic_event {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/15] habanalabs: use EQ MSI/X ID per chip
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (3 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 04/15] habanalabs: Move device CPU code into common file Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 06/15] habanalabs: remove unused defines Oded Gabbay
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

The Event Queue MSI/X ID is different per ASIC. This patch renames the
current define to have the GOYA_ prefix to mark it only for Goya. It also
moves it from the common armcp_if.h file to the ASIC specific goya_fw_if.h
file.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya.c               | 8 ++++----
 drivers/misc/habanalabs/include/armcp_if.h        | 2 --
 drivers/misc/habanalabs/include/goya/goya_fw_if.h | 2 ++
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index a578d01a56a6..6ba0faa979bd 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -2205,10 +2205,10 @@ static int goya_enable_msix(struct hl_device *hdev)
 		}
 	}
 
-	irq = pci_irq_vector(hdev->pdev, EVENT_QUEUE_MSIX_IDX);
+	irq = pci_irq_vector(hdev->pdev, GOYA_EVENT_QUEUE_MSIX_IDX);
 
 	rc = request_irq(irq, hl_irq_handler_eq, 0,
-			goya_irq_name[EVENT_QUEUE_MSIX_IDX],
+			goya_irq_name[GOYA_EVENT_QUEUE_MSIX_IDX],
 			&hdev->event_queue);
 	if (rc) {
 		dev_err(hdev->dev, "Failed to request IRQ %d", irq);
@@ -2239,7 +2239,7 @@ static void goya_sync_irqs(struct hl_device *hdev)
 	for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
 		synchronize_irq(pci_irq_vector(hdev->pdev, i));
 
-	synchronize_irq(pci_irq_vector(hdev->pdev, EVENT_QUEUE_MSIX_IDX));
+	synchronize_irq(pci_irq_vector(hdev->pdev, GOYA_EVENT_QUEUE_MSIX_IDX));
 }
 
 static void goya_disable_msix(struct hl_device *hdev)
@@ -2252,7 +2252,7 @@ static void goya_disable_msix(struct hl_device *hdev)
 
 	goya_sync_irqs(hdev);
 
-	irq = pci_irq_vector(hdev->pdev, EVENT_QUEUE_MSIX_IDX);
+	irq = pci_irq_vector(hdev->pdev, GOYA_EVENT_QUEUE_MSIX_IDX);
 	free_irq(irq, &hdev->event_queue);
 
 	for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) {
diff --git a/drivers/misc/habanalabs/include/armcp_if.h b/drivers/misc/habanalabs/include/armcp_if.h
index ccb82390241e..c8f28cadc335 100644
--- a/drivers/misc/habanalabs/include/armcp_if.h
+++ b/drivers/misc/habanalabs/include/armcp_if.h
@@ -32,8 +32,6 @@ struct hl_eq_entry {
 #define EQ_CTL_EVENT_TYPE_SHIFT		16
 #define EQ_CTL_EVENT_TYPE_MASK		0x03FF0000
 
-#define EVENT_QUEUE_MSIX_IDX		5
-
 enum pq_init_status {
 	PQ_INIT_STATUS_NA = 0,
 	PQ_INIT_STATUS_READY_FOR_CP,
diff --git a/drivers/misc/habanalabs/include/goya/goya_fw_if.h b/drivers/misc/habanalabs/include/goya/goya_fw_if.h
index a9920cb4a07b..0fa80fe9f6cc 100644
--- a/drivers/misc/habanalabs/include/goya/goya_fw_if.h
+++ b/drivers/misc/habanalabs/include/goya/goya_fw_if.h
@@ -8,6 +8,8 @@
 #ifndef GOYA_FW_IF_H
 #define GOYA_FW_IF_H
 
+#define GOYA_EVENT_QUEUE_MSIX_IDX	5
+
 #define CPU_BOOT_ADDR		0x7FF8040000ull
 
 #define UBOOT_FW_OFFSET		0x100000		/* 1MB in SRAM */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/15] habanalabs: remove unused defines
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (4 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 05/15] habanalabs: use EQ MSI/X ID per chip Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 07/15] habanalabs: ratelimit warnings at start of IOCTLs Oded Gabbay
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

This patch removes some old defines which are not in use anymore.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goyaP.h | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h
index 6fdc76b5bde0..ae5e41bc8f7f 100644
--- a/drivers/misc/habanalabs/goya/goyaP.h
+++ b/drivers/misc/habanalabs/goya/goyaP.h
@@ -54,11 +54,9 @@
 /* DRAM Memory Map */
 
 #define CPU_FW_IMAGE_SIZE		0x10000000	/* 256MB */
-#define MMU_PAGE_TABLES_SIZE		0x0DE00000	/* 222MB */
+#define MMU_PAGE_TABLES_SIZE		0x0FC00000	/* 252MB */
 #define MMU_DRAM_DEFAULT_PAGE_SIZE	0x00200000	/* 2MB */
 #define MMU_CACHE_MNG_SIZE		0x00001000	/* 4KB */
-#define CPU_PQ_PKT_SIZE			0x00001000	/* 4KB */
-#define CPU_PQ_DATA_SIZE		0x01FFE000	/* 32MB - 8KB  */
 
 #define CPU_FW_IMAGE_ADDR		DRAM_PHYS_BASE
 #define MMU_PAGE_TABLES_ADDR		(CPU_FW_IMAGE_ADDR + CPU_FW_IMAGE_SIZE)
@@ -66,13 +64,13 @@
 						MMU_PAGE_TABLES_SIZE)
 #define MMU_CACHE_MNG_ADDR		(MMU_DRAM_DEFAULT_PAGE_ADDR + \
 					MMU_DRAM_DEFAULT_PAGE_SIZE)
-#define CPU_PQ_PKT_ADDR			(MMU_CACHE_MNG_ADDR + \
+#define DRAM_KMD_END_ADDR		(MMU_CACHE_MNG_ADDR + \
 						MMU_CACHE_MNG_SIZE)
-#define CPU_PQ_DATA_ADDR		(CPU_PQ_PKT_ADDR + CPU_PQ_PKT_SIZE)
-#define DRAM_BASE_ADDR_USER		(CPU_PQ_DATA_ADDR + CPU_PQ_DATA_SIZE)
 
-#if (DRAM_BASE_ADDR_USER != 0x20000000)
-#error "KMD must reserve 512MB"
+#define DRAM_BASE_ADDR_USER		0x20000000
+
+#if (DRAM_KMD_END_ADDR > DRAM_BASE_ADDR_USER)
+#error "KMD must reserve no more than 512MB"
 #endif
 
 /*
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/15] habanalabs: ratelimit warnings at start of IOCTLs
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (5 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 06/15] habanalabs: remove unused defines Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 08/15] habanalabs: Move PCI code into common file Oded Gabbay
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

At the start of some IOCTLs we check if the device is disabled or in reset.
If it is, we return -EBUSY and print a message to kernel log.

Because these IOCTLs can be called at very high frequency, use ratelimit
to avoid spamming the kernel log. Also use the same type of message -
dev_warn - in all the relevant IOCTLs.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/command_submission.c | 2 +-
 drivers/misc/habanalabs/habanalabs_ioctl.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/habanalabs/command_submission.c b/drivers/misc/habanalabs/command_submission.c
index 19c84214a7ea..f908643f871f 100644
--- a/drivers/misc/habanalabs/command_submission.c
+++ b/drivers/misc/habanalabs/command_submission.c
@@ -604,7 +604,7 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data)
 	bool need_soft_reset = false;
 
 	if (hl_device_disabled_or_in_reset(hdev)) {
-		dev_warn(hdev->dev,
+		dev_warn_ratelimited(hdev->dev,
 			"Device is %s. Can't submit new CS\n",
 			atomic_read(&hdev->in_reset) ? "in_reset" : "disabled");
 		rc = -EBUSY;
diff --git a/drivers/misc/habanalabs/habanalabs_ioctl.c b/drivers/misc/habanalabs/habanalabs_ioctl.c
index 2c2739a3c5ec..19b96afc0308 100644
--- a/drivers/misc/habanalabs/habanalabs_ioctl.c
+++ b/drivers/misc/habanalabs/habanalabs_ioctl.c
@@ -106,7 +106,7 @@ static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data)
 	int rc;
 
 	if (hl_device_disabled_or_in_reset(hdev)) {
-		dev_err(hdev->dev,
+		dev_warn_ratelimited(hdev->dev,
 			"Device is disabled or in reset. Can't execute INFO IOCTL\n");
 		return -EBUSY;
 	}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/15] habanalabs: Move PCI code into common file
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (6 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 07/15] habanalabs: ratelimit warnings at start of IOCTLs Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 09/15] habanalabs: Remove unneeded function pointers Oded Gabbay
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Tomer Tayar

From: Tomer Tayar <ttayar@habana.ai>

Move duplicated PCI-related code from ASIC-specific files into the common
pci.c file.

Signed-off-by: Tomer Tayar <ttayar@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/Makefile              |   2 +-
 drivers/misc/habanalabs/goya/goya.c           | 272 +------------
 drivers/misc/habanalabs/habanalabs.h          |  20 +
 .../include/goya/asic_reg/goya_masks.h        |  12 -
 .../include/hw_ip/pci/pci_general.h           |  23 ++
 drivers/misc/habanalabs/pci.c                 | 370 ++++++++++++++++++
 6 files changed, 434 insertions(+), 265 deletions(-)
 create mode 100644 drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h
 create mode 100644 drivers/misc/habanalabs/pci.c

diff --git a/drivers/misc/habanalabs/Makefile b/drivers/misc/habanalabs/Makefile
index 598740d235f8..f8e85243d672 100644
--- a/drivers/misc/habanalabs/Makefile
+++ b/drivers/misc/habanalabs/Makefile
@@ -6,7 +6,7 @@ obj-m	:= habanalabs.o
 
 habanalabs-y := habanalabs_drv.o device.o context.o asid.o habanalabs_ioctl.o \
 		command_buffer.o hw_queue.o irq.o sysfs.o hwmon.o memory.o \
-		command_submission.o mmu.o firmware_if.o
+		command_submission.o mmu.o firmware_if.o pci.o
 
 habanalabs-$(CONFIG_DEBUG_FS) += debugfs.o
 
diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index 6ba0faa979bd..7e98383ec774 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -364,12 +364,13 @@ static void goya_get_fixed_properties(struct hl_device *hdev)
 	prop->cfg_size = CFG_SIZE;
 	prop->max_asid = MAX_ASID;
 	prop->num_of_events = GOYA_ASYNC_EVENT_ID_SIZE;
+	prop->high_pll = PLL_HIGH_DEFAULT;
 	prop->cb_pool_cb_cnt = GOYA_CB_POOL_CB_CNT;
 	prop->cb_pool_cb_size = GOYA_CB_POOL_CB_SIZE;
 	prop->max_power_default = MAX_POWER_DEFAULT;
 	prop->tpc_enabled_mask = TPC_ENABLED_MASK;
-
-	prop->high_pll = PLL_HIGH_DEFAULT;
+	prop->pcie_dbi_base_address = mmPCIE_DBI_BASE;
+	prop->pcie_aux_dbi_reg_addr = CFG_BASE + mmPCIE_AUX_DBI;
 }
 
 /*
@@ -383,161 +384,20 @@ static void goya_get_fixed_properties(struct hl_device *hdev)
  */
 static int goya_pci_bars_map(struct hl_device *hdev)
 {
-	struct pci_dev *pdev = hdev->pdev;
+	static const char * const name[] = {"SRAM_CFG", "MSIX", "DDR"};
+	bool is_wc[3] = {false, false, true};
 	int rc;
 
-	rc = pci_request_regions(pdev, HL_NAME);
-	if (rc) {
-		dev_err(hdev->dev, "Cannot obtain PCI resources\n");
+	rc = hl_pci_bars_map(hdev, name, is_wc);
+	if (rc)
 		return rc;
-	}
-
-	hdev->pcie_bar[SRAM_CFG_BAR_ID] =
-			pci_ioremap_bar(pdev, SRAM_CFG_BAR_ID);
-	if (!hdev->pcie_bar[SRAM_CFG_BAR_ID]) {
-		dev_err(hdev->dev, "pci_ioremap_bar failed for CFG\n");
-		rc = -ENODEV;
-		goto err_release_regions;
-	}
-
-	hdev->pcie_bar[MSIX_BAR_ID] = pci_ioremap_bar(pdev, MSIX_BAR_ID);
-	if (!hdev->pcie_bar[MSIX_BAR_ID]) {
-		dev_err(hdev->dev, "pci_ioremap_bar failed for MSIX\n");
-		rc = -ENODEV;
-		goto err_unmap_sram_cfg;
-	}
-
-	hdev->pcie_bar[DDR_BAR_ID] = pci_ioremap_wc_bar(pdev, DDR_BAR_ID);
-	if (!hdev->pcie_bar[DDR_BAR_ID]) {
-		dev_err(hdev->dev, "pci_ioremap_bar failed for DDR\n");
-		rc = -ENODEV;
-		goto err_unmap_msix;
-	}
 
 	hdev->rmmio = hdev->pcie_bar[SRAM_CFG_BAR_ID] +
-				(CFG_BASE - SRAM_BASE_ADDR);
-
-	return 0;
-
-err_unmap_msix:
-	iounmap(hdev->pcie_bar[MSIX_BAR_ID]);
-err_unmap_sram_cfg:
-	iounmap(hdev->pcie_bar[SRAM_CFG_BAR_ID]);
-err_release_regions:
-	pci_release_regions(pdev);
-
-	return rc;
-}
-
-/*
- * goya_pci_bars_unmap - Unmap PCI BARS of Goya device
- *
- * @hdev: pointer to hl_device structure
- *
- * Release all PCI BARS and unmap their virtual addresses
- *
- */
-static void goya_pci_bars_unmap(struct hl_device *hdev)
-{
-	struct pci_dev *pdev = hdev->pdev;
-
-	iounmap(hdev->pcie_bar[DDR_BAR_ID]);
-	iounmap(hdev->pcie_bar[MSIX_BAR_ID]);
-	iounmap(hdev->pcie_bar[SRAM_CFG_BAR_ID]);
-	pci_release_regions(pdev);
-}
-
-/*
- * goya_elbi_write - Write through the ELBI interface
- *
- * @hdev: pointer to hl_device structure
- *
- * return 0 on success, -1 on failure
- *
- */
-static int goya_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
-{
-	struct pci_dev *pdev = hdev->pdev;
-	ktime_t timeout;
-	u32 val;
-
-	/* Clear previous status */
-	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0);
-
-	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_ADDR, (u32) addr);
-	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data);
-	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL,
-				PCI_CONFIG_ELBI_CTRL_WRITE);
-
-	timeout = ktime_add_ms(ktime_get(), 10);
-	for (;;) {
-		pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val);
-		if (val & PCI_CONFIG_ELBI_STS_MASK)
-			break;
-		if (ktime_compare(ktime_get(), timeout) > 0) {
-			pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS,
-						&val);
-			break;
-		}
-		usleep_range(300, 500);
-	}
-
-	if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE)
-		return 0;
-
-	if (val & PCI_CONFIG_ELBI_STS_ERR) {
-		dev_err(hdev->dev, "Error writing to ELBI\n");
-		return -EIO;
-	}
-
-	if (!(val & PCI_CONFIG_ELBI_STS_MASK)) {
-		dev_err(hdev->dev, "ELBI write didn't finish in time\n");
-		return -EIO;
-	}
-
-	dev_err(hdev->dev, "ELBI write has undefined bits in status\n");
-	return -EIO;
-}
-
-/*
- * goya_iatu_write - iatu write routine
- *
- * @hdev: pointer to hl_device structure
- *
- */
-static int goya_iatu_write(struct hl_device *hdev, u32 addr, u32 data)
-{
-	u32 dbi_offset;
-	int rc;
-
-	dbi_offset = addr & 0xFFF;
-
-	rc = goya_elbi_write(hdev, CFG_BASE + mmPCIE_AUX_DBI, 0x00300000);
-	rc |= goya_elbi_write(hdev, mmPCIE_DBI_BASE + dbi_offset, data);
-
-	if (rc)
-		return -EIO;
+			(CFG_BASE - SRAM_BASE_ADDR);
 
 	return 0;
 }
 
-static void goya_reset_link_through_bridge(struct hl_device *hdev)
-{
-	struct pci_dev *pdev = hdev->pdev;
-	struct pci_dev *parent_port;
-	u16 val;
-
-	parent_port = pdev->bus->self;
-	pci_read_config_word(parent_port, PCI_BRIDGE_CONTROL, &val);
-	val |= PCI_BRIDGE_CTL_BUS_RESET;
-	pci_write_config_word(parent_port, PCI_BRIDGE_CONTROL, val);
-	ssleep(1);
-
-	val &= ~(PCI_BRIDGE_CTL_BUS_RESET);
-	pci_write_config_word(parent_port, PCI_BRIDGE_CONTROL, val);
-	ssleep(3);
-}
-
 /*
  * goya_set_ddr_bar_base - set DDR bar to map specific device address
  *
@@ -557,20 +417,9 @@ static int goya_set_ddr_bar_base(struct hl_device *hdev, u64 addr)
 		return 0;
 
 	/* Inbound Region 1 - Bar 4 - Point to DDR */
-	rc = goya_iatu_write(hdev, 0x314, lower_32_bits(addr));
-	rc |= goya_iatu_write(hdev, 0x318, upper_32_bits(addr));
-	rc |= goya_iatu_write(hdev, 0x300, 0);
-	/* Enable + Bar match + match enable + Bar 4 */
-	rc |= goya_iatu_write(hdev, 0x304, 0xC0080400);
-
-	/* Return the DBI window to the default location */
-	rc |= goya_elbi_write(hdev, CFG_BASE + mmPCIE_AUX_DBI, 0);
-	rc |= goya_elbi_write(hdev, CFG_BASE + mmPCIE_AUX_DBI_32, 0);
-
-	if (rc) {
-		dev_err(hdev->dev, "failed to map DDR bar to 0x%08llx\n", addr);
-		return -EIO;
-	}
+	rc = hl_pci_set_dram_bar_base(hdev, 1, 4, addr);
+	if (rc)
+		return rc;
 
 	if (goya)
 		goya->ddr_bar_cur_addr = addr;
@@ -588,40 +437,8 @@ static int goya_set_ddr_bar_base(struct hl_device *hdev, u64 addr)
  */
 static int goya_init_iatu(struct hl_device *hdev)
 {
-	int rc;
-
-	/* Inbound Region 0 - Bar 0 - Point to SRAM_BASE_ADDR */
-	rc  = goya_iatu_write(hdev, 0x114, lower_32_bits(SRAM_BASE_ADDR));
-	rc |= goya_iatu_write(hdev, 0x118, upper_32_bits(SRAM_BASE_ADDR));
-	rc |= goya_iatu_write(hdev, 0x100, 0);
-	/* Enable + Bar match + match enable */
-	rc |= goya_iatu_write(hdev, 0x104, 0xC0080000);
-
-	/* Inbound Region 1 - Bar 4 - Point to DDR */
-	rc |= goya_set_ddr_bar_base(hdev, DRAM_PHYS_BASE);
-
-	/* Outbound Region 0 - Point to Host */
-	rc |= goya_iatu_write(hdev, 0x008, lower_32_bits(HOST_PHYS_BASE));
-	rc |= goya_iatu_write(hdev, 0x00C, upper_32_bits(HOST_PHYS_BASE));
-	rc |= goya_iatu_write(hdev, 0x010,
-		lower_32_bits(HOST_PHYS_BASE + HOST_PHYS_SIZE - 1));
-	rc |= goya_iatu_write(hdev, 0x014, 0);
-	rc |= goya_iatu_write(hdev, 0x018, 0);
-	rc |= goya_iatu_write(hdev, 0x020,
-		upper_32_bits(HOST_PHYS_BASE + HOST_PHYS_SIZE - 1));
-	/* Increase region size */
-	rc |= goya_iatu_write(hdev, 0x000, 0x00002000);
-	/* Enable */
-	rc |= goya_iatu_write(hdev, 0x004, 0x80000000);
-
-	/* Return the DBI window to the default location */
-	rc |= goya_elbi_write(hdev, CFG_BASE + mmPCIE_AUX_DBI, 0);
-	rc |= goya_elbi_write(hdev, CFG_BASE + mmPCIE_AUX_DBI_32, 0);
-
-	if (rc)
-		return -EIO;
-
-	return 0;
+	return hl_pci_init_iatu(hdev, SRAM_BASE_ADDR, DRAM_PHYS_BASE,
+				HOST_PHYS_SIZE);
 }
 
 /*
@@ -667,52 +484,9 @@ static int goya_early_init(struct hl_device *hdev)
 
 	prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
 
-	/* set DMA mask for GOYA */
-	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(39));
-	if (rc) {
-		dev_warn(hdev->dev, "Unable to set pci dma mask to 39 bits\n");
-		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_err(hdev->dev,
-				"Unable to set pci dma mask to 32 bits\n");
-			return rc;
-		}
-	}
-
-	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(39));
-	if (rc) {
-		dev_warn(hdev->dev,
-			"Unable to set pci consistent dma mask to 39 bits\n");
-		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_err(hdev->dev,
-				"Unable to set pci consistent dma mask to 32 bits\n");
-			return rc;
-		}
-	}
-
-	if (hdev->reset_pcilink)
-		goya_reset_link_through_bridge(hdev);
-
-	rc = pci_enable_device_mem(pdev);
-	if (rc) {
-		dev_err(hdev->dev, "can't enable PCI device\n");
+	rc = hl_pci_init(hdev);
+	if (rc)
 		return rc;
-	}
-
-	pci_set_master(pdev);
-
-	rc = goya_init_iatu(hdev);
-	if (rc) {
-		dev_err(hdev->dev, "Failed to initialize iATU\n");
-		goto disable_device;
-	}
-
-	rc = goya_pci_bars_map(hdev);
-	if (rc) {
-		dev_err(hdev->dev, "Failed to initialize PCI BARS\n");
-		goto disable_device;
-	}
 
 	if (!hdev->pldm) {
 		val = RREG32(mmPSOC_GLOBAL_CONF_BOOT_STRAP_PINS);
@@ -722,12 +496,6 @@ static int goya_early_init(struct hl_device *hdev)
 	}
 
 	return 0;
-
-disable_device:
-	pci_clear_master(pdev);
-	pci_disable_device(pdev);
-
-	return rc;
 }
 
 /*
@@ -740,10 +508,7 @@ static int goya_early_init(struct hl_device *hdev)
  */
 static int goya_early_fini(struct hl_device *hdev)
 {
-	goya_pci_bars_unmap(hdev);
-
-	pci_clear_master(hdev->pdev);
-	pci_disable_device(hdev->pdev);
+	hl_pci_fini(hdev);
 
 	return 0;
 }
@@ -5072,7 +4837,10 @@ static const struct hl_asic_funcs goya_funcs = {
 	.get_pci_id = goya_get_pci_id,
 	.get_eeprom_data = goya_get_eeprom_data,
 	.send_cpu_message = goya_send_cpu_message,
-	.get_hw_state = goya_get_hw_state
+	.get_hw_state = goya_get_hw_state,
+	.pci_bars_map = goya_pci_bars_map,
+	.set_dram_bar_base = goya_set_ddr_bar_base,
+	.init_iatu = goya_init_iatu
 };
 
 /*
diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h
index 1445ba1cafd4..ed3649d38ff8 100644
--- a/drivers/misc/habanalabs/habanalabs.h
+++ b/drivers/misc/habanalabs/habanalabs.h
@@ -148,6 +148,8 @@ enum hl_device_hw_state {
  *                             mapping DRAM memory.
  * @dram_size_for_default_page_mapping: DRAM size needed to map to avoid page
  *                                      fault.
+ * @pcie_dbi_base_address: Base address of the PCIE_DBI block.
+ * @pcie_aux_dbi_reg_addr: Address of the PCIE_AUX DBI register.
  * @mmu_pgt_addr: base physical address in DRAM of MMU page tables.
  * @mmu_dram_default_page_addr: DRAM default page physical address.
  * @mmu_pgt_size: MMU page tables total size.
@@ -189,6 +191,8 @@ struct asic_fixed_properties {
 	u64			va_space_dram_start_address;
 	u64			va_space_dram_end_address;
 	u64			dram_size_for_default_page_mapping;
+	u64			pcie_dbi_base_address;
+	u64			pcie_aux_dbi_reg_addr;
 	u64			mmu_pgt_addr;
 	u64			mmu_dram_default_page_addr;
 	u32			mmu_pgt_size;
@@ -485,6 +489,9 @@ enum hl_pll_frequency {
  * @get_eeprom_data: retrieve EEPROM data from F/W.
  * @send_cpu_message: send buffer to ArmCP.
  * @get_hw_state: retrieve the H/W state
+ * @pci_bars_map: Map PCI BARs.
+ * @set_dram_bar_base: Set DRAM BAR to map specific device address.
+ * @init_iatu: Initialize the iATU unit inside the PCI controller.
  */
 struct hl_asic_funcs {
 	int (*early_init)(struct hl_device *hdev);
@@ -558,6 +565,9 @@ struct hl_asic_funcs {
 	int (*send_cpu_message)(struct hl_device *hdev, u32 *msg,
 				u16 len, u32 timeout, long *result);
 	enum hl_device_hw_state (*get_hw_state)(struct hl_device *hdev);
+	int (*pci_bars_map)(struct hl_device *hdev);
+	int (*set_dram_bar_base)(struct hl_device *hdev, u64 addr);
+	int (*init_iatu)(struct hl_device *hdev);
 };
 
 
@@ -1368,6 +1378,16 @@ int hl_fw_send_heartbeat(struct hl_device *hdev);
 int hl_fw_armcp_info_get(struct hl_device *hdev);
 int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size);
 
+int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3],
+			bool is_wc[3]);
+int hl_pci_iatu_write(struct hl_device *hdev, u32 addr, u32 data);
+int hl_pci_set_dram_bar_base(struct hl_device *hdev, u8 inbound_region, u8 bar,
+				u64 addr);
+int hl_pci_init_iatu(struct hl_device *hdev, u64 sram_base_address,
+			u64 dram_base_address, u64 host_phys_size);
+int hl_pci_init(struct hl_device *hdev);
+void hl_pci_fini(struct hl_device *hdev);
+
 long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr);
 void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq);
 long hl_get_temperature(struct hl_device *hdev, int sensor_index, u32 attr);
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h b/drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h
index a161ecfe74de..8618891d5afa 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h
+++ b/drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h
@@ -189,18 +189,6 @@
 			1 << CPU_CA53_CFG_ARM_RST_CONTROL_NL2RESET_SHIFT |\
 			1 << CPU_CA53_CFG_ARM_RST_CONTROL_NMBISTRESET_SHIFT)
 
-/* PCI CONFIGURATION SPACE */
-#define mmPCI_CONFIG_ELBI_ADDR		0xFF0
-#define mmPCI_CONFIG_ELBI_DATA		0xFF4
-#define mmPCI_CONFIG_ELBI_CTRL		0xFF8
-#define PCI_CONFIG_ELBI_CTRL_WRITE	(1 << 31)
-
-#define mmPCI_CONFIG_ELBI_STS		0xFFC
-#define PCI_CONFIG_ELBI_STS_ERR		(1 << 30)
-#define PCI_CONFIG_ELBI_STS_DONE	(1 << 31)
-#define PCI_CONFIG_ELBI_STS_MASK	(PCI_CONFIG_ELBI_STS_ERR | \
-					PCI_CONFIG_ELBI_STS_DONE)
-
 #define GOYA_IRQ_HBW_ID_MASK			0x1FFF
 #define GOYA_IRQ_HBW_ID_SHIFT			0
 #define GOYA_IRQ_HBW_INTERNAL_ID_MASK		0xE000
diff --git a/drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h b/drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h
new file mode 100644
index 000000000000..d232081d4e0f
--- /dev/null
+++ b/drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2016-2019 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+#ifndef INCLUDE_PCI_GENERAL_H_
+#define INCLUDE_PCI_GENERAL_H_
+
+/* PCI CONFIGURATION SPACE */
+#define mmPCI_CONFIG_ELBI_ADDR		0xFF0
+#define mmPCI_CONFIG_ELBI_DATA		0xFF4
+#define mmPCI_CONFIG_ELBI_CTRL		0xFF8
+#define PCI_CONFIG_ELBI_CTRL_WRITE	(1 << 31)
+
+#define mmPCI_CONFIG_ELBI_STS		0xFFC
+#define PCI_CONFIG_ELBI_STS_ERR		(1 << 30)
+#define PCI_CONFIG_ELBI_STS_DONE	(1 << 31)
+#define PCI_CONFIG_ELBI_STS_MASK	(PCI_CONFIG_ELBI_STS_ERR | \
+					PCI_CONFIG_ELBI_STS_DONE)
+
+#endif /* INCLUDE_PCI_GENERAL_H_ */
diff --git a/drivers/misc/habanalabs/pci.c b/drivers/misc/habanalabs/pci.c
new file mode 100644
index 000000000000..822ac110b997
--- /dev/null
+++ b/drivers/misc/habanalabs/pci.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2016-2019 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ */
+
+#include "habanalabs.h"
+#include "include/hw_ip/pci/pci_general.h"
+
+#include <linux/pci.h>
+
+/**
+ * hl_pci_bars_map() - Map PCI BARs.
+ * @hdev: Pointer to hl_device structure.
+ * @bar_name: Array of BAR names.
+ * @is_wc: Array with flag per BAR whether a write-combined mapping is needed.
+ *
+ * Request PCI regions and map them to kernel virtual addresses.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3],
+			bool is_wc[3])
+{
+	struct pci_dev *pdev = hdev->pdev;
+	int rc, i, bar;
+
+	rc = pci_request_regions(pdev, HL_NAME);
+	if (rc) {
+		dev_err(hdev->dev, "Cannot obtain PCI resources\n");
+		return rc;
+	}
+
+	for (i = 0 ; i < 3 ; i++) {
+		bar = i * 2; /* 64-bit BARs */
+		hdev->pcie_bar[bar] = is_wc[i] ?
+				pci_ioremap_wc_bar(pdev, bar) :
+				pci_ioremap_bar(pdev, bar);
+		if (!hdev->pcie_bar[bar]) {
+			dev_err(hdev->dev, "pci_ioremap%s_bar failed for %s\n",
+					is_wc[i] ? "_wc" : "", name[i]);
+			rc = -ENODEV;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	for (i = 2 ; i >= 0 ; i--) {
+		bar = i * 2; /* 64-bit BARs */
+		if (hdev->pcie_bar[bar])
+			iounmap(hdev->pcie_bar[bar]);
+	}
+
+	pci_release_regions(pdev);
+
+	return rc;
+}
+
+/*
+ * hl_pci_bars_unmap() - Unmap PCI BARS.
+ * @hdev: Pointer to hl_device structure.
+ *
+ * Release all PCI BARs and unmap their virtual addresses.
+ */
+static void hl_pci_bars_unmap(struct hl_device *hdev)
+{
+	struct pci_dev *pdev = hdev->pdev;
+	int i, bar;
+
+	for (i = 2 ; i >= 0 ; i--) {
+		bar = i * 2; /* 64-bit BARs */
+		iounmap(hdev->pcie_bar[bar]);
+	}
+
+	pci_release_regions(pdev);
+}
+
+/*
+ * hl_pci_elbi_write() - Write through the ELBI interface.
+ * @hdev: Pointer to hl_device structure.
+ *
+ * Return: 0 on success, negative value for failure.
+ */
+static int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
+{
+	struct pci_dev *pdev = hdev->pdev;
+	ktime_t timeout;
+	u32 val;
+
+	/* Clear previous status */
+	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0);
+
+	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_ADDR, (u32) addr);
+	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data);
+	pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL,
+				PCI_CONFIG_ELBI_CTRL_WRITE);
+
+	timeout = ktime_add_ms(ktime_get(), 10);
+	for (;;) {
+		pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val);
+		if (val & PCI_CONFIG_ELBI_STS_MASK)
+			break;
+		if (ktime_compare(ktime_get(), timeout) > 0) {
+			pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS,
+						&val);
+			break;
+		}
+
+		usleep_range(300, 500);
+	}
+
+	if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE)
+		return 0;
+
+	if (val & PCI_CONFIG_ELBI_STS_ERR) {
+		dev_err(hdev->dev, "Error writing to ELBI\n");
+		return -EIO;
+	}
+
+	if (!(val & PCI_CONFIG_ELBI_STS_MASK)) {
+		dev_err(hdev->dev, "ELBI write didn't finish in time\n");
+		return -EIO;
+	}
+
+	dev_err(hdev->dev, "ELBI write has undefined bits in status\n");
+	return -EIO;
+}
+
+/**
+ * hl_pci_iatu_write() - iatu write routine.
+ * @hdev: Pointer to hl_device structure.
+ *
+ * Return: 0 on success, negative value for failure.
+ */
+int hl_pci_iatu_write(struct hl_device *hdev, u32 addr, u32 data)
+{
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	u32 dbi_offset;
+	int rc;
+
+	dbi_offset = addr & 0xFFF;
+
+	rc = hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr, 0x00300000);
+	rc |= hl_pci_elbi_write(hdev, prop->pcie_dbi_base_address + dbi_offset,
+				data);
+
+	if (rc)
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * hl_pci_reset_link_through_bridge() - Reset PCI link.
+ * @hdev: Pointer to hl_device structure.
+ */
+static void hl_pci_reset_link_through_bridge(struct hl_device *hdev)
+{
+	struct pci_dev *pdev = hdev->pdev;
+	struct pci_dev *parent_port;
+	u16 val;
+
+	parent_port = pdev->bus->self;
+	pci_read_config_word(parent_port, PCI_BRIDGE_CONTROL, &val);
+	val |= PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(parent_port, PCI_BRIDGE_CONTROL, val);
+	ssleep(1);
+
+	val &= ~(PCI_BRIDGE_CTL_BUS_RESET);
+	pci_write_config_word(parent_port, PCI_BRIDGE_CONTROL, val);
+	ssleep(3);
+}
+
+/**
+ * hl_pci_set_dram_bar_base() - Set DDR BAR to map specific device address.
+ * @hdev: Pointer to hl_device structure.
+ * @inbound_region: Inbound region number.
+ * @bar: PCI BAR number.
+ * @addr: Address in DRAM. Must be aligned to DRAM bar size.
+ *
+ * Configure the iATU so that the DRAM bar will start at the specified address.
+ *
+ * Return: 0 on success, negative value for failure.
+ */
+int hl_pci_set_dram_bar_base(struct hl_device *hdev, u8 inbound_region, u8 bar,
+				u64 addr)
+{
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	u32 offset;
+	int rc;
+
+	switch (inbound_region) {
+	case 0:
+		offset = 0x100;
+		break;
+	case 1:
+		offset = 0x300;
+		break;
+	case 2:
+		offset = 0x500;
+		break;
+	default:
+		dev_err(hdev->dev, "Invalid inbound region %d\n",
+			inbound_region);
+		return -EINVAL;
+	}
+
+	if (bar != 0 && bar != 2 && bar != 4) {
+		dev_err(hdev->dev, "Invalid PCI BAR %d\n", bar);
+		return -EINVAL;
+	}
+
+	/* Point to the specified address */
+	rc = hl_pci_iatu_write(hdev, offset + 0x14, lower_32_bits(addr));
+	rc |= hl_pci_iatu_write(hdev, offset + 0x18, upper_32_bits(addr));
+	rc |= hl_pci_iatu_write(hdev, offset + 0x0, 0);
+	/* Enable + BAR match + match enable + BAR number */
+	rc |= hl_pci_iatu_write(hdev, offset + 0x4, 0xC0080000 | (bar << 8));
+
+	/* Return the DBI window to the default location */
+	rc |= hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr, 0);
+	rc |= hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr + 4, 0);
+
+	if (rc)
+		dev_err(hdev->dev, "failed to map DRAM bar to 0x%08llx\n",
+			addr);
+
+	return rc;
+}
+
+/**
+ * hl_pci_init_iatu() - Initialize the iATU unit inside the PCI controller.
+ * @hdev: Pointer to hl_device structure.
+ * @sram_base_address: SRAM base address.
+ * @dram_base_address: DRAM base address.
+ * @host_phys_size: Size of host memory for device transactions.
+ *
+ * This is needed in case the firmware doesn't initialize the iATU.
+ *
+ * Return: 0 on success, negative value for failure.
+ */
+int hl_pci_init_iatu(struct hl_device *hdev, u64 sram_base_address,
+			u64 dram_base_address, u64 host_phys_size)
+{
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	u64 host_phys_end_addr;
+	int rc = 0;
+
+	/* Inbound Region 0 - Bar 0 - Point to SRAM base address */
+	rc  = hl_pci_iatu_write(hdev, 0x114, lower_32_bits(sram_base_address));
+	rc |= hl_pci_iatu_write(hdev, 0x118, upper_32_bits(sram_base_address));
+	rc |= hl_pci_iatu_write(hdev, 0x100, 0);
+	/* Enable + Bar match + match enable */
+	rc |= hl_pci_iatu_write(hdev, 0x104, 0xC0080000);
+
+	/* Point to DRAM */
+	if (!hdev->asic_funcs->set_dram_bar_base)
+		return -EINVAL;
+	rc |= hdev->asic_funcs->set_dram_bar_base(hdev, dram_base_address);
+
+	/* Outbound Region 0 - Point to Host */
+	host_phys_end_addr = prop->host_phys_base_address + host_phys_size - 1;
+	rc |= hl_pci_iatu_write(hdev, 0x008,
+				lower_32_bits(prop->host_phys_base_address));
+	rc |= hl_pci_iatu_write(hdev, 0x00C,
+				upper_32_bits(prop->host_phys_base_address));
+	rc |= hl_pci_iatu_write(hdev, 0x010, lower_32_bits(host_phys_end_addr));
+	rc |= hl_pci_iatu_write(hdev, 0x014, 0);
+	rc |= hl_pci_iatu_write(hdev, 0x018, 0);
+	rc |= hl_pci_iatu_write(hdev, 0x020, upper_32_bits(host_phys_end_addr));
+	/* Increase region size */
+	rc |= hl_pci_iatu_write(hdev, 0x000, 0x00002000);
+	/* Enable */
+	rc |= hl_pci_iatu_write(hdev, 0x004, 0x80000000);
+
+	/* Return the DBI window to the default location */
+	rc |= hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr, 0);
+	rc |= hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr + 4, 0);
+
+	if (rc)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * hl_pci_init() - PCI initialization code.
+ * @hdev: Pointer to hl_device structure.
+ *
+ * Set DMA masks, initialize the PCI controller and map the PCI BARs.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+int hl_pci_init(struct hl_device *hdev)
+{
+	struct pci_dev *pdev = hdev->pdev;
+	int rc;
+
+	/* set DMA mask */
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(39));
+	if (rc) {
+		dev_warn(hdev->dev, "Unable to set pci dma mask to 39 bits\n");
+		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc) {
+			dev_err(hdev->dev,
+				"Unable to set pci dma mask to 32 bits\n");
+			return rc;
+		}
+	}
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(39));
+	if (rc) {
+		dev_warn(hdev->dev,
+			"Unable to set pci consistent dma mask to 39 bits\n");
+		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc) {
+			dev_err(hdev->dev,
+				"Unable to set pci consistent dma mask to 32 bits\n");
+			return rc;
+		}
+	}
+
+	if (hdev->reset_pcilink)
+		hl_pci_reset_link_through_bridge(hdev);
+
+	rc = pci_enable_device_mem(pdev);
+	if (rc) {
+		dev_err(hdev->dev, "can't enable PCI device\n");
+		return rc;
+	}
+
+	pci_set_master(pdev);
+
+	rc = hdev->asic_funcs->init_iatu(hdev);
+	if (rc) {
+		dev_err(hdev->dev, "Failed to initialize iATU\n");
+		goto disable_device;
+	}
+
+	rc = hdev->asic_funcs->pci_bars_map(hdev);
+	if (rc) {
+		dev_err(hdev->dev, "Failed to initialize PCI BARs\n");
+		goto disable_device;
+	}
+
+	return 0;
+
+disable_device:
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
+
+	return rc;
+}
+
+/**
+ * hl_fw_fini() - PCI finalization code.
+ * @hdev: Pointer to hl_device structure
+ *
+ * Unmap PCI bars and disable PCI device.
+ */
+void hl_pci_fini(struct hl_device *hdev)
+{
+	hl_pci_bars_unmap(hdev);
+
+	pci_clear_master(hdev->pdev);
+	pci_disable_device(hdev->pdev);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/15] habanalabs: Remove unneeded function pointers
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (7 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 08/15] habanalabs: Move PCI code into common file Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 10/15] uapi/habanalabs: add some comments in habanalabs.h Oded Gabbay
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Tomer Tayar

From: Tomer Tayar <ttayar@habana.ai>

Remove pointers to ASIC-specific functions and instead call the functions
explicitly as they are not accessed from outside the ASIC-specific files.

Signed-off-by: Tomer Tayar <ttayar@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya.c  | 12 +++---------
 drivers/misc/habanalabs/goya/goyaP.h |  4 +---
 2 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index 7e98383ec774..466464c026e0 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -299,7 +299,6 @@ static u32 goya_all_events[] = {
 	GOYA_ASYNC_EVENT_ID_DMA_BM_CH4
 };
 
-static int goya_armcp_info_get(struct hl_device *hdev);
 static void goya_mmu_prepare(struct hl_device *hdev, u32 asid);
 static int goya_mmu_clear_pgt_range(struct hl_device *hdev);
 static int goya_mmu_set_dram_default_page(struct hl_device *hdev);
@@ -539,10 +538,9 @@ static void goya_fetch_psoc_frequency(struct hl_device *hdev)
 static int goya_late_init(struct hl_device *hdev)
 {
 	struct asic_fixed_properties *prop = &hdev->asic_prop;
-	struct goya_device *goya = hdev->asic_specific;
 	int rc;
 
-	rc = goya->armcp_info_get(hdev);
+	rc = goya_armcp_info_get(hdev);
 	if (rc) {
 		dev_err(hdev->dev, "Failed to get armcp info\n");
 		return rc;
@@ -629,9 +627,6 @@ static int goya_sw_init(struct hl_device *hdev)
 	if (!goya)
 		return -ENOMEM;
 
-	goya->test_cpu_queue = goya_test_cpu_queue;
-	goya->armcp_info_get = goya_armcp_info_get;
-
 	/* according to goya_init_iatu */
 	goya->ddr_bar_cur_addr = DRAM_PHYS_BASE;
 
@@ -2969,7 +2964,6 @@ int goya_test_cpu_queue(struct hl_device *hdev)
 
 static int goya_test_queues(struct hl_device *hdev)
 {
-	struct goya_device *goya = hdev->asic_specific;
 	int i, rc, ret_val = 0;
 
 	for (i = 0 ; i < NUMBER_OF_EXT_HW_QUEUES ; i++) {
@@ -2979,7 +2973,7 @@ static int goya_test_queues(struct hl_device *hdev)
 	}
 
 	if (hdev->cpu_queues_enable) {
-		rc = goya->test_cpu_queue(hdev);
+		rc = goya_test_cpu_queue(hdev);
 		if (rc)
 			ret_val = -EINVAL;
 	}
@@ -4657,7 +4651,7 @@ int goya_send_heartbeat(struct hl_device *hdev)
 	return hl_fw_send_heartbeat(hdev);
 }
 
-static int goya_armcp_info_get(struct hl_device *hdev)
+int goya_armcp_info_get(struct hl_device *hdev)
 {
 	struct goya_device *goya = hdev->asic_specific;
 	struct asic_fixed_properties *prop = &hdev->asic_prop;
diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h
index ae5e41bc8f7f..b99d92f197eb 100644
--- a/drivers/misc/habanalabs/goya/goyaP.h
+++ b/drivers/misc/habanalabs/goya/goyaP.h
@@ -143,9 +143,6 @@ enum goya_fw_component {
 };
 
 struct goya_device {
-	int (*test_cpu_queue)(struct hl_device *hdev);
-	int (*armcp_info_get)(struct hl_device *hdev);
-
 	/* TODO: remove hw_queues_lock after moving to scheduler code */
 	spinlock_t	hw_queues_lock;
 
@@ -176,6 +173,7 @@ void goya_debugfs_led_set(struct hl_device *hdev, u8 led, u8 state);
 void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq);
 void goya_add_device_attr(struct hl_device *hdev,
 			struct attribute_group *dev_attr_grp);
+int goya_armcp_info_get(struct hl_device *hdev);
 void goya_init_security(struct hl_device *hdev);
 u64 goya_get_max_power(struct hl_device *hdev);
 void goya_set_max_power(struct hl_device *hdev, u64 value);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/15] uapi/habanalabs: add some comments in habanalabs.h
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (8 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 09/15] habanalabs: Remove unneeded function pointers Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 11/15] habanalabs: Add a printout with the name of a busy engine Oded Gabbay
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

This patch adds two comments in uapi/habanalabs.h:
- From which queue id the internal queues begin
- Invalid values that can be returned in the seq field from the CS IOCTL

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 include/uapi/misc/habanalabs.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h
index 7fd6f633534c..ab1957e31077 100644
--- a/include/uapi/misc/habanalabs.h
+++ b/include/uapi/misc/habanalabs.h
@@ -33,7 +33,7 @@ enum goya_queue_id {
 	GOYA_QUEUE_ID_DMA_3,
 	GOYA_QUEUE_ID_DMA_4,
 	GOYA_QUEUE_ID_CPU_PQ,
-	GOYA_QUEUE_ID_MME,
+	GOYA_QUEUE_ID_MME,	/* Internal queues start here */
 	GOYA_QUEUE_ID_TPC0,
 	GOYA_QUEUE_ID_TPC1,
 	GOYA_QUEUE_ID_TPC2,
@@ -181,7 +181,10 @@ struct hl_cs_in {
 };
 
 struct hl_cs_out {
-	/* this holds the sequence number of the CS to pass to wait ioctl */
+	/*
+	 * seq holds the sequence number of the CS to pass to wait ioctl. All
+	 * values are valid except for 0 and ULLONG_MAX
+	 */
 	__u64 seq;
 	/* HL_CS_STATUS_* */
 	__u32 status;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 11/15] habanalabs: Add a printout with the name of a busy engine
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (9 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 10/15] uapi/habanalabs: add some comments in habanalabs.h Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 12/15] habanalabs: Allow accessing DRAM virtual addresses via debugfs Oded Gabbay
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Tomer Tayar

From: Tomer Tayar <ttayar@habana.ai>

Print the name of a busy engine when checking if a device is idle.
The change is done mainly to help a user to pinpoint problems in his
topology's recipe.

Signed-off-by: Tomer Tayar <ttayar@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya.c        | 24 ++++++++++++----------
 drivers/misc/habanalabs/habanalabs.h       |  8 +++++++-
 drivers/misc/habanalabs/habanalabs_ioctl.c |  2 +-
 3 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index 466464c026e0..b474651db0e5 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -2784,6 +2784,7 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
 	dma_addr_t fence_dma_addr;
 	struct hl_cb *cb;
 	u32 tmp, timeout;
+	char buf[16] = {};
 	int rc;
 
 	if (hdev->pldm)
@@ -2791,9 +2792,10 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
 	else
 		timeout = HL_DEVICE_TIMEOUT_USEC;
 
-	if (!hdev->asic_funcs->is_device_idle(hdev)) {
+	if (!hdev->asic_funcs->is_device_idle(hdev, buf, sizeof(buf))) {
 		dev_err_ratelimited(hdev->dev,
-			"Can't send KMD job on QMAN0 if device is not idle\n");
+			"Can't send KMD job on QMAN0 because %s is busy\n",
+			buf);
 		return -EBUSY;
 	}
 
@@ -4692,7 +4694,7 @@ static void goya_disable_clock_gating(struct hl_device *hdev)
 
 }
 
-static bool goya_is_device_idle(struct hl_device *hdev)
+static bool goya_is_device_idle(struct hl_device *hdev, char *buf, size_t size)
 {
 	u64 offset, dma_qm_reg, tpc_qm_reg, tpc_cmdq_reg, tpc_cfg_reg;
 	int i;
@@ -4704,7 +4706,7 @@ static bool goya_is_device_idle(struct hl_device *hdev)
 
 		if ((RREG32(dma_qm_reg) & DMA_QM_IDLE_MASK) !=
 				DMA_QM_IDLE_MASK)
-			return false;
+			return HL_ENG_BUSY(buf, size, "DMA%d_QM", i);
 	}
 
 	offset = mmTPC1_QM_GLBL_STS0 - mmTPC0_QM_GLBL_STS0;
@@ -4716,31 +4718,31 @@ static bool goya_is_device_idle(struct hl_device *hdev)
 
 		if ((RREG32(tpc_qm_reg) & TPC_QM_IDLE_MASK) !=
 				TPC_QM_IDLE_MASK)
-			return false;
+			return HL_ENG_BUSY(buf, size, "TPC%d_QM", i);
 
 		if ((RREG32(tpc_cmdq_reg) & TPC_CMDQ_IDLE_MASK) !=
 				TPC_CMDQ_IDLE_MASK)
-			return false;
+			return HL_ENG_BUSY(buf, size, "TPC%d_CMDQ", i);
 
 		if ((RREG32(tpc_cfg_reg) & TPC_CFG_IDLE_MASK) !=
 				TPC_CFG_IDLE_MASK)
-			return false;
+			return HL_ENG_BUSY(buf, size, "TPC%d_CFG", i);
 	}
 
 	if ((RREG32(mmMME_QM_GLBL_STS0) & MME_QM_IDLE_MASK) !=
 			MME_QM_IDLE_MASK)
-		return false;
+		return HL_ENG_BUSY(buf, size, "MME_QM");
 
 	if ((RREG32(mmMME_CMDQ_GLBL_STS0) & MME_CMDQ_IDLE_MASK) !=
 			MME_CMDQ_IDLE_MASK)
-		return false;
+		return HL_ENG_BUSY(buf, size, "MME_CMDQ");
 
 	if ((RREG32(mmMME_ARCH_STATUS) & MME_ARCH_IDLE_MASK) !=
 			MME_ARCH_IDLE_MASK)
-		return false;
+		return HL_ENG_BUSY(buf, size, "MME_ARCH");
 
 	if (RREG32(mmMME_SHADOW_0_STATUS) & MME_SHADOW_IDLE_MASK)
-		return false;
+		return HL_ENG_BUSY(buf, size, "MME");
 
 	return true;
 }
diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h
index ed3649d38ff8..9cc841777d81 100644
--- a/drivers/misc/habanalabs/habanalabs.h
+++ b/drivers/misc/habanalabs/habanalabs.h
@@ -555,7 +555,7 @@ struct hl_asic_funcs {
 	int (*send_heartbeat)(struct hl_device *hdev);
 	void (*enable_clock_gating)(struct hl_device *hdev);
 	void (*disable_clock_gating)(struct hl_device *hdev);
-	bool (*is_device_idle)(struct hl_device *hdev);
+	bool (*is_device_idle)(struct hl_device *hdev, char *buf, size_t size);
 	int (*soft_reset_late_init)(struct hl_device *hdev);
 	void (*hw_queues_lock)(struct hl_device *hdev);
 	void (*hw_queues_unlock)(struct hl_device *hdev);
@@ -1010,6 +1010,12 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
 	WREG32(mm##reg, (RREG32(mm##reg) & ~REG_FIELD_MASK(reg, field)) | \
 			(val) << REG_FIELD_SHIFT(reg, field))
 
+#define HL_ENG_BUSY(buf, size, fmt, ...) ({ \
+		if (buf) \
+			snprintf(buf, size, fmt, ##__VA_ARGS__); \
+		false; \
+	})
+
 struct hwmon_chip_info;
 
 /**
diff --git a/drivers/misc/habanalabs/habanalabs_ioctl.c b/drivers/misc/habanalabs/habanalabs_ioctl.c
index 19b96afc0308..37f9de8e7404 100644
--- a/drivers/misc/habanalabs/habanalabs_ioctl.c
+++ b/drivers/misc/habanalabs/habanalabs_ioctl.c
@@ -93,7 +93,7 @@ static int hw_idle(struct hl_device *hdev, struct hl_info_args *args)
 	if ((!max_size) || (!out))
 		return -EINVAL;
 
-	hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev);
+	hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev, NULL, 0);
 
 	return copy_to_user(out, &hw_idle,
 		min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 12/15] habanalabs: Allow accessing DRAM virtual addresses via debugfs
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (10 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 11/15] habanalabs: Add a printout with the name of a busy engine Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 13/15] habanalabs: add MMU shadow mapping Oded Gabbay
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Tomer Tayar

From: Tomer Tayar <ttayar@habana.ai>

The addr/data32 debugfs nodes currently permit the access to only physical
addresses of a device. This patch extends it and allows accessing also
device's DRAM virtual addresses.

Signed-off-by: Tomer Tayar <ttayar@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/debugfs.c | 96 +++++++++++++++++++++++++++++--
 1 file changed, 91 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/habanalabs/debugfs.c b/drivers/misc/habanalabs/debugfs.c
index 974a87789bd8..a4447699ff4e 100644
--- a/drivers/misc/habanalabs/debugfs.c
+++ b/drivers/misc/habanalabs/debugfs.c
@@ -505,22 +505,97 @@ static ssize_t mmu_write(struct file *file, const char __user *buf,
 	return -EINVAL;
 }
 
+static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr,
+				u64 *phys_addr)
+{
+	struct hl_ctx *ctx = hdev->user_ctx;
+	u64 hop_addr, hop_pte_addr, hop_pte;
+	int rc = 0;
+
+	if (!ctx) {
+		dev_err(hdev->dev, "no ctx available\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->mmu_lock);
+
+	/* hop 0 */
+	hop_addr = get_hop0_addr(ctx);
+	hop_pte_addr = get_hop0_pte_addr(ctx, hop_addr, virt_addr);
+	hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
+
+	/* hop 1 */
+	hop_addr = get_next_hop_addr(hop_pte);
+	if (hop_addr == ULLONG_MAX)
+		goto not_mapped;
+	hop_pte_addr = get_hop1_pte_addr(ctx, hop_addr, virt_addr);
+	hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
+
+	/* hop 2 */
+	hop_addr = get_next_hop_addr(hop_pte);
+	if (hop_addr == ULLONG_MAX)
+		goto not_mapped;
+	hop_pte_addr = get_hop2_pte_addr(ctx, hop_addr, virt_addr);
+	hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
+
+	/* hop 3 */
+	hop_addr = get_next_hop_addr(hop_pte);
+	if (hop_addr == ULLONG_MAX)
+		goto not_mapped;
+	hop_pte_addr = get_hop3_pte_addr(ctx, hop_addr, virt_addr);
+	hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
+
+	if (!(hop_pte & LAST_MASK)) {
+		/* hop 4 */
+		hop_addr = get_next_hop_addr(hop_pte);
+		if (hop_addr == ULLONG_MAX)
+			goto not_mapped;
+		hop_pte_addr = get_hop4_pte_addr(ctx, hop_addr, virt_addr);
+		hop_pte = hdev->asic_funcs->read_pte(hdev, hop_pte_addr);
+	}
+
+	if (!(hop_pte & PAGE_PRESENT_MASK))
+		goto not_mapped;
+
+	*phys_addr = (hop_pte & PTE_PHYS_ADDR_MASK) | (virt_addr & OFFSET_MASK);
+
+	goto out;
+
+not_mapped:
+	dev_err(hdev->dev, "virt addr 0x%llx is not mapped to phys addr\n",
+			virt_addr);
+	rc = -EINVAL;
+out:
+	mutex_unlock(&ctx->mmu_lock);
+	return rc;
+}
+
 static ssize_t hl_data_read32(struct file *f, char __user *buf,
 					size_t count, loff_t *ppos)
 {
 	struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 	struct hl_device *hdev = entry->hdev;
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
 	char tmp_buf[32];
+	u64 addr = entry->addr;
 	u32 val;
 	ssize_t rc;
 
 	if (*ppos)
 		return 0;
 
-	rc = hdev->asic_funcs->debugfs_read32(hdev, entry->addr, &val);
+	if (addr >= prop->va_space_dram_start_address &&
+			addr < prop->va_space_dram_end_address &&
+			hdev->mmu_enable &&
+			hdev->dram_supports_virtual_memory) {
+		rc = device_va_to_pa(hdev, entry->addr, &addr);
+		if (rc)
+			return rc;
+	}
+
+	rc = hdev->asic_funcs->debugfs_read32(hdev, addr, &val);
 	if (rc) {
-		dev_err(hdev->dev, "Failed to read from 0x%010llx\n",
-			entry->addr);
+		dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr);
 		return rc;
 	}
 
@@ -536,6 +611,8 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
 {
 	struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
 	struct hl_device *hdev = entry->hdev;
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	u64 addr = entry->addr;
 	u32 value;
 	ssize_t rc;
 
@@ -543,10 +620,19 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
 	if (rc)
 		return rc;
 
-	rc = hdev->asic_funcs->debugfs_write32(hdev, entry->addr, value);
+	if (addr >= prop->va_space_dram_start_address &&
+			addr < prop->va_space_dram_end_address &&
+			hdev->mmu_enable &&
+			hdev->dram_supports_virtual_memory) {
+		rc = device_va_to_pa(hdev, entry->addr, &addr);
+		if (rc)
+			return rc;
+	}
+
+	rc = hdev->asic_funcs->debugfs_write32(hdev, addr, value);
 	if (rc) {
 		dev_err(hdev->dev, "Failed to write 0x%08x to 0x%010llx\n",
-			value, entry->addr);
+			value, addr);
 		return rc;
 	}
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 13/15] habanalabs: add MMU shadow mapping
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (11 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 12/15] habanalabs: Allow accessing DRAM virtual addresses via debugfs Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 14/15] habanalabs: keep track of the device's dma mask Oded Gabbay
  2019-03-17 19:59 ` [PATCH 15/15] habanalabs: never fail hard reset of device Oded Gabbay
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, Omer Shpigelman

From: Omer Shpigelman <oshpigelman@habana.ai>

This patch adds shadow mapping to the MMU module. The shadow mapping
allows traversing the page table in host memory rather reading each PTE
from the device memory.
It brings better performance and avoids reading from invalid device
address upon PCI errors.
Only at the end of map/unmap flow, writings to the device are performed in
order to sync the H/W page tables with the shadow ones.

Signed-off-by: Omer Shpigelman <oshpigelman@habana.ai>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/habanalabs.h          |  24 +-
 .../include/hw_ip/mmu/mmu_general.h           |  16 +-
 drivers/misc/habanalabs/mmu.c                 | 597 ++++++++++--------
 3 files changed, 353 insertions(+), 284 deletions(-)

diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h
index 9cc841777d81..6991a7f260e8 100644
--- a/drivers/misc/habanalabs/habanalabs.h
+++ b/drivers/misc/habanalabs/habanalabs.h
@@ -51,8 +51,9 @@
 
 /**
  * struct pgt_info - MMU hop page info.
- * @node: hash linked-list node for the pgts hash of pgts.
- * @addr: physical address of the pgt.
+ * @node: hash linked-list node for the pgts shadow hash of pgts.
+ * @phys_addr: physical address of the pgt.
+ * @shadow_addr: shadow hop in the host.
  * @ctx: pointer to the owner ctx.
  * @num_of_ptes: indicates how many ptes are used in the pgt.
  *
@@ -62,10 +63,11 @@
  * page, it is freed with its pgt_info structure.
  */
 struct pgt_info {
-	struct hlist_node node;
-	u64 addr;
-	struct hl_ctx *ctx;
-	int num_of_ptes;
+	struct hlist_node	node;
+	u64			phys_addr;
+	u64			shadow_addr;
+	struct hl_ctx		*ctx;
+	int			num_of_ptes;
 };
 
 struct hl_device;
@@ -595,7 +597,8 @@ struct hl_va_range {
  * struct hl_ctx - user/kernel context.
  * @mem_hash: holds mapping from virtual address to virtual memory area
  *		descriptor (hl_vm_phys_pg_list or hl_userptr).
- * @mmu_hash: holds a mapping from virtual address to pgt_info structure.
+ * @mmu_phys_hash: holds a mapping from physical address to pgt_info structure.
+ * @mmu_shadow_hash: holds a mapping from shadow address to pgt_info structure.
  * @hpriv: pointer to the private (KMD) data of the process (fd).
  * @hdev: pointer to the device structure.
  * @refcount: reference counter for the context. Context is released only when
@@ -624,7 +627,8 @@ struct hl_va_range {
  */
 struct hl_ctx {
 	DECLARE_HASHTABLE(mem_hash, MEM_HASH_TABLE_BITS);
-	DECLARE_HASHTABLE(mmu_hash, MMU_HASH_TABLE_BITS);
+	DECLARE_HASHTABLE(mmu_phys_hash, MMU_HASH_TABLE_BITS);
+	DECLARE_HASHTABLE(mmu_shadow_hash, MMU_HASH_TABLE_BITS);
 	struct hl_fpriv		*hpriv;
 	struct hl_device	*hdev;
 	struct kref		refcount;
@@ -1066,7 +1070,8 @@ struct hl_device_reset_work {
  * @asic_specific: ASIC specific information to use only from ASIC files.
  * @mmu_pgt_pool: pool of available MMU hops.
  * @vm: virtual memory manager for MMU.
- * @mmu_cache_lock: protects MMU cache invalidation as it can serve one context
+ * @mmu_cache_lock: protects MMU cache invalidation as it can serve one context.
+ * @mmu_shadow_hop0: shadow mapping of the MMU hop 0 zone.
  * @hwmon_dev: H/W monitor device.
  * @pm_mng_profile: current power management profile.
  * @hl_chip_info: ASIC's sensors information.
@@ -1136,6 +1141,7 @@ struct hl_device {
 	struct gen_pool			*mmu_pgt_pool;
 	struct hl_vm			vm;
 	struct mutex			mmu_cache_lock;
+	void				*mmu_shadow_hop0;
 	struct device			*hwmon_dev;
 	enum hl_pm_mng_profile		pm_mng_profile;
 	struct hwmon_chip_info		*hl_chip_info;
diff --git a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h b/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h
index b680052ee3f0..71ea3c3e8ba3 100644
--- a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h
+++ b/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h
@@ -14,16 +14,16 @@
 #define PAGE_SIZE_4KB			(_AC(1, UL) << PAGE_SHIFT_4KB)
 #define PAGE_MASK_2MB			(~(PAGE_SIZE_2MB - 1))
 
-#define PAGE_PRESENT_MASK		0x0000000000001
-#define SWAP_OUT_MASK			0x0000000000004
-#define LAST_MASK			0x0000000000800
-#define PHYS_ADDR_MASK			0x3FFFFFFFFF000ull
+#define PAGE_PRESENT_MASK		0x0000000000001ull
+#define SWAP_OUT_MASK			0x0000000000004ull
+#define LAST_MASK			0x0000000000800ull
+#define PHYS_ADDR_MASK			0xFFFFFFFFFFFFF000ull
 #define HOP0_MASK			0x3000000000000ull
 #define HOP1_MASK			0x0FF8000000000ull
 #define HOP2_MASK			0x0007FC0000000ull
-#define HOP3_MASK			0x000003FE00000
-#define HOP4_MASK			0x00000001FF000
-#define OFFSET_MASK			0x0000000000FFF
+#define HOP3_MASK			0x000003FE00000ull
+#define HOP4_MASK			0x00000001FF000ull
+#define OFFSET_MASK			0x0000000000FFFull
 
 #define HOP0_SHIFT			48
 #define HOP1_SHIFT			39
@@ -32,7 +32,7 @@
 #define HOP4_SHIFT			12
 
 #define PTE_PHYS_ADDR_SHIFT		12
-#define PTE_PHYS_ADDR_MASK		~0xFFF
+#define PTE_PHYS_ADDR_MASK		~OFFSET_MASK
 
 #define HL_PTE_SIZE			sizeof(u64)
 #define HOP_TABLE_SIZE			PAGE_SIZE_4KB
diff --git a/drivers/misc/habanalabs/mmu.c b/drivers/misc/habanalabs/mmu.c
index 3a5a2cec8305..1ca9508df5f8 100644
--- a/drivers/misc/habanalabs/mmu.c
+++ b/drivers/misc/habanalabs/mmu.c
@@ -11,13 +11,15 @@
 #include <linux/genalloc.h>
 #include <linux/slab.h>
 
-static struct pgt_info *get_pgt_info(struct hl_ctx *ctx, u64 addr)
+static inline u64 get_phys_addr(struct hl_ctx *ctx, u64 shadow_addr);
+
+static struct pgt_info *get_pgt_info(struct hl_ctx *ctx, u64 hop_addr)
 {
 	struct pgt_info *pgt_info = NULL;
 
-	hash_for_each_possible(ctx->mmu_hash, pgt_info, node,
-				(unsigned long) addr)
-		if (addr == pgt_info->addr)
+	hash_for_each_possible(ctx->mmu_shadow_hash, pgt_info, node,
+				(unsigned long) hop_addr)
+		if (hop_addr == pgt_info->shadow_addr)
 			break;
 
 	return pgt_info;
@@ -25,45 +27,108 @@ static struct pgt_info *get_pgt_info(struct hl_ctx *ctx, u64 addr)
 
 static void free_hop(struct hl_ctx *ctx, u64 hop_addr)
 {
+	struct hl_device *hdev = ctx->hdev;
 	struct pgt_info *pgt_info = get_pgt_info(ctx, hop_addr);
 
-	gen_pool_free(pgt_info->ctx->hdev->mmu_pgt_pool, pgt_info->addr,
-			ctx->hdev->asic_prop.mmu_hop_table_size);
+	gen_pool_free(hdev->mmu_pgt_pool, pgt_info->phys_addr,
+			hdev->asic_prop.mmu_hop_table_size);
 	hash_del(&pgt_info->node);
-
+	kfree((u64 *) pgt_info->shadow_addr);
 	kfree(pgt_info);
 }
 
 static u64 alloc_hop(struct hl_ctx *ctx)
 {
 	struct hl_device *hdev = ctx->hdev;
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
 	struct pgt_info *pgt_info;
-	u64 addr;
+	u64 phys_addr, shadow_addr;
 
 	pgt_info = kmalloc(sizeof(*pgt_info), GFP_KERNEL);
 	if (!pgt_info)
 		return ULLONG_MAX;
 
-	addr = (u64) gen_pool_alloc(hdev->mmu_pgt_pool,
-			hdev->asic_prop.mmu_hop_table_size);
-	if (!addr) {
+	phys_addr = (u64) gen_pool_alloc(hdev->mmu_pgt_pool,
+					prop->mmu_hop_table_size);
+	if (!phys_addr) {
 		dev_err(hdev->dev, "failed to allocate page\n");
-		kfree(pgt_info);
-		return ULLONG_MAX;
+		goto pool_add_err;
 	}
 
-	pgt_info->addr = addr;
+	shadow_addr = (u64) kzalloc(prop->mmu_hop_table_size, GFP_KERNEL);
+	if (!shadow_addr)
+		goto shadow_err;
+
+	pgt_info->phys_addr = phys_addr;
+	pgt_info->shadow_addr = shadow_addr;
 	pgt_info->ctx = ctx;
 	pgt_info->num_of_ptes = 0;
-	hash_add(ctx->mmu_hash, &pgt_info->node, addr);
+	hash_add(ctx->mmu_shadow_hash, &pgt_info->node, shadow_addr);
+
+	return shadow_addr;
+
+shadow_err:
+	gen_pool_free(hdev->mmu_pgt_pool, phys_addr, prop->mmu_hop_table_size);
+pool_add_err:
+	kfree(pgt_info);
+
+	return ULLONG_MAX;
+}
+
+static inline u64 get_phys_hop0_addr(struct hl_ctx *ctx)
+{
+	return ctx->hdev->asic_prop.mmu_pgt_addr +
+			(ctx->asid * ctx->hdev->asic_prop.mmu_hop_table_size);
+}
+
+static inline u64 get_hop0_addr(struct hl_ctx *ctx)
+{
+	return (u64) (uintptr_t) ctx->hdev->mmu_shadow_hop0 +
+			(ctx->asid * ctx->hdev->asic_prop.mmu_hop_table_size);
+}
+
+static inline void flush(struct hl_ctx *ctx)
+{
+	/* flush all writes from all cores to reach PCI */
+	mb();
+	ctx->hdev->asic_funcs->read_pte(ctx->hdev, get_phys_hop0_addr(ctx));
+}
+
+/* transform the value to physical address when writing to H/W */
+static inline void write_pte(struct hl_ctx *ctx, u64 shadow_pte_addr, u64 val)
+{
+	/*
+	 * The value to write is actually the address of the next shadow hop +
+	 * flags at the 12 LSBs.
+	 * Hence in order to get the value to write to the physical PTE, we
+	 * clear the 12 LSBs and translate the shadow hop to its associated
+	 * physical hop, and add back the original 12 LSBs.
+	 */
+	u64 phys_val = get_phys_addr(ctx, val & PTE_PHYS_ADDR_MASK) |
+				(val & OFFSET_MASK);
+
+	ctx->hdev->asic_funcs->write_pte(ctx->hdev,
+					get_phys_addr(ctx, shadow_pte_addr),
+					phys_val);
+
+	*(u64 *) shadow_pte_addr = val;
+}
 
-	return addr;
+/* do not transform the value to physical address when writing to H/W */
+static inline void write_final_pte(struct hl_ctx *ctx, u64 shadow_pte_addr,
+					u64 val)
+{
+	ctx->hdev->asic_funcs->write_pte(ctx->hdev,
+					get_phys_addr(ctx, shadow_pte_addr),
+					val);
+	*(u64 *) shadow_pte_addr = val;
 }
 
-static inline void clear_pte(struct hl_device *hdev, u64 pte_addr)
+/* clear the last and present bits */
+static inline void clear_pte(struct hl_ctx *ctx, u64 pte_addr)
 {
-	/* clear the last and present bits */
-	hdev->asic_funcs->write_pte(hdev, pte_addr, 0);
+	/* no need to transform the value to physical address */
+	write_final_pte(ctx, pte_addr, 0);
 }
 
 static inline void get_pte(struct hl_ctx *ctx, u64 hop_addr)
@@ -98,12 +163,6 @@ static inline int put_pte(struct hl_ctx *ctx, u64 hop_addr)
 	return num_of_ptes_left;
 }
 
-static inline u64 get_hop0_addr(struct hl_ctx *ctx)
-{
-	return ctx->hdev->asic_prop.mmu_pgt_addr +
-			(ctx->asid * ctx->hdev->asic_prop.mmu_hop_table_size);
-}
-
 static inline u64 get_hopN_pte_addr(struct hl_ctx *ctx, u64 hop_addr,
 					u64 virt_addr, u64 mask, u64 shift)
 {
@@ -136,7 +195,7 @@ static inline u64 get_hop4_pte_addr(struct hl_ctx *ctx, u64 hop_addr, u64 vaddr)
 	return get_hopN_pte_addr(ctx, hop_addr, vaddr, HOP4_MASK, HOP4_SHIFT);
 }
 
-static inline u64 get_next_hop_addr(u64 curr_pte)
+static inline u64 get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte)
 {
 	if (curr_pte & PAGE_PRESENT_MASK)
 		return curr_pte & PHYS_ADDR_MASK;
@@ -147,7 +206,7 @@ static inline u64 get_next_hop_addr(u64 curr_pte)
 static inline u64 get_alloc_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte,
 						bool *is_new_hop)
 {
-	u64 hop_addr = get_next_hop_addr(curr_pte);
+	u64 hop_addr = get_next_hop_addr(ctx, curr_pte);
 
 	if (hop_addr == ULLONG_MAX) {
 		hop_addr = alloc_hop(ctx);
@@ -157,106 +216,30 @@ static inline u64 get_alloc_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte,
 	return hop_addr;
 }
 
-/*
- * hl_mmu_init - init the mmu module
- *
- * @hdev: pointer to the habanalabs device structure
- *
- * This function does the following:
- * - Allocate max_asid zeroed hop0 pgts so no mapping is available
- * - Enable mmu in hw
- * - Invalidate the mmu cache
- * - Create a pool of pages for pgts
- * - Returns 0 on success
- *
- * This function depends on DMA QMAN to be working!
- */
-int hl_mmu_init(struct hl_device *hdev)
+/* translates shadow address inside hop to a physical address */
+static inline u64 get_phys_addr(struct hl_ctx *ctx, u64 shadow_addr)
 {
-	struct asic_fixed_properties *prop = &hdev->asic_prop;
-	int rc;
+	u64 page_mask = (ctx->hdev->asic_prop.mmu_hop_table_size - 1);
+	u64 shadow_hop_addr = shadow_addr & ~page_mask;
+	u64 pte_offset = shadow_addr & page_mask;
+	u64 phys_hop_addr;
 
-	if (!hdev->mmu_enable)
-		return 0;
-
-	/* MMU HW init was already done in device hw_init() */
-
-	mutex_init(&hdev->mmu_cache_lock);
-
-	hdev->mmu_pgt_pool =
-			gen_pool_create(__ffs(prop->mmu_hop_table_size), -1);
-
-	if (!hdev->mmu_pgt_pool) {
-		dev_err(hdev->dev, "Failed to create page gen pool\n");
-		rc = -ENOMEM;
-		goto err_pool_create;
-	}
-
-	rc = gen_pool_add(hdev->mmu_pgt_pool, prop->mmu_pgt_addr +
-			prop->mmu_hop0_tables_total_size,
-			prop->mmu_pgt_size - prop->mmu_hop0_tables_total_size,
-			-1);
-	if (rc) {
-		dev_err(hdev->dev, "Failed to add memory to page gen pool\n");
-		goto err_pool_add;
-	}
-
-	return 0;
-
-err_pool_add:
-	gen_pool_destroy(hdev->mmu_pgt_pool);
-err_pool_create:
-	mutex_destroy(&hdev->mmu_cache_lock);
+	if (shadow_hop_addr != get_hop0_addr(ctx))
+		phys_hop_addr = get_pgt_info(ctx, shadow_hop_addr)->phys_addr;
+	else
+		phys_hop_addr = get_phys_hop0_addr(ctx);
 
-	return rc;
+	return phys_hop_addr + pte_offset;
 }
 
-/*
- * hl_mmu_fini - release the mmu module.
- *
- * @hdev: pointer to the habanalabs device structure
- *
- * This function does the following:
- * - Disable mmu in hw
- * - free the pgts pool
- *
- * All ctxs should be freed before calling this func
- */
-void hl_mmu_fini(struct hl_device *hdev)
-{
-	if (!hdev->mmu_enable)
-		return;
-
-	gen_pool_destroy(hdev->mmu_pgt_pool);
-
-	mutex_destroy(&hdev->mmu_cache_lock);
-
-	/* MMU HW fini will be done in device hw_fini() */
-}
-
-/**
- * hl_mmu_ctx_init() - initialize a context for using the MMU module.
- * @ctx: pointer to the context structure to initialize.
- *
- * Initialize a mutex to protect the concurrent mapping flow, a hash to hold all
- * page tables hops related to this context and an optional DRAM default page
- * mapping.
- * Return: 0 on success, non-zero otherwise.
- */
-int hl_mmu_ctx_init(struct hl_ctx *ctx)
+static int dram_default_mapping_init(struct hl_ctx *ctx)
 {
 	struct hl_device *hdev = ctx->hdev;
 	struct asic_fixed_properties *prop = &hdev->asic_prop;
-	u64 num_of_hop3, total_hops, hop1_addr, hop2_addr, hop2_pte_addr,
-		hop3_pte_addr, pte_val;
+	u64 num_of_hop3, total_hops, hop0_addr, hop1_addr, hop2_addr,
+		hop2_pte_addr, hop3_pte_addr, pte_val;
 	int rc, i, j, hop3_allocated = 0;
 
-	if (!hdev->mmu_enable)
-		return 0;
-
-	mutex_init(&ctx->mmu_lock);
-	hash_init(ctx->mmu_hash);
-
 	if (!hdev->dram_supports_virtual_memory ||
 			!hdev->dram_default_page_mapping)
 		return 0;
@@ -269,10 +252,10 @@ int hl_mmu_ctx_init(struct hl_ctx *ctx)
 	total_hops = num_of_hop3 + 2;
 
 	ctx->dram_default_hops = kzalloc(HL_PTE_SIZE * total_hops,  GFP_KERNEL);
-	if (!ctx->dram_default_hops) {
-		rc = -ENOMEM;
-		goto alloc_err;
-	}
+	if (!ctx->dram_default_hops)
+		return -ENOMEM;
+
+	hop0_addr = get_hop0_addr(ctx);
 
 	hop1_addr = alloc_hop(ctx);
 	if (hop1_addr == ULLONG_MAX) {
@@ -304,17 +287,17 @@ int hl_mmu_ctx_init(struct hl_ctx *ctx)
 
 	/* need only pte 0 in hops 0 and 1 */
 	pte_val = (hop1_addr & PTE_PHYS_ADDR_MASK) | PAGE_PRESENT_MASK;
-	hdev->asic_funcs->write_pte(hdev, get_hop0_addr(ctx), pte_val);
+	write_pte(ctx, hop0_addr, pte_val);
 
 	pte_val = (hop2_addr & PTE_PHYS_ADDR_MASK) | PAGE_PRESENT_MASK;
-	hdev->asic_funcs->write_pte(hdev, hop1_addr, pte_val);
+	write_pte(ctx, hop1_addr, pte_val);
 	get_pte(ctx, hop1_addr);
 
 	hop2_pte_addr = hop2_addr;
 	for (i = 0 ; i < num_of_hop3 ; i++) {
 		pte_val = (ctx->dram_default_hops[i] & PTE_PHYS_ADDR_MASK) |
 				PAGE_PRESENT_MASK;
-		hdev->asic_funcs->write_pte(hdev, hop2_pte_addr, pte_val);
+		write_pte(ctx, hop2_pte_addr, pte_val);
 		get_pte(ctx, hop2_addr);
 		hop2_pte_addr += HL_PTE_SIZE;
 	}
@@ -325,33 +308,182 @@ int hl_mmu_ctx_init(struct hl_ctx *ctx)
 	for (i = 0 ; i < num_of_hop3 ; i++) {
 		hop3_pte_addr = ctx->dram_default_hops[i];
 		for (j = 0 ; j < PTE_ENTRIES_IN_HOP ; j++) {
-			hdev->asic_funcs->write_pte(hdev, hop3_pte_addr,
-					pte_val);
+			write_final_pte(ctx, hop3_pte_addr, pte_val);
 			get_pte(ctx, ctx->dram_default_hops[i]);
 			hop3_pte_addr += HL_PTE_SIZE;
 		}
 	}
 
-	/* flush all writes to reach PCI */
-	mb();
-	hdev->asic_funcs->read_pte(hdev, hop2_addr);
+	flush(ctx);
 
 	return 0;
 
 hop3_err:
 	for (i = 0 ; i < hop3_allocated ; i++)
 		free_hop(ctx, ctx->dram_default_hops[i]);
+
 	free_hop(ctx, hop2_addr);
 hop2_err:
 	free_hop(ctx, hop1_addr);
 hop1_err:
 	kfree(ctx->dram_default_hops);
-alloc_err:
-	mutex_destroy(&ctx->mmu_lock);
 
 	return rc;
 }
 
+static void dram_default_mapping_fini(struct hl_ctx *ctx)
+{
+	struct hl_device *hdev = ctx->hdev;
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	u64 num_of_hop3, total_hops, hop0_addr, hop1_addr, hop2_addr,
+		hop2_pte_addr, hop3_pte_addr;
+	int i, j;
+
+	if (!hdev->dram_supports_virtual_memory ||
+			!hdev->dram_default_page_mapping)
+		return;
+
+	num_of_hop3 = prop->dram_size_for_default_page_mapping;
+	do_div(num_of_hop3, prop->dram_page_size);
+	do_div(num_of_hop3, PTE_ENTRIES_IN_HOP);
+
+	hop0_addr = get_hop0_addr(ctx);
+	/* add hop1 and hop2 */
+	total_hops = num_of_hop3 + 2;
+	hop1_addr = ctx->dram_default_hops[total_hops - 1];
+	hop2_addr = ctx->dram_default_hops[total_hops - 2];
+
+	for (i = 0 ; i < num_of_hop3 ; i++) {
+		hop3_pte_addr = ctx->dram_default_hops[i];
+		for (j = 0 ; j < PTE_ENTRIES_IN_HOP ; j++) {
+			clear_pte(ctx, hop3_pte_addr);
+			put_pte(ctx, ctx->dram_default_hops[i]);
+			hop3_pte_addr += HL_PTE_SIZE;
+		}
+	}
+
+	hop2_pte_addr = hop2_addr;
+	hop2_pte_addr = hop2_addr;
+	for (i = 0 ; i < num_of_hop3 ; i++) {
+		clear_pte(ctx, hop2_pte_addr);
+		put_pte(ctx, hop2_addr);
+		hop2_pte_addr += HL_PTE_SIZE;
+	}
+
+	clear_pte(ctx, hop1_addr);
+	put_pte(ctx, hop1_addr);
+	clear_pte(ctx, hop0_addr);
+
+	kfree(ctx->dram_default_hops);
+
+	flush(ctx);
+}
+
+/**
+ * hl_mmu_init() - initialize the MMU module.
+ * @hdev: habanalabs device structure.
+ *
+ * This function does the following:
+ * - Allocate max_asid zeroed hop0 pgts so no mapping is available.
+ * - Enable MMU in H/W.
+ * - Invalidate the MMU cache.
+ * - Create a pool of pages for pgt_infos.
+ *
+ * This function depends on DMA QMAN to be working!
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int hl_mmu_init(struct hl_device *hdev)
+{
+	struct asic_fixed_properties *prop = &hdev->asic_prop;
+	int rc;
+
+	if (!hdev->mmu_enable)
+		return 0;
+
+	/* MMU H/W init was already done in device hw_init() */
+
+	mutex_init(&hdev->mmu_cache_lock);
+
+	hdev->mmu_pgt_pool =
+			gen_pool_create(__ffs(prop->mmu_hop_table_size), -1);
+
+	if (!hdev->mmu_pgt_pool) {
+		dev_err(hdev->dev, "Failed to create page gen pool\n");
+		rc = -ENOMEM;
+		goto err_pool_create;
+	}
+
+	rc = gen_pool_add(hdev->mmu_pgt_pool, prop->mmu_pgt_addr +
+			prop->mmu_hop0_tables_total_size,
+			prop->mmu_pgt_size - prop->mmu_hop0_tables_total_size,
+			-1);
+	if (rc) {
+		dev_err(hdev->dev, "Failed to add memory to page gen pool\n");
+		goto err_pool_add;
+	}
+
+	hdev->mmu_shadow_hop0 = kcalloc(prop->max_asid,
+					prop->mmu_hop_table_size, GFP_KERNEL);
+	if (!hdev->mmu_shadow_hop0) {
+		rc = -ENOMEM;
+		goto err_pool_add;
+	}
+
+	return 0;
+
+err_pool_add:
+	gen_pool_destroy(hdev->mmu_pgt_pool);
+err_pool_create:
+	mutex_destroy(&hdev->mmu_cache_lock);
+
+	return rc;
+}
+
+/**
+ * hl_mmu_fini() - release the MMU module.
+ * @hdev: habanalabs device structure.
+ *
+ * This function does the following:
+ * - Disable MMU in H/W.
+ * - Free the pgt_infos pool.
+ *
+ * All contexts should be freed before calling this function.
+ */
+void hl_mmu_fini(struct hl_device *hdev)
+{
+	if (!hdev->mmu_enable)
+		return;
+
+	kfree(hdev->mmu_shadow_hop0);
+	gen_pool_destroy(hdev->mmu_pgt_pool);
+	mutex_destroy(&hdev->mmu_cache_lock);
+
+	/* MMU H/W fini will be done in device hw_fini() */
+}
+
+/**
+ * hl_mmu_ctx_init() - initialize a context for using the MMU module.
+ * @ctx: pointer to the context structure to initialize.
+ *
+ * Initialize a mutex to protect the concurrent mapping flow, a hash to hold all
+ * page tables hops related to this context.
+ * Return: 0 on success, non-zero otherwise.
+ */
+int hl_mmu_ctx_init(struct hl_ctx *ctx)
+{
+	struct hl_device *hdev = ctx->hdev;
+
+	if (!hdev->mmu_enable)
+		return 0;
+
+	mutex_init(&ctx->mmu_lock);
+	hash_init(ctx->mmu_phys_hash);
+	hash_init(ctx->mmu_shadow_hash);
+
+	return dram_default_mapping_init(ctx);
+}
+
 /*
  * hl_mmu_ctx_fini - disable a ctx from using the mmu module
  *
@@ -365,63 +497,23 @@ int hl_mmu_ctx_init(struct hl_ctx *ctx)
 void hl_mmu_ctx_fini(struct hl_ctx *ctx)
 {
 	struct hl_device *hdev = ctx->hdev;
-	struct asic_fixed_properties *prop = &hdev->asic_prop;
 	struct pgt_info *pgt_info;
 	struct hlist_node *tmp;
-	u64 num_of_hop3, total_hops, hop1_addr, hop2_addr, hop2_pte_addr,
-		hop3_pte_addr;
-	int i, j;
+	int i;
 
-	if (!ctx->hdev->mmu_enable)
+	if (!hdev->mmu_enable)
 		return;
 
-	if (hdev->dram_supports_virtual_memory &&
-			hdev->dram_default_page_mapping) {
-
-		num_of_hop3 = prop->dram_size_for_default_page_mapping;
-		do_div(num_of_hop3, prop->dram_page_size);
-		do_div(num_of_hop3, PTE_ENTRIES_IN_HOP);
-
-		/* add hop1 and hop2 */
-		total_hops = num_of_hop3 + 2;
-		hop1_addr = ctx->dram_default_hops[total_hops - 1];
-		hop2_addr = ctx->dram_default_hops[total_hops - 2];
-
-		for (i = 0 ; i < num_of_hop3 ; i++) {
-			hop3_pte_addr = ctx->dram_default_hops[i];
-			for (j = 0 ; j < PTE_ENTRIES_IN_HOP ; j++) {
-				clear_pte(hdev, hop3_pte_addr);
-				put_pte(ctx, ctx->dram_default_hops[i]);
-				hop3_pte_addr += HL_PTE_SIZE;
-			}
-		}
+	dram_default_mapping_fini(ctx);
 
-		hop2_pte_addr = hop2_addr;
-		for (i = 0 ; i < num_of_hop3 ; i++) {
-			clear_pte(hdev, hop2_pte_addr);
-			put_pte(ctx, hop2_addr);
-			hop2_pte_addr += HL_PTE_SIZE;
-		}
-
-		clear_pte(hdev, hop1_addr);
-		put_pte(ctx, hop1_addr);
-		clear_pte(hdev, get_hop0_addr(ctx));
-
-		kfree(ctx->dram_default_hops);
-
-		/* flush all writes to reach PCI */
-		mb();
-		hdev->asic_funcs->read_pte(hdev, hop2_addr);
-	}
-
-	if (!hash_empty(ctx->mmu_hash))
+	if (!hash_empty(ctx->mmu_shadow_hash))
 		dev_err(hdev->dev, "ctx is freed while it has pgts in use\n");
 
-	hash_for_each_safe(ctx->mmu_hash, i, tmp, pgt_info, node) {
+	hash_for_each_safe(ctx->mmu_shadow_hash, i, tmp, pgt_info, node) {
 		dev_err(hdev->dev,
 			"pgt_info of addr 0x%llx of asid %d was not destroyed, num_ptes: %d\n",
-			pgt_info->addr, ctx->asid, pgt_info->num_of_ptes);
-		free_hop(ctx, pgt_info->addr);
+			pgt_info->phys_addr, ctx->asid, pgt_info->num_of_ptes);
+		free_hop(ctx, pgt_info->shadow_addr);
 	}
 
 	mutex_destroy(&ctx->mmu_lock);
@@ -437,45 +529,43 @@ static int _hl_mmu_unmap(struct hl_ctx *ctx, u64 virt_addr)
 		hop3_addr = 0, hop3_pte_addr = 0,
 		hop4_addr = 0, hop4_pte_addr = 0,
 		curr_pte;
-	int clear_hop3 = 1;
-	bool is_dram_addr, is_huge, is_dram_default_page_mapping;
+	bool is_dram_addr, is_huge, clear_hop3 = true;
 
 	is_dram_addr = hl_mem_area_inside_range(virt_addr, PAGE_SIZE_2MB,
 				prop->va_space_dram_start_address,
 				prop->va_space_dram_end_address);
 
 	hop0_addr = get_hop0_addr(ctx);
-
 	hop0_pte_addr = get_hop0_pte_addr(ctx, hop0_addr, virt_addr);
 
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop0_pte_addr);
+	curr_pte = *(u64 *) hop0_pte_addr;
 
-	hop1_addr = get_next_hop_addr(curr_pte);
+	hop1_addr = get_next_hop_addr(ctx, curr_pte);
 
 	if (hop1_addr == ULLONG_MAX)
 		goto not_mapped;
 
 	hop1_pte_addr = get_hop1_pte_addr(ctx, hop1_addr, virt_addr);
 
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop1_pte_addr);
+	curr_pte = *(u64 *) hop1_pte_addr;
 
-	hop2_addr = get_next_hop_addr(curr_pte);
+	hop2_addr = get_next_hop_addr(ctx, curr_pte);
 
 	if (hop2_addr == ULLONG_MAX)
 		goto not_mapped;
 
 	hop2_pte_addr = get_hop2_pte_addr(ctx, hop2_addr, virt_addr);
 
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop2_pte_addr);
+	curr_pte = *(u64 *) hop2_pte_addr;
 
-	hop3_addr = get_next_hop_addr(curr_pte);
+	hop3_addr = get_next_hop_addr(ctx, curr_pte);
 
 	if (hop3_addr == ULLONG_MAX)
 		goto not_mapped;
 
 	hop3_pte_addr = get_hop3_pte_addr(ctx, hop3_addr, virt_addr);
 
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop3_pte_addr);
+	curr_pte = *(u64 *) hop3_pte_addr;
 
 	is_huge = curr_pte & LAST_MASK;
 
@@ -485,27 +575,24 @@ static int _hl_mmu_unmap(struct hl_ctx *ctx, u64 virt_addr)
 		return -EFAULT;
 	}
 
-	is_dram_default_page_mapping =
-			hdev->dram_default_page_mapping && is_dram_addr;
-
 	if (!is_huge) {
-		hop4_addr = get_next_hop_addr(curr_pte);
+		hop4_addr = get_next_hop_addr(ctx, curr_pte);
 
 		if (hop4_addr == ULLONG_MAX)
 			goto not_mapped;
 
 		hop4_pte_addr = get_hop4_pte_addr(ctx, hop4_addr, virt_addr);
 
-		curr_pte = hdev->asic_funcs->read_pte(hdev, hop4_pte_addr);
+		curr_pte = *(u64 *) hop4_pte_addr;
 
-		clear_hop3 = 0;
+		clear_hop3 = false;
 	}
 
-	if (is_dram_default_page_mapping) {
-		u64 zero_pte = (prop->mmu_dram_default_page_addr &
+	if (hdev->dram_default_page_mapping && is_dram_addr) {
+		u64 default_pte = (prop->mmu_dram_default_page_addr &
 				PTE_PHYS_ADDR_MASK) | LAST_MASK |
 					PAGE_PRESENT_MASK;
-		if (curr_pte == zero_pte) {
+		if (curr_pte == default_pte) {
 			dev_err(hdev->dev,
 				"DRAM: hop3 PTE points to zero page, can't unmap, va: 0x%llx\n",
 					virt_addr);
@@ -519,40 +606,43 @@ static int _hl_mmu_unmap(struct hl_ctx *ctx, u64 virt_addr)
 			goto not_mapped;
 		}
 
-		hdev->asic_funcs->write_pte(hdev, hop3_pte_addr, zero_pte);
+		write_final_pte(ctx, hop3_pte_addr, default_pte);
 		put_pte(ctx, hop3_addr);
 	} else {
 		if (!(curr_pte & PAGE_PRESENT_MASK))
 			goto not_mapped;
 
-		clear_pte(hdev, hop4_addr ? hop4_pte_addr : hop3_pte_addr);
+		if (hop4_addr)
+			clear_pte(ctx, hop4_pte_addr);
+		else
+			clear_pte(ctx, hop3_pte_addr);
 
 		if (hop4_addr && !put_pte(ctx, hop4_addr))
-			clear_hop3 = 1;
+			clear_hop3 = true;
 
 		if (!clear_hop3)
 			goto flush;
-		clear_pte(hdev, hop3_pte_addr);
+
+		clear_pte(ctx, hop3_pte_addr);
 
 		if (put_pte(ctx, hop3_addr))
 			goto flush;
-		clear_pte(hdev, hop2_pte_addr);
+
+		clear_pte(ctx, hop2_pte_addr);
 
 		if (put_pte(ctx, hop2_addr))
 			goto flush;
-		clear_pte(hdev, hop1_pte_addr);
+
+		clear_pte(ctx, hop1_pte_addr);
 
 		if (put_pte(ctx, hop1_addr))
 			goto flush;
-		clear_pte(hdev, hop0_pte_addr);
+
+		clear_pte(ctx, hop0_pte_addr);
 	}
 
 flush:
-	/* flush all writes from all cores to reach PCI */
-	mb();
-
-	hdev->asic_funcs->read_pte(hdev,
-				hop4_addr ? hop4_pte_addr : hop3_pte_addr);
+	flush(ctx);
 
 	return 0;
 
@@ -632,8 +722,7 @@ static int _hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
 		hop4_addr = 0, hop4_pte_addr = 0,
 		curr_pte = 0;
 	bool hop1_new = false, hop2_new = false, hop3_new = false,
-		hop4_new = false, is_huge, is_dram_addr,
-		is_dram_default_page_mapping;
+		hop4_new = false, is_huge, is_dram_addr;
 	int rc = -ENOMEM;
 
 	/*
@@ -654,59 +743,46 @@ static int _hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
 		return -EFAULT;
 	}
 
-	is_dram_default_page_mapping =
-			hdev->dram_default_page_mapping && is_dram_addr;
-
 	hop0_addr = get_hop0_addr(ctx);
-
 	hop0_pte_addr = get_hop0_pte_addr(ctx, hop0_addr, virt_addr);
-
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop0_pte_addr);
+	curr_pte = *(u64 *) hop0_pte_addr;
 
 	hop1_addr = get_alloc_next_hop_addr(ctx, curr_pte, &hop1_new);
-
 	if (hop1_addr == ULLONG_MAX)
 		goto err;
 
 	hop1_pte_addr = get_hop1_pte_addr(ctx, hop1_addr, virt_addr);
-
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop1_pte_addr);
+	curr_pte = *(u64 *) hop1_pte_addr;
 
 	hop2_addr = get_alloc_next_hop_addr(ctx, curr_pte, &hop2_new);
-
 	if (hop2_addr == ULLONG_MAX)
 		goto err;
 
 	hop2_pte_addr = get_hop2_pte_addr(ctx, hop2_addr, virt_addr);
-
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop2_pte_addr);
+	curr_pte = *(u64 *) hop2_pte_addr;
 
 	hop3_addr = get_alloc_next_hop_addr(ctx, curr_pte, &hop3_new);
-
 	if (hop3_addr == ULLONG_MAX)
 		goto err;
 
 	hop3_pte_addr = get_hop3_pte_addr(ctx, hop3_addr, virt_addr);
-
-	curr_pte = hdev->asic_funcs->read_pte(hdev, hop3_pte_addr);
+	curr_pte = *(u64 *) hop3_pte_addr;
 
 	if (!is_huge) {
 		hop4_addr = get_alloc_next_hop_addr(ctx, curr_pte, &hop4_new);
-
 		if (hop4_addr == ULLONG_MAX)
 			goto err;
 
 		hop4_pte_addr = get_hop4_pte_addr(ctx, hop4_addr, virt_addr);
-
-		curr_pte = hdev->asic_funcs->read_pte(hdev, hop4_pte_addr);
+		curr_pte = *(u64 *) hop4_pte_addr;
 	}
 
-	if (is_dram_default_page_mapping) {
-		u64 zero_pte = (prop->mmu_dram_default_page_addr &
+	if (hdev->dram_default_page_mapping && is_dram_addr) {
+		u64 default_pte = (prop->mmu_dram_default_page_addr &
 					PTE_PHYS_ADDR_MASK) | LAST_MASK |
 						PAGE_PRESENT_MASK;
 
-		if (curr_pte != zero_pte) {
+		if (curr_pte != default_pte) {
 			dev_err(hdev->dev,
 				"DRAM: mapping already exists for virt_addr 0x%llx\n",
 					virt_addr);
@@ -722,27 +798,21 @@ static int _hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
 		}
 	} else if (curr_pte & PAGE_PRESENT_MASK) {
 		dev_err(hdev->dev,
-				"mapping already exists for virt_addr 0x%llx\n",
-					virt_addr);
+			"mapping already exists for virt_addr 0x%llx\n",
+				virt_addr);
 
 		dev_dbg(hdev->dev, "hop0 pte: 0x%llx (0x%llx)\n",
-				hdev->asic_funcs->read_pte(hdev, hop0_pte_addr),
-				hop0_pte_addr);
+			*(u64 *) hop0_pte_addr, hop0_pte_addr);
 		dev_dbg(hdev->dev, "hop1 pte: 0x%llx (0x%llx)\n",
-				hdev->asic_funcs->read_pte(hdev, hop1_pte_addr),
-				hop1_pte_addr);
+			*(u64 *) hop1_pte_addr, hop1_pte_addr);
 		dev_dbg(hdev->dev, "hop2 pte: 0x%llx (0x%llx)\n",
-				hdev->asic_funcs->read_pte(hdev, hop2_pte_addr),
-				hop2_pte_addr);
+			*(u64 *) hop2_pte_addr, hop2_pte_addr);
 		dev_dbg(hdev->dev, "hop3 pte: 0x%llx (0x%llx)\n",
-				hdev->asic_funcs->read_pte(hdev, hop3_pte_addr),
-				hop3_pte_addr);
+			*(u64 *) hop3_pte_addr, hop3_pte_addr);
 
 		if (!is_huge)
 			dev_dbg(hdev->dev, "hop4 pte: 0x%llx (0x%llx)\n",
-				hdev->asic_funcs->read_pte(hdev,
-							hop4_pte_addr),
-							hop4_pte_addr);
+				*(u64 *) hop4_pte_addr, hop4_pte_addr);
 
 		rc = -EINVAL;
 		goto err;
@@ -751,28 +821,26 @@ static int _hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
 	curr_pte = (phys_addr & PTE_PHYS_ADDR_MASK) | LAST_MASK
 			| PAGE_PRESENT_MASK;
 
-	hdev->asic_funcs->write_pte(hdev,
-				is_huge ? hop3_pte_addr : hop4_pte_addr,
-				curr_pte);
+	if (is_huge)
+		write_final_pte(ctx, hop3_pte_addr, curr_pte);
+	else
+		write_final_pte(ctx, hop4_pte_addr, curr_pte);
 
 	if (hop1_new) {
-		curr_pte = (hop1_addr & PTE_PHYS_ADDR_MASK) |
-				PAGE_PRESENT_MASK;
-		ctx->hdev->asic_funcs->write_pte(ctx->hdev, hop0_pte_addr,
-				curr_pte);
+		curr_pte =
+			(hop1_addr & PTE_PHYS_ADDR_MASK) | PAGE_PRESENT_MASK;
+		write_pte(ctx, hop0_pte_addr, curr_pte);
 	}
 	if (hop2_new) {
-		curr_pte = (hop2_addr & PTE_PHYS_ADDR_MASK) |
-				PAGE_PRESENT_MASK;
-		ctx->hdev->asic_funcs->write_pte(ctx->hdev, hop1_pte_addr,
-				curr_pte);
+		curr_pte =
+			(hop2_addr & PTE_PHYS_ADDR_MASK) | PAGE_PRESENT_MASK;
+		write_pte(ctx, hop1_pte_addr, curr_pte);
 		get_pte(ctx, hop1_addr);
 	}
 	if (hop3_new) {
-		curr_pte = (hop3_addr & PTE_PHYS_ADDR_MASK) |
-				PAGE_PRESENT_MASK;
-		ctx->hdev->asic_funcs->write_pte(ctx->hdev, hop2_pte_addr,
-				curr_pte);
+		curr_pte =
+			(hop3_addr & PTE_PHYS_ADDR_MASK) | PAGE_PRESENT_MASK;
+		write_pte(ctx, hop2_pte_addr, curr_pte);
 		get_pte(ctx, hop2_addr);
 	}
 
@@ -780,8 +848,7 @@ static int _hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
 		if (hop4_new) {
 			curr_pte = (hop4_addr & PTE_PHYS_ADDR_MASK) |
 					PAGE_PRESENT_MASK;
-			ctx->hdev->asic_funcs->write_pte(ctx->hdev,
-					hop3_pte_addr, curr_pte);
+			write_pte(ctx, hop3_pte_addr, curr_pte);
 			get_pte(ctx, hop3_addr);
 		}
 
@@ -790,11 +857,7 @@ static int _hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr,
 		get_pte(ctx, hop3_addr);
 	}
 
-	/* flush all writes from all cores to reach PCI */
-	mb();
-
-	hdev->asic_funcs->read_pte(hdev,
-				is_huge ? hop3_pte_addr : hop4_pte_addr);
+	flush(ctx);
 
 	return 0;
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 14/15] habanalabs: keep track of the device's dma mask
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (12 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 13/15] habanalabs: add MMU shadow mapping Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  2019-03-17 19:59 ` [PATCH 15/15] habanalabs: never fail hard reset of device Oded Gabbay
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

This patch refactors the code that is responsible to set the DMA mask for
the device.

Upon each change of the dma mask, the driver will save the new value that
was set. This is needed in order to make sure we don't try to increase the
mask a second time, in case we failed in the first time. This is
especially relevant for Power machines, as that may cause a change in
configuration of the TVT which will break the device.

Goya will first try to set the device's dma mask to 39 bits, so that the
memory that is allocated on the host machine for communication with the
device's cpu will be in a bus address which is lower then 39 bits. Later,
Goya will try to increase that mask to 48 bits, but only if setting the
mask to 39 bits was successful.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/goya/goya.c      | 32 ++++--------
 drivers/misc/habanalabs/habanalabs.h     |  5 +-
 drivers/misc/habanalabs/habanalabs_drv.c |  3 ++
 drivers/misc/habanalabs/pci.c            | 64 ++++++++++++++++++------
 4 files changed, 65 insertions(+), 39 deletions(-)

diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index b474651db0e5..a4bb963e33fa 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -483,7 +483,7 @@ static int goya_early_init(struct hl_device *hdev)
 
 	prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
 
-	rc = hl_pci_init(hdev);
+	rc = hl_pci_init(hdev, 39);
 	if (rc)
 		return rc;
 
@@ -2446,28 +2446,16 @@ static int goya_hw_init(struct hl_device *hdev)
 		goto disable_msix;
 	}
 
-	/* CPU initialization is finished, we can now move to 48 bit DMA mask */
-	rc = pci_set_dma_mask(hdev->pdev, DMA_BIT_MASK(48));
-	if (rc) {
-		dev_warn(hdev->dev, "Unable to set pci dma mask to 48 bits\n");
-		rc = pci_set_dma_mask(hdev->pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_err(hdev->dev,
-				"Unable to set pci dma mask to 32 bits\n");
-			goto disable_pci_access;
-		}
-	}
-
-	rc = pci_set_consistent_dma_mask(hdev->pdev, DMA_BIT_MASK(48));
-	if (rc) {
-		dev_warn(hdev->dev,
-			"Unable to set pci consistent dma mask to 48 bits\n");
-		rc = pci_set_consistent_dma_mask(hdev->pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_err(hdev->dev,
-				"Unable to set pci consistent dma mask to 32 bits\n");
+	/*
+	 * Check if we managed to set the DMA mask to more then 32 bits. If so,
+	 * let's try to increase it again because in Goya we set the initial
+	 * dma mask to less then 39 bits so that the allocation of the memory
+	 * area for the device's cpu will be under 39 bits
+	 */
+	if (hdev->dma_mask > 32) {
+		rc = hl_pci_set_dma_mask(hdev, 48);
+		if (rc)
 			goto disable_pci_access;
-		}
 	}
 
 	/* Perform read from the device to flush all MSI-X configuration */
diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h
index 6991a7f260e8..e9253d937bfc 100644
--- a/drivers/misc/habanalabs/habanalabs.h
+++ b/drivers/misc/habanalabs/habanalabs.h
@@ -1106,6 +1106,7 @@ struct hl_device_reset_work {
  * @init_done: is the initialization of the device done.
  * @mmu_enable: is MMU enabled.
  * @device_cpu_disabled: is the device CPU disabled (due to timeouts)
+ * @dma_mask: the dma mask that was set for this device
  */
 struct hl_device {
 	struct pci_dev			*pdev;
@@ -1176,6 +1177,7 @@ struct hl_device {
 	u8				dram_default_page_mapping;
 	u8				init_done;
 	u8				device_cpu_disabled;
+	u8				dma_mask;
 
 	/* Parameters for bring-up */
 	u8				mmu_enable;
@@ -1397,8 +1399,9 @@ int hl_pci_set_dram_bar_base(struct hl_device *hdev, u8 inbound_region, u8 bar,
 				u64 addr);
 int hl_pci_init_iatu(struct hl_device *hdev, u64 sram_base_address,
 			u64 dram_base_address, u64 host_phys_size);
-int hl_pci_init(struct hl_device *hdev);
+int hl_pci_init(struct hl_device *hdev, u8 dma_mask);
 void hl_pci_fini(struct hl_device *hdev);
+int hl_pci_set_dma_mask(struct hl_device *hdev, u8 dma_mask);
 
 long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr);
 void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq);
diff --git a/drivers/misc/habanalabs/habanalabs_drv.c b/drivers/misc/habanalabs/habanalabs_drv.c
index 748601463f11..b697339d3904 100644
--- a/drivers/misc/habanalabs/habanalabs_drv.c
+++ b/drivers/misc/habanalabs/habanalabs_drv.c
@@ -229,6 +229,9 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
 		hdev->asic_type = asic_type;
 	}
 
+	/* Set default DMA mask to 32 bits */
+	hdev->dma_mask = 32;
+
 	mutex_lock(&hl_devs_idr_lock);
 
 	if (minor == -1) {
diff --git a/drivers/misc/habanalabs/pci.c b/drivers/misc/habanalabs/pci.c
index 822ac110b997..d472d02a8e6e 100644
--- a/drivers/misc/habanalabs/pci.c
+++ b/drivers/misc/habanalabs/pci.c
@@ -287,42 +287,74 @@ int hl_pci_init_iatu(struct hl_device *hdev, u64 sram_base_address,
 }
 
 /**
- * hl_pci_init() - PCI initialization code.
+ * hl_pci_set_dma_mask() - Set DMA masks for the device.
  * @hdev: Pointer to hl_device structure.
+ * @dma_mask: number of bits for the requested dma mask.
  *
- * Set DMA masks, initialize the PCI controller and map the PCI BARs.
+ * This function sets the DMA masks (regular and consistent) for a specified
+ * value. If it doesn't succeed, it tries to set it to a fall-back value
  *
  * Return: 0 on success, non-zero for failure.
  */
-int hl_pci_init(struct hl_device *hdev)
+int hl_pci_set_dma_mask(struct hl_device *hdev, u8 dma_mask)
 {
 	struct pci_dev *pdev = hdev->pdev;
 	int rc;
 
 	/* set DMA mask */
-	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(39));
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_mask));
 	if (rc) {
-		dev_warn(hdev->dev, "Unable to set pci dma mask to 39 bits\n");
-		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		dev_warn(hdev->dev,
+			"Failed to set pci dma mask to %d bits, error %d\n",
+			dma_mask, rc);
+
+		dma_mask = hdev->dma_mask;
+
+		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_mask));
 		if (rc) {
 			dev_err(hdev->dev,
-				"Unable to set pci dma mask to 32 bits\n");
+				"Failed to set pci dma mask to %d bits, error %d\n",
+				dma_mask, rc);
 			return rc;
 		}
 	}
 
-	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(39));
+	/*
+	 * We managed to set the dma mask, so update the dma mask field. If
+	 * the set to the coherent mask will fail with that mask, we will
+	 * fail the entire function
+	 */
+	hdev->dma_mask = dma_mask;
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(dma_mask));
 	if (rc) {
-		dev_warn(hdev->dev,
-			"Unable to set pci consistent dma mask to 39 bits\n");
-		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc) {
-			dev_err(hdev->dev,
-				"Unable to set pci consistent dma mask to 32 bits\n");
-			return rc;
-		}
+		dev_err(hdev->dev,
+			"Failed to set pci consistent dma mask to %d bits, error %d\n",
+			dma_mask, rc);
+		return rc;
 	}
 
+	return 0;
+}
+
+/**
+ * hl_pci_init() - PCI initialization code.
+ * @hdev: Pointer to hl_device structure.
+ * @dma_mask: number of bits for the requested dma mask.
+ *
+ * Set DMA masks, initialize the PCI controller and map the PCI BARs.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+int hl_pci_init(struct hl_device *hdev, u8 dma_mask)
+{
+	struct pci_dev *pdev = hdev->pdev;
+	int rc;
+
+	rc = hl_pci_set_dma_mask(hdev, dma_mask);
+	if (rc)
+		return rc;
+
 	if (hdev->reset_pcilink)
 		hl_pci_reset_link_through_bridge(hdev);
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 15/15] habanalabs: never fail hard reset of device
  2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
                   ` (13 preceding siblings ...)
  2019-03-17 19:59 ` [PATCH 14/15] habanalabs: keep track of the device's dma mask Oded Gabbay
@ 2019-03-17 19:59 ` Oded Gabbay
  14 siblings, 0 replies; 16+ messages in thread
From: Oded Gabbay @ 2019-03-17 19:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh

Hard-reset of our device should never fail, due to dangers of permanent
damage to the H/W.

This patch removes the last place in the reset path where the driver might
exit before doing the actual reset.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
---
 drivers/misc/habanalabs/device.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/misc/habanalabs/device.c b/drivers/misc/habanalabs/device.c
index 77d51be66c7e..c51d1062d0bc 100644
--- a/drivers/misc/habanalabs/device.c
+++ b/drivers/misc/habanalabs/device.c
@@ -663,17 +663,9 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
 	/* Go over all the queues, release all CS and their jobs */
 	hl_cs_rollback_all(hdev);
 
-	if (hard_reset) {
-		/* Release kernel context */
-		if (hl_ctx_put(hdev->kernel_ctx) != 1) {
-			dev_err(hdev->dev,
-				"kernel ctx is alive during hard reset\n");
-			rc = -EBUSY;
-			goto out_err;
-		}
-
+	/* Release kernel context */
+	if ((hard_reset) && (hl_ctx_put(hdev->kernel_ctx) == 1))
 		hdev->kernel_ctx = NULL;
-	}
 
 	/* Reset the H/W. It will be in idle state after this returns */
 	hdev->asic_funcs->hw_fini(hdev, hard_reset);
@@ -699,6 +691,13 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
 	if (hard_reset) {
 		hdev->device_cpu_disabled = false;
 
+		if (hdev->kernel_ctx) {
+			dev_crit(hdev->dev,
+				"kernel ctx was alive during hard reset, something is terribly wrong\n");
+			rc = -EBUSY;
+			goto out_err;
+		}
+
 		/* Allocate the kernel context */
 		hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx),
 						GFP_KERNEL);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2019-03-17 20:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-17 19:59 [PATCH 00/15] habanalabs: various improvements and updates Oded Gabbay
2019-03-17 19:59 ` [PATCH 01/15] habanalabs: add new device CPU boot status Oded Gabbay
2019-03-17 19:59 ` [PATCH 02/15] habanalabs: rename goya_non_fatal_events array to all events Oded Gabbay
2019-03-17 19:59 ` [PATCH 03/15] habanalabs: remove implicit include from header files Oded Gabbay
2019-03-17 19:59 ` [PATCH 04/15] habanalabs: Move device CPU code into common file Oded Gabbay
2019-03-17 19:59 ` [PATCH 05/15] habanalabs: use EQ MSI/X ID per chip Oded Gabbay
2019-03-17 19:59 ` [PATCH 06/15] habanalabs: remove unused defines Oded Gabbay
2019-03-17 19:59 ` [PATCH 07/15] habanalabs: ratelimit warnings at start of IOCTLs Oded Gabbay
2019-03-17 19:59 ` [PATCH 08/15] habanalabs: Move PCI code into common file Oded Gabbay
2019-03-17 19:59 ` [PATCH 09/15] habanalabs: Remove unneeded function pointers Oded Gabbay
2019-03-17 19:59 ` [PATCH 10/15] uapi/habanalabs: add some comments in habanalabs.h Oded Gabbay
2019-03-17 19:59 ` [PATCH 11/15] habanalabs: Add a printout with the name of a busy engine Oded Gabbay
2019-03-17 19:59 ` [PATCH 12/15] habanalabs: Allow accessing DRAM virtual addresses via debugfs Oded Gabbay
2019-03-17 19:59 ` [PATCH 13/15] habanalabs: add MMU shadow mapping Oded Gabbay
2019-03-17 19:59 ` [PATCH 14/15] habanalabs: keep track of the device's dma mask Oded Gabbay
2019-03-17 19:59 ` [PATCH 15/15] habanalabs: never fail hard reset of device Oded Gabbay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).