cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

platform_early.c (9050B)


      1// SPDX--License-Identifier: GPL-2.0
      2
      3#include <asm/platform_early.h>
      4#include <linux/mod_devicetable.h>
      5#include <linux/pm.h>
      6
      7static __initdata LIST_HEAD(sh_early_platform_driver_list);
      8static __initdata LIST_HEAD(sh_early_platform_device_list);
      9
     10static const struct platform_device_id *
     11platform_match_id(const struct platform_device_id *id,
     12		  struct platform_device *pdev)
     13{
     14	while (id->name[0]) {
     15		if (strcmp(pdev->name, id->name) == 0) {
     16			pdev->id_entry = id;
     17			return id;
     18		}
     19		id++;
     20	}
     21	return NULL;
     22}
     23
     24static int platform_match(struct device *dev, struct device_driver *drv)
     25{
     26	struct platform_device *pdev = to_platform_device(dev);
     27	struct platform_driver *pdrv = to_platform_driver(drv);
     28
     29	/* When driver_override is set, only bind to the matching driver */
     30	if (pdev->driver_override)
     31		return !strcmp(pdev->driver_override, drv->name);
     32
     33	/* Then try to match against the id table */
     34	if (pdrv->id_table)
     35		return platform_match_id(pdrv->id_table, pdev) != NULL;
     36
     37	/* fall-back to driver name match */
     38	return (strcmp(pdev->name, drv->name) == 0);
     39}
     40
     41#ifdef CONFIG_PM
     42static void device_pm_init_common(struct device *dev)
     43{
     44	if (!dev->power.early_init) {
     45		spin_lock_init(&dev->power.lock);
     46		dev->power.qos = NULL;
     47		dev->power.early_init = true;
     48	}
     49}
     50
     51static void pm_runtime_early_init(struct device *dev)
     52{
     53	dev->power.disable_depth = 1;
     54	device_pm_init_common(dev);
     55}
     56#else
     57static void pm_runtime_early_init(struct device *dev) {}
     58#endif
     59
     60/**
     61 * sh_early_platform_driver_register - register early platform driver
     62 * @epdrv: sh_early_platform driver structure
     63 * @buf: string passed from early_param()
     64 *
     65 * Helper function for sh_early_platform_init() / sh_early_platform_init_buffer()
     66 */
     67int __init sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
     68					  char *buf)
     69{
     70	char *tmp;
     71	int n;
     72
     73	/* Simply add the driver to the end of the global list.
     74	 * Drivers will by default be put on the list in compiled-in order.
     75	 */
     76	if (!epdrv->list.next) {
     77		INIT_LIST_HEAD(&epdrv->list);
     78		list_add_tail(&epdrv->list, &sh_early_platform_driver_list);
     79	}
     80
     81	/* If the user has specified device then make sure the driver
     82	 * gets prioritized. The driver of the last device specified on
     83	 * command line will be put first on the list.
     84	 */
     85	n = strlen(epdrv->pdrv->driver.name);
     86	if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
     87		list_move(&epdrv->list, &sh_early_platform_driver_list);
     88
     89		/* Allow passing parameters after device name */
     90		if (buf[n] == '\0' || buf[n] == ',')
     91			epdrv->requested_id = -1;
     92		else {
     93			epdrv->requested_id = simple_strtoul(&buf[n + 1],
     94							     &tmp, 10);
     95
     96			if (buf[n] != '.' || (tmp == &buf[n + 1])) {
     97				epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
     98				n = 0;
     99			} else
    100				n += strcspn(&buf[n + 1], ",") + 1;
    101		}
    102
    103		if (buf[n] == ',')
    104			n++;
    105
    106		if (epdrv->bufsize) {
    107			memcpy(epdrv->buffer, &buf[n],
    108			       min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
    109			epdrv->buffer[epdrv->bufsize - 1] = '\0';
    110		}
    111	}
    112
    113	return 0;
    114}
    115
    116/**
    117 * sh_early_platform_add_devices - adds a number of early platform devices
    118 * @devs: array of early platform devices to add
    119 * @num: number of early platform devices in array
    120 *
    121 * Used by early architecture code to register early platform devices and
    122 * their platform data.
    123 */
    124void __init sh_early_platform_add_devices(struct platform_device **devs, int num)
    125{
    126	struct device *dev;
    127	int i;
    128
    129	/* simply add the devices to list */
    130	for (i = 0; i < num; i++) {
    131		dev = &devs[i]->dev;
    132
    133		if (!dev->devres_head.next) {
    134			pm_runtime_early_init(dev);
    135			INIT_LIST_HEAD(&dev->devres_head);
    136			list_add_tail(&dev->devres_head,
    137				      &sh_early_platform_device_list);
    138		}
    139	}
    140}
    141
    142/**
    143 * sh_early_platform_driver_register_all - register early platform drivers
    144 * @class_str: string to identify early platform driver class
    145 *
    146 * Used by architecture code to register all early platform drivers
    147 * for a certain class. If omitted then only early platform drivers
    148 * with matching kernel command line class parameters will be registered.
    149 */
    150void __init sh_early_platform_driver_register_all(char *class_str)
    151{
    152	/* The "class_str" parameter may or may not be present on the kernel
    153	 * command line. If it is present then there may be more than one
    154	 * matching parameter.
    155	 *
    156	 * Since we register our early platform drivers using early_param()
    157	 * we need to make sure that they also get registered in the case
    158	 * when the parameter is missing from the kernel command line.
    159	 *
    160	 * We use parse_early_options() to make sure the early_param() gets
    161	 * called at least once. The early_param() may be called more than
    162	 * once since the name of the preferred device may be specified on
    163	 * the kernel command line. sh_early_platform_driver_register() handles
    164	 * this case for us.
    165	 */
    166	parse_early_options(class_str);
    167}
    168
    169/**
    170 * sh_early_platform_match - find early platform device matching driver
    171 * @epdrv: early platform driver structure
    172 * @id: id to match against
    173 */
    174static struct platform_device * __init
    175sh_early_platform_match(struct sh_early_platform_driver *epdrv, int id)
    176{
    177	struct platform_device *pd;
    178
    179	list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
    180		if (platform_match(&pd->dev, &epdrv->pdrv->driver))
    181			if (pd->id == id)
    182				return pd;
    183
    184	return NULL;
    185}
    186
    187/**
    188 * sh_early_platform_left - check if early platform driver has matching devices
    189 * @epdrv: early platform driver structure
    190 * @id: return true if id or above exists
    191 */
    192static int __init sh_early_platform_left(struct sh_early_platform_driver *epdrv,
    193				       int id)
    194{
    195	struct platform_device *pd;
    196
    197	list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
    198		if (platform_match(&pd->dev, &epdrv->pdrv->driver))
    199			if (pd->id >= id)
    200				return 1;
    201
    202	return 0;
    203}
    204
    205/**
    206 * sh_early_platform_driver_probe_id - probe drivers matching class_str and id
    207 * @class_str: string to identify early platform driver class
    208 * @id: id to match against
    209 * @nr_probe: number of platform devices to successfully probe before exiting
    210 */
    211static int __init sh_early_platform_driver_probe_id(char *class_str,
    212						 int id,
    213						 int nr_probe)
    214{
    215	struct sh_early_platform_driver *epdrv;
    216	struct platform_device *match;
    217	int match_id;
    218	int n = 0;
    219	int left = 0;
    220
    221	list_for_each_entry(epdrv, &sh_early_platform_driver_list, list) {
    222		/* only use drivers matching our class_str */
    223		if (strcmp(class_str, epdrv->class_str))
    224			continue;
    225
    226		if (id == -2) {
    227			match_id = epdrv->requested_id;
    228			left = 1;
    229
    230		} else {
    231			match_id = id;
    232			left += sh_early_platform_left(epdrv, id);
    233
    234			/* skip requested id */
    235			switch (epdrv->requested_id) {
    236			case EARLY_PLATFORM_ID_ERROR:
    237			case EARLY_PLATFORM_ID_UNSET:
    238				break;
    239			default:
    240				if (epdrv->requested_id == id)
    241					match_id = EARLY_PLATFORM_ID_UNSET;
    242			}
    243		}
    244
    245		switch (match_id) {
    246		case EARLY_PLATFORM_ID_ERROR:
    247			pr_warn("%s: unable to parse %s parameter\n",
    248				class_str, epdrv->pdrv->driver.name);
    249			fallthrough;
    250		case EARLY_PLATFORM_ID_UNSET:
    251			match = NULL;
    252			break;
    253		default:
    254			match = sh_early_platform_match(epdrv, match_id);
    255		}
    256
    257		if (match) {
    258			/*
    259			 * Set up a sensible init_name to enable
    260			 * dev_name() and others to be used before the
    261			 * rest of the driver core is initialized.
    262			 */
    263			if (!match->dev.init_name && slab_is_available()) {
    264				if (match->id != -1)
    265					match->dev.init_name =
    266						kasprintf(GFP_KERNEL, "%s.%d",
    267							  match->name,
    268							  match->id);
    269				else
    270					match->dev.init_name =
    271						kasprintf(GFP_KERNEL, "%s",
    272							  match->name);
    273
    274				if (!match->dev.init_name)
    275					return -ENOMEM;
    276			}
    277
    278			if (epdrv->pdrv->probe(match))
    279				pr_warn("%s: unable to probe %s early.\n",
    280					class_str, match->name);
    281			else
    282				n++;
    283		}
    284
    285		if (n >= nr_probe)
    286			break;
    287	}
    288
    289	if (left)
    290		return n;
    291	else
    292		return -ENODEV;
    293}
    294
    295/**
    296 * sh_early_platform_driver_probe - probe a class of registered drivers
    297 * @class_str: string to identify early platform driver class
    298 * @nr_probe: number of platform devices to successfully probe before exiting
    299 * @user_only: only probe user specified early platform devices
    300 *
    301 * Used by architecture code to probe registered early platform drivers
    302 * within a certain class. For probe to happen a registered early platform
    303 * device matching a registered early platform driver is needed.
    304 */
    305int __init sh_early_platform_driver_probe(char *class_str,
    306				       int nr_probe,
    307				       int user_only)
    308{
    309	int k, n, i;
    310
    311	n = 0;
    312	for (i = -2; n < nr_probe; i++) {
    313		k = sh_early_platform_driver_probe_id(class_str, i, nr_probe - n);
    314
    315		if (k < 0)
    316			break;
    317
    318		n += k;
    319
    320		if (user_only)
    321			break;
    322	}
    323
    324	return n;
    325}
    326
    327/**
    328 * early_platform_cleanup - clean up early platform code
    329 */
    330void __init early_platform_cleanup(void)
    331{
    332	struct platform_device *pd, *pd2;
    333
    334	/* clean up the devres list used to chain devices */
    335	list_for_each_entry_safe(pd, pd2, &sh_early_platform_device_list,
    336				 dev.devres_head) {
    337		list_del(&pd->dev.devres_head);
    338		memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
    339	}
    340}