in fsi-master-gpio.c [424:521]
static int poll_for_response(struct fsi_master_gpio *master,
uint8_t slave, uint8_t size, void *data)
{
struct fsi_gpio_msg response, cmd;
int busy_count = 0, rc, i;
unsigned long flags;
uint8_t tag;
uint8_t *data_byte = data;
int crc_err_retries = 0;
retry:
rc = read_one_response(master, size, &response, &tag);
/* Handle retries on CRC errors */
if (rc == -EAGAIN) {
/* Too many retries ? */
if (crc_err_retries++ > FSI_CRC_ERR_RETRIES) {
/*
* Pass it up as a -EIO otherwise upper level will retry
* the whole command which isn't what we want here.
*/
rc = -EIO;
goto fail;
}
dev_dbg(master->dev,
"CRC error retry %d\n", crc_err_retries);
trace_fsi_master_gpio_crc_rsp_error(master);
build_epoll_command(&cmd, slave);
local_irq_save(flags);
clock_zeros(master, FSI_MASTER_EPOLL_CLOCKS);
serial_out(master, &cmd);
echo_delay(master);
local_irq_restore(flags);
goto retry;
} else if (rc)
goto fail;
switch (tag) {
case FSI_RESP_ACK:
if (size && data) {
uint64_t val = response.msg;
/* clear crc & mask */
val >>= 4;
val &= (1ull << (size * 8)) - 1;
for (i = 0; i < size; i++) {
data_byte[size-i-1] = val;
val >>= 8;
}
}
break;
case FSI_RESP_BUSY:
/*
* Its necessary to clock slave before issuing
* d-poll, not indicated in the hardware protocol
* spec. < 20 clocks causes slave to hang, 21 ok.
*/
if (busy_count++ < FSI_MASTER_MAX_BUSY) {
build_dpoll_command(&cmd, slave);
local_irq_save(flags);
clock_zeros(master, FSI_MASTER_DPOLL_CLOCKS);
serial_out(master, &cmd);
echo_delay(master);
local_irq_restore(flags);
goto retry;
}
dev_warn(master->dev,
"ERR slave is stuck in busy state, issuing TERM\n");
local_irq_save(flags);
clock_zeros(master, FSI_MASTER_DPOLL_CLOCKS);
local_irq_restore(flags);
issue_term(master, slave);
rc = -EIO;
break;
case FSI_RESP_ERRA:
dev_dbg(master->dev, "ERRA received: 0x%x\n", (int)response.msg);
rc = -EIO;
break;
case FSI_RESP_ERRC:
dev_dbg(master->dev, "ERRC received: 0x%x\n", (int)response.msg);
trace_fsi_master_gpio_crc_cmd_error(master);
rc = -EAGAIN;
break;
}
if (busy_count > 0)
trace_fsi_master_gpio_poll_response_busy(master, busy_count);
fail:
/*
* tSendDelay clocks, avoids signal reflections when switching
* from receive of response back to send of data.
*/
local_irq_save(flags);
clock_zeros(master, master->t_send_delay);
local_irq_restore(flags);
return rc;
}