mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
Pull driver core updates from Danilo Krummrich:
"container_of:
- Apply typeof_member(), remove the local __mptr variable to
eliminate variable shadowing warnings on nested container_of()
calls, and remove unnecessary parentheses
core:
- Add driver name to probe debug print for initcall_debug
- Avoid repeatedly printing the same 'Fixed dependency cycle' log
- Unwind device_add() on attribute creation failure in
attribute_container_add_class_device()
- Remove statistics group if encryption group creation fails in
transport_add_class_device()
debugfs:
- Fix lockdown check for mmap_prepare()
- Warn if file creation failed due to uninitialized debugfs
device property:
- Implement fw_devlink support for software nodes by adding
software_node_add_links(), which creates fwnode links from
DEV_PROP_REF properties to enable automatic probe ordering. Add
kunit-managed fwnode helpers and test coverage
- Fix infinite loop in fwnode_for_each_child_node() when the
secondary fwnode has more than one child. Add test cases
- Fix out-of-bounds access in software_node_get_reference_args() when
called with index -1 (UINT_MAX)
- Refactor to use RAII approach with __free()
- Add Bartosz Golaszewski as software node reviewer
firmware loader:
- Fix race where a sysfs fallback request can complete before being
queued as pending, leading to a use-after-free on the next fallback
request
- Reject 0-size built-in firmware and fail the build on empty
firmware files in CONFIG_EXTRA_FIRMWARE
kobject:
- Provide __KOBJ_ATTR() and __KOBJ_ATTR_RO/WO() initialization macros
and allow the constification of kobject attributes, enabling them
to reside in read-only memory
platform:
- Provide platform_device_set_of_node(), platform_device_set_fwnode(),
and platform_device_set_of_node_from_dev() helpers that encapsulate
firmware node reference counting for dynamically allocated platform
devices
Convert all in-tree users that manually assigned dev.of_node or
dev.fwnode, fixing a pre-existing refcount bug in powermac. Switch
to counting references of all firmware node types, not only OF
nodes
- Unify the release path for dynamically allocated platform devices
by removing platform_device_release_full(). Amend the fwnode setter
API contract to warn if a primary software node is overwritten. Add
KUnit tests for correct software node removal on device
unregistration
Rust:
- Auxiliary:
- Add registration_data_with() closure-based API for invariant
ForLt types
- Debugfs:
- Migrate BinaryWriter and BinaryReaderMut trait requirements
from kernel::transmute traits to zerocopy traits
- Device:
- Add BoundInternal device context and InternalBoundContext trait
for bus abstractions that need internal access to a bound
device.
- Make the lifetime on Core and CoreInternal invariant to prevent
coercion to shorter lifetimes
- Devres:
- Fix race between concurrent revokers where the losing revoker
could return before the winning revoker finished dropping the
inner data, causing use-after-free.
- Ensure revocation is complete before the device finishes
unbinding by making the synchronization bidirectional.
- Add DevresLt<F: ForLt>, a wrapper around Devres that shortens
'static back to the caller's borrow scope. Implement ForLt and
CovariantForLt for Bar, IoMem, and ExclusiveIoMem
- Driver:
- Switch from index-based to pointer-based device ID info lookup,
storing static references in driver_data. Centralize device ID
handling in device_id.rs, removing the open-coded ACPI/OF
matching logic and duplicate ID table from driver.rs
- I/O:
- Make I/O regions typed (with a dynamically-sized Region type
for the existing untyped case), create view types representing
subregions of a mapped I/O region, and add io_project!() for
safely creating subviews.
- Split Io into a base trait (IoBase) and an extension trait (Io)
with a blanket implementation, preventing implementers from
overriding provided methods that unsafe code relies on.
- Add a SysMem backend for shared system memory with volatile
access, and make Coherent implement Io via an I/O view type.
Add IoSysMap as sum type of Mmio and SysMem. Add copying
methods (memcpy_{from,to}io()) and read_val()/write_val() for
typed access.
- Replace dma_read!()/dma_write!() with io_read!()/io_write!()
for primitives and copying methods for aggregates; drop the old
macros. Convert nova-core to use I/O projection.
- Fix internal shortcut rule dispatch in the register!() macro,
remove unused rule arguments, and use path fragments for alias
destinations
- IRQ:
- Make irq::Registration compatible with lifetime-bound drivers
by removing the 'static bound on Handler/ThreadedHandler and
replacing Devres<RegistrationInner> with direct
request_irq()/free_irq() calls. Handlers can now directly own
lifetime-bound device resources
- PCI:
- Convert IrqVectorRegistration to a lifetime-annotated owning
type, giving drivers explicit control over the allocation
lifetime. IrqVector embeds a resolved IrqRequest, making the
conversion infallible. Remove the redundant
request_irq()/request_threaded_irq() wrappers from pci::Device.
- Add pci_irq_type() C helper and expose it via irq_type() on
IrqVectorRegistration and IrqVector, returning PCI_IRQ_MSIX,
PCI_IRQ_MSI, or PCI_IRQ_INTX.
- Mark pci::Device refcount methods inline
- Serdev:
- Add Rust abstractions for the serial device bus, including
serdev::Driver trait, serdev::Device wrapping struct
serdev_device, and serdev::Adapter implementing
RegistrationOps. Includes a sample driver. Markus Probst takes
over as serdev maintainer for both C and Rust code
- Misc:
- Split ForLt into a base trait (providing the Of<'a> GAT) and an
unsafe CovariantForLt subtrait guaranteeing covariance,
enabling invariant types (e.g. those containing Mutex<&'bound T>)
to participate in the ForLt abstraction.
- Fix Coherent read past EOF returning -ERANGE instead of zero.
- Fix firmware example UB by avoiding null-pointer ARef
misc:
- Avoid iattr allocation in kernfs listxattr by using
kernfs_iattrs_noalloc().
- Unregister SoC bus on early device registration failure.
- Remove unused DMA_FENCE_TRACE Kconfig symbol.
- Fix /sys/module path in comment.
- Refactor ISA bus init to remove nested blocks.
- Remove redundant nodemask clears in numa_init().
- Add kernel-doc for fwnode_operations and sys_soc.h, mark
internal property data as private for kernel-doc, and add
property.h/fwnode.h to driver-api infrastructure docs.
- Add MAINTAINERS entry for sys_soc.h"
* tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (129 commits)
rust: pci: expose the allocated interrupt type
PCI: Add pci_irq_type() to query the allocated interrupt type
rust: pci: remove request_irq() and request_threaded_irq() from Device
rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector
rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
kernfs: avoid iattr allocation in listxattr
rust: serdev: use ThisModule::as_ptr() instead of field access
ACPI/IORT: use platform_device_set_fwnode()
ACPI/APMT: use platform_device_set_fwnode()
firmware_loader: do not queue completed sysfs fallback requests
rust: pci: Mark Device refcount methods inline
rust: irq: make Registration compatible with lifetime-bound drivers
rust: net/phy: remove expansion from doc
rust: dma: return zero for Coherent reads past EOF
rust: io: register: use path fragment for alias destination
rust: io: register: remove unused rule arguments
rust: io: register: dispatch shortcut rules internally
MAINTAINERS: add sys_soc.h to DRIVER CORE
rust: debugfs: remove unsafe blocks from traits impl for Vec
rust: debugfs: migrate debugfs traits requirements to zerocopy
...
183 lines
4.0 KiB
C
183 lines
4.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* ARM APMT table support.
|
|
* Design document number: ARM DEN0117.
|
|
*
|
|
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
|
|
*
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "ACPI: APMT: " fmt
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/platform_device.h>
|
|
#include "init.h"
|
|
|
|
#define DEV_NAME "arm-cs-arch-pmu"
|
|
|
|
/* There can be up to 3 resources: page 0 and 1 address, and interrupt. */
|
|
#define DEV_MAX_RESOURCE_COUNT 3
|
|
|
|
/* Root pointer to the mapped APMT table */
|
|
static struct acpi_table_header *apmt_table;
|
|
|
|
static int __init apmt_init_resources(struct resource *res,
|
|
struct acpi_apmt_node *node)
|
|
{
|
|
int irq, trigger;
|
|
int num_res = 0;
|
|
|
|
res[num_res].start = node->base_address0;
|
|
res[num_res].end = node->base_address0 + SZ_4K - 1;
|
|
res[num_res].flags = IORESOURCE_MEM;
|
|
|
|
num_res++;
|
|
|
|
if (node->flags & ACPI_APMT_FLAGS_DUAL_PAGE) {
|
|
res[num_res].start = node->base_address1;
|
|
res[num_res].end = node->base_address1 + SZ_4K - 1;
|
|
res[num_res].flags = IORESOURCE_MEM;
|
|
|
|
num_res++;
|
|
}
|
|
|
|
if (node->ovflw_irq != 0) {
|
|
trigger = (node->ovflw_irq_flags & ACPI_APMT_OVFLW_IRQ_FLAGS_MODE);
|
|
trigger = (trigger == ACPI_APMT_OVFLW_IRQ_FLAGS_MODE_LEVEL) ?
|
|
ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
|
|
irq = acpi_register_gsi(NULL, node->ovflw_irq, trigger,
|
|
ACPI_ACTIVE_HIGH);
|
|
|
|
if (irq <= 0) {
|
|
pr_warn("APMT could not register gsi hwirq %d\n", irq);
|
|
return num_res;
|
|
}
|
|
|
|
res[num_res].start = irq;
|
|
res[num_res].end = irq;
|
|
res[num_res].flags = IORESOURCE_IRQ;
|
|
|
|
num_res++;
|
|
}
|
|
|
|
return num_res;
|
|
}
|
|
|
|
/**
|
|
* apmt_add_platform_device() - Allocate a platform device for APMT node
|
|
* @node: Pointer to device ACPI APMT node
|
|
* @fwnode: fwnode associated with the APMT node
|
|
*
|
|
* Returns: 0 on success, <0 failure
|
|
*/
|
|
static int __init apmt_add_platform_device(struct acpi_apmt_node *node,
|
|
struct fwnode_handle *fwnode)
|
|
{
|
|
struct platform_device *pdev;
|
|
int ret, count, uid = node->id & INT_MAX;
|
|
struct resource res[DEV_MAX_RESOURCE_COUNT];
|
|
|
|
if (uid != node->id)
|
|
pr_warn("Unexpectedly large UID 0x%x, truncated to 0x%x\n", node->id, uid);
|
|
pdev = platform_device_alloc(DEV_NAME, uid);
|
|
if (!pdev)
|
|
return -ENOMEM;
|
|
|
|
memset(res, 0, sizeof(res));
|
|
|
|
count = apmt_init_resources(res, node);
|
|
|
|
ret = platform_device_add_resources(pdev, res, count);
|
|
if (ret)
|
|
goto dev_put;
|
|
|
|
/*
|
|
* Add a copy of APMT node pointer to platform_data to be used to
|
|
* retrieve APMT data information.
|
|
*/
|
|
ret = platform_device_add_data(pdev, &node, sizeof(node));
|
|
if (ret)
|
|
goto dev_put;
|
|
|
|
platform_device_set_fwnode(pdev, fwnode);
|
|
|
|
ret = platform_device_add(pdev);
|
|
|
|
if (ret)
|
|
goto dev_put;
|
|
|
|
return 0;
|
|
|
|
dev_put:
|
|
platform_device_put(pdev);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int __init apmt_init_platform_devices(void)
|
|
{
|
|
struct acpi_apmt_node *apmt_node;
|
|
struct acpi_table_apmt *apmt;
|
|
struct fwnode_handle *fwnode;
|
|
u64 offset, end;
|
|
int ret;
|
|
|
|
/*
|
|
* apmt_table and apmt both point to the start of APMT table, but
|
|
* have different struct types
|
|
*/
|
|
apmt = (struct acpi_table_apmt *)apmt_table;
|
|
offset = sizeof(*apmt);
|
|
end = apmt->header.length;
|
|
|
|
while (offset < end) {
|
|
apmt_node = ACPI_ADD_PTR(struct acpi_apmt_node, apmt,
|
|
offset);
|
|
|
|
fwnode = acpi_alloc_fwnode_static();
|
|
if (!fwnode)
|
|
return -ENOMEM;
|
|
|
|
ret = apmt_add_platform_device(apmt_node, fwnode);
|
|
if (ret) {
|
|
acpi_free_fwnode_static(fwnode);
|
|
return ret;
|
|
}
|
|
|
|
offset += apmt_node->length;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __init acpi_apmt_init(void)
|
|
{
|
|
acpi_status status;
|
|
int ret;
|
|
|
|
/**
|
|
* APMT table nodes will be used at runtime after the apmt init,
|
|
* so we don't need to call acpi_put_table() to release
|
|
* the APMT table mapping.
|
|
*/
|
|
status = acpi_get_table(ACPI_SIG_APMT, 0, &apmt_table);
|
|
|
|
if (ACPI_FAILURE(status)) {
|
|
if (status != AE_NOT_FOUND) {
|
|
const char *msg = acpi_format_exception(status);
|
|
|
|
pr_err("Failed to get APMT table, %s\n", msg);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ret = apmt_init_platform_devices();
|
|
if (ret) {
|
|
pr_err("Failed to initialize APMT platform devices, ret: %d\n", ret);
|
|
acpi_put_table(apmt_table);
|
|
}
|
|
}
|