+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.