All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Jander <david@protonic.nl>
To: "Uwe Kleine-König" <u.kleine-koenig@baylibre.com>
Cc: linux-kernel@vger.kernel.org, linux-iio@vger.kernel.org,
	Jonathan Corbet <corbet@lwn.net>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	devicetree@vger.kernel.org, linux-doc@vger.kernel.org,
	Nuno Sa <nuno.sa@analog.com>, Jonathan Cameron <jic23@kernel.org>,
	Oleksij Rempel <o.rempel@pengutronix.de>
Subject: Re: [RFC PATCH 1/7] drivers: Add motion control subsystem
Date: Wed, 5 Mar 2025 16:40:45 +0100	[thread overview]
Message-ID: <20250305164046.4de5b6ef@erd003.prtnl> (raw)
In-Reply-To: <6c6cqaxmsy7miesel4ghdeiea6nrpe4gti4xf5enfyg4uqro5u@vpmtd2t7gydi>


Hi Uwe,

On Fri, 28 Feb 2025 17:44:27 +0100
Uwe Kleine-König <u.kleine-koenig@baylibre.com> wrote:

> Hello David,
> 
> just a few highlevel review comments inline.

Thanks...

> On Thu, Feb 27, 2025 at 05:28:17PM +0100, David Jander wrote:
> [...]
> > +static int motion_open(struct inode *inode, struct file *file)
> > +{
> > +	int minor = iminor(inode);
> > +	struct motion_device *mdev = NULL, *iter;
> > +	int err;
> > +
> > +	mutex_lock(&motion_mtx);  
> 
> If you use guard(), error handling gets a bit easier.

This looks interesting. I didn't know about guard(). Thanks. I see the
benefits, but in some cases it also makes the locked region less clearly
visible. While I agree that guard() in this particular place is nice,
I'm hesitant to try and replace all mutex_lock()/_unlock() calls with guard().
Let me know if my assessment of the intended use of guard() is incorrect.

> > +	list_for_each_entry(iter, &motion_list, list) {
> > +		if (iter->minor != minor)
> > +			continue;
> > +		mdev = iter;
> > +		break;
> > +	}  
> 
> This should be easier. If you use a cdev you can just do
> container_of(inode->i_cdev, ...);

Hmm... I don't yet really understand what you mean. I will have to study the
involved code a bit more.

> [...]
> > +static int motion_release(struct inode *inode, struct file *file)
> > +{
> > +	struct motion_device *mdev = file->private_data;
> > +	int i;
> > +
> > +	if (mdev->ops.device_release)
> > +		mdev->ops.device_release(mdev);
> > +
> > +	for (i = 0; i < mdev->num_gpios; i++) {
> > +		int irq;
> > +		struct motion_gpio_input *gpio = &mdev->gpios[i];
> > +
> > +		if (gpio->function == MOT_INP_FUNC_NONE)
> > +			continue;
> > +		irq = gpiod_to_irq(gpio->gpio);
> > +		devm_free_irq(mdev->dev, irq, gpio);  
> 
> It seems devm is just overhead here if you release by hand anyhow.

Ack. This looks indeed unnecessary... I'll try to use non-devres calls here.

> > [...]
> > +
> > +static const struct class motion_class = {
> > +	.name		= "motion",
> > +	.devnode	= motion_devnode,  
> 
> IIRC it's recommended to not create new classes, but a bus.

Interesting. I did some searching, and all I could find was that the chapter
in driver-api/driver-model about classes magically vanished between versions
5.12 and 5.13. Does anyone know where I can find some information about this?
Sorry if I'm being blind...

> [...]
> > +int motion_register_device(struct motion_device *mdev)
> > +{
> > +	dev_t devt;
> > +	int err = 0;
> > +	struct iio_motion_trigger_info *trig_info;
> > +
> > +	if (!mdev->capabilities.num_channels)
> > +		mdev->capabilities.num_channels = 1;
> > +	if (mdev->capabilities.features | MOT_FEATURE_PROFILE)
> > +		mdev->capabilities.max_profiles = MOT_MAX_PROFILES;
> > +	if (!mdev->capabilities.speed_conv_mul)
> > +		mdev->capabilities.speed_conv_mul = 1;
> > +	if (!mdev->capabilities.speed_conv_div)
> > +		mdev->capabilities.speed_conv_div = 1;
> > +	if (!mdev->capabilities.accel_conv_mul)
> > +		mdev->capabilities.accel_conv_mul = 1;
> > +	if (!mdev->capabilities.accel_conv_div)
> > +		mdev->capabilities.accel_conv_div = 1;
> > +
> > +	mutex_init(&mdev->mutex);
> > +	mutex_init(&mdev->read_mutex);
> > +	INIT_KFIFO(mdev->events);
> > +	init_waitqueue_head(&mdev->wait);
> > +
> > +	err = motion_of_parse_gpios(mdev);
> > +	if (err)
> > +		return err;
> > +
> > +	mdev->minor = motion_minor_alloc();
> > +
> > +	mdev->iiotrig = iio_trigger_alloc(NULL, "mottrig%d", mdev->minor);
> > +	if (!mdev->iiotrig) {
> > +		err = -ENOMEM;
> > +		goto error_free_minor;
> > +	}
> > +
> > +	trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
> > +	if (!trig_info) {
> > +		err = -ENOMEM;
> > +		goto error_free_trigger;
> > +	}
> > +
> > +	iio_trigger_set_drvdata(mdev->iiotrig, trig_info);
> > +
> > +	trig_info->minor = mdev->minor;
> > +	err = iio_trigger_register(mdev->iiotrig);
> > +	if (err)
> > +		goto error_free_trig_info;
> > +
> > +	mdev->iiowork = IRQ_WORK_INIT_HARD(motion_trigger_work);
> > +
> > +	INIT_LIST_HEAD(&mdev->list);
> > +
> > +	mutex_lock(&motion_mtx);
> > +
> > +	devt = MKDEV(motion_major, mdev->minor);
> > +	mdev->dev = device_create_with_groups(&motion_class, mdev->parent,
> > +				devt, mdev, mdev->groups, "motion%d", mdev->minor);  
> 
> What makes sure that mdev doesn't go away while one of the attributes is
> accessed?

Good question. I suppose you mean that since mdev is devres-managed and
device_create_with_groups() apparently isn't aware of that, so there is no
internal lock somewhere that prevents read() or ioctl() being called while the
devres code is freeing the memory of mdev?

I will try to search for some example code to see how something like this is
handled in other places. I assume I'd need to add a per-mdev lock or use the
big motion_mtx everywhere... which sounds like a performance penalty that
should be avoidable. If you know of a good example to learn from, I'd be
grateful to know.

> > +	if (IS_ERR(mdev->dev)) {
> > +		dev_err(mdev->parent, "Error creating motion device %d\n",
> > +				mdev->minor);
> > +		mutex_unlock(&motion_mtx);
> > +		goto error_free_trig_info;
> > +	}
> > +	list_add_tail(&mdev->list, &motion_list);
> > +	mutex_unlock(&motion_mtx);
> > +
> > +	return 0;
> > +
> > +error_free_trig_info:
> > +	kfree(trig_info);
> > +error_free_trigger:
> > +	iio_trigger_free(mdev->iiotrig);
> > +error_free_minor:
> > +	motion_minor_free(mdev->minor);
> > +	dev_info(mdev->parent, "Registering motion device err=%d\n", err);
> > +	return err;
> > +}
> > +EXPORT_SYMBOL(motion_register_device);
> > [...]
> > +struct mot_capabilities {
> > +	__u32 features;
> > +	__u8 type;
> > +	__u8 num_channels;
> > +	__u8 num_int_triggers;
> > +	__u8 num_ext_triggers;
> > +	__u8 max_profiles;
> > +	__u8 max_vpoints;
> > +	__u8 max_apoints;
> > +	__u8 reserved1;
> > +	__u32 subdiv; /* Position unit sub-divisions, microsteps, etc... */
> > +	/*
> > +	 * Coefficients for converting to/from controller time <--> seconds.
> > +	 * Speed[1/s] = Speed[controller_units] * conv_mul / conv_div
> > +	 * Accel[1/s^2] = Accel[controller_units] * conv_mul / conv_div
> > +	 */
> > +	__u32 speed_conv_mul;
> > +	__u32 speed_conv_div;
> > +	__u32 accel_conv_mul;
> > +	__u32 accel_conv_div;
> > +	__u32 reserved2;
> > +};  
> 
> https://docs.kernel.org/gpu/imagination/uapi.html (which has some
> generic bits that apply here, too) has: "The overall struct must be
> padded to 64-bit alignment." If you drop reserved2 the struct is
> properly sized (or I counted wrongly).

Oh, thanks for pointing that out... I wouldn't have searched for that
information in that particular place tbh. ;-)

I am tempted to add another __u32 reserved3 though instead. Better to have
some leeway if something needs to be added in a backwards-compatible way later.

> > +struct mot_speed_duration {
> > +	__u32 channel;
> > +	speed_raw_t speed;  
> 
> What is the unit here?

Speed doesn't have a fixed unit in this case. Or rather, the unit is
device-dependent. For a motor it could be rotations per second, micro-steps per
second, etc... while for a linear actuator, it could be micrometers per second.

Why no fixed unit? That's because in practice many devices (controllers) have
their inherent base-unit, and it would get overly complicated if one needed to
convert back and forth between that and some universal unit just for the sake
of uniformity, and user-space most certainly expects the same unit as the
hardware device it was initially designed for. So in this case it is a design
decision to make user-space deal with unit-conversion if it is necessary to do
so.

> > +	mot_time_t duration;  
> 
> duration_ns? That makes usage much more ideomatic and there should be no
> doubts what the unit is.

Yes, mot_time_t is defined as nanoseconds, so I'll add the _ns suffix here.

> > +	pos_raw_t distance;  
> 
> What is the unit here?

Again this unit can have different meanings: micrometers, micro-steps,
angle-degrees, etc... so what suffix to use?

> > +	__u32 reserved[3];  
> 
> Again the padding is wrong here.

Will fix. thanks.
 
Best regards,

-- 
David Jander

  reply	other threads:[~2025-03-05 15:40 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-27 16:28 [RFC PATCH 0/7] Add Linux Motion Control subsystem David Jander
2025-02-27 16:28 ` [RFC PATCH 1/7] drivers: Add motion control subsystem David Jander
2025-02-28 16:44   ` Uwe Kleine-König
2025-03-05 15:40     ` David Jander [this message]
2025-03-05 23:21       ` Uwe Kleine-König
2025-03-06  7:18         ` Greg Kroah-Hartman
2025-03-06  8:20           ` David Jander
2025-03-06  9:03             ` Greg Kroah-Hartman
2025-03-06  9:34               ` David Jander
2025-03-06 13:39                 ` Greg Kroah-Hartman
2025-03-06 14:25                   ` David Jander
2025-03-06 14:54                     ` Greg Kroah-Hartman
2025-03-06  9:25         ` David Jander
2025-03-09 17:32           ` Jonathan Cameron
2025-03-10  8:45             ` David Jander
2025-02-28 22:36   ` David Lechner
2025-03-03  8:36     ` David Jander
2025-03-03 11:01       ` Pavel Pisa
2025-03-03 16:04         ` David Jander
2025-02-27 16:28 ` [RFC PATCH 2/7] motion: Add ADI/Trinamic TMC5240 stepper motor controller David Jander
2025-02-27 16:28 ` [RFC PATCH 3/7] motion: Add simple-pwm.c PWM based DC motor controller driver David Jander
2025-02-27 16:28 ` [RFC PATCH 4/7] Documentation: Add Linux Motion Control documentation David Jander
2025-02-27 16:37   ` Jonathan Corbet
2025-02-28 13:02     ` David Jander
2025-02-28 14:42       ` Jonathan Corbet
2025-02-28 15:06         ` David Jander
2025-02-27 16:28 ` [RFC PATCH 5/7] dt-bindings: motion: Add common motion device properties David Jander
2025-02-28  7:06   ` Krzysztof Kozlowski
2025-02-28  7:13   ` Krzysztof Kozlowski
2025-02-27 16:28 ` [RFC PATCH 6/7] dt-bindings: motion: Add adi,tmc5240 bindings David Jander
2025-02-28  7:11   ` Krzysztof Kozlowski
2025-02-28  8:48     ` David Jander
2025-02-28  9:35       ` Krzysztof Kozlowski
2025-02-28  9:51         ` David Jander
2025-02-28 14:01           ` Krzysztof Kozlowski
2025-02-28 22:38   ` David Lechner
2025-03-03 11:22     ` David Jander
2025-03-03 12:28       ` David Lechner
2025-03-03 13:18         ` David Jander
2025-02-27 16:28 ` [RFC PATCH 7/7] dt-bindings: motion: Add motion-simple-pwm bindings David Jander
2025-02-27 17:38   ` Rob Herring (Arm)
2025-02-28  7:12   ` Krzysztof Kozlowski
2025-02-28  9:22     ` David Jander
2025-02-28  9:37       ` Krzysztof Kozlowski
2025-02-28 10:09         ` David Jander
2025-02-28 15:18           ` Uwe Kleine-König
2025-03-03 10:53             ` Maud Spierings
2025-03-03 11:40             ` David Jander
2025-03-03 14:18               ` Krzysztof Kozlowski
2025-03-03 16:09                 ` David Jander
2025-02-28 22:41   ` David Lechner
2025-03-03 12:54     ` David Jander
2025-02-28  9:34 ` [RFC PATCH 0/7] Add Linux Motion Control subsystem Pavel Pisa
2025-02-28  9:35 ` Pavel Pisa
2025-02-28 11:57   ` David Jander
2025-02-28 15:23     ` Pavel Pisa
2025-03-03 10:45       ` David Jander
2025-02-28 22:36 ` David Lechner
2025-03-03  8:28   ` David Jander

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250305164046.4de5b6ef@erd003.prtnl \
    --to=david@protonic.nl \
    --cc=conor+dt@kernel.org \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=jic23@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nuno.sa@analog.com \
    --cc=o.rempel@pengutronix.de \
    --cc=robh@kernel.org \
    --cc=u.kleine-koenig@baylibre.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.