Subject: [PATCH v3 07/14] habanalabs/gaudi: allow user to get MAC addresses in INFO IOCTL

From: Oded Gabbay <[email-masked]>
Date: Tue, 15 Sep 2020 20:10:15 +0300

From: Omer Shpigelman <[email-masked]>

The user needs this information when working in a distributed environment
with master/slave configuration. All the slaves get their MAC addresses
from the driver and send them to the master.

Signed-off-by: Omer Shpigelman <[email-masked]>
Reviewed-by: Oded Gabbay <[email-masked]>
Signed-off-by: Oded Gabbay <[email-masked]>
---
 drivers/misc/habanalabs/common/habanalabs.h   |  5 +++
 .../misc/habanalabs/common/habanalabs_ioctl.c | 31 +++++++++++++++++++
 drivers/misc/habanalabs/gaudi/gaudi.c         |  1 +
 drivers/misc/habanalabs/gaudi/gaudiP.h        |  2 ++
 drivers/misc/habanalabs/gaudi/gaudi_nic.c     | 27 ++++++++++++++++
 drivers/misc/habanalabs/goya/goya.c           |  9 ++++++
 include/uapi/misc/habanalabs.h                | 20 +++++++++++-
 7 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h
index 45feb4884ab3..fee04299360d 100644
--- a/drivers/misc/habanalabs/common/habanalabs.h
+++ b/drivers/misc/habanalabs/common/habanalabs.h
@@ -619,6 +619,8 @@ enum div_select_defs {
 	DIV_SEL_DIVIDED_PLL = 3,
 };
 
+struct hl_info_mac_addr;
+
 /**
  * struct hl_asic_funcs - ASIC specific functions that are can be called from
  *                        common code.
@@ -696,6 +698,7 @@ enum div_select_defs {
  * @get_hw_state: retrieve the H/W state
  * @pci_bars_map: Map PCI BARs.
  * @init_iatu: Initialize the iATU unit inside the PCI controller.
+ * @get_mac_addr: Get list of MAC addresses.
  * @rreg: Read a register. Needed for simulator support.
  * @wreg: Write a register. Needed for simulator support.
  * @halt_coresight: stop the ETF and ETR traces.
@@ -799,6 +802,8 @@ struct hl_asic_funcs {
 	enum hl_device_hw_state (*get_hw_state)(struct hl_device *hdev);
 	int (*pci_bars_map)(struct hl_device *hdev);
 	int (*init_iatu)(struct hl_device *hdev);
+	int (*get_mac_addr)(struct hl_device *hdev,
+				struct hl_info_mac_addr *mac_addr);
 	u32 (*rreg)(struct hl_device *hdev, u32 reg);
 	void (*wreg)(struct hl_device *hdev, u32 reg, u32 val);
 	void (*halt_coresight)(struct hl_device *hdev);
diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c
index 07317ea49129..5db6c978415c 100644
--- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c
+++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c
@@ -203,6 +203,33 @@ static int debug_coresight(struct hl_device *hdev, struct hl_debug_args *args)
 	return rc;
 }
 
+static int mac_addr_info(struct hl_device *hdev, struct hl_info_args *args)
+{
+	void __user *out = (void __user *) (uintptr_t) args->return_pointer;
+	struct hl_info_mac_addr *mac_addr;
+	u32 max_size = args->return_size;
+	int rc;
+
+	if (!max_size || !out)
+		return -EINVAL;
+
+	mac_addr = kzalloc(sizeof(struct hl_info_mac_addr), GFP_KERNEL);
+	if (!mac_addr)
+		return -ENOMEM;
+
+	rc = hdev->asic_funcs->get_mac_addr(hdev, mac_addr);
+	if (rc)
+		goto out;
+
+	rc = copy_to_user(out, mac_addr,
+		min((size_t) max_size, sizeof(struct hl_info_mac_addr))) ?
+								-EFAULT : 0;
+
+out:
+	kfree(mac_addr);
+	return rc;
+}
+
 static int device_utilization(struct hl_device *hdev, struct hl_info_args *args)
 {
 	struct hl_info_device_utilization device_util = {0};
@@ -423,6 +450,10 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
 		rc = hw_idle(hdev, args);
 		break;
 
+	case HL_INFO_MAC_ADDR:
+		rc = mac_addr_info(hdev, args);
+		break;
+
 	case HL_INFO_DEVICE_UTILIZATION:
 		rc = device_utilization(hdev, args);
 		break;
diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c
index eee83e0a8c6d..d2f51497fa8e 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi.c
+++ b/drivers/misc/habanalabs/gaudi/gaudi.c
@@ -7472,6 +7472,7 @@ static const struct hl_asic_funcs gaudi_funcs = {
 	.get_hw_state = gaudi_get_hw_state,
 	.pci_bars_map = gaudi_pci_bars_map,
 	.init_iatu = gaudi_init_iatu,
+	.get_mac_addr = gaudi_nic_get_mac_addr,
 	.rreg = hl_rreg,
 	.wreg = hl_wreg,
 	.halt_coresight = gaudi_halt_coresight,
diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h
index 6dea73c5682f..69b3656eaaeb 100644
--- a/drivers/misc/habanalabs/gaudi/gaudiP.h
+++ b/drivers/misc/habanalabs/gaudi/gaudiP.h
@@ -564,6 +564,8 @@ void gaudi_nic_ports_fini(struct hl_device *hdev);
 int gaudi_nic_hard_reset_prepare(struct hl_device *hdev);
 void gaudi_nic_stop(struct hl_device *hdev);
 void gaudi_nic_ports_reopen(struct hl_device *hdev);
+int gaudi_nic_get_mac_addr(struct hl_device *hdev,
+				struct hl_info_mac_addr *mac_addr);
 void gaudi_nic_ctx_fini(struct hl_ctx *ctx);
 irqreturn_t gaudi_nic_rx_irq_handler(int irq, void *arg);
 irqreturn_t gaudi_nic_cq_irq_handler(int irq, void *arg);
diff --git a/drivers/misc/habanalabs/gaudi/gaudi_nic.c b/drivers/misc/habanalabs/gaudi/gaudi_nic.c
index 1e3f58297e5e..fc4fc80eb005 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi_nic.c
+++ b/drivers/misc/habanalabs/gaudi/gaudi_nic.c
@@ -2774,6 +2774,33 @@ void gaudi_nic_ports_reopen(struct hl_device *hdev)
 	gaudi->hw_cap_initialized |= HW_CAP_NIC_DRV;
 }
 
+int gaudi_nic_get_mac_addr(struct hl_device *hdev,
+				struct hl_info_mac_addr *mac_addr)
+{
+	struct gaudi_device *gaudi = hdev->asic_specific;
+	struct net_device *ndev;
+	int i, number_of_ports;
+
+	if (!(gaudi->hw_cap_initialized & HW_CAP_NIC_DRV))
+		goto out;
+
+	number_of_ports = min_t(int, NIC_NUMBER_OF_PORTS,
+				HL_INFO_MAC_ADDR_MAX_NUM);
+
+	for (i = 0 ; i < number_of_ports ; i++) {
+		if (!(hdev->nic_ports_mask & BIT(i)))
+			continue;
+
+		ndev = gaudi->nic_devices[i].ndev;
+		if (!ndev)
+			continue;
+
+		ether_addr_copy(mac_addr->array[i].addr, ndev->dev_addr);
+		mac_addr->mask[i / 64] |= BIT_ULL(i % 64);
+	}
+out:
+	return 0;
+}
 void gaudi_nic_ctx_fini(struct hl_ctx *ctx)
 {
 }
diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index f82212310114..75e3b3bac47c 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -5269,6 +5269,14 @@ static enum hl_device_hw_state goya_get_hw_state(struct hl_device *hdev)
 	return RREG32(mmHW_STATE);
 }
 
+static int goya_get_mac_addr(struct hl_device *hdev,
+			struct hl_info_mac_addr *mac_addr)
+{
+	dev_err_ratelimited(hdev->dev,
+				"No MAC addresses are assigned to Goya\n");
+	return -ENXIO;
+}
+
 static int goya_ctx_init(struct hl_ctx *ctx)
 {
 	return 0;
@@ -5388,6 +5396,7 @@ static const struct hl_asic_funcs goya_funcs = {
 	.get_hw_state = goya_get_hw_state,
 	.pci_bars_map = goya_pci_bars_map,
 	.init_iatu = goya_init_iatu,
+	.get_mac_addr = goya_get_mac_addr,
 	.rreg = hl_rreg,
 	.wreg = hl_wreg,
 	.halt_coresight = goya_halt_coresight,
diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h
index cd9d05e03464..4c545ae8b6df 100644
--- a/include/uapi/misc/habanalabs.h
+++ b/include/uapi/misc/habanalabs.h
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
+#include <linux/if_ether.h>
 
 /*
  * Defines that are asic-specific but constitutes as ABI between kernel driver
@@ -248,6 +249,8 @@ enum hl_device_status {
  *                         internal engine.
  * HL_INFO_DEVICE_STATUS - Retrieve the device's status. This opcode doesn't
  *                         require an open context.
+ * HL_INFO_MAC_ADDR      - Retrieve the list of MAC addresses of the device's
+ *                         network ports, if the device has network ports.
  * HL_INFO_DEVICE_UTILIZATION  - Retrieve the total utilization of the device
  *                               over the last period specified by the user.
  *                               The period can be between 100ms to 1s, in
@@ -274,6 +277,7 @@ enum hl_device_status {
 #define HL_INFO_DRAM_USAGE		2
 #define HL_INFO_HW_IDLE			3
 #define HL_INFO_DEVICE_STATUS		4
+#define HL_INFO_MAC_ADDR		5
 #define HL_INFO_DEVICE_UTILIZATION	6
 #define HL_INFO_HW_EVENTS_AGGREGATE	7
 #define HL_INFO_CLK_RATE		8
@@ -285,9 +289,11 @@ enum hl_device_status {
 #define HL_INFO_SYNC_MANAGER		14
 #define HL_INFO_TOTAL_ENERGY		15
 
-#define HL_INFO_VERSION_MAX_LEN	128
+#define HL_INFO_VERSION_MAX_LEN		128
 #define HL_INFO_CARD_NAME_MAX_LEN	16
 
+#define HL_INFO_MAC_ADDR_MAX_NUM	128
+
 struct hl_info_hw_ip_info {
 	__u64 sram_base_address;
 	__u64 dram_base_address;
@@ -334,6 +340,18 @@ struct hl_info_device_status {
 	__u32 pad;
 };
 
+struct hl_mac_addr {
+	__u8 addr[ETH_ALEN];
+	__u8 pad[2];
+};
+
+struct hl_info_mac_addr {
+	/* MAC address at index N is of the corresponding PORT ID */
+	struct hl_mac_addr array[HL_INFO_MAC_ADDR_MAX_NUM];
+	/* Mask of valid entries at the MAC addresses array */
+	__u64 mask[2];
+};
+
 struct hl_info_device_utilization {
 	__u32 utilization;
 	__u32 pad;
-- 
2.17.1