Commit cfe3e656 authored by Dean Luick's avatar Dean Luick Committed by Doug Ledford

staging/rdma/hfi1: Correct TWSI reset

Change the TWSI reset function so it will stop the reset
once the lines are in an expected state.
Reviewed-by: default avatarEaswar Hariharan <easwar.hariharan@intel.com>
Reviewed-by: default avatarDean Luick <dean.luick@intel.com>
Signed-off-by: default avatarPablo Cacho <pablo.cacho@intel.com>
Signed-off-by: default avatarJubin John <jubin.john@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 0096765b
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* *
* BSD LICENSE * BSD LICENSE
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -106,7 +106,6 @@ int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, ...@@ -106,7 +106,6 @@ int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
if (ret) { if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port, hfi1_dev_porterr(ppd->dd, ppd->port,
"I2C write interface reset failed\n"); "I2C write interface reset failed\n");
ret = -EIO;
goto done; goto done;
} }
...@@ -179,7 +178,6 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, ...@@ -179,7 +178,6 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
if (ret) { if (ret) {
hfi1_dev_porterr(ppd->dd, ppd->port, hfi1_dev_porterr(ppd->dd, ppd->port,
"I2C read interface reset failed\n"); "I2C read interface reset failed\n");
ret = -EIO;
goto done; goto done;
} }
...@@ -213,7 +211,7 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -213,7 +211,7 @@ 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 write interface reset failed\n"); "QSFP write interface reset failed\n");
mutex_unlock(&ppd->dd->qsfp_i2c_mutex); mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
return -EIO; return ret;
} }
while (count < len) { while (count < len) {
...@@ -279,7 +277,7 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, ...@@ -279,7 +277,7 @@ 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 read interface reset failed\n"); "QSFP read interface reset failed\n");
mutex_unlock(&ppd->dd->qsfp_i2c_mutex); mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
return -EIO; return ret;
} }
while (count < len) { while (count < len) {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* *
* BSD LICENSE * BSD LICENSE
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -136,6 +136,19 @@ static void scl_out(struct hfi1_devdata *dd, u32 target, u8 bit) ...@@ -136,6 +136,19 @@ static void scl_out(struct hfi1_devdata *dd, u32 target, u8 bit)
i2c_wait_for_writes(dd, target); i2c_wait_for_writes(dd, target);
} }
static u8 scl_in(struct hfi1_devdata *dd, u32 target, int wait)
{
u32 read_val, mask;
mask = QSFP_HFI0_I2CCLK;
/* SCL is meant to be bare-drain, so never set "OUT", just DIR */
hfi1_gpio_mod(dd, target, 0, 0, mask);
read_val = hfi1_gpio_mod(dd, target, 0, 0, 0);
if (wait)
i2c_wait_for_writes(dd, target);
return (read_val & mask) >> GPIO_SCL_NUM;
}
static void sda_out(struct hfi1_devdata *dd, u32 target, u8 bit) static void sda_out(struct hfi1_devdata *dd, u32 target, u8 bit)
{ {
u32 mask; u32 mask;
...@@ -274,13 +287,12 @@ static void stop_cmd(struct hfi1_devdata *dd, u32 target) ...@@ -274,13 +287,12 @@ static void stop_cmd(struct hfi1_devdata *dd, u32 target)
/** /**
* hfi1_twsi_reset - reset I2C communication * hfi1_twsi_reset - reset I2C communication
* @dd: the hfi1_ib device * @dd: the hfi1_ib device
* returns 0 if ok, -EIO on error
*/ */
int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target) int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target)
{ {
int clock_cycles_left = 9; int clock_cycles_left = 9;
int was_high = 0; u32 mask;
u32 pins, mask;
/* Both SCL and SDA should be high. If not, there /* Both SCL and SDA should be high. If not, there
* is something wrong. * is something wrong.
...@@ -294,43 +306,23 @@ int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target) ...@@ -294,43 +306,23 @@ int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target)
*/ */
hfi1_gpio_mod(dd, target, 0, 0, mask); hfi1_gpio_mod(dd, target, 0, 0, mask);
/* /* Check if SCL is low, if it is low then we have a slave device
* Clock nine times to get all listeners into a sane state. * misbehaving and there is not much we can do.
* If SDA does not go high at any point, we are wedged. */
* One vendor recommends then issuing START followed by STOP. if (!scl_in(dd, target, 0))
* we cannot use our "normal" functions to do that, because return -EIO;
* if SCL drops between them, another vendor's part will
* wedge, dropping SDA and keeping it low forever, at the end of /* Check if SDA is low, if it is low then we have to clock SDA
* the next transaction (even if it was not the device addressed). * up to 9 times for the device to release the bus
* So our START and STOP take place with SCL held high.
*/ */
while (clock_cycles_left--) { while (clock_cycles_left--) {
if (sda_in(dd, target, 0))
return 0;
scl_out(dd, target, 0); scl_out(dd, target, 0);
scl_out(dd, target, 1); scl_out(dd, target, 1);
/* Note if SDA is high, but keep clocking to sync slave */
was_high |= sda_in(dd, target, 0);
}
if (was_high) {
/*
* We saw a high, which we hope means the slave is sync'd.
* Issue START, STOP, pause for T_BUF.
*/
pins = hfi1_gpio_mod(dd, target, 0, 0, 0);
if ((pins & mask) != mask)
dd_dev_err(dd, "GPIO pins not at rest: %d\n",
pins & mask);
/* Drop SDA to issue START */
udelay(1); /* Guarantee .6 uSec setup */
sda_out(dd, target, 0);
udelay(1); /* Guarantee .6 uSec hold */
/* At this point, SCL is high, SDA low. Raise SDA for STOP */
sda_out(dd, target, 1);
udelay(TWSI_BUF_WAIT_USEC);
} }
return !was_high; return -EIO;
} }
#define HFI1_TWSI_START 0x100 #define HFI1_TWSI_START 0x100
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* *
* BSD LICENSE * BSD LICENSE
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -54,8 +54,9 @@ ...@@ -54,8 +54,9 @@
struct hfi1_devdata; struct hfi1_devdata;
/* Bit position of SDA pin in ASIC_QSFP* registers */ /* Bit position of SDA/SCL pins in ASIC_QSFP* registers */
#define GPIO_SDA_NUM 1 #define GPIO_SDA_NUM 1
#define GPIO_SCL_NUM 0
/* these functions must be called with qsfp_lock held */ /* these functions must be called with qsfp_lock held */
int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target); int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target);
......
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