linux_dsm_epyc7002/drivers/base/devcon.c
Suzuki K Poulose 418e3ea157 bus_find_device: Unify the match callback with class_find_device
There is an arbitrary difference between the prototypes of
bus_find_device() and class_find_device() preventing their callers
from passing the same pair of data and match() arguments to both of
them, which is the const qualifier used in the prototype of
class_find_device().  If that qualifier is also used in the
bus_find_device() prototype, it will be possible to pass the same
match() callback function to both bus_find_device() and
class_find_device(), which will allow some optimizations to be made in
order to avoid code duplication going forward.  Also with that, constify
the "data" parameter as it is passed as a const to the match function.

For this reason, change the prototype of bus_find_device() to match
the prototype of class_find_device() and adjust its callers to use the
const qualifier in accordance with the new prototype of it.

Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Andreas Noever <andreas.noever@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Corey Minyard <minyard@acm.org>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: David Kershner <david.kershner@unisys.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: David Airlie <airlied@linux.ie>
Cc: Felipe Balbi <balbi@kernel.org>
Cc: Frank Rowand <frowand.list@gmail.com>
Cc: Grygorii Strashko <grygorii.strashko@ti.com>
Cc: Harald Freudenberger <freude@linux.ibm.com>
Cc: Hartmut Knaack <knaack.h@gmx.de>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: "James E.J. Bottomley" <jejb@linux.ibm.com>
Cc: Len Brown <lenb@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michael Jamet <michael.jamet@intel.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Peter Oberparleiter <oberpar@linux.ibm.com>
Cc: Sebastian Ott <sebott@linux.ibm.com>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Cc: Yehezkel Bernat <YehezkelShB@gmail.com>
Cc: rafael@kernel.org
Acked-by: Corey Minyard <minyard@acm.org>
Acked-by: David Kershner <david.kershner@unisys.com>
Acked-by: Mark Brown <broonie@kernel.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Acked-by: Wolfram Sang <wsa@the-dreams.de> # for the I2C parts
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-06-24 05:22:31 +02:00

193 lines
4.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
/**
* Device connections
*
* Copyright (C) 2018 Intel Corporation
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
*/
#include <linux/device.h>
#include <linux/property.h>
static DEFINE_MUTEX(devcon_lock);
static LIST_HEAD(devcon_list);
typedef void *(*devcon_match_fn_t)(struct device_connection *con, int ep,
void *data);
static void *
fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct device_connection con = { .id = con_id };
struct fwnode_handle *ep;
void *ret;
fwnode_graph_for_each_endpoint(fwnode, ep) {
con.fwnode = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode_device_is_available(con.fwnode))
continue;
ret = match(&con, -1, data);
fwnode_handle_put(con.fwnode);
if (ret) {
fwnode_handle_put(ep);
return ret;
}
}
return NULL;
}
/**
* device_connection_find_match - Find physical connection to a device
* @dev: Device with the connection
* @con_id: Identifier for the connection
* @data: Data for the match function
* @match: Function to check and convert the connection description
*
* Find a connection with unique identifier @con_id between @dev and another
* device. @match will be used to convert the connection description to data the
* caller is expecting to be returned.
*/
void *device_connection_find_match(struct device *dev, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
const char *devname = dev_name(dev);
struct device_connection *con;
void *ret = NULL;
int ep;
if (!match)
return NULL;
if (fwnode) {
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
}
mutex_lock(&devcon_lock);
list_for_each_entry(con, &devcon_list, list) {
ep = match_string(con->endpoint, 2, devname);
if (ep < 0)
continue;
if (con_id && strcmp(con->id, con_id))
continue;
ret = match(con, !ep, data);
if (ret)
break;
}
mutex_unlock(&devcon_lock);
return ret;
}
EXPORT_SYMBOL_GPL(device_connection_find_match);
extern struct bus_type platform_bus_type;
extern struct bus_type pci_bus_type;
extern struct bus_type i2c_bus_type;
extern struct bus_type spi_bus_type;
static struct bus_type *generic_match_buses[] = {
&platform_bus_type,
#ifdef CONFIG_PCI
&pci_bus_type,
#endif
#ifdef CONFIG_I2C
&i2c_bus_type,
#endif
#ifdef CONFIG_SPI_MASTER
&spi_bus_type,
#endif
NULL,
};
static int device_fwnode_match(struct device *dev, const void *fwnode)
{
return dev_fwnode(dev) == fwnode;
}
static void *device_connection_fwnode_match(struct device_connection *con)
{
struct bus_type *bus;
struct device *dev;
for (bus = generic_match_buses[0]; bus; bus++) {
dev = bus_find_device(bus, NULL, (void *)con->fwnode,
device_fwnode_match);
if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id)))
return dev;
put_device(dev);
}
return NULL;
}
/* This tries to find the device from the most common bus types by name. */
static void *generic_match(struct device_connection *con, int ep, void *data)
{
struct bus_type *bus;
struct device *dev;
if (con->fwnode)
return device_connection_fwnode_match(con);
for (bus = generic_match_buses[0]; bus; bus++) {
dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]);
if (dev)
return dev;
}
/*
* We only get called if a connection was found, tell the caller to
* wait for the other device to show up.
*/
return ERR_PTR(-EPROBE_DEFER);
}
/**
* device_connection_find - Find two devices connected together
* @dev: Device with the connection
* @con_id: Identifier for the connection
*
* Find a connection with unique identifier @con_id between @dev and
* another device. On success returns handle to the device that is connected
* to @dev, with the reference count for the found device incremented. Returns
* NULL if no matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a
* connection was found but the other device has not been enumerated yet.
*/
struct device *device_connection_find(struct device *dev, const char *con_id)
{
return device_connection_find_match(dev, con_id, NULL, generic_match);
}
EXPORT_SYMBOL_GPL(device_connection_find);
/**
* device_connection_add - Register a connection description
* @con: The connection description to be registered
*/
void device_connection_add(struct device_connection *con)
{
mutex_lock(&devcon_lock);
list_add_tail(&con->list, &devcon_list);
mutex_unlock(&devcon_lock);
}
EXPORT_SYMBOL_GPL(device_connection_add);
/**
* device_connections_remove - Unregister connection description
* @con: The connection description to be unregistered
*/
void device_connection_remove(struct device_connection *con)
{
mutex_lock(&devcon_lock);
list_del(&con->list);
mutex_unlock(&devcon_lock);
}
EXPORT_SYMBOL_GPL(device_connection_remove);