[PATCH 05/19] soundwire: amd: add soundwire interrupt handling
Pierre-Louis Bossart
pierre-louis.bossart at linux.intel.com
Wed Jan 11 16:19:57 CET 2023
>
> +static void amd_sdwc_process_ping_status(u64 response, struct amd_sdwc_ctrl *ctrl)
> +{
> + u64 slave_stat = 0;
> + u32 val = 0;
> + u16 dev_index;
> +
> + /* slave status from ping response*/
response */
> + slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response);
> + slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8;
> +
> + dev_dbg(ctrl->dev, "%s: slave_stat:0x%llx\n", __func__, slave_stat);
> + for (dev_index = 0; dev_index <= SDW_MAX_DEVICES; ++dev_index) {
> + val = (slave_stat >> (dev_index * 2)) & AMD_SDW_MCP_SLAVE_STATUS_MASK;
> + dev_dbg(ctrl->dev, "%s val:0x%x\n", __func__, val);
> + switch (val) {
> + case SDW_SLAVE_ATTACHED:
> + ctrl->status[dev_index] = SDW_SLAVE_ATTACHED;
> + break;
> + case SDW_SLAVE_UNATTACHED:
> + ctrl->status[dev_index] = SDW_SLAVE_UNATTACHED;
> + break;
> + case SDW_SLAVE_ALERT:
> + ctrl->status[dev_index] = SDW_SLAVE_ALERT;
> + break;
> + default:
> + ctrl->status[dev_index] = SDW_SLAVE_RESERVED;
> + break;
> + }
> + }
> +}
> +
> +static void amd_sdwc_read_and_process_ping_status(struct amd_sdwc_ctrl *ctrl)
> +{
> + u64 response = 0;
> +
> + mutex_lock(&ctrl->bus.msg_lock);
> + response = amd_sdwc_send_cmd_get_resp(ctrl, 0, 0);
> + mutex_unlock(&ctrl->bus.msg_lock);
> + amd_sdwc_process_ping_status(response, ctrl);
Is this saying that you actually need to send a PING frame manually
every time the manager needs to check the device status, including
interrupts?
> +}
> +
> static u32 amd_sdwc_read_ping_status(struct sdw_bus *bus)
> {
> struct amd_sdwc_ctrl *ctrl = to_amd_sdw(bus);
> @@ -1132,6 +1173,119 @@ static int amd_sdwc_register_dais(struct amd_sdwc_ctrl *ctrl)
> dais, num_dais);
> }
>
> +static void amd_sdwc_update_slave_status_work(struct work_struct *work)
> +{
> + struct amd_sdwc_ctrl *ctrl =
> + container_of(work, struct amd_sdwc_ctrl, amd_sdw_work);
> + u32 sw_status_change_mask_0to7_reg;
> + u32 sw_status_change_mask_8to11_reg;
> +
> + switch (ctrl->instance) {
> + case ACP_SDW0:
> + sw_status_change_mask_0to7_reg = SW_STATE_CHANGE_STATUS_MASK_0TO7;
> + sw_status_change_mask_8to11_reg = SW_STATE_CHANGE_STATUS_MASK_8TO11;
> + break;
> + case ACP_SDW1:
> + sw_status_change_mask_0to7_reg = P1_SW_STATE_CHANGE_STATUS_MASK_0TO7;
> + sw_status_change_mask_8to11_reg = P1_SW_STATE_CHANGE_STATUS_MASK_8TO11;
> + break;
> + default:
> + dev_err(ctrl->dev, "Invalid Soundwire controller instance\n");
> + return;
> + }
> +
> + if (ctrl->status[0] == SDW_SLAVE_ATTACHED) {
> + acp_reg_writel(0, ctrl->mmio + sw_status_change_mask_0to7_reg);
> + acp_reg_writel(0, ctrl->mmio + sw_status_change_mask_8to11_reg);
> + }
> +
> +update_status:
> + sdw_handle_slave_status(&ctrl->bus, ctrl->status);
> + if (ctrl->status[0] == SDW_SLAVE_ATTACHED) {
> + acp_reg_writel(AMD_SDW_IRQ_MASK_0TO7, ctrl->mmio + sw_status_change_mask_0to7_reg);
> + acp_reg_writel(AMD_SDW_IRQ_MASK_8TO11,
> + ctrl->mmio + sw_status_change_mask_8to11_reg);
> + amd_sdwc_read_and_process_ping_status(ctrl);
> + goto update_status;
> + }
well no, you have to use some sort of retry count. You cannot handle
interrupts in a loop like this, a faulty or chatty device would keep
signaling an issue and you would be stuck here for a while.
In addition, it's not clear if this is really needed. We added this loop
in cadence_master.c because of issues with multiple devices becoming
attached at the same time and how the hardware works. As it turns out,
this update_status loop seems to be a paranoid case, the actually cause
for devices de-attaching was found by Cirrus Logic and fixed in
"soundwire: cadence: fix updating slave status when a bus has multiple
peripherals"
You would need to explain how the status is detected and if any race
conditions can occur.
More information about the Alsa-devel
mailing list