Commit c7cb7635 authored by Mike Marciniszyn's avatar Mike Marciniszyn Committed by Doug Ledford

staging/rdma/hfi1: Fix QSFP memory read/write across 128 byte boundary

The QSFP memory cache reads both lower and upper page 0H in one shot,
which leads to the address counter wrapping around to the beginning of
lower page 00H at byte 128, as defined by SFF-8636.
This patch fixes this by modifying the underlying QSFP read and writes
to avoid this wrap around.
Reviewed-by: default avatarDean Luick <dean.luick@intel.com>
Reviewed-by: default avatarIra Weiny <ira.weiny@intel.com>
Signed-off-by: default avatarEaswar Hariharan <easwar.hariharan@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 76ef8c07
...@@ -186,6 +186,10 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, ...@@ -186,6 +186,10 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
return ret; return ret;
} }
/*
* Write page n, offset m of QSFP memory as defined by SFF 8636
* in the cache by writing @addr = ((256 * n) + m)
*/
int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len) int len)
{ {
...@@ -217,15 +221,15 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -217,15 +221,15 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
break; break;
} }
/* truncate write to end of page if crossing page boundary */
offset = addr % QSFP_PAGESIZE; offset = addr % QSFP_PAGESIZE;
nwrite = len - count; nwrite = len - count;
if ((offset + nwrite) > QSFP_PAGESIZE) /* truncate write to boundary if crossing boundary */
nwrite = QSFP_PAGESIZE - offset; if (((addr % QSFP_RW_BOUNDARY) + nwrite) > QSFP_RW_BOUNDARY)
nwrite = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
ret = __i2c_write(ppd, target, QSFP_DEV, offset, bp + count, ret = __i2c_write(ppd, target, QSFP_DEV, offset, bp + count,
nwrite); nwrite);
if (ret <= 0) /* stop on error or nothing read */ if (ret <= 0) /* stop on error or nothing written */
break; break;
count += ret; count += ret;
...@@ -239,6 +243,10 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -239,6 +243,10 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
return count; return count;
} }
/*
* Access page n, offset m of QSFP memory as defined by SFF 8636
* in the cache by reading @addr = ((256 * n) + m)
*/
int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
int len) int len)
{ {
...@@ -269,11 +277,11 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -269,11 +277,11 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
break; break;
} }
/* truncate read to end of page if crossing page boundary */
offset = addr % QSFP_PAGESIZE; offset = addr % QSFP_PAGESIZE;
nread = len - count; nread = len - count;
if ((offset + nread) > QSFP_PAGESIZE) /* truncate read to boundary if crossing boundary */
nread = QSFP_PAGESIZE - offset; if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY)
nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
ret = __i2c_read(ppd, target, QSFP_DEV, offset, bp + count, ret = __i2c_read(ppd, target, QSFP_DEV, offset, bp + count,
nread); nread);
...@@ -295,6 +303,11 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -295,6 +303,11 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
* This function caches the QSFP memory range in 128 byte chunks. * This function caches the QSFP memory range in 128 byte chunks.
* As an example, the next byte after address 255 is byte 128 from * As an example, the next byte after address 255 is byte 128 from
* upper page 01H (if existing) rather than byte 0 from lower page 00H. * upper page 01H (if existing) rather than byte 0 from lower page 00H.
* Access page n, offset m of QSFP memory as defined by SFF 8636
* in the cache by reading byte ((128 * n) + m)
* The calls to qsfp_{read,write} in this function correctly handle the
* address map difference between this mapping and the mapping implemented
* by those functions
*/ */
int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp) int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
{ {
...@@ -305,23 +318,24 @@ int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp) ...@@ -305,23 +318,24 @@ int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
/* ensure sane contents on invalid reads, for cable swaps */ /* ensure sane contents on invalid reads, for cable swaps */
memset(cache, 0, (QSFP_MAX_NUM_PAGES*128)); memset(cache, 0, (QSFP_MAX_NUM_PAGES*128));
dd_dev_info(ppd->dd, "%s: called\n", __func__); spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
ppd->qsfp_info.cache_valid = 0;
spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags);
dd_dev_info(ppd->dd, "%s called\n", __func__);
if (!qsfp_mod_present(ppd)) { if (!qsfp_mod_present(ppd)) {
ret = -ENODEV; ret = -ENODEV;
goto bail; goto bail;
} }
ret = qsfp_read(ppd, target, 0, cache, 256); ret = qsfp_read(ppd, target, 0, cache, QSFP_PAGESIZE);
if (ret != 256) { if (ret != QSFP_PAGESIZE) {
dd_dev_info(ppd->dd, dd_dev_info(ppd->dd,
"%s: Read of pages 00H failed, expected 256, got %d\n", "%s: Page 0 read failed, expected %d, got %d\n",
__func__, ret); __func__, QSFP_PAGESIZE, ret);
goto bail; goto bail;
} }
if (cache[0] != 0x0C && cache[0] != 0x0D)
goto bail;
/* Is paging enabled? */ /* Is paging enabled? */
if (!(cache[2] & 4)) { if (!(cache[2] & 4)) {
......
...@@ -67,15 +67,16 @@ ...@@ -67,15 +67,16 @@
/* QSFP is paged at 256 bytes */ /* QSFP is paged at 256 bytes */
#define QSFP_PAGESIZE 256 #define QSFP_PAGESIZE 256
/* Reads/writes cannot cross 128 byte boundaries */
#define QSFP_RW_BOUNDARY 128
/* Defined fields that Intel requires of qualified cables */ /* Defined fields that Intel requires of qualified cables */
/* Byte 0 is Identifier, not checked */ /* Byte 0 is Identifier, not checked */
/* Byte 1 is reserved "status MSB" */ /* Byte 1 is reserved "status MSB" */
/* Byte 2 is "status LSB" We only care that D2 "Flat Mem" is set. */ #define QSFP_TX_CTRL_BYTE_OFFS 86
/* #define QSFP_PWR_CTRL_BYTE_OFFS 93
* Rest of first 128 not used, although 127 is reserved for page select #define QSFP_CDR_CTRL_BYTE_OFFS 98
* if module is not "Flat memory".
*/
#define QSFP_PAGE_SELECT_BYTE_OFFS 127 #define QSFP_PAGE_SELECT_BYTE_OFFS 127
/* Byte 128 is Identifier: must be 0x0c for QSFP, or 0x0d for QSFP+ */ /* Byte 128 is Identifier: must be 0x0c for QSFP, or 0x0d for QSFP+ */
#define QSFP_MOD_ID_OFFS 128 #define QSFP_MOD_ID_OFFS 128
...@@ -87,7 +88,8 @@ ...@@ -87,7 +88,8 @@
/* Byte 130 is Connector type. Not Intel req'd */ /* Byte 130 is Connector type. Not Intel req'd */
/* Bytes 131..138 are Transceiver types, bit maps for various tech, none IB */ /* Bytes 131..138 are Transceiver types, bit maps for various tech, none IB */
/* Byte 139 is encoding. code 0x01 is 8b10b. Not Intel req'd */ /* Byte 139 is encoding. code 0x01 is 8b10b. Not Intel req'd */
/* byte 140 is nominal bit-rate, in units of 100Mbits/sec Not Intel req'd */ /* byte 140 is nominal bit-rate, in units of 100Mbits/sec */
#define QSFP_NOM_BIT_RATE_100_OFFS 140
/* Byte 141 is Extended Rate Select. Not Intel req'd */ /* Byte 141 is Extended Rate Select. Not Intel req'd */
/* Bytes 142..145 are lengths for various fiber types. Not Intel req'd */ /* Bytes 142..145 are lengths for various fiber types. Not Intel req'd */
/* Byte 146 is length for Copper. Units of 1 meter */ /* Byte 146 is length for Copper. Units of 1 meter */
...@@ -135,11 +137,18 @@ extern const char *const hfi1_qsfp_devtech[16]; ...@@ -135,11 +137,18 @@ extern const char *const hfi1_qsfp_devtech[16];
*/ */
#define QSFP_ATTEN_OFFS 186 #define QSFP_ATTEN_OFFS 186
#define QSFP_ATTEN_LEN 2 #define QSFP_ATTEN_LEN 2
/* Bytes 188,189 are Wavelength tolerance, not Intel req'd */ /*
* Bytes 188,189 are Wavelength tolerance, if optical
* If copper, they are attenuation in dB:
* Byte 188 is at 12.5 Gb/s, Byte 189 at 25 Gb/s
*/
#define QSFP_CU_ATTEN_7G_OFFS 188
#define QSFP_CU_ATTEN_12G_OFFS 189
/* Byte 190 is Max Case Temp. Not Intel req'd */ /* Byte 190 is Max Case Temp. Not Intel req'd */
/* Byte 191 is LSB of sum of bytes 128..190. Not Intel req'd */ /* Byte 191 is LSB of sum of bytes 128..190. Not Intel req'd */
#define QSFP_CC_OFFS 191 #define QSFP_CC_OFFS 191
/* Bytes 192..195 are Options implemented in qsfp. Not Intel req'd */ #define QSFP_EQ_INFO_OFFS 193
#define QSFP_CDR_INFO_OFFS 194
/* Bytes 196..211 are Serial Number, String */ /* Bytes 196..211 are Serial Number, String */
#define QSFP_SN_OFFS 196 #define QSFP_SN_OFFS 196
#define QSFP_SN_LEN 16 #define QSFP_SN_LEN 16
...@@ -150,6 +159,8 @@ extern const char *const hfi1_qsfp_devtech[16]; ...@@ -150,6 +159,8 @@ extern const char *const hfi1_qsfp_devtech[16];
#define QSFP_LOT_OFFS 218 #define QSFP_LOT_OFFS 218
#define QSFP_LOT_LEN 2 #define QSFP_LOT_LEN 2
/* Bytes 220, 221 indicate monitoring options, Not Intel req'd */ /* Bytes 220, 221 indicate monitoring options, Not Intel req'd */
/* Byte 222 indicates nominal bitrate in units of 250Mbits/sec */
#define QSFP_NOM_BIT_RATE_250_OFFS 222
/* Byte 223 is LSB of sum of bytes 192..222 */ /* Byte 223 is LSB of sum of bytes 192..222 */
#define QSFP_CC_EXT_OFFS 223 #define QSFP_CC_EXT_OFFS 223
...@@ -191,6 +202,7 @@ extern const char *const hfi1_qsfp_devtech[16]; ...@@ -191,6 +202,7 @@ extern const char *const hfi1_qsfp_devtech[16];
*/ */
#define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3) #define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3)
#define QSFP_HIGH_PWR(pbyte) (((pbyte) & 3) | 4)
#define QSFP_ATTEN_SDR(attenarray) (attenarray[0]) #define QSFP_ATTEN_SDR(attenarray) (attenarray[0])
#define QSFP_ATTEN_DDR(attenarray) (attenarray[1]) #define QSFP_ATTEN_DDR(attenarray) (attenarray[1])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment