RE: [PATCH 4/5] firmware: imx: support BBM module

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Cristian,

> Subject: Re: [PATCH 4/5] firmware: imx: support BBM module
> 
....

> > +msecs_to_jiffies(DEBOUNCE_TIME));
> > +
> > +	/*
> > +	 * Directly report key event after resume to make no key press
> > +	 * event is missed.
> > +	 */
> > +	if (bbnsm->suspended) {
> 
> So this bbnsm->suspended is checked here from inside the SCMI
> notifier and it is set by a couple of pm_ops you provide down below
> which are called by the core PM subsys, so is it not high likely that you
> could have issues with the order of such reads/writes ?
> 
> Would it be worth to add a READ_ONCE here and WRITE_ONCE in the
> pm_ops...or I am overthinking ?

Just checked other input drivers, only two use READ_ONCE.
It might be good to avoid potential issues with READ/WRITE_ONCE.

Other comments will be addressed. BTW,
I will split rtc and pwr key into two drivers and put
them in input and rtc directory.

Thanks,
Peng

> 
> > +		bbnsm->keystate = 1;
> > +		input_event(input, EV_KEY, bbnsm->keycode, 1);
> > +		input_sync(input);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void scmi_imx_bbm_pwrkey_act(void *pdata) {
> > +	struct scmi_imx_bbm *bbnsm = pdata;
> > +
> > +	cancel_delayed_work_sync(&bbnsm->check_work);
> > +}
> > +
> > +static int scmi_imx_bbm_notifier(struct notifier_block *nb, unsigned
> > +long event, void *data) {
> > +	struct scmi_imx_bbm *bbnsm = container_of(nb, struct
> scmi_imx_bbm, nb);
> > +	struct scmi_imx_bbm_notif_report *r = data;
> > +
> > +	if (r->is_rtc)
> > +		rtc_update_irq(bbnsm->rtc_dev, 1, RTC_AF |
> RTC_IRQF);
> > +	if (r->is_button) {
> > +		pr_debug("BBM Button Power key pressed\n");
> > +		scmi_imx_bbm_pwrkey_event(bbnsm);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int scmi_imx_bbm_pwrkey_init(struct scmi_device *sdev) {
> > +	const struct scmi_handle *handle = sdev->handle;
> > +	struct device *dev = &sdev->dev;
> > +	struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
> > +	struct input_dev *input;
> > +	int ret;
> > +
> > +	if (device_property_read_u32(dev, "linux,code", &bbnsm-
> >keycode)) {
> > +		bbnsm->keycode = KEY_POWER;
> > +		dev_warn(dev, "key code is not specified, using
> default KEY_POWER\n");
> > +	}
> > +
> > +	INIT_DELAYED_WORK(&bbnsm->check_work,
> > +scmi_imx_bbm_pwrkey_check_for_events);
> > +
> > +	input = devm_input_allocate_device(dev);
> > +	if (!input) {
> > +		dev_err(dev, "failed to allocate the input device for
> SCMI IMX BBM\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	input->name = dev_name(dev);
> > +	input->phys = "bbnsm-pwrkey/input0";
> > +	input->id.bustype = BUS_HOST;
> > +
> > +	input_set_capability(input, EV_KEY, bbnsm->keycode);
> > +
> > +	ret = devm_add_action_or_reset(dev,
> scmi_imx_bbm_pwrkey_act, bbnsm);
> > +	if (ret) {
> > +		dev_err(dev, "failed to register remove action\n");
> > +		return ret;
> > +	}
> > +
> > +	bbnsm->input = input;
> > +
> > +	ret = handle->notify_ops->devm_event_notifier_register(sdev,
> SCMI_PROTOCOL_IMX_BBM,
> > +
> SCMI_EVENT_IMX_BBM_BUTTON,
> > +							       NULL,
> &bbnsm->nb);
> 
> So you are registering for another SCMI event but you want to use the
> same callback and notifier_bock to handle different events, BUT
> internally the SCMI core creates a DISTINCT kernel regular notification
> chain for each event and each resource (or one for ALL resources of an
> event) against which a
> devm_event_notifier_register() has been called AND so, being a
> notification_chain the notifier_blocks that you provide MUST be
> distinct, because the notification chain is indeed a simply-linked list
> and so when you register bbnsm->nb the second time you will indeed
> add the nb to another list at the same....
> 
> ...thing which I suppose could work in your case since you have only
> nb/callback per event BUT as soon as you (or someone else) will try to
> register another nb for these same events the 2 notification chains will
> start melting together....
> 
> ...and it will be a hell to debug...
> 
> so IOW...even if it works now for you, please use 2 distinct nb_pwr.
> nb_rtc notifier blocks with 2 distinct callbacks (to be able to use
> container_of in
> them) to register to 2 distinct events...you can register for multiple
> sources using only one nb BUT you cannot register for multiple events
> using the same nb/callback as of now.
> 
> With this internal design the queues and the worker threads
> dispatching these notifs are dedicated to a single event and possible to
> a single event/resource...
> ...no event ever queues behind any other...
> 
> This probably would need better clarification in the SCMI docs, my bad,
> and maybe a new option to register for ANY event the same nb (like
> you can do with src_id if you dont specify one), IF you are fine with the
> possibility that your events notification will be serialized in a single
> queue.
> 
> > +
> > +	if (ret)
> > +		dev_err(dev, "Failed to register BBM Button
> Events %d:", ret);
> > +
> 
> So why not failing if you could NOT register the notifications ?
> 
> > +	ret = input_register_device(input);
> > +	if (ret) {
> > +		dev_err(dev, "failed to register input device\n");
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int scmi_imx_bbm_rtc_init(struct scmi_device *sdev) {
> > +	const struct scmi_handle *handle = sdev->handle;
> > +	struct device *dev = &sdev->dev;
> > +	struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
> > +	int ret;
> > +
> > +	bbnsm->rtc_dev = devm_rtc_allocate_device(dev);
> > +	if (IS_ERR(bbnsm->rtc_dev))
> > +		return PTR_ERR(bbnsm->rtc_dev);
> > +
> > +	bbnsm->rtc_dev->ops = &smci_imx_bbm_rtc_ops;
> > +	bbnsm->rtc_dev->range_min = 0;
> > +	bbnsm->rtc_dev->range_max = U32_MAX;
> > +
> > +	ret = devm_rtc_register_device(bbnsm->rtc_dev);
> > +	if (ret)
> > +		return ret;
> > +
> > +	bbnsm->nb.notifier_call = &scmi_imx_bbm_notifier;
> > +	return handle->notify_ops->devm_event_notifier_register(sdev,
> SCMI_PROTOCOL_IMX_BBM,
> > +
> 	SCMI_EVENT_IMX_BBM_RTC,
> > +
> 	NULL, &bbnsm->nb);
> 
> As said, this will get mixed up when pwrkey_init tries to register again
> the same nb for a different event...
> 
> > +}
> > +
> > +static int scmi_imx_bbm_probe(struct scmi_device *sdev) {
> > +	const struct scmi_handle *handle = sdev->handle;
> > +	struct device *dev = &sdev->dev;
> > +	struct scmi_protocol_handle *ph;
> > +	struct scmi_imx_bbm *bbnsm;
> > +	int ret;
> > +
> > +	if (!handle)
> > +		return -ENODEV;
> > +
> > +	bbnsm = devm_kzalloc(dev, sizeof(struct scmi_imx_bbm),
> GFP_KERNEL);
> 
> sizeof(*bbnsm)
> 
> > +	if (!bbnsm)
> > +		return -ENOMEM;
> > +
> > +	bbnsm->ops = handle->devm_protocol_get(sdev,
> SCMI_PROTOCOL_IMX_BBM,
> > +&ph);
> 
> proto ops can be global really..since are always the same pointer even
> if this is probed mutiple times... this could be
> 
> 	bbnsm_ops = handle->devm_protocol_get(sdev,
> SCMI_PROTOCOL_IMX_BBM, &bbnsm->ph);
> 
> with bbnsm_ops static global to this file
> 
> > +	if (IS_ERR(bbnsm->ops))
> > +		return PTR_ERR(bbnsm->ops);
> > +
> > +	bbnsm->ph = ph;
> > +
> > +	device_init_wakeup(dev, true);
> 
> Not fully familiar with this, but it seems to me that when this is issued
> some wakeup related sysfs entries are created too...so I suppose you
> want to disable this back on failure to have those entries removed.
> 
> or maybe just move this right before the final return 0....but I am not
> sure if you want to have it called BEFORE the pwrkey notifier if
> registered or AFTER is fine too...potentially loosing some wakeup,
> though.
> 
> > +
> > +	dev_set_drvdata(dev, bbnsm);
> > +
> > +	ret = scmi_imx_bbm_rtc_init(sdev);
> > +	if (ret) {
> > +		dev_err(dev, "rtc init failed: %d\n", ret);
> 
> like ??
> 		device_init_wakeup(dev, false);
> 
> > +		return ret;
> > +	}
> > +
> > +	ret = scmi_imx_bbm_pwrkey_init(sdev);
> > +	if (ret) {
> > +		dev_err(dev, "pwr init failed: %d\n", ret);
> and...
> 		device_init_wakeup(dev, false);
> 
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int __maybe_unused scmi_imx_bbm_suspend(struct device
> *dev) {
> > +	struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
> > +
> > +	bbnsm->suspended = true;
> > +
> > +	return 0;
> > +}
> > +
> > +static int __maybe_unused scmi_imx_bbm_resume(struct device
> *dev) {
> > +	struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
> > +
> > +	bbnsm->suspended = false;
> > +
> > +	return 0;
> > +}
> > +
> > +static SIMPLE_DEV_PM_OPS(scmi_imx_bbm_pm_ops,
> scmi_imx_bbm_suspend,
> > +scmi_imx_bbm_resume);
> > +
> > +static const struct scmi_device_id scmi_id_table[] = {
> > +	{ SCMI_PROTOCOL_IMX_BBM, "imx-bbm" },
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(scmi, scmi_id_table);
> > +
> > +static struct scmi_driver scmi_imx_bbm_driver = {
> > +	.driver = {
> > +		.pm = &scmi_imx_bbm_pm_ops,
> > +	},
> > +	.name = "scmi-imx-bbm",
> > +	.probe = scmi_imx_bbm_probe,
> > +	.id_table = scmi_id_table,
> > +};
> > +module_scmi_driver(scmi_imx_bbm_driver);
> > +
> 
> Thanks,
> Cristian





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux