|
|
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 |
|