static int handle_response()

in fsi-master-ast-cf.c [467:569]


static int handle_response(struct fsi_master_acf *master,
			   uint8_t slave, uint8_t size, void *data)
{
	int busy_count = 0, rc;
	int crc_err_retries = 0;
	struct fsi_msg cmd;
	uint32_t response;
	uint8_t tag;
retry:
	rc = read_copro_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 bail;
		}
		trace_fsi_master_acf_crc_rsp_error(master, crc_err_retries);
		if (master->trace_enabled)
			dump_ucode_trace(master);
		rc = clock_zeros(master, FSI_MASTER_EPOLL_CLOCKS);
		if (rc) {
			dev_warn(master->dev,
				 "Error %d clocking zeros for E_POLL\n", rc);
			return rc;
		}
		build_epoll_command(&cmd, slave);
		rc = send_request(master, &cmd, size);
		if (rc) {
			dev_warn(master->dev, "Error %d sending E_POLL\n", rc);
			return -EIO;
		}
		goto retry;
	}
	if (rc)
		return rc;

	switch (tag) {
	case FSI_RESP_ACK:
		if (size && data) {
			if (size == 32)
				*(__be32 *)data = cpu_to_be32(response);
			else if (size == 16)
				*(__be16 *)data = cpu_to_be16(response);
			else
				*(u8 *)data = response;
		}
		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.
		 */
		dev_dbg(master->dev, "Busy, retrying...\n");
		if (master->trace_enabled)
			dump_ucode_trace(master);
		rc = clock_zeros(master, FSI_MASTER_DPOLL_CLOCKS);
		if (rc) {
			dev_warn(master->dev,
				 "Error %d clocking zeros for D_POLL\n", rc);
			break;
		}
		if (busy_count++ < FSI_MASTER_MAX_BUSY) {
			build_dpoll_command(&cmd, slave);
			rc = send_request(master, &cmd, size);
			if (rc) {
				dev_warn(master->dev, "Error %d sending D_POLL\n", rc);
				break;
			}
			goto retry;
		}
		dev_dbg(master->dev,
			"ERR slave is stuck in busy state, issuing TERM\n");
		send_term(master, slave);
		rc = -EIO;
		break;

	case FSI_RESP_ERRA:
		dev_dbg(master->dev, "ERRA received\n");
		if (master->trace_enabled)
			dump_ucode_trace(master);
		rc = -EIO;
		break;
	case FSI_RESP_ERRC:
		dev_dbg(master->dev, "ERRC received\n");
		if (master->trace_enabled)
			dump_ucode_trace(master);
		rc = -EAGAIN;
		break;
	}
 bail:
	if (busy_count > 0) {
		trace_fsi_master_acf_poll_response_busy(master, busy_count);
	}

	return rc;
}