File Index
Files and directories
Sign in
FILE

platform_early.c

File preview with syntax highlighting.

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