linux/drivers/peci/core.c
Linus Torvalds c2a96b7f18 Driver core changes for 6.11-rc1
Here is the big set of driver core changes for 6.11-rc1.
 
 Lots of stuff in here, with not a huge diffstat, but apis are evolving
 which required lots of files to be touched.  Highlights of the changes
 in here are:
   - platform remove callback api final fixups (Uwe took many releases to
     get here, finally!)
   - Rust bindings for basic firmware apis and initial driver-core
     interactions.  It's not all that useful for a "write a whole driver
     in rust" type of thing, but the firmware bindings do help out the
     phy rust drivers, and the driver core bindings give a solid base on
     which others can start their work.  There is still a long way to go
     here before we have a multitude of rust drivers being added, but
     it's a great first step.
   - driver core const api changes.  This reached across all bus types,
     and there are some fix-ups for some not-common bus types that
     linux-next and 0-day testing shook out.  This work is being done to
     help make the rust bindings more safe, as well as the C code, moving
     toward the end-goal of allowing us to put driver structures into
     read-only memory.  We aren't there yet, but are getting closer.
   - minor devres cleanups and fixes found by code inspection
   - arch_topology minor changes
   - other minor driver core cleanups
 
 All of these have been in linux-next for a very long time with no
 reported problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZqH+aQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymoOQCfVBdLcBjEDAGh3L8qHRGMPy4rV2EAoL/r+zKm
 cJEYtJpGtWX6aAtugm9E
 =ZyJV
 -----END PGP SIGNATURE-----

Merge tag 'driver-core-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core updates from Greg KH:
 "Here is the big set of driver core changes for 6.11-rc1.

  Lots of stuff in here, with not a huge diffstat, but apis are evolving
  which required lots of files to be touched. Highlights of the changes
  in here are:

   - platform remove callback api final fixups (Uwe took many releases
     to get here, finally!)

   - Rust bindings for basic firmware apis and initial driver-core
     interactions.

     It's not all that useful for a "write a whole driver in rust" type
     of thing, but the firmware bindings do help out the phy rust
     drivers, and the driver core bindings give a solid base on which
     others can start their work.

     There is still a long way to go here before we have a multitude of
     rust drivers being added, but it's a great first step.

   - driver core const api changes.

     This reached across all bus types, and there are some fix-ups for
     some not-common bus types that linux-next and 0-day testing shook
     out.

     This work is being done to help make the rust bindings more safe,
     as well as the C code, moving toward the end-goal of allowing us to
     put driver structures into read-only memory. We aren't there yet,
     but are getting closer.

   - minor devres cleanups and fixes found by code inspection

   - arch_topology minor changes

   - other minor driver core cleanups

  All of these have been in linux-next for a very long time with no
  reported problems"

* tag 'driver-core-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (55 commits)
  ARM: sa1100: make match function take a const pointer
  sysfs/cpu: Make crash_hotplug attribute world-readable
  dio: Have dio_bus_match() callback take a const *
  zorro: make match function take a const pointer
  driver core: module: make module_[add|remove]_driver take a const *
  driver core: make driver_find_device() take a const *
  driver core: make driver_[create|remove]_file take a const *
  firmware_loader: fix soundness issue in `request_internal`
  firmware_loader: annotate doctests as `no_run`
  devres: Correct code style for functions that return a pointer type
  devres: Initialize an uninitialized struct member
  devres: Fix memory leakage caused by driver API devm_free_percpu()
  devres: Fix devm_krealloc() wasting memory
  driver core: platform: Switch to use kmemdup_array()
  driver core: have match() callback in struct bus_type take a const *
  MAINTAINERS: add Rust device abstractions to DRIVER CORE
  device: rust: improve safety comments
  MAINTAINERS: add Danilo as FIRMWARE LOADER maintainer
  MAINTAINERS: add Rust FW abstractions to FIRMWARE LOADER
  firmware: rust: improve safety comments
  ...
2024-07-25 10:42:22 -07:00

236 lines
5.4 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2021 Intel Corporation
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/peci.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/slab.h>
#include "internal.h"
static DEFINE_IDA(peci_controller_ida);
static void peci_controller_dev_release(struct device *dev)
{
struct peci_controller *controller = to_peci_controller(dev);
mutex_destroy(&controller->bus_lock);
ida_free(&peci_controller_ida, controller->id);
kfree(controller);
}
const struct device_type peci_controller_type = {
.release = peci_controller_dev_release,
};
int peci_controller_scan_devices(struct peci_controller *controller)
{
int ret;
u8 addr;
for (addr = PECI_BASE_ADDR; addr < PECI_BASE_ADDR + PECI_DEVICE_NUM_MAX; addr++) {
ret = peci_device_create(controller, addr);
if (ret)
return ret;
}
return 0;
}
static struct peci_controller *peci_controller_alloc(struct device *dev,
const struct peci_controller_ops *ops)
{
struct peci_controller *controller;
int ret;
if (!ops->xfer)
return ERR_PTR(-EINVAL);
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
return ERR_PTR(-ENOMEM);
ret = ida_alloc_max(&peci_controller_ida, U8_MAX, GFP_KERNEL);
if (ret < 0)
goto err;
controller->id = ret;
controller->ops = ops;
controller->dev.parent = dev;
controller->dev.bus = &peci_bus_type;
controller->dev.type = &peci_controller_type;
device_initialize(&controller->dev);
mutex_init(&controller->bus_lock);
return controller;
err:
kfree(controller);
return ERR_PTR(ret);
}
static int unregister_child(struct device *dev, void *dummy)
{
peci_device_destroy(to_peci_device(dev));
return 0;
}
static void unregister_controller(void *_controller)
{
struct peci_controller *controller = _controller;
/*
* Detach any active PECI devices. This can't fail, thus we do not
* check the returned value.
*/
device_for_each_child_reverse(&controller->dev, NULL, unregister_child);
device_unregister(&controller->dev);
fwnode_handle_put(controller->dev.fwnode);
pm_runtime_disable(&controller->dev);
}
/**
* devm_peci_controller_add() - add PECI controller
* @dev: device for devm operations
* @ops: pointer to controller specific methods
*
* In final stage of its probe(), peci_controller driver calls
* devm_peci_controller_add() to register itself with the PECI bus.
*
* Return: Pointer to the newly allocated controller or ERR_PTR() in case of failure.
*/
struct peci_controller *devm_peci_controller_add(struct device *dev,
const struct peci_controller_ops *ops)
{
struct peci_controller *controller;
int ret;
controller = peci_controller_alloc(dev, ops);
if (IS_ERR(controller))
return controller;
ret = dev_set_name(&controller->dev, "peci-%d", controller->id);
if (ret)
goto err_put;
pm_runtime_no_callbacks(&controller->dev);
pm_suspend_ignore_children(&controller->dev, true);
pm_runtime_enable(&controller->dev);
device_set_node(&controller->dev, fwnode_handle_get(dev_fwnode(dev)));
ret = device_add(&controller->dev);
if (ret)
goto err_fwnode;
ret = devm_add_action_or_reset(dev, unregister_controller, controller);
if (ret)
return ERR_PTR(ret);
/*
* Ignoring retval since failures during scan are non-critical for
* controller itself.
*/
peci_controller_scan_devices(controller);
return controller;
err_fwnode:
fwnode_handle_put(controller->dev.fwnode);
pm_runtime_disable(&controller->dev);
err_put:
put_device(&controller->dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
static const struct peci_device_id *
peci_bus_match_device_id(const struct peci_device_id *id, struct peci_device *device)
{
while (id->x86_vfm != 0) {
if (id->x86_vfm == device->info.x86_vfm)
return id;
id++;
}
return NULL;
}
static int peci_bus_device_match(struct device *dev, const struct device_driver *drv)
{
struct peci_device *device = to_peci_device(dev);
const struct peci_driver *peci_drv = to_peci_driver(drv);
if (dev->type != &peci_device_type)
return 0;
return !!peci_bus_match_device_id(peci_drv->id_table, device);
}
static int peci_bus_device_probe(struct device *dev)
{
struct peci_device *device = to_peci_device(dev);
struct peci_driver *driver = to_peci_driver(dev->driver);
return driver->probe(device, peci_bus_match_device_id(driver->id_table, device));
}
static void peci_bus_device_remove(struct device *dev)
{
struct peci_device *device = to_peci_device(dev);
struct peci_driver *driver = to_peci_driver(dev->driver);
if (driver->remove)
driver->remove(device);
}
const struct bus_type peci_bus_type = {
.name = "peci",
.match = peci_bus_device_match,
.probe = peci_bus_device_probe,
.remove = peci_bus_device_remove,
.bus_groups = peci_bus_groups,
};
static int __init peci_init(void)
{
int ret;
ret = bus_register(&peci_bus_type);
if (ret < 0) {
pr_err("peci: failed to register PECI bus type!\n");
return ret;
}
return 0;
}
module_init(peci_init);
static void __exit peci_exit(void)
{
bus_unregister(&peci_bus_type);
}
module_exit(peci_exit);
MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>");
MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
MODULE_DESCRIPTION("PECI bus core module");
MODULE_LICENSE("GPL");