/* write set of regs to hardware - call with spinlock claimed */ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
{ struct cti_config *config = &drvdata->config; int i;
/* cannot enable due to error */
cti_err_not_enabled:
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); return rc;
}
/* re-enable CTI on CPU when using CPU hotplug */ staticvoid cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
{ struct cti_config *config = &drvdata->config;
/* add connection usage bit info to overall info */
drvdata->config.trig_in_use |= tc->con_in->used_mask;
drvdata->config.trig_out_use |= tc->con_out->used_mask;
return0;
}
/* create a trigger connection with appropriately sized signal groups */ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs)
{ struct cti_trig_con *tc = NULL; struct cti_trig_grp *in = NULL, *out = NULL;
tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL); if (!tc) return tc;
in = devm_kzalloc(dev,
offsetof(struct cti_trig_grp, sig_types[in_sigs]),
GFP_KERNEL); if (!in) return NULL;
out = devm_kzalloc(dev,
offsetof(struct cti_trig_grp, sig_types[out_sigs]),
GFP_KERNEL); if (!out) return NULL;
/** cti channel api **/ /* attach/detach channel from trigger - write through if enabled. */ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, enum cti_trig_dir direction, u32 channel_idx,
u32 trigger_idx)
{ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config;
u32 trig_bitmask;
u32 chan_bitmask;
u32 reg_value; int reg_offset;
/* ensure indexes in range */ if ((channel_idx >= config->nr_ctm_channels) ||
(trigger_idx >= config->nr_trig_max)) return -EINVAL;
trig_bitmask = BIT(trigger_idx);
/* ensure registered triggers and not out filtered */ if (direction == CTI_TRIG_IN) { if (!(trig_bitmask & config->trig_in_use)) return -EINVAL;
} else { if (!(trig_bitmask & config->trig_out_use)) return -EINVAL;
if ((config->trig_filter_enable) &&
(config->trig_out_filter & trig_bitmask)) return -EINVAL;
}
/* update the local register values */
chan_bitmask = BIT(channel_idx);
reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
CTIOUTEN(trigger_idx));
raw_spin_lock(&drvdata->spinlock);
/* read - modify write - the trigger / channel enable value */
reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :
config->ctiouten[trigger_idx]; if (op == CTI_CHAN_ATTACH)
reg_value |= chan_bitmask; else
reg_value &= ~chan_bitmask;
/* write local copy */ if (direction == CTI_TRIG_IN)
config->ctiinen[trigger_idx] = reg_value; else
config->ctiouten[trigger_idx] = reg_value;
/* write through if enabled */ if (cti_active(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
raw_spin_unlock(&drvdata->spinlock); return0;
}
link_err = coresight_add_sysfs_link(&link_info); if (link_err)
dev_warn(&drvdata->csdev->dev, "Failed to set CTI sysfs link %s<=>%s\n",
link_info.orig_name, link_info.target_name); return !link_err;
}
list_for_each_entry(tc, &ctidev->trig_cons, node) { if (tc->con_dev_name) { if (!strcmp(node_name, tc->con_dev_name)) { /* match: so swap in csdev name & dev */
tc->con_dev_name = dev_name(&csdev->dev);
tc->con_dev = csdev; /* try to set sysfs link */ if (cti_add_sysfs_link(drvdata, tc)) returntrue; /* link failed - remove CTI reference */
tc->con_dev = NULL; break;
}
}
} returnfalse;
}
/* exit if current is an ECT device.*/ if ((csdev->type == CORESIGHT_DEV_TYPE_HELPER &&
csdev->subtype.helper_subtype ==
CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI) ||
list_empty(&ect_net)) goto cti_add_done;
/* if we didn't find the csdev previously we used the fwnode name */
node_name = cti_plat_get_node_name(dev_fwnode(csdev->dev.parent)); if (!node_name) goto cti_add_done;
/* for each CTI in list... */
list_for_each_entry(ect_item, &ect_net, node) {
ctidev = &ect_item->ctidev; if (cti_match_fixup_csdev(ctidev, node_name, csdev)) { /* *ifwefoundamatchingcsdevthenupdatetheECT *associationpointerforthedevicewiththisCTI.
*/
coresight_add_helper(csdev, ect_item->csdev); break;
}
}
cti_add_done:
mutex_unlock(&ect_mutex);
}
list_for_each_entry(tc, &ctidev->trig_cons, node) { if (tc->con_dev) { /* if we can set the sysfs link */ if (cti_add_sysfs_link(drvdata, tc)) /* set the CTI/csdev association */
coresight_add_helper(tc->con_dev,
drvdata->csdev); else /* otherwise remove reference from CTI */
tc->con_dev = NULL;
}
}
}
if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu)) return NOTIFY_BAD;
raw_spin_lock(&drvdata->spinlock);
switch (cmd) { case CPU_PM_ENTER: /* CTI regs all static - we have a copy & nothing to save */
drvdata->config.hw_powered = false; if (drvdata->config.hw_enabled)
coresight_disclaim_device(csdev); break;
case CPU_PM_ENTER_FAILED:
drvdata->config.hw_powered = true; if (drvdata->config.hw_enabled) { if (coresight_claim_device(csdev))
drvdata->config.hw_enabled = false;
} break;
case CPU_PM_EXIT: /* write hardware registers to re-enable. */
drvdata->config.hw_powered = true;
drvdata->config.hw_enabled = false;
/* check enable reference count to enable HW */ if (drvdata->config.enable_req_count) { /* check we can claim the device as we re-power */ if (coresight_claim_device(csdev)) goto cti_notify_exit;
/* default to powered - could change on PM notifications */
drvdata->config.hw_powered = true;
/* set up device name - will depend if cpu bound or otherwise */ if (drvdata->ctidev.cpu >= 0)
cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d",
drvdata->ctidev.cpu); else
cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev); if (!cti_desc.name) return -ENOMEM;
/* setup CPU power management handling for CPU bound CTI devices. */
ret = cti_pm_setup(drvdata); if (ret) return ret;
/* create dynamic attributes for connections */
ret = cti_create_cons_sysfs(dev, drvdata); if (ret) {
dev_err(dev, "%s: create dynamic sysfs entries failed\n",
cti_desc.name); goto pm_release;
}
coresight_clear_self_claim_tag(&cti_desc.access);
drvdata->csdev = coresight_register(&cti_desc); if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev); goto pm_release;
}
/* add to list of CTI devices */
mutex_lock(&ect_mutex);
list_add(&drvdata->node, &ect_net); /* set any cross references */
cti_update_conn_xrefs(drvdata);
mutex_unlock(&ect_mutex);
/* set up release chain */
drvdata->csdev_release = drvdata->csdev->dev.release;
drvdata->csdev->dev.release = cti_device_release;
/* all done - dec pm refcount */
pm_runtime_put(&adev->dev);
dev_info(&drvdata->csdev->dev, "CTI initialized\n"); return0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.