Skip to content

libmetal: lib: linux: improve Linux UIO-backed device open and test coverage#365

Open
bentheredonethat wants to merge 3 commits into
OpenAMP:mainfrom
bentheredonethat:uio-update
Open

libmetal: lib: linux: improve Linux UIO-backed device open and test coverage#365
bentheredonethat wants to merge 3 commits into
OpenAMP:mainfrom
bentheredonethat:uio-update

Conversation

@bentheredonethat
Copy link
Copy Markdown
Contributor

This series improves the Linux UIO-backed device-open flow in libmetal and
adds test coverage for the new API and Linux-specific helper paths.

The immediate motivation is to support Linux userspace applications that open
UIO-exposed devices through libmetal while keeping the existing bus/device
contract intact. In the current Linux implementation, the basic UIO path is
already present, but the backend is tightly coupled to bus probing, does not
cleanly separate resolved Linux device identities, does not unregister Linux
IRQ device state on close, and does not correctly retain the raw mapping
needed when a UIO map uses a non-zero offset.

This series addresses those gaps in three steps:

1. Add an explicit public helper,                                              
   metal_device_open_from_bus(), for bus/device based open while keeping       
   metal_device_open() as a compatibility wrapper.                             
                                                                               
2. Refactor the Linux UIO backend so it can populate a libmetal device         
   after resolving either a bus device name or a UIO class name, track the  
   resolved Linux identities more clearly, validate UIO map offsets, retain 
   raw mmap pointers for correct unmap, unregister Linux IRQ device state   
   on close, and tolerate Linux bus probe failure during metal_sys_init().  
                                                                               
3. Add cross-platform and Linux-specific tests for the new device-open         
   helper and the Linux UIO/IRQ bookkeeping helpers.                           

With these changes, downstream Linux host applications can continue to use
libmetal's device-open and IRQ registration model while relying on the
improved Linux UIO device handling in the library.

The public device-open API already takes bus and
device names, but the current interface does not
make that contract explicit. Add metal_device_open_from_bus()
as a named helper for bus/device based open and keep
metal_device_open() as a compatibility wrapper.

This makes the Linux bus-based device flow easier to
reference from downstream code without changing existing callers.

Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
Refactor the Linux UIO device path so the backend can
reuse the same population flow after resolving a device from either
a platform bus name or a UIO class name. Track the resolved
Linux identities separately, validate UIO map offsets,
retain the raw mmap pointers for correct unmap, and clear Linux
IRQ registration state when a device is closed.

Also make metal_sys_init() tolerate Linux bus probe failure so
Linux initialization can still complete even when bus-based
open is unavailable. This keeps the existing Linux UIO path
working while making it easier for downstream host applications
to use UIO-exposed devices.

Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
Add a standalone Linux system test for the device-open and Linux helper
paths added by the UIO-backed device open work.

The new test registers a temporary in-process bus and device to verify
metal_device_open_from_bus(), the existing metal_device_open()
compatibility wrapper, and expected error handling for invalid arguments,
missing buses, missing devices, and buses without dev_open callbacks.

It also covers the Linux-specific helper behavior without requiring real
UIO hardware by validating UIO map offset checks and exercising IRQ device
bookkeeping with an eventfd-backed IRQ. The IRQ coverage verifies that a
registered device is visible, enable state is tracked, and unregistering
the device clears both the device pointer and enabled state.

Only the Linux system test collection is updated so the coverage remains
isolated from the existing cross-platform tests.

Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
Comment thread lib/system/linux/device.c
#include <metal/utilities.h>
#include <metal/irq.h>

#include <stdbool.h>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit is quite large and difficult to understand if you are not familiar with the AMD implementation based on UIO, which is my case.

  • Could you split it into smaller, more readable commits?
  • Does it make sense to keep UIO support in the Linux subsystem, or is it specific to AMD?

Comment thread lib/system/linux/device.c
#include "irq.h"

#define MAX_DRIVERS 64
#define METAL_UIO_CLASS_PATH "/sys/class/uio"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does UIO support is required on the target in order to use OpenAMP in Linux user space?

Comment thread lib/system/linux/irq.h
void metal_linux_irq_register_dev(struct metal_device *dev, int irq);
void metal_linux_irq_unregister_dev(int irq);
struct metal_device *metal_linux_irq_get_dev(int irq);
int metal_linux_irq_is_enabled(int irq);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APIs should have a doxygen documentation header

Comment thread lib/system/linux/sys.h
void *output, int len);
int metal_linux_uio_validate_offset(const char *dev_name,
unsigned int index,
unsigned long offset);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doxygen documentation header

Comment thread lib/device.c

int metal_device_open(const char *bus_name, const char *dev_name,
struct metal_device **device)
int metal_device_open_from_bus(const char *bus_name, const char *dev_name,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand the need to create a new API. It looks to me like this introduces confusion by duplicating APIs instead of making things more obvious.

Having a single system-agnostic API makes more sense to me.

@bentheredonethat
Copy link
Copy Markdown
Contributor Author

Hi @arnopo

Thanks for the review. I agree the Linux change is too large as posted, and I can split it into smaller commits before respinning.

The main problem I am trying to solve is narrower than the current series makes it look. Linux userspace libmetal already opens platform/PCI devices through the existing Linux UIO-backed path.
Today applications have to pass the Linux bus device name, for example "ff360000.ipi". That name comes from the platform device/unit-address naming and is not a stable logical name across SoCs or
even across different instances.

For demos and portable userspace applications, we would like to use a logical name such as "demo-ipi". On systems using UIO, that logical name can be exposed by the kernel as the UIO class name,
for example:

  /sys/class/uio/uioX/name = demo-ipi

The Linux libmetal backend can then resolve that UIO class name back to the real bus device:

  demo-ipi
    -> /sys/class/uio/uioX/name
    -> /sys/class/uio/uioX/device
    -> /sys/bus/platform/devices/ff360000.ipi

and continue through the existing Linux bus open/bind/map/IRQ/close flow.

So the intended direction is not to make UIO mandatory for OpenAMP generally, and not to introduce a new Linux device model. It is only to let the existing Linux UIO backend accept the UIO class
name as an alias for the native bus device name.

I also agree with your comment about the new public API. The UIO-name use case does not require adding metal_device_open_from_bus(). I can drop that patch and keep the existing system-agnostic
API:

  metal_device_open("platform", "demo-ipi", &dev);

The Linux backend would interpret the device argument as either:

  1. the native bus device name, preserving existing behavior, or
  2. a UIO class-name alias, resolved internally to the native platform/PCI device.

Internally I plan to keep both identities clear, e.g. requested name / resolved bus device name / UIO name. For minimum behavior change, the returned device->name can remain the resolved native
bus device name; the UIO name is just an open-time alias.

For the respin, does the following direction sound acceptable?

  1. Drop the new metal_device_open_from_bus() public API.
  2. Split the Linux changes into smaller commits, likely:
    • UIO mmap offset validation and correct raw-pointer unmap tracking.
    • IRQ bookkeeping cleanup on device close.
    • UIO class-name alias resolution for the existing Linux UIO backend.
    • Tests and documentation updates.
  3. Include Doxygen comments in the same commits that introduce new internal Linux helpers.
  4. Clarify in the commit messages that UIO-name lookup is optional alias resolution for the existing Linux backend, not a requirement for OpenAMP Linux userspace in general.

If this direction makes sense, I will rework the series around that.

@arnopo
Copy link
Copy Markdown
Contributor

arnopo commented May 12, 2026

Hi @arnopo

Thanks for the review. I agree the Linux change is too large as posted, and I can split it into smaller commits before respinning.

The main problem I am trying to solve is narrower than the current series makes it look. Linux userspace libmetal already opens platform/PCI devices through the existing Linux UIO-backed path. Today applications have to pass the Linux bus device name, for example "ff360000.ipi". That name comes from the platform device/unit-address naming and is not a stable logical name across SoCs or even across different instances.

For demos and portable userspace applications, we would like to use a logical name such as "demo-ipi". On systems using UIO, that logical name can be exposed by the kernel as the UIO class name, for example:

  /sys/class/uio/uioX/name = demo-ipi

The Linux libmetal backend can then resolve that UIO class name back to the real bus device:

  demo-ipi
    -> /sys/class/uio/uioX/name
    -> /sys/class/uio/uioX/device
    -> /sys/bus/platform/devices/ff360000.ipi

and continue through the existing Linux bus open/bind/map/IRQ/close flow.

What about using symbolic link for that, as proposed by @tnmysh in OpenAMP/openamp-system-reference#101.
That would avoid resolution by /sys/class/uio/uioX/name if a /sys/class/uio/<name>/device symbolic is created with a udev rule.
Would it work in your case?

So the intended direction is not to make UIO mandatory for OpenAMP generally, and not to introduce a new Linux device model. It is only to let the existing Linux UIO backend accept the UIO class name as an alias for the native bus device name.

I also agree with your comment about the new public API. The UIO-name use case does not require adding metal_device_open_from_bus(). I can drop that patch and keep the existing system-agnostic API:

  metal_device_open("platform", "demo-ipi", &dev);

The Linux backend would interpret the device argument as either:

  1. the native bus device name, preserving existing behavior, or
  2. a UIO class-name alias, resolved internally to the native platform/PCI device.

Internally I plan to keep both identities clear, e.g. requested name / resolved bus device name / UIO name. For minimum behavior change, the returned device->name can remain the resolved native bus device name; the UIO name is just an open-time alias.

For the respin, does the following direction sound acceptable?

  1. Drop the new metal_device_open_from_bus() public API.

  2. Split the Linux changes into smaller commits, likely:

    • UIO mmap offset validation and correct raw-pointer unmap tracking.
    • IRQ bookkeeping cleanup on device close.
    • UIO class-name alias resolution for the existing Linux UIO backend.
    • Tests and documentation updates.
  3. Include Doxygen comments in the same commits that introduce new internal Linux helpers.

  4. Clarify in the commit messages that UIO-name lookup is optional alias resolution for the existing Linux backend, not a requirement for OpenAMP Linux userspace in general.

Sound good.

Thanks
arnaud

If this direction makes sense, I will rework the series around that.

@bentheredonethat
Copy link
Copy Markdown
Contributor Author

Thanks @arnopo, this is a good point.

Using a udev-created symlink such as:

/sys/class/uio/<logical-name>/device
would work in our use case and is a nice optimization when present, since it avoids scanning uioX/name.

For upstream libmetal, I would prefer to treat this as optional platform integration rather than a hard dependency, because not all deployments guarantee custom udev rules. So my plan is:

  1. keep the generic fallback that resolves via /sys/class/uio/uioX/name,
  2. optionally try the symlink path first when it exists.

That keeps behavior portable out of the box while allowing integrators to use the symlink approach for faster/cleaner lookup.

If you agree, I will document this in the commit message as “optional udev optimization, generic fallback preserved”.

@arnopo
Copy link
Copy Markdown
Contributor

arnopo commented May 12, 2026

Thanks @arnopo, this is a good point.

Using a udev-created symlink such as:

/sys/class/uio/<logical-name>/device would work in our use case and is a nice optimization when present, since it avoids scanning uioX/name.

For upstream libmetal, I would prefer to treat this as optional platform integration rather than a hard dependency, because not all deployments guarantee custom udev rules. So my plan is:

  1. keep the generic fallback that resolves via /sys/class/uio/uioX/name,
  2. optionally try the symlink path first when it exists.

That keeps behavior portable out of the box while allowing integrators to use the symlink approach for faster/cleaner lookup.

If you agree, I will document this in the commit message as “optional udev optimization, generic fallback preserved”.

I would prefer that we handle this in the same way we manage /dev/rpmsgX or /sys/class/remoteproc/remoteprocX devices, rather than adding it to libmetal.

I propose adding this PR to the agenda for the next OpenAMP meeting so we can discuss it further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants