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: Easwar Hariharan <easwar.hariharan@intel.com> Reviewed-by: Dean Luick <dean.luick@intel.com> Signed-off-by: Pablo Cacho <pablo.cacho@intel.com> Signed-off-by: Jubin John <jubin.john@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
Родитель
0096765be0
Коммит
cfe3e656d8
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* 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
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -18,7 +18,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2015 Intel Corporation.
|
||||
* Copyright(c) 2015, 2016 Intel Corporation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* 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,
|
|||
if (ret) {
|
||||
hfi1_dev_porterr(ppd->dd, ppd->port,
|
||||
"I2C write interface reset failed\n");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -179,7 +178,6 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
|
|||
if (ret) {
|
||||
hfi1_dev_porterr(ppd->dd, ppd->port,
|
||||
"I2C read interface reset failed\n");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -213,7 +211,7 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|||
hfi1_dev_porterr(ppd->dd, ppd->port,
|
||||
"QSFP write interface reset failed\n");
|
||||
mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (count < len) {
|
||||
|
@ -279,7 +277,7 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
|
|||
hfi1_dev_porterr(ppd->dd, ppd->port,
|
||||
"QSFP read interface reset failed\n");
|
||||
mutex_unlock(&ppd->dd->qsfp_i2c_mutex);
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (count < len) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* 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
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -18,7 +18,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2015 Intel Corporation.
|
||||
* Copyright(c) 2015, 2016 Intel Corporation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -136,6 +136,19 @@ static void scl_out(struct hfi1_devdata *dd, u32 target, u8 bit)
|
|||
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)
|
||||
{
|
||||
u32 mask;
|
||||
|
@ -274,13 +287,12 @@ static void stop_cmd(struct hfi1_devdata *dd, u32 target)
|
|||
/**
|
||||
* hfi1_twsi_reset - reset I2C communication
|
||||
* @dd: the hfi1_ib device
|
||||
* returns 0 if ok, -EIO on error
|
||||
*/
|
||||
|
||||
int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target)
|
||||
{
|
||||
int clock_cycles_left = 9;
|
||||
int was_high = 0;
|
||||
u32 pins, mask;
|
||||
u32 mask;
|
||||
|
||||
/* Both SCL and SDA should be high. If not, there
|
||||
* is something wrong.
|
||||
|
@ -294,43 +306,23 @@ int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target)
|
|||
*/
|
||||
hfi1_gpio_mod(dd, target, 0, 0, mask);
|
||||
|
||||
/*
|
||||
* Clock nine times to get all listeners into a sane state.
|
||||
* If SDA does not go high at any point, we are wedged.
|
||||
* One vendor recommends then issuing START followed by STOP.
|
||||
* we cannot use our "normal" functions to do that, because
|
||||
* if SCL drops between them, another vendor's part will
|
||||
* wedge, dropping SDA and keeping it low forever, at the end of
|
||||
* the next transaction (even if it was not the device addressed).
|
||||
* So our START and STOP take place with SCL held high.
|
||||
/* Check if SCL is low, if it is low then we have a slave device
|
||||
* misbehaving and there is not much we can do.
|
||||
*/
|
||||
if (!scl_in(dd, target, 0))
|
||||
return -EIO;
|
||||
|
||||
/* Check if SDA is low, if it is low then we have to clock SDA
|
||||
* up to 9 times for the device to release the bus
|
||||
*/
|
||||
while (clock_cycles_left--) {
|
||||
if (sda_in(dd, target, 0))
|
||||
return 0;
|
||||
scl_out(dd, target, 0);
|
||||
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
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* 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
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -20,7 +20,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2015 Intel Corporation.
|
||||
* Copyright(c) 2015, 2016 Intel Corporation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -54,8 +54,9 @@
|
|||
|
||||
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_SCL_NUM 0
|
||||
|
||||
/* these functions must be called with qsfp_lock held */
|
||||
int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target);
|
||||
|
|
Загрузка…
Ссылка в новой задаче