1f48ad614SDennis Dalessandro /* 2f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation. 3f48ad614SDennis Dalessandro * 4f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6f48ad614SDennis Dalessandro * 7f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8f48ad614SDennis Dalessandro * 9f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12f48ad614SDennis Dalessandro * 13f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16f48ad614SDennis Dalessandro * General Public License for more details. 17f48ad614SDennis Dalessandro * 18f48ad614SDennis Dalessandro * BSD LICENSE 19f48ad614SDennis Dalessandro * 20f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22f48ad614SDennis Dalessandro * are met: 23f48ad614SDennis Dalessandro * 24f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29f48ad614SDennis Dalessandro * distribution. 30f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33f48ad614SDennis Dalessandro * 34f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45f48ad614SDennis Dalessandro * 46f48ad614SDennis Dalessandro */ 47f48ad614SDennis Dalessandro 48f48ad614SDennis Dalessandro #include <linux/delay.h> 49f48ad614SDennis Dalessandro #include <linux/pci.h> 50f48ad614SDennis Dalessandro #include <linux/vmalloc.h> 51f48ad614SDennis Dalessandro 52f48ad614SDennis Dalessandro #include "hfi.h" 53f48ad614SDennis Dalessandro #include "twsi.h" 54f48ad614SDennis Dalessandro 55f48ad614SDennis Dalessandro /* 56f48ad614SDennis Dalessandro * QSFP support for hfi driver, using "Two Wire Serial Interface" driver 57f48ad614SDennis Dalessandro * in twsi.c 58f48ad614SDennis Dalessandro */ 59f48ad614SDennis Dalessandro #define I2C_MAX_RETRY 4 60f48ad614SDennis Dalessandro 61f48ad614SDennis Dalessandro /* 62f48ad614SDennis Dalessandro * Raw i2c write. No set-up or lock checking. 63f48ad614SDennis Dalessandro */ 64f48ad614SDennis Dalessandro static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, 65f48ad614SDennis Dalessandro int offset, void *bp, int len) 66f48ad614SDennis Dalessandro { 67f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 68f48ad614SDennis Dalessandro int ret, cnt; 69f48ad614SDennis Dalessandro u8 *buff = bp; 70f48ad614SDennis Dalessandro 71f48ad614SDennis Dalessandro cnt = 0; 72f48ad614SDennis Dalessandro while (cnt < len) { 73f48ad614SDennis Dalessandro int wlen = len - cnt; 74f48ad614SDennis Dalessandro 75f48ad614SDennis Dalessandro ret = hfi1_twsi_blk_wr(dd, target, i2c_addr, offset, 76f48ad614SDennis Dalessandro buff + cnt, wlen); 77f48ad614SDennis Dalessandro if (ret) { 78f48ad614SDennis Dalessandro /* hfi1_twsi_blk_wr() 1 for error, else 0 */ 79f48ad614SDennis Dalessandro return -EIO; 80f48ad614SDennis Dalessandro } 81f48ad614SDennis Dalessandro offset += wlen; 82f48ad614SDennis Dalessandro cnt += wlen; 83f48ad614SDennis Dalessandro } 84f48ad614SDennis Dalessandro 85f48ad614SDennis Dalessandro /* Must wait min 20us between qsfp i2c transactions */ 86f48ad614SDennis Dalessandro udelay(20); 87f48ad614SDennis Dalessandro 88f48ad614SDennis Dalessandro return cnt; 89f48ad614SDennis Dalessandro } 90f48ad614SDennis Dalessandro 91f48ad614SDennis Dalessandro /* 92f48ad614SDennis Dalessandro * Caller must hold the i2c chain resource. 93f48ad614SDennis Dalessandro */ 94f48ad614SDennis Dalessandro int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, 95f48ad614SDennis Dalessandro void *bp, int len) 96f48ad614SDennis Dalessandro { 97f48ad614SDennis Dalessandro int ret; 98f48ad614SDennis Dalessandro 99f48ad614SDennis Dalessandro if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) 100f48ad614SDennis Dalessandro return -EACCES; 101f48ad614SDennis Dalessandro 102f48ad614SDennis Dalessandro /* make sure the TWSI bus is in a sane state */ 103f48ad614SDennis Dalessandro ret = hfi1_twsi_reset(ppd->dd, target); 104f48ad614SDennis Dalessandro if (ret) { 105f48ad614SDennis Dalessandro hfi1_dev_porterr(ppd->dd, ppd->port, 106f48ad614SDennis Dalessandro "I2C chain %d write interface reset failed\n", 107f48ad614SDennis Dalessandro target); 108f48ad614SDennis Dalessandro return ret; 109f48ad614SDennis Dalessandro } 110f48ad614SDennis Dalessandro 111f48ad614SDennis Dalessandro return __i2c_write(ppd, target, i2c_addr, offset, bp, len); 112f48ad614SDennis Dalessandro } 113f48ad614SDennis Dalessandro 114f48ad614SDennis Dalessandro /* 115f48ad614SDennis Dalessandro * Raw i2c read. No set-up or lock checking. 116f48ad614SDennis Dalessandro */ 117f48ad614SDennis Dalessandro static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, 118f48ad614SDennis Dalessandro int offset, void *bp, int len) 119f48ad614SDennis Dalessandro { 120f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 121f48ad614SDennis Dalessandro int ret, cnt, pass = 0; 122f48ad614SDennis Dalessandro int orig_offset = offset; 123f48ad614SDennis Dalessandro 124f48ad614SDennis Dalessandro cnt = 0; 125f48ad614SDennis Dalessandro while (cnt < len) { 126f48ad614SDennis Dalessandro int rlen = len - cnt; 127f48ad614SDennis Dalessandro 128f48ad614SDennis Dalessandro ret = hfi1_twsi_blk_rd(dd, target, i2c_addr, offset, 129f48ad614SDennis Dalessandro bp + cnt, rlen); 130f48ad614SDennis Dalessandro /* Some QSFP's fail first try. Retry as experiment */ 131f48ad614SDennis Dalessandro if (ret && cnt == 0 && ++pass < I2C_MAX_RETRY) 132f48ad614SDennis Dalessandro continue; 133f48ad614SDennis Dalessandro if (ret) { 134f48ad614SDennis Dalessandro /* hfi1_twsi_blk_rd() 1 for error, else 0 */ 135f48ad614SDennis Dalessandro ret = -EIO; 136f48ad614SDennis Dalessandro goto exit; 137f48ad614SDennis Dalessandro } 138f48ad614SDennis Dalessandro offset += rlen; 139f48ad614SDennis Dalessandro cnt += rlen; 140f48ad614SDennis Dalessandro } 141f48ad614SDennis Dalessandro 142f48ad614SDennis Dalessandro ret = cnt; 143f48ad614SDennis Dalessandro 144f48ad614SDennis Dalessandro exit: 145f48ad614SDennis Dalessandro if (ret < 0) { 146f48ad614SDennis Dalessandro hfi1_dev_porterr(dd, ppd->port, 147f48ad614SDennis Dalessandro "I2C chain %d read failed, addr 0x%x, offset 0x%x, len %d\n", 148f48ad614SDennis Dalessandro target, i2c_addr, orig_offset, len); 149f48ad614SDennis Dalessandro } 150f48ad614SDennis Dalessandro 151f48ad614SDennis Dalessandro /* Must wait min 20us between qsfp i2c transactions */ 152f48ad614SDennis Dalessandro udelay(20); 153f48ad614SDennis Dalessandro 154f48ad614SDennis Dalessandro return ret; 155f48ad614SDennis Dalessandro } 156f48ad614SDennis Dalessandro 157f48ad614SDennis Dalessandro /* 158f48ad614SDennis Dalessandro * Caller must hold the i2c chain resource. 159f48ad614SDennis Dalessandro */ 160f48ad614SDennis Dalessandro int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, 161f48ad614SDennis Dalessandro void *bp, int len) 162f48ad614SDennis Dalessandro { 163f48ad614SDennis Dalessandro int ret; 164f48ad614SDennis Dalessandro 165f48ad614SDennis Dalessandro if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) 166f48ad614SDennis Dalessandro return -EACCES; 167f48ad614SDennis Dalessandro 168f48ad614SDennis Dalessandro /* make sure the TWSI bus is in a sane state */ 169f48ad614SDennis Dalessandro ret = hfi1_twsi_reset(ppd->dd, target); 170f48ad614SDennis Dalessandro if (ret) { 171f48ad614SDennis Dalessandro hfi1_dev_porterr(ppd->dd, ppd->port, 172f48ad614SDennis Dalessandro "I2C chain %d read interface reset failed\n", 173f48ad614SDennis Dalessandro target); 174f48ad614SDennis Dalessandro return ret; 175f48ad614SDennis Dalessandro } 176f48ad614SDennis Dalessandro 177f48ad614SDennis Dalessandro return __i2c_read(ppd, target, i2c_addr, offset, bp, len); 178f48ad614SDennis Dalessandro } 179f48ad614SDennis Dalessandro 180f48ad614SDennis Dalessandro /* 181f48ad614SDennis Dalessandro * Write page n, offset m of QSFP memory as defined by SFF 8636 182f48ad614SDennis Dalessandro * by writing @addr = ((256 * n) + m) 183f48ad614SDennis Dalessandro * 184f48ad614SDennis Dalessandro * Caller must hold the i2c chain resource. 185f48ad614SDennis Dalessandro */ 186f48ad614SDennis Dalessandro int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, 187f48ad614SDennis Dalessandro int len) 188f48ad614SDennis Dalessandro { 189f48ad614SDennis Dalessandro int count = 0; 190f48ad614SDennis Dalessandro int offset; 191f48ad614SDennis Dalessandro int nwrite; 192f48ad614SDennis Dalessandro int ret; 193f48ad614SDennis Dalessandro u8 page; 194f48ad614SDennis Dalessandro 195f48ad614SDennis Dalessandro if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) 196f48ad614SDennis Dalessandro return -EACCES; 197f48ad614SDennis Dalessandro 198f48ad614SDennis Dalessandro /* make sure the TWSI bus is in a sane state */ 199f48ad614SDennis Dalessandro ret = hfi1_twsi_reset(ppd->dd, target); 200f48ad614SDennis Dalessandro if (ret) { 201f48ad614SDennis Dalessandro hfi1_dev_porterr(ppd->dd, ppd->port, 202f48ad614SDennis Dalessandro "QSFP chain %d write interface reset failed\n", 203f48ad614SDennis Dalessandro target); 204f48ad614SDennis Dalessandro return ret; 205f48ad614SDennis Dalessandro } 206f48ad614SDennis Dalessandro 207f48ad614SDennis Dalessandro while (count < len) { 208f48ad614SDennis Dalessandro /* 209f48ad614SDennis Dalessandro * Set the qsfp page based on a zero-based address 210f48ad614SDennis Dalessandro * and a page size of QSFP_PAGESIZE bytes. 211f48ad614SDennis Dalessandro */ 212f48ad614SDennis Dalessandro page = (u8)(addr / QSFP_PAGESIZE); 213f48ad614SDennis Dalessandro 214f48ad614SDennis Dalessandro ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, 215f48ad614SDennis Dalessandro QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1); 216f48ad614SDennis Dalessandro if (ret != 1) { 217f48ad614SDennis Dalessandro hfi1_dev_porterr(ppd->dd, ppd->port, 218f48ad614SDennis Dalessandro "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n", 219f48ad614SDennis Dalessandro target, ret); 220f48ad614SDennis Dalessandro ret = -EIO; 221f48ad614SDennis Dalessandro break; 222f48ad614SDennis Dalessandro } 223f48ad614SDennis Dalessandro 224f48ad614SDennis Dalessandro offset = addr % QSFP_PAGESIZE; 225f48ad614SDennis Dalessandro nwrite = len - count; 226f48ad614SDennis Dalessandro /* truncate write to boundary if crossing boundary */ 227f48ad614SDennis Dalessandro if (((addr % QSFP_RW_BOUNDARY) + nwrite) > QSFP_RW_BOUNDARY) 228f48ad614SDennis Dalessandro nwrite = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY); 229f48ad614SDennis Dalessandro 230f48ad614SDennis Dalessandro ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, 231f48ad614SDennis Dalessandro offset, bp + count, nwrite); 232f48ad614SDennis Dalessandro if (ret <= 0) /* stop on error or nothing written */ 233f48ad614SDennis Dalessandro break; 234f48ad614SDennis Dalessandro 235f48ad614SDennis Dalessandro count += ret; 236f48ad614SDennis Dalessandro addr += ret; 237f48ad614SDennis Dalessandro } 238f48ad614SDennis Dalessandro 239f48ad614SDennis Dalessandro if (ret < 0) 240f48ad614SDennis Dalessandro return ret; 241f48ad614SDennis Dalessandro return count; 242f48ad614SDennis Dalessandro } 243f48ad614SDennis Dalessandro 244f48ad614SDennis Dalessandro /* 245f48ad614SDennis Dalessandro * Perform a stand-alone single QSFP write. Acquire the resource, do the 246f48ad614SDennis Dalessandro * read, then release the resource. 247f48ad614SDennis Dalessandro */ 248f48ad614SDennis Dalessandro int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, 249f48ad614SDennis Dalessandro int len) 250f48ad614SDennis Dalessandro { 251f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 252f48ad614SDennis Dalessandro u32 resource = qsfp_resource(dd); 253f48ad614SDennis Dalessandro int ret; 254f48ad614SDennis Dalessandro 255f48ad614SDennis Dalessandro ret = acquire_chip_resource(dd, resource, QSFP_WAIT); 256f48ad614SDennis Dalessandro if (ret) 257f48ad614SDennis Dalessandro return ret; 258f48ad614SDennis Dalessandro ret = qsfp_write(ppd, target, addr, bp, len); 259f48ad614SDennis Dalessandro release_chip_resource(dd, resource); 260f48ad614SDennis Dalessandro 261f48ad614SDennis Dalessandro return ret; 262f48ad614SDennis Dalessandro } 263f48ad614SDennis Dalessandro 264f48ad614SDennis Dalessandro /* 265f48ad614SDennis Dalessandro * Access page n, offset m of QSFP memory as defined by SFF 8636 266f48ad614SDennis Dalessandro * by reading @addr = ((256 * n) + m) 267f48ad614SDennis Dalessandro * 268f48ad614SDennis Dalessandro * Caller must hold the i2c chain resource. 269f48ad614SDennis Dalessandro */ 270f48ad614SDennis Dalessandro int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, 271f48ad614SDennis Dalessandro int len) 272f48ad614SDennis Dalessandro { 273f48ad614SDennis Dalessandro int count = 0; 274f48ad614SDennis Dalessandro int offset; 275f48ad614SDennis Dalessandro int nread; 276f48ad614SDennis Dalessandro int ret; 277f48ad614SDennis Dalessandro u8 page; 278f48ad614SDennis Dalessandro 279f48ad614SDennis Dalessandro if (!check_chip_resource(ppd->dd, i2c_target(target), __func__)) 280f48ad614SDennis Dalessandro return -EACCES; 281f48ad614SDennis Dalessandro 282f48ad614SDennis Dalessandro /* make sure the TWSI bus is in a sane state */ 283f48ad614SDennis Dalessandro ret = hfi1_twsi_reset(ppd->dd, target); 284f48ad614SDennis Dalessandro if (ret) { 285f48ad614SDennis Dalessandro hfi1_dev_porterr(ppd->dd, ppd->port, 286f48ad614SDennis Dalessandro "QSFP chain %d read interface reset failed\n", 287f48ad614SDennis Dalessandro target); 288f48ad614SDennis Dalessandro return ret; 289f48ad614SDennis Dalessandro } 290f48ad614SDennis Dalessandro 291f48ad614SDennis Dalessandro while (count < len) { 292f48ad614SDennis Dalessandro /* 293f48ad614SDennis Dalessandro * Set the qsfp page based on a zero-based address 294f48ad614SDennis Dalessandro * and a page size of QSFP_PAGESIZE bytes. 295f48ad614SDennis Dalessandro */ 296f48ad614SDennis Dalessandro page = (u8)(addr / QSFP_PAGESIZE); 297f48ad614SDennis Dalessandro ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, 298f48ad614SDennis Dalessandro QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1); 299f48ad614SDennis Dalessandro if (ret != 1) { 300f48ad614SDennis Dalessandro hfi1_dev_porterr(ppd->dd, ppd->port, 301f48ad614SDennis Dalessandro "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n", 302f48ad614SDennis Dalessandro target, ret); 303f48ad614SDennis Dalessandro ret = -EIO; 304f48ad614SDennis Dalessandro break; 305f48ad614SDennis Dalessandro } 306f48ad614SDennis Dalessandro 307f48ad614SDennis Dalessandro offset = addr % QSFP_PAGESIZE; 308f48ad614SDennis Dalessandro nread = len - count; 309f48ad614SDennis Dalessandro /* truncate read to boundary if crossing boundary */ 310f48ad614SDennis Dalessandro if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY) 311f48ad614SDennis Dalessandro nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY); 312f48ad614SDennis Dalessandro 313f48ad614SDennis Dalessandro /* QSFPs require a 5-10msec delay after write operations */ 314f48ad614SDennis Dalessandro mdelay(5); 315f48ad614SDennis Dalessandro ret = __i2c_read(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE, 316f48ad614SDennis Dalessandro offset, bp + count, nread); 317f48ad614SDennis Dalessandro if (ret <= 0) /* stop on error or nothing read */ 318f48ad614SDennis Dalessandro break; 319f48ad614SDennis Dalessandro 320f48ad614SDennis Dalessandro count += ret; 321f48ad614SDennis Dalessandro addr += ret; 322f48ad614SDennis Dalessandro } 323f48ad614SDennis Dalessandro 324f48ad614SDennis Dalessandro if (ret < 0) 325f48ad614SDennis Dalessandro return ret; 326f48ad614SDennis Dalessandro return count; 327f48ad614SDennis Dalessandro } 328f48ad614SDennis Dalessandro 329f48ad614SDennis Dalessandro /* 330f48ad614SDennis Dalessandro * Perform a stand-alone single QSFP read. Acquire the resource, do the 331f48ad614SDennis Dalessandro * read, then release the resource. 332f48ad614SDennis Dalessandro */ 333f48ad614SDennis Dalessandro int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, 334f48ad614SDennis Dalessandro int len) 335f48ad614SDennis Dalessandro { 336f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 337f48ad614SDennis Dalessandro u32 resource = qsfp_resource(dd); 338f48ad614SDennis Dalessandro int ret; 339f48ad614SDennis Dalessandro 340f48ad614SDennis Dalessandro ret = acquire_chip_resource(dd, resource, QSFP_WAIT); 341f48ad614SDennis Dalessandro if (ret) 342f48ad614SDennis Dalessandro return ret; 343f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, addr, bp, len); 344f48ad614SDennis Dalessandro release_chip_resource(dd, resource); 345f48ad614SDennis Dalessandro 346f48ad614SDennis Dalessandro return ret; 347f48ad614SDennis Dalessandro } 348f48ad614SDennis Dalessandro 349f48ad614SDennis Dalessandro /* 350f48ad614SDennis Dalessandro * This function caches the QSFP memory range in 128 byte chunks. 351f48ad614SDennis Dalessandro * As an example, the next byte after address 255 is byte 128 from 352f48ad614SDennis Dalessandro * upper page 01H (if existing) rather than byte 0 from lower page 00H. 353f48ad614SDennis Dalessandro * Access page n, offset m of QSFP memory as defined by SFF 8636 354f48ad614SDennis Dalessandro * in the cache by reading byte ((128 * n) + m) 355f48ad614SDennis Dalessandro * The calls to qsfp_{read,write} in this function correctly handle the 356f48ad614SDennis Dalessandro * address map difference between this mapping and the mapping implemented 357f48ad614SDennis Dalessandro * by those functions 358f48ad614SDennis Dalessandro * 359f48ad614SDennis Dalessandro * The caller must be holding the QSFP i2c chain resource. 360f48ad614SDennis Dalessandro */ 361f48ad614SDennis Dalessandro int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp) 362f48ad614SDennis Dalessandro { 363f48ad614SDennis Dalessandro u32 target = ppd->dd->hfi1_id; 364f48ad614SDennis Dalessandro int ret; 365f48ad614SDennis Dalessandro unsigned long flags; 366f48ad614SDennis Dalessandro u8 *cache = &cp->cache[0]; 367f48ad614SDennis Dalessandro 368f48ad614SDennis Dalessandro /* ensure sane contents on invalid reads, for cable swaps */ 369f48ad614SDennis Dalessandro memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128)); 370f48ad614SDennis Dalessandro spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); 371f48ad614SDennis Dalessandro ppd->qsfp_info.cache_valid = 0; 372f48ad614SDennis Dalessandro spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags); 373f48ad614SDennis Dalessandro 374f48ad614SDennis Dalessandro if (!qsfp_mod_present(ppd)) { 375f48ad614SDennis Dalessandro ret = -ENODEV; 376f48ad614SDennis Dalessandro goto bail; 377f48ad614SDennis Dalessandro } 378f48ad614SDennis Dalessandro 379f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 0, cache, QSFP_PAGESIZE); 380f48ad614SDennis Dalessandro if (ret != QSFP_PAGESIZE) { 381f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, 382f48ad614SDennis Dalessandro "%s: Page 0 read failed, expected %d, got %d\n", 383f48ad614SDennis Dalessandro __func__, QSFP_PAGESIZE, ret); 384f48ad614SDennis Dalessandro goto bail; 385f48ad614SDennis Dalessandro } 386f48ad614SDennis Dalessandro 387f48ad614SDennis Dalessandro /* Is paging enabled? */ 388f48ad614SDennis Dalessandro if (!(cache[2] & 4)) { 389f48ad614SDennis Dalessandro /* Paging enabled, page 03 required */ 390f48ad614SDennis Dalessandro if ((cache[195] & 0xC0) == 0xC0) { 391f48ad614SDennis Dalessandro /* all */ 392f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 384, cache + 256, 128); 393f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 394f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 395f48ad614SDennis Dalessandro goto bail; 396f48ad614SDennis Dalessandro } 397f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 640, cache + 384, 128); 398f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 399f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 400f48ad614SDennis Dalessandro goto bail; 401f48ad614SDennis Dalessandro } 402f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 896, cache + 512, 128); 403f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 404f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 405f48ad614SDennis Dalessandro goto bail; 406f48ad614SDennis Dalessandro } 407f48ad614SDennis Dalessandro } else if ((cache[195] & 0x80) == 0x80) { 408f48ad614SDennis Dalessandro /* only page 2 and 3 */ 409f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 640, cache + 384, 128); 410f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 411f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 412f48ad614SDennis Dalessandro goto bail; 413f48ad614SDennis Dalessandro } 414f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 896, cache + 512, 128); 415f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 416f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 417f48ad614SDennis Dalessandro goto bail; 418f48ad614SDennis Dalessandro } 419f48ad614SDennis Dalessandro } else if ((cache[195] & 0x40) == 0x40) { 420f48ad614SDennis Dalessandro /* only page 1 and 3 */ 421f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 384, cache + 256, 128); 422f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 423f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 424f48ad614SDennis Dalessandro goto bail; 425f48ad614SDennis Dalessandro } 426f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 896, cache + 512, 128); 427f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 428f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 429f48ad614SDennis Dalessandro goto bail; 430f48ad614SDennis Dalessandro } 431f48ad614SDennis Dalessandro } else { 432f48ad614SDennis Dalessandro /* only page 3 */ 433f48ad614SDennis Dalessandro ret = qsfp_read(ppd, target, 896, cache + 512, 128); 434f48ad614SDennis Dalessandro if (ret <= 0 || ret != 128) { 435f48ad614SDennis Dalessandro dd_dev_info(ppd->dd, "%s failed\n", __func__); 436f48ad614SDennis Dalessandro goto bail; 437f48ad614SDennis Dalessandro } 438f48ad614SDennis Dalessandro } 439f48ad614SDennis Dalessandro } 440f48ad614SDennis Dalessandro 441f48ad614SDennis Dalessandro spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); 442f48ad614SDennis Dalessandro ppd->qsfp_info.cache_valid = 1; 443f48ad614SDennis Dalessandro ppd->qsfp_info.cache_refresh_required = 0; 444f48ad614SDennis Dalessandro spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags); 445f48ad614SDennis Dalessandro 446f48ad614SDennis Dalessandro return 0; 447f48ad614SDennis Dalessandro 448f48ad614SDennis Dalessandro bail: 449f48ad614SDennis Dalessandro memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128)); 450f48ad614SDennis Dalessandro return ret; 451f48ad614SDennis Dalessandro } 452f48ad614SDennis Dalessandro 453f48ad614SDennis Dalessandro const char * const hfi1_qsfp_devtech[16] = { 454f48ad614SDennis Dalessandro "850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP", 455f48ad614SDennis Dalessandro "1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML", 456f48ad614SDennis Dalessandro "Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq", 457f48ad614SDennis Dalessandro "Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq" 458f48ad614SDennis Dalessandro }; 459f48ad614SDennis Dalessandro 460f48ad614SDennis Dalessandro #define QSFP_DUMP_CHUNK 16 /* Holds longest string */ 461f48ad614SDennis Dalessandro #define QSFP_DEFAULT_HDR_CNT 224 462f48ad614SDennis Dalessandro 463f48ad614SDennis Dalessandro #define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3) 464f48ad614SDennis Dalessandro #define QSFP_HIGH_PWR(pbyte) ((pbyte) & 3) 465f48ad614SDennis Dalessandro /* For use with QSFP_HIGH_PWR macro */ 466f48ad614SDennis Dalessandro #define QSFP_HIGH_PWR_UNUSED 0 /* Bits [1:0] = 00 implies low power module */ 467f48ad614SDennis Dalessandro 468f48ad614SDennis Dalessandro /* 469f48ad614SDennis Dalessandro * Takes power class byte [Page 00 Byte 129] in SFF 8636 470f48ad614SDennis Dalessandro * Returns power class as integer (1 through 7, per SFF 8636 rev 2.4) 471f48ad614SDennis Dalessandro */ 472f48ad614SDennis Dalessandro int get_qsfp_power_class(u8 power_byte) 473f48ad614SDennis Dalessandro { 474f48ad614SDennis Dalessandro if (QSFP_HIGH_PWR(power_byte) == QSFP_HIGH_PWR_UNUSED) 475f48ad614SDennis Dalessandro /* power classes count from 1, their bit encodings from 0 */ 476f48ad614SDennis Dalessandro return (QSFP_PWR(power_byte) + 1); 477f48ad614SDennis Dalessandro /* 478f48ad614SDennis Dalessandro * 00 in the high power classes stands for unused, bringing 479f48ad614SDennis Dalessandro * balance to the off-by-1 offset above, we add 4 here to 480f48ad614SDennis Dalessandro * account for the difference between the low and high power 481f48ad614SDennis Dalessandro * groups 482f48ad614SDennis Dalessandro */ 483f48ad614SDennis Dalessandro return (QSFP_HIGH_PWR(power_byte) + 4); 484f48ad614SDennis Dalessandro } 485f48ad614SDennis Dalessandro 486f48ad614SDennis Dalessandro int qsfp_mod_present(struct hfi1_pportdata *ppd) 487f48ad614SDennis Dalessandro { 488f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 489f48ad614SDennis Dalessandro u64 reg; 490f48ad614SDennis Dalessandro 491f48ad614SDennis Dalessandro reg = read_csr(dd, dd->hfi1_id ? ASIC_QSFP2_IN : ASIC_QSFP1_IN); 492f48ad614SDennis Dalessandro return !(reg & QSFP_HFI0_MODPRST_N); 493f48ad614SDennis Dalessandro } 494f48ad614SDennis Dalessandro 495f48ad614SDennis Dalessandro /* 496f48ad614SDennis Dalessandro * This function maps QSFP memory addresses in 128 byte chunks in the following 497f48ad614SDennis Dalessandro * fashion per the CableInfo SMA query definition in the IBA 1.3 spec/OPA Gen 1 498f48ad614SDennis Dalessandro * spec 499f48ad614SDennis Dalessandro * For addr 000-127, lower page 00h 500f48ad614SDennis Dalessandro * For addr 128-255, upper page 00h 501f48ad614SDennis Dalessandro * For addr 256-383, upper page 01h 502f48ad614SDennis Dalessandro * For addr 384-511, upper page 02h 503f48ad614SDennis Dalessandro * For addr 512-639, upper page 03h 504f48ad614SDennis Dalessandro * 505f48ad614SDennis Dalessandro * For addresses beyond this range, it returns the invalid range of data buffer 506f48ad614SDennis Dalessandro * set to 0. 507f48ad614SDennis Dalessandro * For upper pages that are optional, if they are not valid, returns the 508f48ad614SDennis Dalessandro * particular range of bytes in the data buffer set to 0. 509f48ad614SDennis Dalessandro */ 510f48ad614SDennis Dalessandro int get_cable_info(struct hfi1_devdata *dd, u32 port_num, u32 addr, u32 len, 511f48ad614SDennis Dalessandro u8 *data) 512f48ad614SDennis Dalessandro { 513f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 514f48ad614SDennis Dalessandro u32 excess_len = 0; 515f48ad614SDennis Dalessandro int ret = 0; 516f48ad614SDennis Dalessandro 517f48ad614SDennis Dalessandro if (port_num > dd->num_pports || port_num < 1) { 518f48ad614SDennis Dalessandro dd_dev_info(dd, "%s: Invalid port number %d\n", 519f48ad614SDennis Dalessandro __func__, port_num); 520f48ad614SDennis Dalessandro ret = -EINVAL; 521f48ad614SDennis Dalessandro goto set_zeroes; 522f48ad614SDennis Dalessandro } 523f48ad614SDennis Dalessandro 524f48ad614SDennis Dalessandro ppd = dd->pport + (port_num - 1); 525f48ad614SDennis Dalessandro if (!qsfp_mod_present(ppd)) { 526f48ad614SDennis Dalessandro ret = -ENODEV; 527f48ad614SDennis Dalessandro goto set_zeroes; 528f48ad614SDennis Dalessandro } 529f48ad614SDennis Dalessandro 530f48ad614SDennis Dalessandro if (!ppd->qsfp_info.cache_valid) { 531f48ad614SDennis Dalessandro ret = -EINVAL; 532f48ad614SDennis Dalessandro goto set_zeroes; 533f48ad614SDennis Dalessandro } 534f48ad614SDennis Dalessandro 535f48ad614SDennis Dalessandro if (addr >= (QSFP_MAX_NUM_PAGES * 128)) { 536f48ad614SDennis Dalessandro ret = -ERANGE; 537f48ad614SDennis Dalessandro goto set_zeroes; 538f48ad614SDennis Dalessandro } 539f48ad614SDennis Dalessandro 540f48ad614SDennis Dalessandro if ((addr + len) > (QSFP_MAX_NUM_PAGES * 128)) { 541f48ad614SDennis Dalessandro excess_len = (addr + len) - (QSFP_MAX_NUM_PAGES * 128); 542f48ad614SDennis Dalessandro memcpy(data, &ppd->qsfp_info.cache[addr], (len - excess_len)); 543f48ad614SDennis Dalessandro data += (len - excess_len); 544f48ad614SDennis Dalessandro goto set_zeroes; 545f48ad614SDennis Dalessandro } 546f48ad614SDennis Dalessandro 547f48ad614SDennis Dalessandro memcpy(data, &ppd->qsfp_info.cache[addr], len); 548f48ad614SDennis Dalessandro return 0; 549f48ad614SDennis Dalessandro 550f48ad614SDennis Dalessandro set_zeroes: 551f48ad614SDennis Dalessandro memset(data, 0, excess_len); 552f48ad614SDennis Dalessandro return ret; 553f48ad614SDennis Dalessandro } 554f48ad614SDennis Dalessandro 555f48ad614SDennis Dalessandro static const char *pwr_codes[8] = {"N/AW", 556f48ad614SDennis Dalessandro "1.5W", 557f48ad614SDennis Dalessandro "2.0W", 558f48ad614SDennis Dalessandro "2.5W", 559f48ad614SDennis Dalessandro "3.5W", 560f48ad614SDennis Dalessandro "4.0W", 561f48ad614SDennis Dalessandro "4.5W", 562f48ad614SDennis Dalessandro "5.0W" 563f48ad614SDennis Dalessandro }; 564f48ad614SDennis Dalessandro 565f48ad614SDennis Dalessandro int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len) 566f48ad614SDennis Dalessandro { 567f48ad614SDennis Dalessandro u8 *cache = &ppd->qsfp_info.cache[0]; 568f48ad614SDennis Dalessandro u8 bin_buff[QSFP_DUMP_CHUNK]; 569f48ad614SDennis Dalessandro char lenstr[6]; 570f48ad614SDennis Dalessandro int sofar; 571f48ad614SDennis Dalessandro int bidx = 0; 572f48ad614SDennis Dalessandro u8 *atten = &cache[QSFP_ATTEN_OFFS]; 573f48ad614SDennis Dalessandro u8 *vendor_oui = &cache[QSFP_VOUI_OFFS]; 574f48ad614SDennis Dalessandro u8 power_byte = 0; 575f48ad614SDennis Dalessandro 576f48ad614SDennis Dalessandro sofar = 0; 577f48ad614SDennis Dalessandro lenstr[0] = ' '; 578f48ad614SDennis Dalessandro lenstr[1] = '\0'; 579f48ad614SDennis Dalessandro 580f48ad614SDennis Dalessandro if (ppd->qsfp_info.cache_valid) { 581f48ad614SDennis Dalessandro if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS])) 582f48ad614SDennis Dalessandro sprintf(lenstr, "%dM ", cache[QSFP_MOD_LEN_OFFS]); 583f48ad614SDennis Dalessandro 584f48ad614SDennis Dalessandro power_byte = cache[QSFP_MOD_PWR_OFFS]; 585f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n", 586f48ad614SDennis Dalessandro pwr_codes[get_qsfp_power_class(power_byte)]); 587f48ad614SDennis Dalessandro 588f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n", 589f48ad614SDennis Dalessandro lenstr, 590f48ad614SDennis Dalessandro hfi1_qsfp_devtech[(cache[QSFP_MOD_TECH_OFFS]) >> 4]); 591f48ad614SDennis Dalessandro 592f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n", 593f48ad614SDennis Dalessandro QSFP_VEND_LEN, &cache[QSFP_VEND_OFFS]); 594f48ad614SDennis Dalessandro 595f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n", 596f48ad614SDennis Dalessandro QSFP_OUI(vendor_oui)); 597f48ad614SDennis Dalessandro 598f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n", 599f48ad614SDennis Dalessandro QSFP_PN_LEN, &cache[QSFP_PN_OFFS]); 600f48ad614SDennis Dalessandro 601f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n", 602f48ad614SDennis Dalessandro QSFP_REV_LEN, &cache[QSFP_REV_OFFS]); 603f48ad614SDennis Dalessandro 604f48ad614SDennis Dalessandro if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS])) 605f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, 606f48ad614SDennis Dalessandro "Atten:%d, %d\n", 607f48ad614SDennis Dalessandro QSFP_ATTEN_SDR(atten), 608f48ad614SDennis Dalessandro QSFP_ATTEN_DDR(atten)); 609f48ad614SDennis Dalessandro 610f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n", 611f48ad614SDennis Dalessandro QSFP_SN_LEN, &cache[QSFP_SN_OFFS]); 612f48ad614SDennis Dalessandro 613f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n", 614f48ad614SDennis Dalessandro QSFP_DATE_LEN, &cache[QSFP_DATE_OFFS]); 615f48ad614SDennis Dalessandro 616f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n", 617f48ad614SDennis Dalessandro QSFP_LOT_LEN, &cache[QSFP_LOT_OFFS]); 618f48ad614SDennis Dalessandro 619f48ad614SDennis Dalessandro while (bidx < QSFP_DEFAULT_HDR_CNT) { 620f48ad614SDennis Dalessandro int iidx; 621f48ad614SDennis Dalessandro 622f48ad614SDennis Dalessandro memcpy(bin_buff, &cache[bidx], QSFP_DUMP_CHUNK); 623f48ad614SDennis Dalessandro for (iidx = 0; iidx < QSFP_DUMP_CHUNK; ++iidx) { 624f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, 625f48ad614SDennis Dalessandro " %02X", bin_buff[iidx]); 626f48ad614SDennis Dalessandro } 627f48ad614SDennis Dalessandro sofar += scnprintf(buf + sofar, len - sofar, "\n"); 628f48ad614SDennis Dalessandro bidx += QSFP_DUMP_CHUNK; 629f48ad614SDennis Dalessandro } 630f48ad614SDennis Dalessandro } 631f48ad614SDennis Dalessandro return sofar; 632f48ad614SDennis Dalessandro } 633