Skip to content

Commit

Permalink
core/i2c: split i2c_request_send()
Browse files Browse the repository at this point in the history
Split the i2c_request_send() method into two methods: i2c_request_send()
which allocates and populates and i2c_request structure, and
i2c_request_sync() which take a request structure and blocks until it
completes.

This allows code that allocates a i2c_request structure elsewhere to
make use of the existing busy-wait and request retry logic. Fix the
return types to use int64_t while we're here since these are returning
OPAL_API error codes.

Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
  • Loading branch information
oohal authored and stewartsmith committed Mar 28, 2019
1 parent d290b24 commit 319e7d9
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 45 deletions.
97 changes: 53 additions & 44 deletions core/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,56 @@ opal_call(OPAL_I2C_REQUEST, opal_i2c_request, 3);
#define MAX_NACK_RETRIES 2
#define REQ_COMPLETE_POLLING 5 /* Check if req is complete
in 5ms interval */
int64_t i2c_request_sync(struct i2c_request *req)
{
uint64_t timer_period = msecs_to_tb(5), timer_count;
uint64_t time_to_wait = 0;
int64_t rc, waited, retries;

for (retries = 0; retries <= MAX_NACK_RETRIES; retries++) {
waited = 0;
timer_count = 0;

i2c_queue_req(req);

do {
time_to_wait = i2c_run_req(req);
if (!time_to_wait)
time_to_wait = REQ_COMPLETE_POLLING;
time_wait(time_to_wait);
waited += time_to_wait;
timer_count += time_to_wait;
if (timer_count > timer_period) {
/*
* The above request may be relying on
* timers to complete, yet there may
* not be called, especially during
* opal init. We could be looping here
* forever. So explicitly check the
* timers once in a while
*/
check_timers(false);
timer_count = 0;
}
} while (req->req_state != i2c_req_done);

lwsync();
rc = req->result;

/* retry on NACK, otherwise exit */
if (rc != OPAL_I2C_NACK_RCVD)
break;
req->req_state = i2c_req_new;
}

prlog(PR_DEBUG, "I2C: %s req op=%x offset=%x buf=%016llx buflen=%d "
"delay=%lu/%lld rc=%lld\n",
(rc) ? "!!!!" : "----", req->op, req->offset,
*(uint64_t*) req->rw_buf, req->rw_len, tb_to_msecs(waited), req->timeout, rc);

return rc;
}

/**
* i2c_request_send - send request to i2c bus synchronously
* @bus_id: i2c bus id
Expand All @@ -155,15 +205,13 @@ opal_call(OPAL_I2C_REQUEST, opal_i2c_request, 3);
*
* Returns: Zero on success otherwise a negative error code
*/
int i2c_request_send(int bus_id, int dev_addr, int read_write,
int64_t i2c_request_send(int bus_id, int dev_addr, int read_write,
uint32_t offset, uint32_t offset_bytes, void* buf,
size_t buflen, int timeout)
{
int rc, waited, retries;
struct i2c_request *req;
struct i2c_bus *bus;
uint64_t time_to_wait = 0;
uint64_t timer_period = msecs_to_tb(5), timer_count;
int64_t rc;

bus = i2c_find_bus_by_id(bus_id);
if (!bus) {
Expand Down Expand Up @@ -197,46 +245,7 @@ int i2c_request_send(int bus_id, int dev_addr, int read_write,
req->rw_len = buflen;
req->timeout = timeout;

for (retries = 0; retries <= MAX_NACK_RETRIES; retries++) {
waited = 0;
timer_count = 0;

i2c_queue_req(req);

do {
time_to_wait = i2c_run_req(req);
if (!time_to_wait)
time_to_wait = REQ_COMPLETE_POLLING;
time_wait(time_to_wait);
waited += time_to_wait;
timer_count += time_to_wait;
if (timer_count > timer_period) {
/*
* The above request may be relying on
* timers to complete, yet there may
* not be called, especially during
* opal init. We could be looping here
* forever. So explicitly check the
* timers once in a while
*/
check_timers(false);
timer_count = 0;
}
} while (req->req_state != i2c_req_done);

lwsync();
rc = req->result;

/* retry on NACK, otherwise exit */
if (rc != OPAL_I2C_NACK_RCVD)
break;
req->req_state = i2c_req_new;
}

prlog(PR_DEBUG, "I2C: %s req op=%x offset=%x buf=%016llx buflen=%d "
"delay=%lu/%d rc=%d\n",
(rc) ? "!!!!" : "----", req->op, req->offset,
*(uint64_t*) buf, req->rw_len, tb_to_msecs(waited), timeout, rc);
rc = i2c_request_sync(req);

free(req);
if (rc)
Expand Down
3 changes: 2 additions & 1 deletion include/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ static inline int i2c_check_quirk(struct i2c_request *req, int *rc)
}

/* I2C synchronous request API */
int i2c_request_send(int bus_id, int dev_addr, int read_write,
int64_t i2c_request_sync(struct i2c_request *req);
int64_t i2c_request_send(int bus_id, int dev_addr, int read_write,
uint32_t offset, uint32_t offset_bytes, void* buf,
size_t buflen, int timeout);

Expand Down

0 comments on commit 319e7d9

Please sign in to comment.