summaryrefslogtreecommitdiffstats
path: root/hw/p8-i2c.c
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-06-10 15:03:30 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-06-14 16:00:15 +1000
commit5808b75d08d7936d19923045b7f35c0e8ae75755 (patch)
treed986aea3809d91037ee811f05247573b3b25190a /hw/p8-i2c.c
parente6b2e38abb906023c1ef3631b21ad00d26fc0b5f (diff)
downloadtalos-skiboot-5808b75d08d7936d19923045b7f35c0e8ae75755.tar.gz
talos-skiboot-5808b75d08d7936d19923045b7f35c0e8ae75755.zip
hw/p8-i2c: Allow to set I2C request timeout
Prior to PCI enumeration, the PHB slot's power state might be changed during fundamental reset. The fundamental reset is implemented by state machine and it's driven by a polling mechanism in predetermined interval (A). On the other hand, PCI slot's power supply is controlled by I2C chip on Firenze platform. It means the PCI slot's power supply state is changed through I2C request which has a timeout timer running in variable interval (B). Comparing to (A), (B) is small and short. That means I2C timeout is reached before first poll running in interval of (A). It's unexpected behaviour. This allows to set I2C request timeout ((B)) to avoid the issue. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Reviewed-by: Stewart Smith <stewart@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/p8-i2c.c')
-rw-r--r--hw/p8-i2c.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/hw/p8-i2c.c b/hw/p8-i2c.c
index 593eb88a..fde9a808 100644
--- a/hw/p8-i2c.c
+++ b/hw/p8-i2c.c
@@ -386,10 +386,15 @@ static int p8_i2c_prog_mode(struct p8_i2c_master_port *port, bool enhanced_mode)
static void p8_i2c_complete_request(struct p8_i2c_master *master,
struct i2c_request *req, int ret)
{
+ struct p8_i2c_request *request =
+ container_of(req, struct p8_i2c_request, req);
+
/* We only complete the current top level request */
assert(req == list_top(&master->req_list, struct i2c_request, link));
cancel_timer_async(&master->timeout);
+ request->timeout = 0ul;
+
list_del(&req->link);
master->state = state_idle;
req->result = ret;
@@ -973,8 +978,12 @@ static int p8_i2c_start_request(struct p8_i2c_master *master,
now = schedule_timer(&master->poller, master->poll_interval);
/* Calculate and start timeout */
- tbytes = req->rw_len + req->offset_bytes + 2;
- request->timeout = now + tbytes * master->byte_timeout;
+ if (request->timeout) {
+ request->timeout += now;
+ } else {
+ tbytes = req->rw_len + req->offset_bytes + 2;
+ request->timeout = now + tbytes * master->byte_timeout;
+ }
/* Start the timeout */
schedule_timer_at(&master->timeout, request->timeout);
@@ -1046,6 +1055,15 @@ static void p8_i2c_free_request(struct i2c_request *req)
free(request);
}
+static void p8_i2c_set_request_timeout(struct i2c_request *req,
+ uint64_t duration)
+{
+ struct p8_i2c_request *request =
+ container_of(req, struct p8_i2c_request, req);
+
+ request->timeout = msecs_to_tb(duration);
+}
+
static inline uint32_t p8_i2c_get_bit_rate_divisor(uint32_t lb_freq,
uint32_t bus_speed)
{
@@ -1093,6 +1111,8 @@ static void p8_i2c_timeout(struct timer *t __unused, void *data, uint64_t now)
DBG("I2C: Timeout with request not expired\n");
goto exit;
}
+
+ request->timeout = 0ul;
port = container_of(req->bus, struct p8_i2c_master_port, bus);
/* Allright, we have a request and it has timed out ... */
@@ -1372,6 +1392,7 @@ static void p8_i2c_init_one(struct dt_node *i2cm, enum p8_i2c_master_type type)
port->bus.queue_req = p8_i2c_queue_request;
port->bus.alloc_req = p8_i2c_alloc_request;
port->bus.free_req = p8_i2c_free_request;
+ port->bus.set_req_timeout = p8_i2c_set_request_timeout;
i2c_add_bus(&port->bus);
/* Add OPAL properties to the bus node */
OpenPOWER on IntegriCloud