2a1b01
From c77b5adfb3f94762a08554d1b4d75f6cbd8a6abe Mon Sep 17 00:00:00 2001
2a1b01
From: Ido Schimmel <idosch@nvidia.com>
2a1b01
Date: Tue, 12 Oct 2021 16:25:17 +0300
2a1b01
Subject: [PATCH 18/35] sff-8636: Initialize SFF-8636 memory map
2a1b01
2a1b01
The SFF-8636 memory map [1] consists of Lower Memory and Upper Memory.
2a1b01
2a1b01
The content of the Lower Memory is fixed and can be addressed using an
2a1b01
offset between 0 and 127 (inclusive).
2a1b01
2a1b01
The Upper Memory is variable and optional and can be addressed by
2a1b01
specifying a page number and an offset between 128 and 255 (inclusive).
2a1b01
2a1b01
Create a structure describing this memory map and initialize it with
2a1b01
pointers to available pages.
2a1b01
2a1b01
In the IOCTL path, the structure holds pointers to regions of the
2a1b01
continuous buffer passed to user space via the 'ETHTOOL_GMODULEEEPROM'
2a1b01
command.
2a1b01
2a1b01
In the netlink path, the structure holds pointers to individual pages
2a1b01
passed to user space via the 'MODULE_EEPROM_GET' message.
2a1b01
2a1b01
This structure will later allow us to consolidate the IOCTL and netlink
2a1b01
parsing code paths and also easily support additional EEPROM pages, when
2a1b01
needed.
2a1b01
2a1b01
[1] SFF-8636 Rev. 2.10a, pag. 30, section 6.1, Figure 6-1
2a1b01
2a1b01
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
2a1b01
---
2a1b01
 qsfp.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2a1b01
 1 file changed, 65 insertions(+)
2a1b01
2a1b01
diff --git a/qsfp.c b/qsfp.c
2a1b01
index dc6407d3ef6f..80000d40f6e8 100644
2a1b01
--- a/qsfp.c
2a1b01
+++ b/qsfp.c
2a1b01
@@ -60,6 +60,15 @@
2a1b01
 #include "qsfp.h"
2a1b01
 #include "cmis.h"
2a1b01
 
2a1b01
+struct sff8636_memory_map {
2a1b01
+	const __u8 *lower_memory;
2a1b01
+	const __u8 *upper_memory[4];
2a1b01
+#define page_00h upper_memory[0x0]
2a1b01
+#define page_03h upper_memory[0x3]
2a1b01
+};
2a1b01
+
2a1b01
+#define SFF8636_PAGE_SIZE	0x80
2a1b01
+
2a1b01
 #define MAX_DESC_SIZE	42
2a1b01
 
2a1b01
 static struct sff8636_aw_flags {
2a1b01
@@ -853,13 +862,40 @@ static void sff8636_show_page_zero(const __u8 *id)
2a1b01
 
2a1b01
 }
2a1b01
 
2a1b01
+static void sff8636_memory_map_init_buf(struct sff8636_memory_map *map,
2a1b01
+					const __u8 *id, __u32 eeprom_len)
2a1b01
+{
2a1b01
+	/* Lower Memory and Page 00h are always present.
2a1b01
+	 *
2a1b01
+	 * Offset into Upper Memory is between page size and twice the page
2a1b01
+	 * size. Therefore, set the base address of each page to base address
2a1b01
+	 * plus page size multiplied by the page number.
2a1b01
+	 */
2a1b01
+	map->lower_memory = id;
2a1b01
+	map->page_00h = id;
2a1b01
+
2a1b01
+	/* Page 03h is only present when the module memory model is paged and
2a1b01
+	 * not flat and when we got a big enough buffer from the kernel.
2a1b01
+	 */
2a1b01
+	if (map->lower_memory[SFF8636_STATUS_2_OFFSET] &
2a1b01
+	    SFF8636_STATUS_PAGE_3_PRESENT ||
2a1b01
+	    eeprom_len != ETH_MODULE_SFF_8636_MAX_LEN)
2a1b01
+		return;
2a1b01
+
2a1b01
+	map->page_03h = id + 3 * SFF8636_PAGE_SIZE;
2a1b01
+}
2a1b01
+
2a1b01
 void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len)
2a1b01
 {
2a1b01
+	struct sff8636_memory_map map = {};
2a1b01
+
2a1b01
 	if (id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP_DD) {
2a1b01
 		cmis_show_all_ioctl(id);
2a1b01
 		return;
2a1b01
 	}
2a1b01
 
2a1b01
+	sff8636_memory_map_init_buf(&map, id, eeprom_len);
2a1b01
+
2a1b01
 	sff8636_show_identifier(id);
2a1b01
 	switch (id[SFF8636_ID_OFFSET]) {
2a1b01
 	case SFF8024_ID_QSFP:
2a1b01
@@ -871,9 +907,38 @@ void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len)
2a1b01
 	}
2a1b01
 }
2a1b01
 
2a1b01
+static void
2a1b01
+sff8636_memory_map_init_pages(struct sff8636_memory_map *map,
2a1b01
+			      const struct ethtool_module_eeprom *page_zero,
2a1b01
+			      const struct ethtool_module_eeprom *page_three)
2a1b01
+{
2a1b01
+	/* Lower Memory and Page 00h are always present.
2a1b01
+	 *
2a1b01
+	 * Offset into Upper Memory is between page size and twice the page
2a1b01
+	 * size. Therefore, set the base address of each page to its base
2a1b01
+	 * address minus page size. For Page 00h, this is the address of the
2a1b01
+	 * Lower Memory.
2a1b01
+	 */
2a1b01
+	map->lower_memory = page_zero->data;
2a1b01
+	map->page_00h = page_zero->data;
2a1b01
+
2a1b01
+	/* Page 03h is only present when the module memory model is paged and
2a1b01
+	 * not flat.
2a1b01
+	 */
2a1b01
+	if (map->lower_memory[SFF8636_STATUS_2_OFFSET] &
2a1b01
+	    SFF8636_STATUS_PAGE_3_PRESENT)
2a1b01
+		return;
2a1b01
+
2a1b01
+	map->page_03h = page_three->data - SFF8636_PAGE_SIZE;
2a1b01
+}
2a1b01
+
2a1b01
 void sff8636_show_all_nl(const struct ethtool_module_eeprom *page_zero,
2a1b01
 			 const struct ethtool_module_eeprom *page_three)
2a1b01
 {
2a1b01
+	struct sff8636_memory_map map = {};
2a1b01
+
2a1b01
+	sff8636_memory_map_init_pages(&map, page_zero, page_three);
2a1b01
+
2a1b01
 	sff8636_show_identifier(page_zero->data);
2a1b01
 	sff8636_show_page_zero(page_zero->data);
2a1b01
 	if (page_three)
2a1b01
-- 
2a1b01
2.35.1
2a1b01