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:
Dean Luick 2016-02-03 14:36:14 -08:00 коммит произвёл Doug Ledford
Родитель 0096765be0
Коммит cfe3e656d8
3 изменённых файлов: 36 добавлений и 45 удалений

Просмотреть файл

@ -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);