diff mbox

[v5,03/15] hw/p8-i2c: Allow to disable timeout

Message ID 1430115993-20560-4-git-send-email-gwshan@linux.vnet.ibm.com
State Superseded
Delegated to: Benjamin Herrenschmidt
Headers show

Commit Message

Gavin Shan April 27, 2015, 6:26 a.m. UTC
When changing power supply status to PCI slot during bootup, which
is done through I2C requests, the interrupt stuff isn't working yet
and we have to invoke polling timers proactively at fixed interval.
Unfortunately, the I2C master's timeout is usually very short and
we will encounter master timeout on the first poll at system bootup
time. In order to avoid the problem, the patch allows users to disable
the timeout by setting I2C request's timeout set (uint64_t)(-1).

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 hw/p8-i2c.c   | 26 ++++++++++++++++++++------
 include/i2c.h |  9 +++++++++
 2 files changed, 29 insertions(+), 6 deletions(-)
diff mbox

Patch

diff --git a/hw/p8-i2c.c b/hw/p8-i2c.c
index 3d5b9d4..5450b89 100644
--- a/hw/p8-i2c.c
+++ b/hw/p8-i2c.c
@@ -367,10 +367,14 @@  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);
+	if (request->timeout != (uint64_t)(-1))
+		cancel_timer_async(&master->timeout);
 	list_del(&req->link);
 	master->state = state_idle;
 	unlock(&master->lock);
@@ -925,11 +929,11 @@  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;
-
-	/* Start the timeout */
-	schedule_timer_at(&master->timeout, request->timeout);
+	if (request->timeout != (uint64_t)(-1)) {
+		tbytes = req->rw_len + req->offset_bytes + 2;
+		request->timeout = now + tbytes * master->byte_timeout;
+		schedule_timer_at(&master->timeout, request->timeout);
+	}
 
 	return OPAL_SUCCESS;
 }
@@ -998,6 +1002,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 timeout)
+{
+	struct p8_i2c_request *request =
+		container_of(req, struct p8_i2c_request, req);
+
+	request->timeout = timeout;
+}
+
 static inline uint32_t p8_i2c_get_bit_rate_divisor(uint32_t lb_freq,
 						   uint32_t bus_speed)
 {
@@ -1264,6 +1277,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 */
diff --git a/include/i2c.h b/include/i2c.h
index dea0644..5963726 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -26,6 +26,8 @@  struct i2c_bus {
 	int			(*queue_req)(struct i2c_request *req);
 	struct i2c_request	*(*alloc_req)(struct i2c_bus *bus);
 	void			(*free_req)(struct i2c_request *req);
+	void			(*set_req_timeout)(struct i2c_request *req,
+						   uint64_t timeout);
 };
 
 /*
@@ -80,6 +82,13 @@  static inline int i2c_queue_req(struct i2c_request *req)
 	return req->bus->queue_req(req);
 }
 
+static inline void i2c_set_req_timeout(struct i2c_request *req,
+				       uint64_t timeout)
+{
+	if (req->bus->set_req_timeout)
+		req->bus->set_req_timeout(req, timeout);
+}
+
 /* P8 implementation details */
 extern void p8_i2c_init(void);
 extern void p8_i2c_interrupt(uint32_t chip_id);