|
@@ -59,7 +59,7 @@
|
|
#define I2C_MAX_RETRY 4
|
|
#define I2C_MAX_RETRY 4
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Unlocked i2c write. Must hold dd->qsfp_i2c_mutex.
|
|
|
|
|
|
+ * Raw i2c write. No set-up or lock checking.
|
|
*/
|
|
*/
|
|
static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
|
|
static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
|
|
int offset, void *bp, int len)
|
|
int offset, void *bp, int len)
|
|
@@ -88,15 +88,16 @@ static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
|
|
return cnt;
|
|
return cnt;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Caller must hold the i2c chain resource.
|
|
|
|
+ */
|
|
int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|
int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|
void *bp, int len)
|
|
void *bp, int len)
|
|
{
|
|
{
|
|
- struct hfi1_devdata *dd = ppd->dd;
|
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ret = mutex_lock_interruptible(&dd->qsfp_i2c_mutex);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ if (!check_chip_resource(ppd->dd, qsfp_resource(ppd->dd), __func__))
|
|
|
|
+ return -EACCES;
|
|
|
|
|
|
/* make sure the TWSI bus is in a sane state */
|
|
/* make sure the TWSI bus is in a sane state */
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
@@ -104,18 +105,14 @@ int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
"I2C chain %d write interface reset failed\n",
|
|
"I2C chain %d write interface reset failed\n",
|
|
target);
|
|
target);
|
|
- goto done;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = __i2c_write(ppd, target, i2c_addr, offset, bp, len);
|
|
|
|
-
|
|
|
|
-done:
|
|
|
|
- mutex_unlock(&dd->qsfp_i2c_mutex);
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return __i2c_write(ppd, target, i2c_addr, offset, bp, len);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Unlocked i2c read. Must hold dd->qsfp_i2c_mutex.
|
|
|
|
|
|
+ * Raw i2c read. No set-up or lock checking.
|
|
*/
|
|
*/
|
|
static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
|
|
static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
|
|
int offset, void *bp, int len)
|
|
int offset, void *bp, int len)
|
|
@@ -157,15 +154,16 @@ exit:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Caller must hold the i2c chain resource.
|
|
|
|
+ */
|
|
int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|
int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|
void *bp, int len)
|
|
void *bp, int len)
|
|
{
|
|
{
|
|
- struct hfi1_devdata *dd = ppd->dd;
|
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ret = mutex_lock_interruptible(&dd->qsfp_i2c_mutex);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ if (!check_chip_resource(ppd->dd, qsfp_resource(ppd->dd), __func__))
|
|
|
|
+ return -EACCES;
|
|
|
|
|
|
/* make sure the TWSI bus is in a sane state */
|
|
/* make sure the TWSI bus is in a sane state */
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
@@ -173,19 +171,17 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
"I2C chain %d read interface reset failed\n",
|
|
"I2C chain %d read interface reset failed\n",
|
|
target);
|
|
target);
|
|
- goto done;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = __i2c_read(ppd, target, i2c_addr, offset, bp, len);
|
|
|
|
-
|
|
|
|
-done:
|
|
|
|
- mutex_unlock(&dd->qsfp_i2c_mutex);
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return __i2c_read(ppd, target, i2c_addr, offset, bp, len);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
* Write page n, offset m of QSFP memory as defined by SFF 8636
|
|
* Write page n, offset m of QSFP memory as defined by SFF 8636
|
|
* by writing @addr = ((256 * n) + m)
|
|
* by writing @addr = ((256 * n) + m)
|
|
|
|
+ *
|
|
|
|
+ * Caller must hold the i2c chain resource.
|
|
*/
|
|
*/
|
|
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)
|
|
@@ -196,9 +192,8 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
int ret;
|
|
int ret;
|
|
u8 page;
|
|
u8 page;
|
|
|
|
|
|
- ret = mutex_lock_interruptible(&ppd->dd->qsfp_i2c_mutex);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ if (!check_chip_resource(ppd->dd, qsfp_resource(ppd->dd), __func__))
|
|
|
|
+ return -EACCES;
|
|
|
|
|
|
/* make sure the TWSI bus is in a sane state */
|
|
/* make sure the TWSI bus is in a sane state */
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
@@ -206,7 +201,6 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
"QSFP chain %d write interface reset failed\n",
|
|
"QSFP chain %d write interface reset failed\n",
|
|
target);
|
|
target);
|
|
- mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -242,16 +236,36 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
addr += ret;
|
|
addr += ret;
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
|
|
|
|
-
|
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
return count;
|
|
return count;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Perform a stand-alone single QSFP write. Acquire the resource, do the
|
|
|
|
+ * read, then release the resource.
|
|
|
|
+ */
|
|
|
|
+int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
|
|
+ int len)
|
|
|
|
+{
|
|
|
|
+ struct hfi1_devdata *dd = ppd->dd;
|
|
|
|
+ u32 resource = qsfp_resource(dd);
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = acquire_chip_resource(dd, resource, QSFP_WAIT);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+ ret = qsfp_write(ppd, target, addr, bp, len);
|
|
|
|
+ release_chip_resource(dd, resource);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Access page n, offset m of QSFP memory as defined by SFF 8636
|
|
* Access page n, offset m of QSFP memory as defined by SFF 8636
|
|
* by reading @addr = ((256 * n) + m)
|
|
* by reading @addr = ((256 * n) + m)
|
|
|
|
+ *
|
|
|
|
+ * Caller must hold the i2c chain resource.
|
|
*/
|
|
*/
|
|
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)
|
|
@@ -262,9 +276,8 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
int ret;
|
|
int ret;
|
|
u8 page;
|
|
u8 page;
|
|
|
|
|
|
- ret = mutex_lock_interruptible(&ppd->dd->qsfp_i2c_mutex);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ if (!check_chip_resource(ppd->dd, qsfp_resource(ppd->dd), __func__))
|
|
|
|
+ return -EACCES;
|
|
|
|
|
|
/* make sure the TWSI bus is in a sane state */
|
|
/* make sure the TWSI bus is in a sane state */
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
ret = hfi1_twsi_reset(ppd->dd, target);
|
|
@@ -272,7 +285,6 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
hfi1_dev_porterr(ppd->dd, ppd->port,
|
|
"QSFP chain %d read interface reset failed\n",
|
|
"QSFP chain %d read interface reset failed\n",
|
|
target);
|
|
target);
|
|
- mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -309,13 +321,31 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
addr += ret;
|
|
addr += ret;
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
|
|
|
|
-
|
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
return count;
|
|
return count;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Perform a stand-alone single QSFP read. Acquire the resource, do the
|
|
|
|
+ * read, then release the resource.
|
|
|
|
+ */
|
|
|
|
+int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|
|
|
+ int len)
|
|
|
|
+{
|
|
|
|
+ struct hfi1_devdata *dd = ppd->dd;
|
|
|
|
+ u32 resource = qsfp_resource(dd);
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = acquire_chip_resource(dd, resource, QSFP_WAIT);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+ ret = qsfp_read(ppd, target, addr, bp, len);
|
|
|
|
+ release_chip_resource(dd, resource);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* 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
|
|
@@ -341,9 +371,13 @@ int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
|
|
|
|
|
|
if (!qsfp_mod_present(ppd)) {
|
|
if (!qsfp_mod_present(ppd)) {
|
|
ret = -ENODEV;
|
|
ret = -ENODEV;
|
|
- goto bail;
|
|
|
|
|
|
+ goto bail_no_release;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ret = acquire_chip_resource(ppd->dd, qsfp_resource(ppd->dd), QSFP_WAIT);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto bail_no_release;
|
|
|
|
+
|
|
ret = qsfp_read(ppd, target, 0, cache, QSFP_PAGESIZE);
|
|
ret = qsfp_read(ppd, target, 0, cache, QSFP_PAGESIZE);
|
|
if (ret != QSFP_PAGESIZE) {
|
|
if (ret != QSFP_PAGESIZE) {
|
|
dd_dev_info(ppd->dd,
|
|
dd_dev_info(ppd->dd,
|
|
@@ -406,6 +440,8 @@ int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ release_chip_resource(ppd->dd, qsfp_resource(ppd->dd));
|
|
|
|
+
|
|
spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
|
|
spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags);
|
|
ppd->qsfp_info.cache_valid = 1;
|
|
ppd->qsfp_info.cache_valid = 1;
|
|
ppd->qsfp_info.cache_refresh_required = 0;
|
|
ppd->qsfp_info.cache_refresh_required = 0;
|
|
@@ -414,6 +450,8 @@ int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
bail:
|
|
bail:
|
|
|
|
+ release_chip_resource(ppd->dd, qsfp_resource(ppd->dd));
|
|
|
|
+bail_no_release:
|
|
memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128));
|
|
memset(cache, 0, (QSFP_MAX_NUM_PAGES * 128));
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|