lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 13 May 2021 11:57:19 +0300
From:   Guy Zadicario <guy.zadicario@...el.com>
To:     gregkh@...uxfoundation.org, linux-kernel@...r.kernel.org
Cc:     olof@...om.net, alexander.shishkin@...ux.intel.com,
        andriy.shevchenko@...el.com, yochai.shefi-simchon@...el.com,
        guy.zadicario@...el.com
Subject: [PATCH v2 09/15] misc: nnpi: Process device response messages

The nnpdev_process_messages function handles all messages coming
from a NNP-I device. Based on an opcode field attached to each message,
it calls the correct response processing handler. The function is
called from the NNP-I device driver, from a threaded interrupt handler, when
responses arrive in the HW response queue.

Signed-off-by: Guy Zadicario <guy.zadicario@...el.com>
Reviewed-by: Alexander Shishkin <alexander.shishkin@...ux.intel.com>
---
 drivers/misc/intel-nnpi/device.c   | 136 +++++++++++++++++++++++++++++++++++++
 drivers/misc/intel-nnpi/device.h   |  10 +++
 drivers/misc/intel-nnpi/nnp_pcie.c |   3 +
 3 files changed, 149 insertions(+)

diff --git a/drivers/misc/intel-nnpi/device.c b/drivers/misc/intel-nnpi/device.c
index f4fc975..2e6ab82 100644
--- a/drivers/misc/intel-nnpi/device.c
+++ b/drivers/misc/intel-nnpi/device.c
@@ -23,6 +23,142 @@ bool nnpdev_no_devices(void)
 	return ida_is_empty(&dev_ida);
 }
 
+/**
+ * handle_bios_protocol() - process response coming from card's BIOS.
+ * @nnpdev: The nnp device
+ * @msgbuf: pointer to response message content
+ * @avail_qwords: number of 64-bit units available in @msgbuf
+ *
+ * IPC protocol with card's BIOS may have different response sizes.
+ * @avail_qwords is the number of 64-bit units available in @msgbuf buffer.
+ * If the actual response size is larger then available data in the buffer,
+ * the function returns 0 to indicate that this is a partial response. Otherwise
+ * the actual response size is returned (in units of qwords).
+ *
+ * Return: 0 if @msgbuf contains a partial response otherwise the number of
+ * qwords of the response in @msgbuf.
+ */
+static int handle_bios_protocol(struct nnp_device *nnpdev, const u64 *msgbuf,
+				int avail_qwords)
+{
+	int msg_size, msg_qwords;
+
+	msg_size = FIELD_GET(NNP_C2H_BIOS_PROTOCOL_TYPE_MASK, msgbuf[0]);
+
+	/* The +1 is because size field does not include header */
+	msg_qwords = DIV_ROUND_UP(msg_size, 8) + 1;
+
+	if (msg_qwords > avail_qwords)
+		return 0;
+
+	return msg_qwords;
+}
+
+typedef int (*response_handler)(struct nnp_device *nnpdev, const u64 *msgbuf,
+				int avail_qwords);
+
+static response_handler resp_handlers[NNP_IPC_C2H_OPCODE_LAST + 1] = {
+	[NNP_IPC_C2H_OP_BIOS_PROTOCOL] = handle_bios_protocol
+};
+
+/**
+ * nnpdev_process_messages() - process response messages from nnpi device
+ * @nnpdev: The nnp device
+ * @hw_msg: pointer to response message content
+ * @hw_nof_msg: number of 64-bit units available in hw_msg buffer.
+ *
+ * This function is called from the PCIe device driver when response messages
+ * are arrived in the HWQ. It is called in sequence, should not be re-entrant.
+ * The function may not block !
+ */
+void nnpdev_process_messages(struct nnp_device *nnpdev, u64 *hw_msg,
+			     unsigned int hw_nof_msg)
+{
+	int j = 0;
+	int msg_size;
+	u64 *msg;
+	unsigned int nof_msg;
+	bool fatal_protocol_error = false;
+
+	/* ignore any response if protocol error detected */
+	if ((nnpdev->state & NNP_DEVICE_PROTOCOL_ERROR) != 0)
+		return;
+
+	/*
+	 * If we have pending messages from previous round
+	 * copy the new messages to the pending list and process
+	 * the pending list.
+	 * otherwise process the messages received from HW directly
+	 */
+	msg = hw_msg;
+	nof_msg = hw_nof_msg;
+	if (nnpdev->response_num_msgs > 0) {
+		/*
+		 * Check to prevent response buffer overrun.
+		 * This should never happen since the buffer is twice
+		 * the size of the HW response queue. This check is
+		 * for safety and debug purposes.
+		 */
+		if (hw_nof_msg + nnpdev->response_num_msgs >=
+		    NNP_DEVICE_RESPONSE_BUFFER_LEN) {
+			dev_dbg(nnpdev->dev,
+				"device response buffer would overrun: %d + %d !!\n",
+				nnpdev->response_num_msgs, hw_nof_msg);
+			return;
+		}
+
+		memcpy(&nnpdev->response_buf[nnpdev->response_num_msgs], hw_msg,
+		       hw_nof_msg * sizeof(u64));
+		msg = nnpdev->response_buf;
+		nof_msg = nnpdev->response_num_msgs + hw_nof_msg;
+	}
+
+	/*
+	 * loop for each message
+	 */
+	do {
+		int op_code = FIELD_GET(NNP_C2H_OP_MASK, msg[j]);
+		response_handler handler;
+
+		/* opcodes above OP_BIOS_PROTOCOL are not yet supported */
+		if (op_code > NNP_IPC_C2H_OP_BIOS_PROTOCOL) {
+			fatal_protocol_error = true;
+			break;
+		}
+
+		/* dispatch the message request */
+		handler = resp_handlers[op_code];
+		if (!handler) {
+			/* Should not happen! */
+			dev_dbg(nnpdev->dev,
+				"Unknown response opcode received %d (0x%llx)\n",
+				op_code, msg[j]);
+			fatal_protocol_error = true;
+			break;
+		}
+
+		msg_size = (*handler)(nnpdev, &msg[j], (nof_msg - j));
+
+		j += msg_size;
+	} while (j < nof_msg || !msg_size);
+
+	if (fatal_protocol_error)
+		nnpdev->state |= NNP_DEVICE_PROTOCOL_ERROR;
+
+	/*
+	 * If unprocessed messages left, copy it to the pending messages buffer
+	 * for the next time this function will be called.
+	 */
+	if (j < nof_msg) {
+		memcpy(&nnpdev->response_buf[0], &msg[j],
+		       (nof_msg - j) * sizeof(u64));
+		nnpdev->response_num_msgs = nof_msg - j;
+	} else {
+		nnpdev->response_num_msgs = 0;
+	}
+}
+EXPORT_SYMBOL(nnpdev_process_messages);
+
 static void send_sysinfo_request_to_bios(struct nnp_device *nnpdev)
 {
 	u64 cmd[3];
diff --git a/drivers/misc/intel-nnpi/device.h b/drivers/misc/intel-nnpi/device.h
index 3745f5c..b83f67a 100644
--- a/drivers/misc/intel-nnpi/device.h
+++ b/drivers/misc/intel-nnpi/device.h
@@ -48,6 +48,9 @@
 #define NNP_DEVICE_CORRUPTED_BOOT_IMAGE BIT(30)
 #define NNP_DEVICE_ERROR_MASK        GENMASK(31, 16)
 
+#define NNP_DEVICE_RESPONSE_FIFO_LEN    16
+#define NNP_DEVICE_RESPONSE_BUFFER_LEN  (NNP_DEVICE_RESPONSE_FIFO_LEN * 2)
+
 /**
  * struct nnp_device - structure for NNP-I device info
  * @ops: device operations implemented by the underlying device driver
@@ -61,6 +64,8 @@
  * @lock: protects accesses to @state
  * @is_recovery_bios: true if device has booted from the recovery bios flash
  * @boot_image_loaded: true if boot image load has started
+ * @response_buf: buffer of device response messages arrived from "pci" layer.
+ * @response_num_msgs: number of qwords available in @response_buf
  * @bios_system_info_dma_addr: dma page allocated for bios system info.
  * @bios_system_info: virtual pointer to bios system info page
  * @bios_version_str: the device's started bios version string
@@ -83,6 +88,9 @@ struct nnp_device {
 	bool           is_recovery_bios;
 	bool           boot_image_loaded;
 
+	u64            response_buf[NNP_DEVICE_RESPONSE_BUFFER_LEN];
+	unsigned int   response_num_msgs;
+
 	dma_addr_t                  bios_system_info_dma_addr;
 	struct nnp_c2h_system_info  *bios_system_info;
 	char                        bios_version_str[NNP_BIOS_VERSION_LEN];
@@ -118,6 +126,8 @@ int nnpdev_init(struct nnp_device *nnpdev, struct device *dev,
 void nnpdev_destroy(struct nnp_device *nnpdev);
 void nnpdev_card_doorbell_value_changed(struct nnp_device *nnpdev,
 					u32 doorbell_val);
+void nnpdev_process_messages(struct nnp_device *nnpdev, u64 *hw_msg,
+			     unsigned int hw_nof_msg);
 
 /*
  * Framework internal functions (not exported)
diff --git a/drivers/misc/intel-nnpi/nnp_pcie.c b/drivers/misc/intel-nnpi/nnp_pcie.c
index 3840a53..4c9b4c6 100644
--- a/drivers/misc/intel-nnpi/nnp_pcie.c
+++ b/drivers/misc/intel-nnpi/nnp_pcie.c
@@ -150,6 +150,9 @@ static void nnp_process_commands(struct nnp_pci *nnp_pci)
 	response_pci_control |= FIELD_PREP(RESPQ_READ_PTR_MASK, read_pointer);
 	nnp_mmio_write(nnp_pci, ELBI_RESPONSE_PCI_CONTROL,
 		       response_pci_control);
+
+	nnpdev_process_messages(&nnp_pci->nnpdev, nnp_pci->response_buf,
+				avail_slots);
 }
 
 static void mask_all_interrupts(struct nnp_pci *nnp_pci)
-- 
1.8.3.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ